Skip to content

Commit dda8b24

Browse files
committed
test_dissolve_v3_green_path_refund_tao_stake_alpha
1 parent e8cdc1c commit dda8b24

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed

pallets/swap/src/pallet/tests.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,3 +2536,177 @@ fn refund_alpha_same_cold_multiple_hotkeys_conserved_to_owner() {
25362536
);
25372537
});
25382538
}
2539+
2540+
#[test]
2541+
fn test_dissolve_v3_green_path_refund_tao_stake_alpha_and_clear_state() {
2542+
new_test_ext().execute_with(|| {
2543+
// --- Setup ---
2544+
let netuid = NetUid::from(42);
2545+
let cold = OK_COLDKEY_ACCOUNT_ID;
2546+
let hot = OK_HOTKEY_ACCOUNT_ID;
2547+
2548+
assert_ok!(Swap::toggle_user_liquidity(
2549+
RuntimeOrigin::root(),
2550+
netuid.into(),
2551+
true
2552+
));
2553+
assert_ok!(Pallet::<Test>::maybe_initialize_v3(netuid));
2554+
assert!(SwapV3Initialized::<Test>::get(netuid));
2555+
2556+
// Tight in‑range band so BOTH τ and α are required.
2557+
let ct = CurrentTick::<Test>::get(netuid);
2558+
let tick_low = ct.saturating_sub(10);
2559+
let tick_high = ct.saturating_add(10);
2560+
let liquidity: u64 = 1_250_000;
2561+
2562+
// Add liquidity and capture required τ/α.
2563+
let (_pos_id, tao_needed, alpha_needed) =
2564+
Pallet::<Test>::do_add_liquidity(netuid, &cold, &hot, tick_low, tick_high, liquidity)
2565+
.expect("add in-range liquidity");
2566+
assert!(tao_needed > 0, "in-range pos must require TAO");
2567+
assert!(alpha_needed > 0, "in-range pos must require ALPHA");
2568+
2569+
// Determine the permitted validator with the highest trust (green path).
2570+
let trust = <Test as Config>::SubnetInfo::get_validator_trust(netuid.into());
2571+
let permit = <Test as Config>::SubnetInfo::get_validator_permit(netuid.into());
2572+
assert_eq!(trust.len(), permit.len(), "trust/permit must align");
2573+
let target_uid: u16 = trust
2574+
.iter()
2575+
.zip(permit.iter())
2576+
.enumerate()
2577+
.filter(|(_, (_t, p))| **p)
2578+
.max_by_key(|(_, (t, _))| *t)
2579+
.map(|(i, _)| i as u16)
2580+
.expect("at least one permitted validator");
2581+
let validator_hotkey: <Test as frame_system::Config>::AccountId =
2582+
<Test as Config>::SubnetInfo::hotkey_of_uid(netuid.into(), target_uid)
2583+
.expect("uid -> hotkey mapping must exist");
2584+
2585+
// --- Snapshot BEFORE we withdraw τ/α to fund the position ---
2586+
let tao_before = <Test as Config>::BalanceOps::tao_balance(&cold);
2587+
2588+
let alpha_before_hot =
2589+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &hot);
2590+
let alpha_before_owner =
2591+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &cold);
2592+
let alpha_before_val =
2593+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &validator_hotkey);
2594+
2595+
let alpha_before_total = if validator_hotkey == hot {
2596+
// Avoid double counting when validator == user's hotkey.
2597+
alpha_before_hot + alpha_before_owner
2598+
} else {
2599+
alpha_before_hot + alpha_before_owner + alpha_before_val
2600+
};
2601+
2602+
// --- Mirror extrinsic bookkeeping: withdraw τ & α; bump provided reserves ---
2603+
let tao_taken = <Test as Config>::BalanceOps::decrease_balance(&cold, tao_needed.into())
2604+
.expect("decrease TAO");
2605+
let alpha_taken = <Test as Config>::BalanceOps::decrease_stake(
2606+
&cold,
2607+
&hot,
2608+
netuid.into(),
2609+
alpha_needed.into(),
2610+
)
2611+
.expect("decrease ALPHA");
2612+
2613+
<Test as Config>::BalanceOps::increase_provided_tao_reserve(netuid.into(), tao_taken);
2614+
<Test as Config>::BalanceOps::increase_provided_alpha_reserve(netuid.into(), alpha_taken);
2615+
2616+
// --- Act: dissolve (GREEN PATH: permitted validators exist) ---
2617+
assert_ok!(Pallet::<Test>::do_dissolve_all_liquidity_providers(netuid));
2618+
2619+
// --- Assert: τ principal refunded to user ---
2620+
let tao_after = <Test as Config>::BalanceOps::tao_balance(&cold);
2621+
assert_eq!(tao_after, tao_before, "TAO principal must be refunded");
2622+
2623+
// --- α ledger assertions ---
2624+
let alpha_after_hot =
2625+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &hot);
2626+
let alpha_after_owner =
2627+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &cold);
2628+
let alpha_after_val =
2629+
<Test as Config>::BalanceOps::alpha_balance(netuid.into(), &cold, &validator_hotkey);
2630+
2631+
// Owner ledger must be unchanged in the green path.
2632+
assert_eq!(
2633+
alpha_after_owner, alpha_before_owner,
2634+
"Owner α ledger must be unchanged (staked to validator, not refunded)"
2635+
);
2636+
2637+
if validator_hotkey == hot {
2638+
// Net effect: user's hot ledger returns to its original balance.
2639+
assert_eq!(
2640+
alpha_after_hot, alpha_before_hot,
2641+
"When validator == hotkey, user's hot ledger must net back to its original balance"
2642+
);
2643+
2644+
// Totals without double-counting the same ledger.
2645+
let alpha_after_total = alpha_after_hot + alpha_after_owner;
2646+
assert_eq!(
2647+
alpha_after_total, alpha_before_total,
2648+
"Total α for the coldkey must be conserved (validator==hotkey)"
2649+
);
2650+
} else {
2651+
assert!(
2652+
alpha_before_hot >= alpha_after_hot,
2653+
"hot ledger should not increase"
2654+
);
2655+
assert!(
2656+
alpha_after_val >= alpha_before_val,
2657+
"validator ledger should not decrease"
2658+
);
2659+
2660+
let hot_loss = alpha_before_hot - alpha_after_hot;
2661+
let val_gain = alpha_after_val - alpha_before_val;
2662+
2663+
assert_eq!(
2664+
val_gain, hot_loss,
2665+
"α that left the user's hot ledger must equal α credited to the validator ledger"
2666+
);
2667+
2668+
// Totals across distinct ledgers must be conserved.
2669+
let alpha_after_total = alpha_after_hot + alpha_after_owner + alpha_after_val;
2670+
assert_eq!(
2671+
alpha_after_total, alpha_before_total,
2672+
"Total α for the coldkey must be conserved"
2673+
);
2674+
}
2675+
2676+
// --- Assert: All positions (user + protocol) removed and V3 state cleared ---
2677+
let protocol_id = Pallet::<Test>::protocol_account_id();
2678+
2679+
assert_eq!(Pallet::<Test>::count_positions(netuid, &cold), 0);
2680+
let prot_positions_after =
2681+
Positions::<Test>::iter_prefix_values((netuid, protocol_id)).collect::<Vec<_>>();
2682+
assert!(
2683+
prot_positions_after.is_empty(),
2684+
"protocol positions must be removed"
2685+
);
2686+
2687+
// Ticks / liquidity / price / flags cleared
2688+
assert!(Ticks::<Test>::iter_prefix(netuid).next().is_none());
2689+
assert!(Ticks::<Test>::get(netuid, TickIndex::MIN).is_none());
2690+
assert!(Ticks::<Test>::get(netuid, TickIndex::MAX).is_none());
2691+
assert!(!CurrentLiquidity::<Test>::contains_key(netuid));
2692+
assert!(!CurrentTick::<Test>::contains_key(netuid));
2693+
assert!(!AlphaSqrtPrice::<Test>::contains_key(netuid));
2694+
assert!(!SwapV3Initialized::<Test>::contains_key(netuid));
2695+
2696+
// Fee globals cleared
2697+
assert!(!FeeGlobalTao::<Test>::contains_key(netuid));
2698+
assert!(!FeeGlobalAlpha::<Test>::contains_key(netuid));
2699+
2700+
// Active tick bitmap cleared
2701+
assert!(
2702+
TickIndexBitmapWords::<Test>::iter_prefix((netuid,))
2703+
.next()
2704+
.is_none(),
2705+
"active tick bitmap words must be cleared"
2706+
);
2707+
2708+
// Knobs removed
2709+
assert!(!FeeRate::<Test>::contains_key(netuid));
2710+
assert!(!EnabledUserLiquidity::<Test>::contains_key(netuid));
2711+
});
2712+
}

0 commit comments

Comments
 (0)