@@ -1216,26 +1216,29 @@ impl<T: Config> Pallet<T> {
12161216 /// Dissolve all LPs and clean state.
12171217 pub fn do_dissolve_all_liquidity_providers ( netuid : NetUid ) -> DispatchResult {
12181218 if SwapV3Initialized :: < T > :: get ( netuid) {
1219- // 1) Snapshot (owner, position_id).
1219+ // 1) Snapshot only *non‑protocol* positions: (owner, position_id).
12201220 struct CloseItem < A > {
12211221 owner : A ,
12221222 pos_id : PositionId ,
12231223 }
1224+ let protocol_account = Self :: protocol_account_id ( ) ;
1225+
12241226 let mut to_close: sp_std:: vec:: Vec < CloseItem < T :: AccountId > > = sp_std:: vec:: Vec :: new ( ) ;
12251227 for ( ( owner, pos_id) , _pos) in Positions :: < T > :: iter_prefix ( ( netuid, ) ) {
1226- to_close. push ( CloseItem { owner, pos_id } ) ;
1228+ if owner != protocol_account {
1229+ to_close. push ( CloseItem { owner, pos_id } ) ;
1230+ }
12271231 }
12281232
1229- let protocol_account = Self :: protocol_account_id ( ) ;
1230-
1231- // Non‑protocol first
1232- to_close
1233- . sort_by ( |a, b| ( a. owner == protocol_account) . cmp ( & ( b. owner == protocol_account) ) ) ;
1233+ if to_close. is_empty ( ) {
1234+ log:: debug!(
1235+ "dissolve_all_lp: no user positions; netuid={netuid:?}, protocol liquidity untouched"
1236+ ) ;
1237+ return Ok ( ( ) ) ;
1238+ }
12341239
12351240 let mut user_refunded_tao = TaoCurrency :: ZERO ;
12361241 let mut user_staked_alpha = AlphaCurrency :: ZERO ;
1237- let mut burned_tao = TaoCurrency :: ZERO ;
1238- let mut burned_alpha = AlphaCurrency :: ZERO ;
12391242
12401243 let trust: Vec < u16 > = T :: SubnetInfo :: get_validator_trust ( netuid. into ( ) ) ;
12411244 let permit: Vec < bool > = T :: SubnetInfo :: get_validator_permit ( netuid. into ( ) ) ;
@@ -1271,65 +1274,50 @@ impl<T: Config> Pallet<T> {
12711274 let alpha_total_from_pool: AlphaCurrency =
12721275 rm. alpha . saturating_add ( rm. fee_alpha ) ;
12731276
1274- if owner == protocol_account {
1275- // ---------------- PROTOCOL: burn everything ----------------
1276- if rm. tao > TaoCurrency :: ZERO {
1277- burned_tao = burned_tao. saturating_add ( rm. tao ) ;
1278- }
1279- if alpha_total_from_pool > AlphaCurrency :: ZERO {
1280- burned_alpha = burned_alpha. saturating_add ( alpha_total_from_pool) ;
1281- }
1282- let tao = rm. tao ;
1283- log:: debug!(
1284- "dissolve_all_lp: burned protocol pos: netuid={netuid:?}, pos_id={pos_id:?}, τ={tao:?}, α_total={alpha_total_from_pool:?}"
1285- ) ;
1286- } else {
1287- // ---------------- USER: refund τ and convert α → τ ----------------
1288-
1289- // 1) Refund τ principal directly.
1290- if rm. tao > TaoCurrency :: ZERO {
1291- T :: BalanceOps :: increase_balance ( & owner, rm. tao ) ;
1292- user_refunded_tao = user_refunded_tao. saturating_add ( rm. tao ) ;
1293- T :: BalanceOps :: decrease_provided_tao_reserve ( netuid, rm. tao ) ;
1294- }
1277+ // ---------------- USER: refund τ and convert α → stake ----------------
12951278
1296- // 2) Stake ALL withdrawn α ( principal + fees) to the best permitted validator .
1297- if alpha_total_from_pool > AlphaCurrency :: ZERO {
1298- if let Some ( target_uid ) = pick_target_uid ( & trust , & permit ) {
1299- let validator_hotkey : T :: AccountId =
1300- T :: SubnetInfo :: hotkey_of_uid ( netuid. into ( ) , target_uid )
1301- . ok_or ( sp_runtime :: DispatchError :: Other (
1302- "validator_hotkey_missing" ,
1303- ) ) ? ;
1304-
1305- // Stake α from LP owner (coldkey) to chosen validator (hotkey).
1306- T :: BalanceOps :: increase_stake (
1307- & owner ,
1308- & validator_hotkey ,
1309- netuid ,
1310- alpha_total_from_pool ,
1279+ // 1) Refund τ principal directly .
1280+ if rm . tao > TaoCurrency :: ZERO {
1281+ T :: BalanceOps :: increase_balance ( & owner , rm . tao ) ;
1282+ user_refunded_tao = user_refunded_tao . saturating_add ( rm . tao ) ;
1283+ T :: BalanceOps :: decrease_provided_tao_reserve ( netuid, rm . tao ) ;
1284+ }
1285+
1286+ // 2) Stake ALL withdrawn α (principal + fees) to the best permitted validator.
1287+ if alpha_total_from_pool > AlphaCurrency :: ZERO {
1288+ if let Some ( target_uid ) = pick_target_uid ( & trust , & permit ) {
1289+ let validator_hotkey : T :: AccountId =
1290+ T :: SubnetInfo :: hotkey_of_uid ( netuid . into ( ) , target_uid ) . ok_or (
1291+ sp_runtime :: DispatchError :: Other (
1292+ "validator_hotkey_missing" ,
1293+ ) ,
13111294 ) ?;
13121295
1313- user_staked_alpha =
1314- user_staked_alpha. saturating_add ( alpha_total_from_pool) ;
1315-
1316- log:: debug!(
1317- "dissolve_all_lp: user dissolved & staked α: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_staked={alpha_total_from_pool:?}, target_uid={target_uid}"
1318- ) ;
1319- } else {
1320- // No permitted validators; burn to avoid balance drift.
1321- burned_alpha =
1322- burned_alpha. saturating_add ( alpha_total_from_pool) ;
1323- log:: debug!(
1324- "dissolve_all_lp: no permitted validators; α burned: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_total={alpha_total_from_pool:?}"
1325- ) ;
1326- }
1327-
1328- T :: BalanceOps :: decrease_provided_alpha_reserve (
1296+ // Stake α from LP owner (coldkey) to chosen validator (hotkey).
1297+ T :: BalanceOps :: increase_stake (
1298+ & owner,
1299+ & validator_hotkey,
13291300 netuid,
13301301 alpha_total_from_pool,
1302+ ) ?;
1303+
1304+ user_staked_alpha =
1305+ user_staked_alpha. saturating_add ( alpha_total_from_pool) ;
1306+
1307+ log:: debug!(
1308+ "dissolve_all_lp: user dissolved & staked α: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_staked={alpha_total_from_pool:?}, target_uid={target_uid}"
1309+ ) ;
1310+ } else {
1311+ // No permitted validators; burn to avoid balance drift.
1312+ log:: debug!(
1313+ "dissolve_all_lp: no permitted validators; α burned: netuid={netuid:?}, owner={owner:?}, pos_id={pos_id:?}, α_total={alpha_total_from_pool:?}"
13311314 ) ;
13321315 }
1316+
1317+ T :: BalanceOps :: decrease_provided_alpha_reserve (
1318+ netuid,
1319+ alpha_total_from_pool,
1320+ ) ;
13331321 }
13341322 }
13351323 Err ( e) => {
@@ -1341,41 +1329,74 @@ impl<T: Config> Pallet<T> {
13411329 }
13421330 }
13431331
1344- // 3) Clear active tick index entries, then all swap state.
1345- let active_ticks: sp_std:: vec:: Vec < TickIndex > =
1346- Ticks :: < T > :: iter_prefix ( netuid) . map ( |( ti, _) | ti) . collect ( ) ;
1347- for ti in active_ticks {
1348- ActiveTickIndexManager :: < T > :: remove ( netuid, ti) ;
1349- }
1332+ log:: debug!(
1333+ "dissolve_all_liquidity_providers (users-only): netuid={netuid:?}, users_refunded_total_τ={user_refunded_tao:?}, users_staked_total_α={user_staked_alpha:?}; protocol liquidity untouched"
1334+ ) ;
13501335
1351- let _ = Positions :: < T > :: clear_prefix ( ( netuid , ) , u32 :: MAX , None ) ;
1352- let _ = Ticks :: < T > :: clear_prefix ( netuid , u32 :: MAX , None ) ;
1336+ return Ok ( ( ) ) ;
1337+ }
13531338
1354- FeeGlobalTao :: < T > :: remove ( netuid) ;
1355- FeeGlobalAlpha :: < T > :: remove ( netuid) ;
1356- CurrentLiquidity :: < T > :: remove ( netuid) ;
1357- CurrentTick :: < T > :: remove ( netuid) ;
1358- AlphaSqrtPrice :: < T > :: remove ( netuid) ;
1359- SwapV3Initialized :: < T > :: remove ( netuid) ;
1339+ log:: debug!(
1340+ "dissolve_all_liquidity_providers: netuid={netuid:?}, mode=V2-or-nonV3, leaving all liquidity/state intact"
1341+ ) ;
13601342
1361- let _ = TickIndexBitmapWords :: < T > :: clear_prefix ( ( netuid, ) , u32:: MAX , None ) ;
1362- FeeRate :: < T > :: remove ( netuid) ;
1363- EnabledUserLiquidity :: < T > :: remove ( netuid) ;
1343+ Ok ( ( ) )
1344+ }
13641345
1365- log :: debug! (
1366- "dissolve_all_liquidity_providers: netuid={netuid:?}, users_refunded_total_τ={user_refunded_tao:?}, users_staked_total_α={user_staked_alpha:?}; protocol_burned: τ={burned_tao:?}, α={burned_alpha:?}; state cleared"
1367- ) ;
1346+ /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`.
1347+ pub fn do_clear_protocol_liquidity ( netuid : NetUid ) -> DispatchResult {
1348+ let protocol_account = Self :: protocol_account_id ( ) ;
13681349
1369- return Ok ( ( ) ) ;
1350+ // 1) Force-close only protocol positions, burning proceeds.
1351+ let mut burned_tao = TaoCurrency :: ZERO ;
1352+ let mut burned_alpha = AlphaCurrency :: ZERO ;
1353+
1354+ // Collect protocol position IDs first to avoid mutating while iterating.
1355+ let protocol_pos_ids: sp_std:: vec:: Vec < PositionId > = Positions :: < T > :: iter_prefix ( ( netuid, ) )
1356+ . filter_map ( |( ( owner, pos_id) , _) | {
1357+ if owner == protocol_account {
1358+ Some ( pos_id)
1359+ } else {
1360+ None
1361+ }
1362+ } )
1363+ . collect ( ) ;
1364+
1365+ for pos_id in protocol_pos_ids {
1366+ match Self :: do_remove_liquidity ( netuid, & protocol_account, pos_id) {
1367+ Ok ( rm) => {
1368+ let alpha_total_from_pool: AlphaCurrency =
1369+ rm. alpha . saturating_add ( rm. fee_alpha ) ;
1370+ let tao = rm. tao ;
1371+
1372+ if tao > TaoCurrency :: ZERO {
1373+ burned_tao = burned_tao. saturating_add ( tao) ;
1374+ }
1375+ if alpha_total_from_pool > AlphaCurrency :: ZERO {
1376+ burned_alpha = burned_alpha. saturating_add ( alpha_total_from_pool) ;
1377+ }
1378+
1379+ log:: debug!(
1380+ "clear_protocol_liquidity: burned protocol pos: netuid={netuid:?}, pos_id={pos_id:?}, τ={tao:?}, α_total={alpha_total_from_pool:?}"
1381+ ) ;
1382+ }
1383+ Err ( e) => {
1384+ log:: debug!(
1385+ "clear_protocol_liquidity: force-close failed: netuid={netuid:?}, pos_id={pos_id:?}, err={e:?}"
1386+ ) ;
1387+ continue ;
1388+ }
1389+ }
13701390 }
13711391
1372- // V2 / non‑V3: ensure V3 residues are cleared (safe no‑ops).
1373- let _ = Positions :: < T > :: clear_prefix ( ( netuid, ) , u32:: MAX , None ) ;
1392+ // 2) Clear active tick index entries, then all swap state (idempotent even if empty/non‑V3).
13741393 let active_ticks: sp_std:: vec:: Vec < TickIndex > =
13751394 Ticks :: < T > :: iter_prefix ( netuid) . map ( |( ti, _) | ti) . collect ( ) ;
13761395 for ti in active_ticks {
13771396 ActiveTickIndexManager :: < T > :: remove ( netuid, ti) ;
13781397 }
1398+
1399+ let _ = Positions :: < T > :: clear_prefix ( ( netuid, ) , u32:: MAX , None ) ;
13791400 let _ = Ticks :: < T > :: clear_prefix ( netuid, u32:: MAX , None ) ;
13801401
13811402 FeeGlobalTao :: < T > :: remove ( netuid) ;
@@ -1386,12 +1407,11 @@ impl<T: Config> Pallet<T> {
13861407 SwapV3Initialized :: < T > :: remove ( netuid) ;
13871408
13881409 let _ = TickIndexBitmapWords :: < T > :: clear_prefix ( ( netuid, ) , u32:: MAX , None ) ;
1389-
13901410 FeeRate :: < T > :: remove ( netuid) ;
13911411 EnabledUserLiquidity :: < T > :: remove ( netuid) ;
13921412
13931413 log:: debug!(
1394- "dissolve_all_liquidity_providers : netuid={netuid:?}, mode=V2-or-nonV3, state_cleared "
1414+ "clear_protocol_liquidity : netuid={netuid:?}, protocol_burned: τ={burned_tao:?}, α={burned_alpha:?}; state cleared "
13951415 ) ;
13961416
13971417 Ok ( ( ) )
@@ -1494,6 +1514,9 @@ impl<T: Config> SwapHandler<T::AccountId> for Pallet<T> {
14941514 fn toggle_user_liquidity ( netuid : NetUid , enabled : bool ) {
14951515 EnabledUserLiquidity :: < T > :: insert ( netuid, enabled)
14961516 }
1517+ fn clear_protocol_liquidity ( netuid : NetUid ) -> DispatchResult {
1518+ Self :: do_clear_protocol_liquidity ( netuid)
1519+ }
14971520}
14981521
14991522#[ derive( Debug , PartialEq ) ]
0 commit comments