Transactions

move-swap-stake

Move stake to a new hotkey and swap it to a new subnet in one transaction.

View as Markdown

Same-subnet move_stake onto the destination hotkey, then swap_stake_limit to the destination subnet, wrapped in Utility.batch_all so both legs land or neither does. Prefer move_stake (which uses move_stake_limit) for a single cross-subnet move. MEV shield is on by default. The two hotkeys and the two netuids must differ. Same-hotkey crosses are swap_stake; same-subnet re-delegates are move_stake.

Share-pool rounding can make the post-move dest position readable as one rao less than the amount moved. The swap therefore uses amount - 1 so the batch does not fail with NotEnoughStakeToWithdraw, and 1 rao stays on the dest hotkey at the origin subnet. A real one-call extrinsic still needs the chain (issue #3081). Pass all to take the entire origin position.

SignerOriginPalletWraps
coldkeysigned account (pallet role may apply)SubtensorModuleSubtensorModule.move_stake, SubtensorModule.swap_stake, SubtensorModule.swap_stake_limit, Utility.batch_all

Parameters

ParameterTypeRequiredDescription
origin_hotkey_ss58stringyesHotkey the stake moves away from.
origin_netuidintegeryesSubnet the stake currently sits on.
dest_hotkey_ss58stringyesHotkey the stake lands on.
dest_netuidintegeryesSubnet the stake ends up on. When it differs from the origin, the position is swapped through both subnet pools, which can incur slippage on each leg.
amount_alphanumber | "all"yesHow much of the origin position to move and swap, or all.
slippage_protectionbooleannoBound the price the swap may execute at (on by default): the call fails (SlippageTooHigh) instead of filling once the pool price moves more than rate_tolerance from the price at submission. Disable to execute at any price.
rate_tolerancenumbernoMaximum price move slippage protection accepts, as a fraction (0.05 = 5%). Ignored when slippage protection is disabled.

Address parameters (--hotkey, --coldkey, --dest, ...) accept a raw ss58 address, an address-book or proxy-book name, or a local wallet/hotkey name.

CLI

Preview with --dry-run (shows fee, effects, and policy result without submitting), then submit:

btcli tx move-swap-stake \
  --origin-hotkey <ss58|name> \
  --origin-netuid <int> \
  --dest-hotkey <ss58|name> \
  --dest-netuid <int> \
  --amount-alpha <amount|all> --dry-run
btcli tx move-swap-stake \
  --origin-hotkey <ss58|name> \
  --origin-netuid <int> \
  --dest-hotkey <ss58|name> \
  --dest-netuid <int> \
  --amount-alpha <amount|all> -w my_coldkey

Python

import bittensor as bt
from bittensor.wallet import Wallet

wallet = Wallet(name="my_coldkey", hotkey="my_hotkey")
intent = bt.MoveSwapStake(origin_hotkey_ss58="5F...origin", origin_netuid=1, dest_hotkey_ss58="5G...destination", dest_netuid=2, amount_alpha=1.0)

sub = bt.Subtensor()
plan = sub.plan(intent, wallet)   # fee, effects, policy — no submission
result = sub.execute(intent, wallet)
if not result.success:
    print(result.error.code, result.error.remediation)

(bt.Subtensor is also the async client — async with bt.Subtensor() as client: — see The client.) Or build the intent by op name, as an agent would:

result = sub.execute_tool("move_swap_stake", {...}, wallet)

On-chain implementation

Chain callSource
SubtensorModule.move_stakepallets/subtensor/src/macros/dispatches.rs#L1281
SubtensorModule.swap_stakepallets/subtensor/src/macros/dispatches.rs#L1367
SubtensorModule.swap_stake_limitpallets/subtensor/src/macros/dispatches.rs#L1515
Utility.batch_allpallets/utility/src/lib.rs#L314

Every file is browsable under /code exactly as built into the runtime, or as plain text under /code/raw/<path> (index: /code/index.json).