diff --git a/pallets/transaction-fee/src/lib.rs b/pallets/transaction-fee/src/lib.rs index fbbe2cd805..918d9cd319 100644 --- a/pallets/transaction-fee/src/lib.rs +++ b/pallets/transaction-fee/src/lib.rs @@ -305,6 +305,33 @@ impl SubtensorTxFeeHandler { origin_netuid, .. }) => alpha_vec.push((hotkey.clone(), *origin_netuid)), + Some(SubtensorCall::swap_hotkey { + hotkey, + new_hotkey: _, + netuid, + }) => match netuid { + Some(netuid) => alpha_vec.push((hotkey.clone(), *netuid)), + None => { + let netuids = OU::get_all_netuids_for_coldkey_and_hotkey(who, hotkey); + netuids + .into_iter() + .for_each(|netuid| alpha_vec.push((hotkey.clone(), netuid))); + } + }, + Some(SubtensorCall::swap_hotkey_v2 { + hotkey, + new_hotkey: _, + netuid, + keep_stake: _, + }) => match netuid { + Some(netuid) => alpha_vec.push((hotkey.clone(), *netuid)), + None => { + let netuids = OU::get_all_netuids_for_coldkey_and_hotkey(who, hotkey); + netuids + .into_iter() + .for_each(|netuid| alpha_vec.push((hotkey.clone(), netuid))); + } + }, Some(SubtensorCall::recycle_alpha { hotkey, amount: _, diff --git a/pallets/transaction-fee/src/tests/mod.rs b/pallets/transaction-fee/src/tests/mod.rs index f452634cfe..c4ee2a39dc 100644 --- a/pallets/transaction-fee/src/tests/mod.rs +++ b/pallets/transaction-fee/src/tests/mod.rs @@ -204,6 +204,72 @@ fn test_rejects_multi_subnet_alpha_fee_deduction() { assert_eq!(alpha_before_1, alpha_after_1); }); } +// cargo test --package subtensor-transaction-fee --lib -- tests::test_swap_hotkey_fees_alpha --exact --show-output +#[test] +fn test_swap_hotkey_fees_alpha() { + new_test_ext().execute_with(|| { + let sn = setup_subnets(2, 2); + let stake_amount = TAO; + setup_stake( + sn.subnets[0].netuid, + &sn.coldkey, + &sn.hotkeys[0], + stake_amount, + ); + setup_stake( + sn.subnets[1].netuid, + &sn.coldkey, + &sn.hotkeys[0], + stake_amount, + ); + + // swap_hotkey and swap_hotkey_v2 move alpha stake off the origin hotkey, + // so their fees must be eligible to be paid in alpha on every subnet that + // hotkey has stake. Before the fix `fees_in_alpha` returned an empty vec + // for these calls, forcing a TAO fee (and rejecting alpha-only callers). + + // netuid = None -> every subnet the origin hotkey has stake on (2 here). + let call_all = RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey { + hotkey: sn.hotkeys[0], + new_hotkey: sn.hotkeys[1], + netuid: None, + }); + let alpha_vec_all = + SubtensorTxFeeHandler::>::fees_in_alpha::( + &sn.coldkey, + &call_all, + ); + assert_eq!(alpha_vec_all.len(), 2); + + // netuid = Some(single) -> only that subnet. + let call_one = RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey { + hotkey: sn.hotkeys[0], + new_hotkey: sn.hotkeys[1], + netuid: Some(sn.subnets[0].netuid), + }); + let alpha_vec_one = + SubtensorTxFeeHandler::>::fees_in_alpha::( + &sn.coldkey, + &call_one, + ); + assert_eq!(alpha_vec_one.len(), 1); + + // swap_hotkey_v2 moves the same alpha and must be eligible too. + let call_v2 = RuntimeCall::SubtensorModule(pallet_subtensor::Call::swap_hotkey_v2 { + hotkey: sn.hotkeys[0], + new_hotkey: sn.hotkeys[1], + netuid: None, + keep_stake: false, + }); + let alpha_vec_v2 = + SubtensorTxFeeHandler::>::fees_in_alpha::( + &sn.coldkey, + &call_v2, + ); + assert_eq!(alpha_vec_v2.len(), 2); + }); +} + // cargo test --package subtensor-transaction-fee --lib -- tests::test_remove_stake_fees_alpha --exact --show-output #[test] fn test_remove_stake_fees_alpha() {