Skip to content

Commit 7d43c7e

Browse files
committed
add swap_stake & tests
1 parent f0f4c6b commit 7d43c7e

File tree

4 files changed

+504
-3
lines changed

4 files changed

+504
-3
lines changed

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,9 +1608,6 @@ mod dispatches {
16081608
/// * `destination_netuid` - The network/subnet ID to move stake to (for cross-subnet transfer).
16091609
/// * `alpha_amount` - The amount of stake to transfer.
16101610
///
1611-
/// # Weight
1612-
/// Uses a fixed weight of 3_000_000 (plus any DB write overhead).
1613-
///
16141611
/// # Errors
16151612
/// Returns an error if:
16161613
/// * The origin is not signed by the correct coldkey.
@@ -1640,5 +1637,46 @@ mod dispatches {
16401637
alpha_amount,
16411638
)
16421639
}
1640+
1641+
/// Swaps a specified amount of stake from one subnet to another, while keeping the same coldkey and hotkey.
1642+
///
1643+
/// # Arguments
1644+
/// * `origin` - The origin of the transaction, which must be signed by the coldkey that owns the `hotkey`.
1645+
/// * `hotkey` - The hotkey whose stake is being swapped.
1646+
/// * `origin_netuid` - The network/subnet ID from which stake is removed.
1647+
/// * `destination_netuid` - The network/subnet ID to which stake is added.
1648+
/// * `alpha_amount` - The amount of stake to swap.
1649+
///
1650+
/// # Errors
1651+
/// Returns an error if:
1652+
/// * The transaction is not signed by the correct coldkey (i.e., `coldkey_owns_hotkey` fails).
1653+
/// * Either `origin_netuid` or `destination_netuid` does not exist.
1654+
/// * The hotkey does not exist.
1655+
/// * There is insufficient stake on `(coldkey, hotkey, origin_netuid)`.
1656+
/// * The swap amount is below the minimum stake requirement.
1657+
///
1658+
/// # Events
1659+
/// May emit a `StakeSwapped` event on success.
1660+
#[pallet::call_index(87)]
1661+
#[pallet::weight((
1662+
Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)),
1663+
DispatchClass::Operational,
1664+
Pays::No
1665+
))]
1666+
pub fn swap_stake(
1667+
origin: T::RuntimeOrigin,
1668+
hotkey: T::AccountId,
1669+
origin_netuid: u16,
1670+
destination_netuid: u16,
1671+
alpha_amount: u64,
1672+
) -> DispatchResult {
1673+
Self::do_swap_stake(
1674+
origin,
1675+
hotkey,
1676+
origin_netuid,
1677+
destination_netuid,
1678+
alpha_amount,
1679+
)
1680+
}
16431681
}
16441682
}

pallets/subtensor/src/macros/events.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,11 @@ mod events {
253253
/// Parameters:
254254
/// (origin_coldkey, destination_coldkey, hotkey, origin_netuid, destination_netuid, amount)
255255
StakeTransferred(T::AccountId, T::AccountId, T::AccountId, u16, u16, u64),
256+
257+
/// Stake has been swapped from one subnet to another for the same coldkey-hotkey pair.
258+
///
259+
/// Parameters:
260+
/// (coldkey, hotkey, origin_netuid, destination_netuid, amount)
261+
StakeSwapped(T::AccountId, T::AccountId, u16, u16, u64),
256262
}
257263
}

pallets/subtensor/src/staking/move_stake.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,101 @@ impl<T: Config> Pallet<T> {
217217
// 10. Return success.
218218
Ok(())
219219
}
220+
221+
/// Swaps a specified amount of stake for the same `(coldkey, hotkey)` pair from one subnet
222+
/// (`origin_netuid`) to another (`destination_netuid`).
223+
///
224+
/// # Arguments
225+
/// * `origin` - The origin of the transaction, which must be signed by the coldkey that owns the hotkey.
226+
/// * `hotkey` - The hotkey whose stake is being swapped.
227+
/// * `origin_netuid` - The subnet ID from which stake is removed.
228+
/// * `destination_netuid` - The subnet ID to which stake is added.
229+
/// * `alpha_amount` - The amount of stake to swap.
230+
///
231+
/// # Returns
232+
/// * `DispatchResult` - Indicates success or failure.
233+
///
234+
/// # Errors
235+
/// This function returns an error if:
236+
/// * The origin is not signed by the correct coldkey (i.e., not associated with `hotkey`).
237+
/// * Either the `origin_netuid` or the `destination_netuid` does not exist.
238+
/// * The specified `hotkey` does not exist.
239+
/// * The `(coldkey, hotkey, origin_netuid)` does not have enough stake (`alpha_amount`).
240+
/// * The unstaked amount is below `DefaultMinStake`.
241+
///
242+
/// # Events
243+
/// Emits a `StakeSwapped` event upon successful completion.
244+
pub fn do_swap_stake(
245+
origin: T::RuntimeOrigin,
246+
hotkey: T::AccountId,
247+
origin_netuid: u16,
248+
destination_netuid: u16,
249+
alpha_amount: u64,
250+
) -> dispatch::DispatchResult {
251+
// 1. Ensure the extrinsic is signed by the coldkey.
252+
let coldkey = ensure_signed(origin)?;
253+
254+
// 2. Check that both subnets exist.
255+
ensure!(
256+
Self::if_subnet_exist(origin_netuid),
257+
Error::<T>::SubnetNotExists
258+
);
259+
ensure!(
260+
Self::if_subnet_exist(destination_netuid),
261+
Error::<T>::SubnetNotExists
262+
);
263+
264+
// 3. Check that the hotkey exists.
265+
ensure!(
266+
Self::hotkey_account_exists(&hotkey),
267+
Error::<T>::HotKeyAccountNotExists
268+
);
269+
270+
// 4. Ensure this coldkey actually owns the hotkey.
271+
ensure!(
272+
Self::coldkey_owns_hotkey(&coldkey, &hotkey),
273+
Error::<T>::NonAssociatedColdKey
274+
);
275+
276+
// 5. Ensure there is enough stake in the origin subnet.
277+
let origin_alpha =
278+
Self::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, origin_netuid);
279+
ensure!(
280+
alpha_amount <= origin_alpha,
281+
Error::<T>::NotEnoughStakeToWithdraw
282+
);
283+
284+
// 6. Unstake from the origin subnet, returning TAO (or a 1:1 equivalent).
285+
let tao_unstaked =
286+
Self::unstake_from_subnet(&hotkey, &coldkey, origin_netuid, alpha_amount);
287+
288+
// 7. Check that the unstaked amount is above the minimum stake threshold.
289+
ensure!(
290+
tao_unstaked >= DefaultMinStake::<T>::get(),
291+
Error::<T>::AmountTooLow
292+
);
293+
294+
// 8. Stake the unstaked amount into the destination subnet, using the same coldkey/hotkey.
295+
Self::stake_into_subnet(&hotkey, &coldkey, destination_netuid, tao_unstaked);
296+
297+
// 9. Emit an event for logging.
298+
log::info!(
299+
"StakeSwapped(coldkey: {:?}, hotkey: {:?}, origin_netuid: {:?}, destination_netuid: {:?}, amount: {:?})",
300+
coldkey,
301+
hotkey,
302+
origin_netuid,
303+
destination_netuid,
304+
tao_unstaked
305+
);
306+
Self::deposit_event(Event::StakeSwapped(
307+
coldkey,
308+
hotkey,
309+
origin_netuid,
310+
destination_netuid,
311+
tao_unstaked,
312+
));
313+
314+
// 10. Return success.
315+
Ok(())
316+
}
220317
}

0 commit comments

Comments
 (0)