bittensor-cli 8.2.0rc7__tar.gz → 8.2.0rc14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/PKG-INFO +1 -1
  2. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/__init__.py +1 -1
  3. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/cli.py +436 -38
  4. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/__init__.py +1 -0
  5. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/balances.py +29 -1
  6. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/chain_data.py +25 -8
  7. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/subtensor_interface.py +64 -77
  8. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/utils.py +25 -5
  9. bittensor-cli-8.2.0rc14/bittensor_cli/src/commands/stake/move.py +992 -0
  10. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/stake/stake.py +45 -1156
  11. bittensor-cli-8.2.0rc14/bittensor_cli/src/commands/subnets/__init__.py +0 -0
  12. bittensor-cli-8.2.0rc14/bittensor_cli/src/commands/subnets/price.py +867 -0
  13. {bittensor-cli-8.2.0rc7/bittensor_cli/src/commands → bittensor-cli-8.2.0rc14/bittensor_cli/src/commands/subnets}/subnets.py +55 -50
  14. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/sudo.py +18 -9
  15. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/wallets.py +71 -232
  16. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/PKG-INFO +1 -1
  17. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/SOURCES.txt +5 -2
  18. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/requires.txt +3 -0
  19. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/README.md +0 -0
  20. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/doc_generation_helper.py +0 -0
  21. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/__init__.py +0 -0
  22. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/async_substrate_interface.py +0 -0
  23. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/extrinsics/__init__.py +0 -0
  24. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/extrinsics/registration.py +0 -0
  25. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/extrinsics/root.py +0 -0
  26. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/extrinsics/transfer.py +0 -0
  27. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/minigraph.py +0 -0
  28. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/networking.py +0 -0
  29. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/bittensor/templates/table.j2 +0 -0
  30. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/__init__.py +0 -0
  31. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/stake/__init__.py +0 -0
  32. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/stake/children_hotkeys.py +0 -0
  33. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli/src/commands/weights.py +0 -0
  34. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/dependency_links.txt +0 -0
  35. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/entry_points.txt +0 -0
  36. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/bittensor_cli.egg-info/top_level.txt +0 -0
  37. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/setup.cfg +0 -0
  38. {bittensor-cli-8.2.0rc7 → bittensor-cli-8.2.0rc14}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bittensor-cli
3
- Version: 8.2.0rc7
3
+ Version: 8.2.0rc14
4
4
  Summary: Bittensor CLI
5
5
  Home-page: https://github.com/opentensor/btcli
6
6
  Author: bittensor.com
@@ -18,6 +18,6 @@
18
18
  from .cli import CLIManager
19
19
 
20
20
 
21
- __version__ = "8.2.0rc7"
21
+ __version__ = "8.2.0rc14"
22
22
 
23
23
  __all__ = ["CLIManager", "__version__"]
@@ -29,9 +29,10 @@ from bittensor_cli.src.bittensor.balances import Balance
29
29
  from bittensor_cli.src.bittensor.async_substrate_interface import (
30
30
  SubstrateRequestException,
31
31
  )
32
- from bittensor_cli.src.commands import subnets, sudo, wallets
32
+ from bittensor_cli.src.commands import sudo, wallets
33
33
  from bittensor_cli.src.commands import weights as weights_cmds
34
- from bittensor_cli.src.commands.stake import children_hotkeys, stake
34
+ from bittensor_cli.src.commands.subnets import price, subnets
35
+ from bittensor_cli.src.commands.stake import children_hotkeys, stake, move
35
36
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
36
37
  from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
37
38
  from bittensor_cli.src.bittensor.utils import (
@@ -41,13 +42,14 @@ from bittensor_cli.src.bittensor.utils import (
41
42
  is_valid_ss58_address,
42
43
  print_error,
43
44
  validate_chain_endpoint,
44
- retry_prompt,
45
45
  validate_netuid,
46
46
  is_rao_network,
47
47
  get_effective_network,
48
48
  prompt_for_identity,
49
49
  validate_uri,
50
50
  prompt_for_subnet_identity,
51
+ print_linux_dependency_message,
52
+ is_linux,
51
53
  )
52
54
  from typing_extensions import Annotated
53
55
  from textwrap import dedent
@@ -62,7 +64,7 @@ except ImportError:
62
64
  pass
63
65
 
64
66
 
65
- __version__ = "8.2.0rc7"
67
+ __version__ = "8.2.0rc14"
66
68
 
67
69
 
68
70
  _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0)
@@ -645,12 +647,13 @@ class CLIManager:
645
647
  "balance", rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"]
646
648
  )(self.wallet_balance)
647
649
  self.wallet_app.command(
648
- "history", rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"]
650
+ "history",
651
+ rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"],
652
+ hidden=True,
649
653
  )(self.wallet_history)
650
654
  self.wallet_app.command(
651
655
  "overview",
652
656
  rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"],
653
- hidden=True,
654
657
  )(self.wallet_overview)
655
658
  self.wallet_app.command(
656
659
  "transfer", rich_help_panel=HELP_PANELS["WALLET"]["OPERATIONS"]
@@ -684,8 +687,14 @@ class CLIManager:
684
687
  "list", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
685
688
  )(self.stake_list)
686
689
  self.stake_app.command(
687
- "move", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
690
+ "move", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
688
691
  )(self.stake_move)
692
+ self.stake_app.command(
693
+ "transfer", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
694
+ )(self.stake_transfer)
695
+ self.stake_app.command(
696
+ "swap", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
697
+ )(self.stake_swap)
689
698
 
690
699
  # stake-children commands
691
700
  children_app = typer.Typer()
@@ -748,10 +757,13 @@ class CLIManager:
748
757
  )(self.subnets_register)
749
758
  self.subnets_app.command(
750
759
  "metagraph", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"], hidden=True
751
- )(self.subnets_show) #Aliased to `s show` for now
760
+ )(self.subnets_show) # Aliased to `s show` for now
752
761
  self.subnets_app.command(
753
762
  "show", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
754
763
  )(self.subnets_show)
764
+ self.subnets_app.command(
765
+ "price", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
766
+ )(self.subnets_price)
755
767
 
756
768
  # weights commands
757
769
  self.weights_app.command(
@@ -1409,12 +1421,6 @@ class CLIManager:
1409
1421
  "Hotkeys names must be a comma-separated list, e.g., `--exclude-hotkeys hk1,hk2`.",
1410
1422
  )
1411
1423
 
1412
- # For Rao games
1413
- effective_network = get_effective_network(self.config, network)
1414
- if is_rao_network(effective_network):
1415
- print_error("This command is disabled on the 'rao' network.")
1416
- raise typer.Exit()
1417
-
1418
1424
  return self._run_command(
1419
1425
  wallets.overview(
1420
1426
  wallet,
@@ -1425,6 +1431,7 @@ class CLIManager:
1425
1431
  include_hotkeys,
1426
1432
  exclude_hotkeys,
1427
1433
  netuids_filter=netuids,
1434
+ verbose=verbose,
1428
1435
  )
1429
1436
  )
1430
1437
 
@@ -1600,6 +1607,8 @@ class CLIManager:
1600
1607
 
1601
1608
  [bold]Note[/bold]: The `inspect` command is for displaying information only and does not perform any transactions or state changes on the blockchain. It is intended to be used with Bittensor CLI and not as a standalone function in user code.
1602
1609
  """
1610
+ print_error("This command is disabled on the 'rao' network.")
1611
+ raise typer.Exit()
1603
1612
  self.verbosity_handler(quiet, verbose)
1604
1613
 
1605
1614
  if netuids:
@@ -1615,11 +1624,6 @@ class CLIManager:
1615
1624
  wallet = self.wallet_ask(
1616
1625
  wallet_name, wallet_path, wallet_hotkey, ask_for=ask_for, validate=validate
1617
1626
  )
1618
- # For Rao games
1619
- effective_network = get_effective_network(self.config, network)
1620
- if is_rao_network(effective_network):
1621
- print_error("This command is disabled on the 'rao' network.")
1622
- raise typer.Exit()
1623
1627
 
1624
1628
  self.initialize_chain(network)
1625
1629
  return self._run_command(
@@ -2791,7 +2795,7 @@ class CLIManager:
2791
2795
  [blue bold]Note[/blue bold]: This command is for users who wish to reallocate their stake or withdraw them from the network. It allows for flexible management of TAO stake across different neurons (hotkeys) on the network.
2792
2796
  """
2793
2797
  self.verbosity_handler(quiet, verbose)
2794
- # TODO: Coldkey related unstakes need to be updated. Patching for now.
2798
+ # TODO: Coldkey related unstakes need to be updated. Patching for now.
2795
2799
  unstake_all_alpha = False
2796
2800
  unstake_all = False
2797
2801
 
@@ -2930,14 +2934,18 @@ class CLIManager:
2930
2934
 
2931
2935
  def stake_move(
2932
2936
  self,
2933
- network=Options.network,
2937
+ network: Optional[list[str]] = Options.network,
2934
2938
  wallet_name=Options.wallet_name,
2935
2939
  wallet_path=Options.wallet_path,
2936
2940
  wallet_hotkey=Options.wallet_hotkey,
2937
- origin_netuid: int = typer.Option(help="Origin netuid", prompt=True),
2938
- destination_netuid: int = typer.Option(help="Destination netuid", prompt=True),
2941
+ origin_netuid: Optional[int] = typer.Option(
2942
+ None, "--origin-netuid", help="Origin netuid"
2943
+ ),
2944
+ destination_netuid: Optional[int] = typer.Option(
2945
+ None, "--dest-netuid", help="Destination netuid"
2946
+ ),
2939
2947
  destination_hotkey: Optional[str] = typer.Option(
2940
- None, help="Destination hotkey", prompt=False
2948
+ None, "--dest-ss58", "--dest", help="Destination hotkey", prompt=False
2941
2949
  ),
2942
2950
  amount: float = typer.Option(
2943
2951
  None,
@@ -2951,40 +2959,343 @@ class CLIManager:
2951
2959
  prompt: bool = Options.prompt,
2952
2960
  ):
2953
2961
  """
2954
- Move Staked TAO to a hotkey from one subnet to another.
2962
+ Move staked TAO between hotkeys while keeping the same coldkey ownership.
2955
2963
 
2956
- THe move commands converts the origin subnet's dTao to Tao, and then converts Tao to destination subnet's dTao.
2964
+ This command allows you to:
2965
+ - Move stake from one hotkey to another hotkey
2966
+ - Move stake between different subnets
2967
+ - Keep the same coldkey ownership
2968
+
2969
+ You can specify:
2970
+ - The origin subnet (--origin-netuid)
2971
+ - The destination subnet (--dest-netuid)
2972
+ - The destination hotkey (--dest-hotkey)
2973
+ - The amount to move (--amount)
2974
+
2975
+ If no arguments are provided, an interactive selection menu will be shown.
2957
2976
 
2958
2977
  EXAMPLE
2959
2978
 
2960
2979
  [green]$[/green] btcli stake move
2961
2980
  """
2962
- # TODO: Improve logic of moving stake (dest hotkey)
2963
- ask_for = (
2964
- [WO.NAME, WO.PATH] if destination_hotkey else [WO.NAME, WO.HOTKEY, WO.PATH]
2981
+ console.print(
2982
+ "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]"
2965
2983
  )
2966
- validate = WV.WALLET if destination_hotkey else WV.WALLET_AND_HOTKEY
2984
+ if not destination_hotkey:
2985
+ dest_wallet_or_ss58 = Prompt.ask(
2986
+ "Enter the [blue]destination wallet[/blue] where destination hotkey is located or [blue]ss58 address[/blue]"
2987
+ )
2988
+ if is_valid_ss58_address(dest_wallet_or_ss58):
2989
+ destination_hotkey = dest_wallet_or_ss58
2990
+ else:
2991
+ dest_wallet = self.wallet_ask(
2992
+ dest_wallet_or_ss58,
2993
+ wallet_path,
2994
+ None,
2995
+ ask_for=[WO.NAME, WO.PATH],
2996
+ validate=WV.WALLET,
2997
+ )
2998
+ destination_hotkey = Prompt.ask(
2999
+ "Enter the [blue]destination hotkey[/blue] name",
3000
+ default=dest_wallet.hotkey_str,
3001
+ )
3002
+ destination_wallet = self.wallet_ask(
3003
+ dest_wallet_or_ss58,
3004
+ wallet_path,
3005
+ destination_hotkey,
3006
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3007
+ validate=WV.WALLET_AND_HOTKEY,
3008
+ )
3009
+ destination_hotkey = destination_wallet.hotkey.ss58_address
3010
+ else:
3011
+ if is_valid_ss58_address(destination_hotkey):
3012
+ destination_hotkey = destination_hotkey
3013
+ else:
3014
+ print_error(
3015
+ "Invalid destination hotkey ss58 address. Please enter a valid ss58 address or wallet name."
3016
+ )
3017
+ raise typer.Exit()
2967
3018
 
3019
+ if not wallet_name:
3020
+ wallet_name = Prompt.ask(
3021
+ "Enter the [blue]origin wallet name[/blue]",
3022
+ default=self.config.get("wallet_name") or defaults.wallet.name,
3023
+ )
2968
3024
  wallet = self.wallet_ask(
2969
- wallet_name,
2970
- wallet_path,
2971
- wallet_hotkey,
2972
- ask_for=ask_for,
2973
- validate=validate,
3025
+ wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
2974
3026
  )
2975
- if not destination_hotkey:
2976
- destination_hotkey = wallet.hotkey.ss58_address
3027
+
3028
+ interactive_selection = False
3029
+ if not wallet_hotkey:
3030
+ origin_hotkey = Prompt.ask(
3031
+ "Enter the [blue]origin hotkey[/blue] name or "
3032
+ "[blue]ss58 address[/blue] where the stake will be moved from "
3033
+ "[dim](or Press Enter to view existing stakes)[/dim]"
3034
+ )
3035
+ if origin_hotkey == "":
3036
+ interactive_selection = True
3037
+
3038
+ elif is_valid_ss58_address(origin_hotkey):
3039
+ origin_hotkey = origin_hotkey
3040
+ else:
3041
+ wallet = self.wallet_ask(
3042
+ wallet_name,
3043
+ wallet_path,
3044
+ origin_hotkey,
3045
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3046
+ validate=WV.WALLET_AND_HOTKEY,
3047
+ )
3048
+ origin_hotkey = wallet.hotkey.ss58_address
3049
+ else:
3050
+ wallet = self.wallet_ask(
3051
+ wallet_name,
3052
+ wallet_path,
3053
+ wallet_hotkey,
3054
+ ask_for=[],
3055
+ validate=WV.WALLET_AND_HOTKEY,
3056
+ )
3057
+ origin_hotkey = wallet.hotkey.ss58_address
3058
+
3059
+ if not interactive_selection:
3060
+ if not origin_netuid:
3061
+ origin_netuid = IntPrompt.ask(
3062
+ "Enter the [blue]origin subnet[/blue] (netuid) to move stake from"
3063
+ )
3064
+
3065
+ if not destination_netuid:
3066
+ destination_netuid = IntPrompt.ask(
3067
+ "Enter the [blue]destination subnet[/blue] (netuid) to move stake to"
3068
+ )
2977
3069
 
2978
3070
  return self._run_command(
2979
- stake.move_stake(
3071
+ move.move_stake(
2980
3072
  subtensor=self.initialize_chain(network),
2981
3073
  wallet=wallet,
2982
3074
  origin_netuid=origin_netuid,
3075
+ origin_hotkey=origin_hotkey,
2983
3076
  destination_netuid=destination_netuid,
2984
3077
  destination_hotkey=destination_hotkey,
2985
3078
  amount=amount,
2986
3079
  stake_all=stake_all,
3080
+ interactive_selection=interactive_selection,
3081
+ prompt=prompt,
3082
+ )
3083
+ )
3084
+
3085
+ def stake_transfer(
3086
+ self,
3087
+ network: Optional[list[str]] = Options.network,
3088
+ wallet_name: Optional[str] = Options.wallet_name,
3089
+ wallet_path: Optional[str] = Options.wallet_path,
3090
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3091
+ origin_netuid: Optional[int] = typer.Option(
3092
+ None,
3093
+ "--origin-netuid",
3094
+ help="The netuid to transfer stake from",
3095
+ ),
3096
+ dest_netuid: Optional[int] = typer.Option(
3097
+ None,
3098
+ "--dest-netuid",
3099
+ help="The netuid to transfer stake to",
3100
+ ),
3101
+ dest_ss58: Optional[str] = typer.Option(
3102
+ None,
3103
+ "--dest-ss58",
3104
+ "--dest",
3105
+ "--dest-coldkey",
3106
+ help="The destination wallet name or SS58 address to transfer stake to",
3107
+ ),
3108
+ amount: float = typer.Option(
3109
+ None,
3110
+ "--amount",
3111
+ "-a",
3112
+ help="Amount of stake to transfer",
3113
+ ),
3114
+ prompt: bool = Options.prompt,
3115
+ quiet: bool = Options.quiet,
3116
+ verbose: bool = Options.verbose,
3117
+ ):
3118
+ """
3119
+ Transfer stake between coldkeys while keeping the same hotkey ownership.
3120
+
3121
+ This command allows you to:
3122
+ - Transfer stake from one coldkey to another coldkey
3123
+ - Keep the same hotkey ownership
3124
+ - Transfer stake between different subnets
3125
+
3126
+ You can specify:
3127
+ - The origin subnet (--origin-netuid)
3128
+ - The destination subnet (--dest-netuid)
3129
+ - The destination wallet/address (--dest)
3130
+ - The amount to transfer (--amount)
3131
+
3132
+ If no arguments are provided, an interactive selection menu will be shown.
3133
+
3134
+ EXAMPLE
3135
+
3136
+ Transfer 100 TAO from subnet 1 to subnet 2:
3137
+ [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest wallet2 --amount 100
3138
+
3139
+ Using SS58 address:
3140
+ [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --amount 100
3141
+ """
3142
+ console.print(
3143
+ "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]"
3144
+ )
3145
+ self.verbosity_handler(quiet, verbose)
3146
+
3147
+ wallet = self.wallet_ask(
3148
+ wallet_name,
3149
+ wallet_path,
3150
+ wallet_hotkey,
3151
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3152
+ validate=WV.WALLET_AND_HOTKEY,
3153
+ )
3154
+
3155
+ if not dest_ss58:
3156
+ dest_ss58 = Prompt.ask(
3157
+ "Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3158
+ )
3159
+
3160
+ if is_valid_ss58_address(dest_ss58):
3161
+ dest_ss58 = dest_ss58
3162
+ else:
3163
+ dest_wallet = self.wallet_ask(
3164
+ dest_ss58,
3165
+ wallet_path,
3166
+ None,
3167
+ ask_for=[WO.NAME, WO.PATH],
3168
+ validate=WV.WALLET,
3169
+ )
3170
+ dest_ss58 = dest_wallet.coldkeypub.ss58_address
3171
+
3172
+ interactive_selection = False
3173
+ if origin_netuid is None and dest_netuid is None and not amount:
3174
+ interactive_selection = True
3175
+ else:
3176
+ if origin_netuid is None:
3177
+ origin_netuid = IntPrompt.ask(
3178
+ "Enter the [blue]origin subnet[/blue] (netuid)"
3179
+ )
3180
+ if not amount:
3181
+ amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to transfer")
3182
+
3183
+ if dest_netuid is None:
3184
+ dest_netuid = IntPrompt.ask(
3185
+ "Enter the [blue]destination subnet[/blue] (netuid)"
3186
+ )
3187
+
3188
+ return self._run_command(
3189
+ move.transfer_stake(
3190
+ wallet=wallet,
3191
+ subtensor=self.initialize_chain(network),
3192
+ origin_netuid=origin_netuid,
3193
+ dest_netuid=dest_netuid,
3194
+ dest_coldkey_ss58=dest_ss58,
3195
+ amount=amount,
3196
+ interactive_selection=interactive_selection,
3197
+ prompt=prompt,
3198
+ )
3199
+ )
3200
+
3201
+ def stake_swap(
3202
+ self,
3203
+ network: Optional[list[str]] = Options.network,
3204
+ wallet_name: Optional[str] = Options.wallet_name,
3205
+ wallet_path: Optional[str] = Options.wallet_path,
3206
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3207
+ origin_netuid: Optional[int] = typer.Option(
3208
+ None,
3209
+ "--origin-netuid",
3210
+ "-o",
3211
+ "--origin",
3212
+ help="The netuid to swap stake from",
3213
+ ),
3214
+ dest_netuid: Optional[int] = typer.Option(
3215
+ None,
3216
+ "--dest-netuid",
3217
+ "-d",
3218
+ "--dest",
3219
+ help="The netuid to swap stake to",
3220
+ ),
3221
+ amount: float = typer.Option(
3222
+ None,
3223
+ "--amount",
3224
+ "-a",
3225
+ help="Amount of stake to swap",
3226
+ ),
3227
+ swap_all: bool = typer.Option(
3228
+ False,
3229
+ "--swap-all",
3230
+ "--all",
3231
+ help="Swap all available stake",
3232
+ ),
3233
+ prompt: bool = Options.prompt,
3234
+ wait_for_inclusion: bool = Options.wait_for_inclusion,
3235
+ wait_for_finalization: bool = Options.wait_for_finalization,
3236
+ quiet: bool = Options.quiet,
3237
+ verbose: bool = Options.verbose,
3238
+ ):
3239
+ """
3240
+ Swap stake between different subnets while keeping the same coldkey-hotkey pair ownership.
3241
+
3242
+ This command allows you to:
3243
+ - Move stake from one subnet to another subnet
3244
+ - Keep the same coldkey ownership
3245
+ - Keep the same hotkey ownership
3246
+
3247
+ You can specify:
3248
+ - The origin subnet (--origin-netuid)
3249
+ - The destination subnet (--dest-netuid)
3250
+ - The amount to swap (--amount)
3251
+
3252
+ If no arguments are provided, an interactive selection menu will be shown.
3253
+
3254
+ EXAMPLE
3255
+
3256
+ Swap 100 TAO from subnet 1 to subnet 2:
3257
+ [green]$[/green] btcli stake swap --wallet-name default --wallet-hotkey default --origin-netuid 1 --dest-netuid 2 --amount 100
3258
+ """
3259
+ console.print(
3260
+ "[dim]This command moves stake from one subnet to another subnet while keeping the same coldkey-hotkey pair.[/dim]"
3261
+ )
3262
+ self.verbosity_handler(quiet, verbose)
3263
+
3264
+ wallet = self.wallet_ask(
3265
+ wallet_name,
3266
+ wallet_path,
3267
+ wallet_hotkey,
3268
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3269
+ validate=WV.WALLET_AND_HOTKEY,
3270
+ )
3271
+
3272
+ interactive_selection = False
3273
+ if origin_netuid is None and dest_netuid is None and not amount:
3274
+ interactive_selection = True
3275
+ else:
3276
+ if origin_netuid is None:
3277
+ origin_netuid = IntPrompt.ask(
3278
+ "Enter the [blue]origin subnet[/blue] (netuid)"
3279
+ )
3280
+ if dest_netuid is None:
3281
+ dest_netuid = IntPrompt.ask(
3282
+ "Enter the [blue]destination subnet[/blue] (netuid)"
3283
+ )
3284
+ if not amount and not swap_all:
3285
+ amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to swap")
3286
+
3287
+ return self._run_command(
3288
+ move.swap_stake(
3289
+ wallet=wallet,
3290
+ subtensor=self.initialize_chain(network),
3291
+ origin_netuid=origin_netuid,
3292
+ destination_netuid=dest_netuid,
3293
+ amount=amount,
3294
+ swap_all=swap_all,
3295
+ interactive_selection=interactive_selection,
2987
3296
  prompt=prompt,
3297
+ wait_for_inclusion=wait_for_inclusion,
3298
+ wait_for_finalization=wait_for_finalization,
2988
3299
  )
2989
3300
  )
2990
3301
 
@@ -3562,6 +3873,93 @@ class CLIManager:
3562
3873
  )
3563
3874
  )
3564
3875
 
3876
+ def subnets_price(
3877
+ self,
3878
+ network: Optional[list[str]] = Options.network,
3879
+ netuids: str = typer.Option(
3880
+ None,
3881
+ "--netuids",
3882
+ "--netuid",
3883
+ "-n",
3884
+ help="Netuid(s) to show the price for.",
3885
+ ),
3886
+ interval_hours: int = typer.Option(
3887
+ 24,
3888
+ "--interval-hours",
3889
+ "--interval",
3890
+ help="The number of hours to show the historical price for.",
3891
+ ),
3892
+ all_netuids: bool = typer.Option(
3893
+ False,
3894
+ "--all-netuids",
3895
+ "--all",
3896
+ help="Show the price for all subnets.",
3897
+ ),
3898
+ log_scale: bool = typer.Option(
3899
+ False,
3900
+ "--log-scale",
3901
+ "--log",
3902
+ help="Show the price in log scale.",
3903
+ ),
3904
+ html_output: bool = Options.html_output,
3905
+ ):
3906
+ """
3907
+ Shows the historical price of a subnet for the past 24 hours.
3908
+
3909
+ This command displays the historical price of a subnet for the past 24 hours.
3910
+ If the `--all` flag is used, the command will display the price for all subnets in html format.
3911
+ If the `--html` flag is used, the command will display the price in an HTML chart.
3912
+ If the `--log-scale` flag is used, the command will display the price in log scale.
3913
+ If no html flag is used, the command will display the price in the cli.
3914
+
3915
+ EXAMPLE
3916
+
3917
+ [green]$[/green] btcli subnets price --netuid 1
3918
+ [green]$[/green] btcli subnets price --netuid 1 --html --log
3919
+ [green]$[/green] btcli subnets price --all --html
3920
+ [green]$[/green] btcli subnets price --netuids 1,2,3,4 --html
3921
+ """
3922
+ if netuids:
3923
+ netuids = parse_to_list(
3924
+ netuids,
3925
+ int,
3926
+ "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
3927
+ )
3928
+ if all_netuids and netuids:
3929
+ print_error("Cannot specify both --netuid and --all-netuids")
3930
+ raise typer.Exit()
3931
+
3932
+ if not netuids and not all_netuids:
3933
+ netuids = Prompt.ask(
3934
+ "Enter the [blue]netuid(s)[/blue] to view the price of in comma-separated format [dim](or Press Enter to view all subnets)[/dim]",
3935
+ )
3936
+ if not netuids:
3937
+ all_netuids = True
3938
+ html_output = True
3939
+ else:
3940
+ netuids = parse_to_list(
3941
+ netuids,
3942
+ int,
3943
+ "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
3944
+ )
3945
+
3946
+ if all_netuids:
3947
+ html_output = True
3948
+
3949
+ if html_output and is_linux():
3950
+ print_linux_dependency_message()
3951
+
3952
+ return self._run_command(
3953
+ price.price(
3954
+ self.initialize_chain(network),
3955
+ netuids,
3956
+ all_netuids,
3957
+ interval_hours,
3958
+ html_output,
3959
+ log_scale,
3960
+ )
3961
+ )
3962
+
3565
3963
  def subnets_show(
3566
3964
  self,
3567
3965
  network: Optional[list[str]] = Options.network,
@@ -869,6 +869,7 @@ HELP_PANELS = {
869
869
  "STAKE": {
870
870
  "STAKE_MGMT": "Stake Management",
871
871
  "CHILD": "Child Hotkeys",
872
+ "MOVEMENT": "Stake Movement",
872
873
  },
873
874
  "SUDO": {
874
875
  "CONFIG": "Subnet Configuration",
@@ -17,7 +17,7 @@
17
17
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
18
  # DEALINGS IN THE SOFTWARE.
19
19
 
20
- from typing import Union
20
+ from typing import Union, TypedDict
21
21
  from bittensor_cli.src import UNITS
22
22
 
23
23
 
@@ -301,3 +301,31 @@ class Balance:
301
301
  self.unit = Balance.get_unit(netuid)
302
302
  self.rao_unit = Balance.get_unit(netuid)
303
303
  return self
304
+
305
+
306
+ class FixedPoint(TypedDict):
307
+ """
308
+ Represents a fixed point ``U64F64`` number.
309
+ Where ``bits`` is a U128 representation of the fixed point number.
310
+
311
+ This matches the type of the Alpha shares.
312
+ """
313
+
314
+ bits: int
315
+
316
+
317
+ def fixed_to_float(fixed: FixedPoint) -> float:
318
+ # Currently this is stored as a U64F64
319
+ # which is 64 bits of integer and 64 bits of fractional
320
+ uint_bits = 64
321
+ frac_bits = 64
322
+
323
+ data: int = fixed["bits"]
324
+
325
+ # Shift bits to extract integer part (assuming 64 bits for integer part)
326
+ integer_part = data >> frac_bits
327
+ fractional_part = data & (2**frac_bits - 1)
328
+
329
+ frac_float = fractional_part / (2**frac_bits)
330
+
331
+ return integer_part + frac_float