Skip to content

Commit 91e9959

Browse files
committed
add clear_protocol_liquidity
1 parent dda8b24 commit 91e9959

File tree

3 files changed

+111
-86
lines changed

3 files changed

+111
-86
lines changed

pallets/subtensor/src/coinbase/root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ impl<T: Config> Pallet<T> {
375375
// 2. --- Perform the cleanup before removing the network.
376376
T::SwapInterface::dissolve_all_liquidity_providers(netuid)?;
377377
Self::destroy_alpha_in_out_stakes(netuid)?;
378+
T::SwapInterface::clear_protocol_liquidity(netuid)?;
378379
T::CommitmentsInterface::purge_netuid(netuid);
379380

380381
// 3. --- Remove the network

pallets/swap-interface/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub trait SwapHandler<AccountId> {
3636
fn is_user_liquidity_enabled(netuid: NetUid) -> bool;
3737
fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult;
3838
fn toggle_user_liquidity(netuid: NetUid, enabled: bool);
39+
fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult;
3940
}
4041

4142
#[derive(Debug, PartialEq)]

pallets/swap/src/pallet/impls.rs

Lines changed: 109 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)