bittensor-cli 9.19.0rc2__tar.gz → 9.20.1__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 (67) hide show
  1. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/PKG-INFO +4 -3
  2. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/cli.py +144 -57
  3. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/__init__.py +7 -43
  4. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/chain_data.py +18 -6
  5. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/registration.py +5 -3
  6. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/transfer.py +2 -2
  7. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/subtensor_interface.py +124 -105
  8. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/utils.py +21 -2
  9. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/proxy.py +46 -19
  10. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/add.py +165 -53
  11. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/auto_staking.py +6 -30
  12. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/list.py +24 -26
  13. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/move.py +71 -56
  14. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/remove.py +249 -71
  15. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/wizard.py +6 -15
  16. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/subnets/subnets.py +3 -28
  17. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/sudo.py +20 -22
  18. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/view.py +17 -26
  19. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/wallets.py +373 -119
  20. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/pyproject.toml +4 -3
  21. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/README.md +0 -0
  22. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/__init__.py +0 -0
  23. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/doc_generation_helper.py +0 -0
  24. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/__init__.py +0 -0
  25. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/balances.py +0 -0
  26. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/__init__.py +0 -0
  27. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/mev_shield.py +0 -0
  28. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/root.py +0 -0
  29. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/extrinsics/serving.py +0 -0
  30. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/minigraph.py +0 -0
  31. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/networking.py +0 -0
  32. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/main-filters.j2 +0 -0
  33. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/main-header.j2 +0 -0
  34. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/neuron-details.j2 +0 -0
  35. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/price-multi.j2 +0 -0
  36. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/price-single.j2 +0 -0
  37. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/subnet-details-header.j2 +0 -0
  38. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/subnet-details.j2 +0 -0
  39. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/subnet-metrics.j2 +0 -0
  40. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/subnets-table.j2 +0 -0
  41. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/table.j2 +0 -0
  42. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/view.css +0 -0
  43. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/view.j2 +0 -0
  44. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/bittensor/templates/view.js +0 -0
  45. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/__init__.py +0 -0
  46. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/axon/__init__.py +0 -0
  47. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/axon/axon.py +0 -0
  48. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/__init__.py +0 -0
  49. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/contribute.py +0 -0
  50. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/contributors.py +0 -0
  51. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/create.py +0 -0
  52. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/dissolve.py +0 -0
  53. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/refund.py +0 -0
  54. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/update.py +0 -0
  55. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/utils.py +0 -0
  56. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/crowd/view.py +0 -0
  57. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/liquidity/__init__.py +0 -0
  58. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/liquidity/liquidity.py +0 -0
  59. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/liquidity/utils.py +0 -0
  60. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/__init__.py +0 -0
  61. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/children_hotkeys.py +0 -0
  62. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/stake/claim.py +0 -0
  63. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/subnets/__init__.py +0 -0
  64. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/subnets/mechanisms.py +0 -0
  65. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/subnets/price.py +0 -0
  66. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/src/commands/weights.py +0 -0
  67. {bittensor_cli-9.19.0rc2 → bittensor_cli-9.20.1}/bittensor_cli/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bittensor-cli
3
- Version: 9.19.0rc2
3
+ Version: 9.20.1
4
4
  Summary: Bittensor CLI
5
5
  Author: bittensor.com
6
6
  Requires-Python: >=3.10
@@ -19,7 +19,7 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
19
19
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
20
  Classifier: Topic :: Utilities
21
21
  Requires-Dist: wheel
22
- Requires-Dist: async-substrate-interface>=1.6.2
22
+ Requires-Dist: async-substrate-interface>=1.6.2,<2.0.0
23
23
  Requires-Dist: aiohttp~=3.13
24
24
  Requires-Dist: backoff~=2.2.1
25
25
  Requires-Dist: bittensor-drand>=1.3.0
@@ -32,7 +32,8 @@ Requires-Dist: PyYAML~=6.0
32
32
  Requires-Dist: rich>=13.7,<15.0
33
33
  Requires-Dist: scalecodec==1.2.12
34
34
  Requires-Dist: typer>=0.16
35
- Requires-Dist: bittensor-wallet>=4.0.0
35
+ Requires-Dist: typing_extensions>4.0.0; python_version<'3.11'
36
+ Requires-Dist: bittensor-wallet==4.0.1
36
37
  Requires-Dist: packaging
37
38
  Requires-Dist: plotille>=5.0.0
38
39
  Requires-Dist: plotly>=6.0.0
@@ -641,8 +641,8 @@ def get_creation_data(
641
641
  return mnemonic, seed, json_path, json_password
642
642
 
643
643
 
644
- def config_selector(conf: dict, title: str):
645
- def curses_selector(stdscr):
644
+ def config_selector(conf: dict[str, bool], title: str) -> dict[str, bool]:
645
+ def curses_selector(stdscr) -> dict[str, bool]:
646
646
  """
647
647
  Enhanced Curses TUI to make selections.
648
648
  """
@@ -698,7 +698,7 @@ def config_selector(conf: dict, title: str):
698
698
  return curses.wrapper(curses_selector)
699
699
 
700
700
 
701
- def version_callback(value: bool):
701
+ def version_callback(value: bool) -> None:
702
702
  """
703
703
  Prints the current version/branch-name
704
704
  """
@@ -716,7 +716,7 @@ def version_callback(value: bool):
716
716
  raise typer.Exit()
717
717
 
718
718
 
719
- def commands_callback(value: bool):
719
+ def commands_callback(value: bool) -> None:
720
720
  """
721
721
  Prints a tree of commands for the app
722
722
  """
@@ -726,7 +726,7 @@ def commands_callback(value: bool):
726
726
  raise typer.Exit()
727
727
 
728
728
 
729
- def debug_callback(value: bool):
729
+ def debug_callback(value: bool) -> None:
730
730
  if value:
731
731
  debug_file_loc = Path(
732
732
  os.getenv("BTCLI_DEBUG_FILE")
@@ -1389,7 +1389,7 @@ class CLIManager:
1389
1389
  Generates a rich.Tree of the commands, subcommands, and groups of this app
1390
1390
  """
1391
1391
 
1392
- def build_rich_tree(data: dict, parent: Tree):
1392
+ def build_rich_tree(data: dict, parent: Tree) -> None:
1393
1393
  for group, content in data.get("groups", {}).items():
1394
1394
  group_node = parent.add(
1395
1395
  f"[bold cyan]{group}[/]"
@@ -1943,7 +1943,7 @@ class CLIManager:
1943
1943
  with open(self.config_path, "w") as f:
1944
1944
  safe_dump(self.config, f)
1945
1945
 
1946
- def get_config(self):
1946
+ def get_config(self) -> None:
1947
1947
  """
1948
1948
  Prints the current config file in a table.
1949
1949
  """
@@ -2079,7 +2079,7 @@ class CLIManager:
2079
2079
  print_error(f"Proxy {name} not found in address book.")
2080
2080
  self.config_get_proxies()
2081
2081
 
2082
- def config_get_proxies(self):
2082
+ def config_get_proxies(self) -> None:
2083
2083
  """
2084
2084
  Displays the current proxies address book
2085
2085
 
@@ -2228,7 +2228,7 @@ class CLIManager:
2228
2228
  console.print("Proxy updated")
2229
2229
  self.config_get_proxies()
2230
2230
 
2231
- def config_clear_proxy_book(self):
2231
+ def config_clear_proxy_book(self) -> None:
2232
2232
  """
2233
2233
  Clears the proxy address book. Use with caution.
2234
2234
  Really only useful if you have corrupted your proxy address book.
@@ -2913,7 +2913,17 @@ class CLIManager:
2913
2913
  ),
2914
2914
  wallet_name: str = Options.wallet_name,
2915
2915
  wallet_path: str = Options.wallet_path,
2916
- wallet_hotkey: str = Options.wallet_hotkey,
2916
+ wallet_hotkey: str = Options.edit_help(
2917
+ "wallet_hotkey",
2918
+ help_text="Deprecated option, "
2919
+ "preserved for backwards compatibility to not break workflows which utilise it.",
2920
+ ),
2921
+ ss58_address: Optional[str] = typer.Option(
2922
+ None,
2923
+ "--ss58-address",
2924
+ "--ss58",
2925
+ help="SS58 address of the coldkey to inspect. Allows inspecting any coldkey without a local wallet file.",
2926
+ ),
2917
2927
  network: Optional[list[str]] = Options.network,
2918
2928
  netuids: str = Options.netuids,
2919
2929
  quiet: bool = Options.quiet,
@@ -2921,9 +2931,11 @@ class CLIManager:
2921
2931
  json_output: bool = Options.json_output,
2922
2932
  ):
2923
2933
  """
2924
- Displays the details of the user's wallet pairs (coldkey, hotkey) on the Bittensor network.
2934
+ Displays the details of the user's wallet (coldkey) on the Bittensor network.
2925
2935
 
2926
- The output is presented as a table with the below columns:
2936
+ The output is presented as two separate tables:
2937
+
2938
+ [bold]Coldkey Overview[/bold]:
2927
2939
 
2928
2940
  - [blue bold]Coldkey[/blue bold]: The coldkey associated with the user's wallet.
2929
2941
 
@@ -2931,14 +2943,22 @@ class CLIManager:
2931
2943
 
2932
2944
  - [blue bold]Delegate[/blue bold]: The name of the delegate to which the coldkey has staked TAO.
2933
2945
 
2934
- - [blue bold]Stake[/blue bold]: The amount of stake held by both the coldkey and hotkey.
2946
+ - [blue bold]Stake[/blue bold]: The amount of stake delegated.
2935
2947
 
2936
- - [blue bold]Emission[/blue bold]: The emission or rewards earned from staking.
2948
+ - [blue bold]Emission[/blue bold]: The daily emission earned from delegation.
2949
+
2950
+ [bold]Hotkey Details[/bold]:
2937
2951
 
2938
- - [blue bold]Netuid[/blue bold]: The network unique identifier of the subnet where the hotkey is active (i.e., validating).
2952
+ - [blue bold]Coldkey[/blue bold]: The parent coldkey of the hotkey.
2953
+
2954
+ - [blue bold]Netuid[/blue bold]: The network unique identifier of the subnet where the hotkey is active.
2939
2955
 
2940
2956
  - [blue bold]Hotkey[/blue bold]: The hotkey associated with the neuron on the network.
2941
2957
 
2958
+ - [blue bold]Stake[/blue bold]: The amount of stake held by the hotkey.
2959
+
2960
+ - [blue bold]Emission[/blue bold]: The emission or rewards earned from staking.
2961
+
2942
2962
  USAGE
2943
2963
 
2944
2964
  This command can be used to inspect a single wallet or all the wallets located at a specified path. It is useful for a comprehensive overview of a user's participation and performance in the Bittensor network.
@@ -2949,10 +2969,10 @@ class CLIManager:
2949
2969
 
2950
2970
  [green]$[/green] btcli wallet inspect --all -n 1 -n 2 -n 3
2951
2971
 
2972
+ [green]$[/green] btcli wallet inspect --ss58-address 5FHneW46...
2973
+
2952
2974
  [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.
2953
2975
  """
2954
- print_error("This command is disabled on the 'rao' network.")
2955
- raise typer.Exit()
2956
2976
  self.verbosity_handler(quiet, verbose, json_output, False)
2957
2977
 
2958
2978
  if netuids:
@@ -2962,18 +2982,28 @@ class CLIManager:
2962
2982
  "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
2963
2983
  )
2964
2984
 
2985
+ if ss58_address:
2986
+ return self._run_command(
2987
+ wallets.inspect(
2988
+ None,
2989
+ self.initialize_chain(network),
2990
+ netuids_filter=netuids,
2991
+ all_wallets=False,
2992
+ ss58_address=ss58_address,
2993
+ )
2994
+ )
2995
+
2965
2996
  # if all-wallets is entered, ask for path
2966
2997
  ask_for = [WO.NAME, WO.PATH] if not all_wallets else [WO.PATH]
2967
2998
  validate = WV.WALLET if not all_wallets else WV.NONE
2968
2999
  wallet = self.wallet_ask(
2969
- wallet_name, wallet_path, wallet_hotkey, ask_for=ask_for, validate=validate
3000
+ wallet_name, wallet_path, None, ask_for=ask_for, validate=validate
2970
3001
  )
2971
3002
 
2972
- self.initialize_chain(network)
2973
3003
  return self._run_command(
2974
3004
  wallets.inspect(
2975
3005
  wallet,
2976
- self.subtensor,
3006
+ self.initialize_chain(network),
2977
3007
  netuids_filter=netuids,
2978
3008
  all_wallets=all_wallets,
2979
3009
  )
@@ -4144,7 +4174,11 @@ class CLIManager:
4144
4174
  self,
4145
4175
  action: str = typer.Argument(
4146
4176
  None,
4147
- help="Action to perform: 'announce' to announce intent, 'execute' to complete swap after delay, 'dispute' to freeze the swap.",
4177
+ help=(
4178
+ "Action to perform: 'announce' to announce intent, "
4179
+ "'execute' to complete swap after delay, 'dispute' to freeze the swap, "
4180
+ "'clear' to withdraw announcement, 'check' to view status."
4181
+ ),
4148
4182
  ),
4149
4183
  wallet_name: Optional[str] = Options.wallet_name,
4150
4184
  wallet_path: Optional[str] = Options.wallet_path,
@@ -4176,6 +4210,9 @@ class CLIManager:
4176
4210
  If you suspect compromise, you can [bold]Dispute[/bold] an active announcement to freeze
4177
4211
  all activity for the coldkey until the triumvirate can intervene.
4178
4212
 
4213
+ If you want to withdraw your announcement, you can [bold]Clear[/bold] (withdraw) an announcement once the
4214
+ reannouncement delay has elapsed.
4215
+
4179
4216
  EXAMPLES
4180
4217
 
4181
4218
  Step 1 - Announce your intent to swap:
@@ -4190,9 +4227,13 @@ class CLIManager:
4190
4227
 
4191
4228
  [green]$[/green] btcli wallet swap-coldkey dispute
4192
4229
 
4193
- Check status of pending swaps:
4230
+ Clear (withdraw) an announcement:
4231
+
4232
+ [green]$[/green] btcli wallet swap-coldkey clear
4194
4233
 
4195
- [green]$[/green] btcli wallet swap-check
4234
+ Check status of your swap:
4235
+
4236
+ [green]$[/green] btcli wallet swap-coldkey check
4196
4237
  """
4197
4238
  self.verbosity_handler(quiet, verbose, prompt=False, json_output=False)
4198
4239
 
@@ -4201,18 +4242,19 @@ class CLIManager:
4201
4242
  "\n[bold][blue]Coldkey Swap Actions:[/blue][/bold]\n"
4202
4243
  " [dark_sea_green3]announce[/dark_sea_green3] - Start the swap process (pays fee, starts delay timer)\n"
4203
4244
  " [dark_sea_green3]execute[/dark_sea_green3] - Complete the swap (after delay period)\n"
4204
- " [dark_sea_green3]dispute[/dark_sea_green3] - Freeze the swap process if you suspect compromise\n\n"
4205
- " [dim]You can check the current status of your swap with 'btcli wallet swap-check'.[/dim]\n"
4245
+ " [dark_sea_green3]dispute[/dark_sea_green3] - Freeze the swap process if you suspect compromise\n"
4246
+ " [dark_sea_green3]clear[/dark_sea_green3] - Withdraw your swap announcement\n"
4247
+ " [dark_sea_green3]check[/dark_sea_green3] - Check the status of your swap\n\n"
4206
4248
  )
4207
4249
  action = Prompt.ask(
4208
4250
  "Select action",
4209
- choices=["announce", "execute", "dispute"],
4251
+ choices=["announce", "execute", "dispute", "clear", "check"],
4210
4252
  default="announce",
4211
4253
  )
4212
4254
 
4213
- if action.lower() not in ("announce", "execute", "dispute"):
4255
+ if action.lower() not in ("announce", "execute", "dispute", "clear", "check"):
4214
4256
  print_error(
4215
- f"Invalid action: {action}. Must be 'announce', 'execute', or 'dispute'."
4257
+ f"Invalid action: {action}. Must be 'announce', 'execute', 'dispute', 'clear', or 'check'."
4216
4258
  )
4217
4259
  raise typer.Exit(1)
4218
4260
 
@@ -4233,7 +4275,7 @@ class CLIManager:
4233
4275
  )
4234
4276
 
4235
4277
  new_wallet_coldkey_ss58 = None
4236
- if action != "dispute":
4278
+ if action not in ("dispute", "clear", "check"):
4237
4279
  if not new_wallet_or_ss58:
4238
4280
  new_wallet_or_ss58 = Prompt.ask(
4239
4281
  "Enter the [blue]new wallet name[/blue] or [blue]SS58 address[/blue] of the new coldkey",
@@ -4285,6 +4327,24 @@ class CLIManager:
4285
4327
  mev_protection=mev_protection,
4286
4328
  )
4287
4329
  )
4330
+ elif action == "clear":
4331
+ return self._run_command(
4332
+ wallets.clear_coldkey_swap_announcement(
4333
+ wallet=wallet,
4334
+ subtensor=self.initialize_chain(network),
4335
+ decline=decline,
4336
+ quiet=quiet,
4337
+ prompt=prompt,
4338
+ mev_protection=mev_protection,
4339
+ )
4340
+ )
4341
+ elif action == "check":
4342
+ return self._run_command(
4343
+ wallets.check_swap_status(
4344
+ subtensor=self.initialize_chain(network),
4345
+ origin_ss58=wallet.coldkeypub.ss58_address,
4346
+ )
4347
+ )
4288
4348
  else:
4289
4349
  return self._run_command(
4290
4350
  wallets.execute_coldkey_swap(
@@ -5452,33 +5512,20 @@ class CLIManager:
5452
5512
  console.print(
5453
5513
  "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]"
5454
5514
  )
5515
+ interactive_selection = False
5455
5516
  if not destination_hotkey:
5456
5517
  dest_wallet_or_ss58 = Prompt.ask(
5457
- "Enter the [blue]destination wallet[/blue] where destination hotkey is located or "
5458
- "[blue]ss58 address[/blue]"
5518
+ "Enter the [blue]ss58 address[/blue] of the hotkey to move the stake to, leave blank for other options"
5459
5519
  )
5460
5520
  if is_valid_ss58_address(dest_wallet_or_ss58):
5461
5521
  destination_hotkey = dest_wallet_or_ss58
5522
+ elif dest_wallet_or_ss58.strip() == "":
5523
+ interactive_selection = True
5462
5524
  else:
5463
- dest_wallet = self.wallet_ask(
5464
- dest_wallet_or_ss58,
5465
- wallet_path,
5466
- None,
5467
- ask_for=[WO.NAME, WO.PATH],
5468
- validate=WV.WALLET,
5469
- )
5470
- destination_hotkey = Prompt.ask(
5471
- "Enter the [blue]destination hotkey[/blue] name",
5472
- default=dest_wallet.hotkey_str,
5473
- )
5474
- destination_wallet = self.wallet_ask(
5475
- dest_wallet_or_ss58,
5476
- wallet_path,
5477
- destination_hotkey,
5478
- ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
5479
- validate=WV.WALLET_AND_HOTKEY,
5525
+ print_error(
5526
+ "Invalid destination hotkey ss58 address. Please enter a valid ss58 address."
5480
5527
  )
5481
- destination_hotkey = get_hotkey_pub_ss58(destination_wallet)
5528
+ raise typer.Exit()
5482
5529
  else:
5483
5530
  if is_valid_ss58_address(destination_hotkey):
5484
5531
  destination_hotkey = destination_hotkey
@@ -5497,7 +5544,6 @@ class CLIManager:
5497
5544
  wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
5498
5545
  )
5499
5546
 
5500
- interactive_selection = False
5501
5547
  if not wallet_hotkey:
5502
5548
  origin_hotkey = Prompt.ask(
5503
5549
  "Enter the [blue]origin hotkey[/blue] name or "
@@ -9807,13 +9853,18 @@ class CLIManager:
9807
9853
  def proxy_remove(
9808
9854
  self,
9809
9855
  delegate: Annotated[
9810
- str,
9856
+ Optional[str],
9811
9857
  typer.Option(
9812
9858
  callback=is_valid_ss58_address_param,
9813
- prompt="Enter the SS58 address of the delegate to remove, e.g. 5dxds...",
9814
- help="The SS58 address of the delegate to remove",
9859
+ prompt=False,
9860
+ help="The SS58 address of the delegate to remove (required if --all is not used)",
9815
9861
  ),
9816
- ] = "",
9862
+ ] = None,
9863
+ all_: bool = typer.Option(
9864
+ False,
9865
+ "--all",
9866
+ help="Remove all proxies associated with this account",
9867
+ ),
9817
9868
  network: Optional[list[str]] = Options.network,
9818
9869
  proxy_type: ProxyType = Options.proxy_type,
9819
9870
  delay: int = typer.Option(0, help="Delay, in number of blocks"),
@@ -9840,10 +9891,10 @@ class CLIManager:
9840
9891
  [green]$[/green] btcli proxy remove --delegate 5GDel... --proxy-type Transfer
9841
9892
 
9842
9893
  """
9843
- # TODO should add a --all flag to call Proxy.remove_proxies ?
9844
9894
  logger.debug(
9845
9895
  "args:\n"
9846
9896
  f"delegate: {delegate}\n"
9897
+ f"all: {all_}\n"
9847
9898
  f"network: {network}\n"
9848
9899
  f"proxy_type: {proxy_type}\n"
9849
9900
  f"delay: {delay}\n"
@@ -9851,6 +9902,41 @@ class CLIManager:
9851
9902
  f"wait_for_inclusion: {wait_for_inclusion}\n"
9852
9903
  f"era: {period}\n"
9853
9904
  )
9905
+ # Validate that --delegate and --all are not used together
9906
+ if all_ and delegate:
9907
+ if not json_output:
9908
+ print_error("--delegate cannot be used together with --all flag.")
9909
+ else:
9910
+ json_console.print_json(
9911
+ data={
9912
+ "success": False,
9913
+ "message": "--delegate cannot be used together with --all flag.",
9914
+ "extrinsic_identifier": None,
9915
+ }
9916
+ )
9917
+ return
9918
+
9919
+ # If --all is not used and delegate is not provided, prompt or error
9920
+ if not all_ and not delegate:
9921
+ if not prompt:
9922
+ if not json_output:
9923
+ print_error(
9924
+ "Either --delegate must be provided or --all flag must be used."
9925
+ )
9926
+ else:
9927
+ json_console.print_json(
9928
+ data={
9929
+ "success": False,
9930
+ "message": "Either --delegate must be provided or --all flag must be used.",
9931
+ "extrinsic_identifier": None,
9932
+ }
9933
+ )
9934
+ return
9935
+ delegate = Prompt.ask(
9936
+ "Enter the SS58 address of the delegate to remove, e.g. 5dxds..."
9937
+ )
9938
+ delegate = is_valid_ss58_address_param(delegate)
9939
+
9854
9940
  self.verbosity_handler(quiet, verbose, json_output, prompt)
9855
9941
  wallet = self.wallet_ask(
9856
9942
  wallet_name=wallet_name,
@@ -9873,6 +9959,7 @@ class CLIManager:
9873
9959
  wait_for_finalization=wait_for_finalization,
9874
9960
  period=period,
9875
9961
  json_output=json_output,
9962
+ remove_all=all_,
9876
9963
  )
9877
9964
  )
9878
9965
 
@@ -10275,11 +10362,11 @@ class CLIManager:
10275
10362
  )
10276
10363
  return True
10277
10364
 
10278
- def run(self):
10365
+ def run(self) -> None:
10279
10366
  self.app()
10280
10367
 
10281
10368
 
10282
- def main():
10369
+ def main() -> None:
10283
10370
  manager = CLIManager()
10284
10371
  manager.run()
10285
10372
 
@@ -1,6 +1,4 @@
1
1
  from enum import Enum
2
- from dataclasses import dataclass
3
- from typing import Any, Optional
4
2
 
5
3
 
6
4
  class Constants:
@@ -37,47 +35,6 @@ class Constants:
37
35
  delegates_detail_url = "https://raw.githubusercontent.com/opentensor/bittensor-delegates/main/public/delegates.json"
38
36
 
39
37
 
40
- @dataclass
41
- class DelegatesDetails:
42
- display: str
43
- additional: list[tuple[str, str]]
44
- web: str
45
- legal: Optional[str] = None
46
- riot: Optional[str] = None
47
- email: Optional[str] = None
48
- pgp_fingerprint: Optional[str] = None
49
- image: Optional[str] = None
50
- twitter: Optional[str] = None
51
-
52
- @classmethod
53
- def from_chain_data(cls, data: dict[str, Any]) -> "DelegatesDetails":
54
- def decode(key: str, default=""):
55
- try:
56
- if isinstance(data.get(key), dict):
57
- value = next(data.get(key).values())
58
- return bytes(value[0]).decode("utf-8")
59
- elif isinstance(data.get(key), int):
60
- return data.get(key)
61
- elif isinstance(data.get(key), tuple):
62
- return bytes(data.get(key)[0]).decode("utf-8")
63
- else:
64
- return default
65
- except (UnicodeDecodeError, TypeError):
66
- return default
67
-
68
- return cls(
69
- display=decode("display"),
70
- additional=decode("additional", []),
71
- web=decode("web"),
72
- legal=decode("legal"),
73
- riot=decode("riot"),
74
- email=decode("email"),
75
- pgp_fingerprint=decode("pgp_fingerprint", None),
76
- image=decode("image"),
77
- twitter=decode("twitter"),
78
- )
79
-
80
-
81
38
  class Defaults:
82
39
  netuid = 1
83
40
  rate_tolerance = 0.005
@@ -692,6 +649,7 @@ HYPERPARAMS = {
692
649
  "alpha_low": ("", RootSudoOnly.FALSE), # Derived from alpha_values
693
650
  "subnet_is_active": ("", RootSudoOnly.FALSE), # Set via btcli subnets start
694
651
  "yuma_version": ("", RootSudoOnly.FALSE), # Related to yuma3_enabled
652
+ "max_allowed_uids": ("sudo_set_max_allowed_uids", RootSudoOnly.FALSE),
695
653
  }
696
654
 
697
655
  HYPERPARAMS_MODULE = {
@@ -941,6 +899,12 @@ HYPERPARAMS_METADATA = {
941
899
  "owner_settable": True,
942
900
  "docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters#yuma3",
943
901
  },
902
+ "max_allowed_uids": {
903
+ "description": "Maximum number of UIDs (neurons) on the subnet, essentially 'untrimming'.",
904
+ "side_effects": "See description for min_allowed_uids",
905
+ "owner_settable": True,
906
+ "docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters#maxalloweduids",
907
+ },
944
908
  }
945
909
 
946
910
  # Help Panels for cli help
@@ -1,7 +1,8 @@
1
1
  from abc import abstractmethod
2
2
  from dataclasses import dataclass
3
+ from collections.abc import Sequence
3
4
  from enum import Enum
4
- from typing import Optional, Any, Union
5
+ from typing import Optional, Any, Union, Callable, Hashable
5
6
 
6
7
  import netaddr
7
8
  from scalecodec.utils.ss58 import ss58_encode
@@ -16,6 +17,11 @@ from bittensor_cli.src.bittensor.utils import (
16
17
  get_netuid_and_subuid_by_storage_index,
17
18
  )
18
19
 
20
+ try:
21
+ from typing import Self
22
+ except ImportError:
23
+ from typing_extensions import Self
24
+
19
25
 
20
26
  class ChainDataType(Enum):
21
27
  NeuronInfo = 1
@@ -69,9 +75,12 @@ def _chr_str(codes: tuple[int]) -> str:
69
75
  return "".join(map(chr, codes))
70
76
 
71
77
 
72
- def process_nested(data: Union[tuple, dict], chr_transform):
78
+ def process_nested(
79
+ data: Sequence[dict[Hashable, tuple[int]]] | dict | Any,
80
+ chr_transform: Callable[[tuple[int]], str],
81
+ ) -> list[dict[Hashable, str]] | dict[Hashable, str] | Any:
73
82
  """Processes nested data structures by applying a transformation function to their elements."""
74
- if isinstance(data, (list, tuple)):
83
+ if isinstance(data, Sequence):
75
84
  if len(data) > 0 and isinstance(data[0], dict):
76
85
  return [
77
86
  {k: chr_transform(v) for k, v in item.items()}
@@ -79,9 +88,12 @@ def process_nested(data: Union[tuple, dict], chr_transform):
79
88
  else None
80
89
  for item in data
81
90
  ]
91
+ # TODO @abe why do we kind of silently fail here?
82
92
  return {}
83
93
  elif isinstance(data, dict):
84
94
  return {k: chr_transform(v) for k, v in data.items()}
95
+ else:
96
+ return data
85
97
 
86
98
 
87
99
  @dataclass
@@ -127,17 +139,17 @@ class InfoBase:
127
139
  """Base dataclass for info objects."""
128
140
 
129
141
  @abstractmethod
130
- def _fix_decoded(self, decoded: Any) -> "InfoBase":
142
+ def _fix_decoded(self, decoded: Any) -> Self:
131
143
  raise NotImplementedError(
132
144
  "This is an abstract method and must be implemented in a subclass."
133
145
  )
134
146
 
135
147
  @classmethod
136
- def from_any(cls, data: Any) -> "InfoBase":
148
+ def from_any(cls, data: Any) -> Self:
137
149
  return cls._fix_decoded(data)
138
150
 
139
151
  @classmethod
140
- def list_from_any(cls, data_list: list[Any]) -> list["InfoBase"]:
152
+ def list_from_any(cls, data_list: list[Any]) -> list[Self]:
141
153
  return [cls.from_any(data) for data in data_list]
142
154
 
143
155
  def __getitem__(self, item):
@@ -708,11 +708,13 @@ async def burned_register_extrinsic(
708
708
  f":satellite: Checking Account on [bold]subnet:{netuid}[/bold]...",
709
709
  spinner="aesthetic",
710
710
  ) as status:
711
+ block_hash = await subtensor.substrate.get_chain_head()
711
712
  my_uid = await subtensor.query(
712
- "SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
713
+ module="SubtensorModule",
714
+ storage_function="Uids",
715
+ params=[netuid, get_hotkey_pub_ss58(wallet)],
716
+ block_hash=block_hash,
713
717
  )
714
- block_hash = await subtensor.substrate.get_chain_head()
715
-
716
718
  print_verbose("Checking if already registered", status)
717
719
  neuron = await subtensor.neuron_for_uid(
718
720
  uid=my_uid, netuid=netuid, block_hash=block_hash
@@ -156,10 +156,10 @@ async def transfer_extrinsic(
156
156
  f" would bring you under the existential deposit: [bright_cyan]{existential_deposit}[/bright_cyan].\n"
157
157
  )
158
158
  return False, None
159
- if account_balance < amount and allow_death:
159
+ if proxy_balance < amount and allow_death:
160
160
  print_error(
161
161
  "[bold red]Not enough balance[/bold red]:\n\n"
162
- f" balance: [bright_red]{account_balance}[/bright_red]\n"
162
+ f" balance: [bright_red]{proxy_balance}[/bright_red]\n"
163
163
  f" amount: [bright_red]{amount}[/bright_red]\n"
164
164
  )
165
165
  return False, None