diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 7517c2da6..f9188c965 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1387,8 +1387,52 @@ mod dispatches { destination_netuid: u16, alpha_amount: u64, ) -> DispatchResult { + let coldkey = ensure_signed(origin)?; Self::do_move_stake( - origin, + coldkey, + origin_hotkey, + destination_hotkey, + origin_netuid, + destination_netuid, + alpha_amount, + ) + } + + /// Moves all stake from one hotkey to another across subnets. + /// + /// # Arguments + /// * `origin` - The origin of the transaction, which must be signed by the `origin_hotkey`. + /// * `origin_hotkey` - The account ID of the hotkey from which the stake is being moved. + /// * `destination_hotkey` - The account ID of the hotkey to which the stake is being moved. + /// * `origin_netuid` - The network ID of the origin subnet. + /// * `destination_netuid` - The network ID of the destination subnet. + /// + /// # Returns + /// * `DispatchResult` - Indicates the success or failure of the operation. + /// + /// # Errors + /// This function will return an error if: + /// * The origin is not signed by the `origin_hotkey`. + /// * Either the origin or destination subnet does not exist. + /// * The `origin_hotkey` or `destination_hotkey` does not exist. + /// * There are locked funds that cannot be moved across subnets. + /// + /// # Events + /// Emits a `StakeMoved` event upon successful completion of the stake movement. + #[pallet::call_index(83)] + #[pallet::weight((Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] + pub fn move_all_stake( + origin: OriginFor, + origin_hotkey: T::AccountId, + destination_hotkey: T::AccountId, + origin_netuid: u16, + destination_netuid: u16, + ) -> DispatchResult { + let coldkey = ensure_signed(origin.clone())?; + let alpha_amount = + Alpha::::get((origin_hotkey.clone(), coldkey.clone(), origin_netuid)); + Self::do_move_stake( + coldkey, origin_hotkey, destination_hotkey, origin_netuid, diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs index 843b21560..4bda9acbf 100644 --- a/pallets/subtensor/src/staking/move_stake.rs +++ b/pallets/subtensor/src/staking/move_stake.rs @@ -24,17 +24,14 @@ impl Pallet { /// # Events /// Emits a `StakeMoved` event upon successful completion of the stake movement. pub fn do_move_stake( - origin: T::RuntimeOrigin, + coldkey: T::AccountId, origin_hotkey: T::AccountId, destination_hotkey: T::AccountId, origin_netuid: u16, destination_netuid: u16, alpha_amount: u64, ) -> dispatch::DispatchResult { - // --- 1. Check that the origin is signed by the origin_hotkey. - let coldkey = ensure_signed(origin)?; - - // --- 2. Check that the subnet exists. + // --- 1. Check that the subnet exists. ensure!( Self::if_subnet_exist(origin_netuid), Error::::SubnetNotExists @@ -44,19 +41,19 @@ impl Pallet { Error::::SubnetNotExists ); - // --- 3. Check that the origin_hotkey exists. + // --- 2. Check that the origin_hotkey exists. ensure!( Self::hotkey_account_exists(&origin_hotkey), Error::::HotKeyAccountNotExists ); - // --- 4. Check that the destination_hotkey exists. + // --- 3. Check that the destination_hotkey exists. ensure!( Self::hotkey_account_exists(&destination_hotkey), Error::::HotKeyAccountNotExists ); - // --- 6. Get the current alpha stake for the origin hotkey-coldkey pair in the origin subnet + // --- 4. Get the current alpha stake for the origin hotkey-coldkey pair in the origin subnet let origin_alpha = Alpha::::get((origin_hotkey.clone(), coldkey.clone(), origin_netuid)); ensure!( alpha_amount <= origin_alpha, @@ -79,7 +76,7 @@ impl Pallet { Error::::UnstakeRateLimitExceeded ); - // --- 7. Unstake the amount of alpha from the origin subnet, converting it to TAO + // --- 5. Unstake the amount of alpha from the origin subnet, converting it to TAO let origin_tao = Self::unstake_from_subnet( &origin_hotkey.clone(), &coldkey.clone(), @@ -87,7 +84,7 @@ impl Pallet { alpha_amount, ); - // --- 8. Stake the resulting TAO into the destination subnet for the destination hotkey + // --- 6. Stake the resulting TAO into the destination subnet for the destination hotkey Self::stake_into_subnet( &destination_hotkey.clone(), &coldkey.clone(), @@ -116,7 +113,7 @@ impl Pallet { LastAddStakeIncrease::::insert(&destination_hotkey, &coldkey, current_block); } - // --- 10. Log the event. + // --- 7. Log the event. log::info!( "StakeMoved( coldkey:{:?}, origin_hotkey:{:?}, origin_netuid:{:?}, destination_hotkey:{:?}, destination_netuid:{:?} )", coldkey.clone(), @@ -133,7 +130,7 @@ impl Pallet { destination_netuid, )); - // -- 11. Ok and return. + // -- 8. Ok and return. Ok(()) } } diff --git a/pallets/subtensor/tests/move.rs b/pallets/subtensor/tests/move.rs index 38e667052..dcf44ab20 100644 --- a/pallets/subtensor/tests/move.rs +++ b/pallets/subtensor/tests/move.rs @@ -26,7 +26,7 @@ fn test_do_move_success() { // Perform the move assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -77,7 +77,7 @@ fn test_do_move_different_subnets() { // Perform the move assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, origin_netuid, @@ -125,7 +125,7 @@ fn test_do_move_nonexistent_subnet() { // Attempt to move stake to a non-existent subnet assert_noop!( SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, origin_netuid, @@ -162,7 +162,7 @@ fn test_do_move_nonexistent_origin_hotkey() { add_network(netuid, 0, 0); assert_noop!( SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, nonexistent_origin_hotkey, destination_hotkey, netuid, @@ -211,7 +211,7 @@ fn test_do_move_nonexistent_destination_hotkey() { add_network(netuid, 0, 0); assert_noop!( SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, nonexistent_destination_hotkey, netuid, @@ -257,7 +257,7 @@ fn test_do_move_zero_stake() { SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey); SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -306,7 +306,7 @@ fn test_do_move_all_stake() { SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey); SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -352,7 +352,7 @@ fn test_do_move_half_stake() { SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey); SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -401,7 +401,7 @@ fn test_do_move_partial_stake() { SubtensorModule::create_account_if_non_existent(&coldkey, &origin_hotkey); SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -452,20 +452,10 @@ fn test_do_move_multiple_times() { TargetStakesPerInterval::::set(1000); for _ in 0..3 { assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), - hotkey1, - hotkey2, - netuid, - netuid, - alpha, + coldkey, hotkey1, hotkey2, netuid, netuid, alpha, )); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), - hotkey2, - hotkey1, - netuid, - netuid, - alpha, + coldkey, hotkey2, hotkey1, netuid, netuid, alpha, )); } @@ -504,7 +494,7 @@ fn test_do_move_wrong_origin() { SubtensorModule::create_account_if_non_existent(&coldkey, &destination_hotkey); assert_err!( SubtensorModule::do_move_stake( - RuntimeOrigin::signed(wrong_coldkey), + wrong_coldkey, origin_hotkey, destination_hotkey, netuid, @@ -553,12 +543,7 @@ fn test_do_move_same_hotkey() { // Attempt to move stake to the same hotkey assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), - hotkey, - hotkey, - netuid, - netuid, - alpha, + coldkey, hotkey, hotkey, netuid, netuid, alpha, )); // Check that stake remains unchanged @@ -591,7 +576,7 @@ fn test_do_move_event_emission() { // Move stake and capture events System::reset_events(); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -630,7 +615,7 @@ fn test_do_move_storage_updates() { let alpha = Alpha::::get((origin_hotkey, coldkey, origin_netuid)); assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, origin_netuid, @@ -679,7 +664,7 @@ fn test_do_move_max_values() { // Move maximum stake assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), + coldkey, origin_hotkey, destination_hotkey, netuid, @@ -726,22 +711,10 @@ fn test_do_move_rate_limit_enforced() { // Move stake multiple times assert_ok!(SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), - hotkey1, - hotkey2, - netuid, - netuid, - alpha, + coldkey, hotkey1, hotkey2, netuid, netuid, alpha, )); assert_err!( - SubtensorModule::do_move_stake( - RuntimeOrigin::signed(coldkey), - hotkey2, - hotkey1, - netuid, - netuid, - alpha, - ), + SubtensorModule::do_move_stake(coldkey, hotkey2, hotkey1, netuid, netuid, alpha,), Error::::StakeRateLimitExceeded, );