bittensor-cli 9.9.0__tar.gz → 9.10.0__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 (57) hide show
  1. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/PKG-INFO +13 -5
  2. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/README.md +9 -1
  3. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/cli.py +165 -54
  4. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/extrinsics/registration.py +29 -25
  5. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/extrinsics/root.py +6 -5
  6. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/extrinsics/transfer.py +1 -1
  7. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/subtensor_interface.py +2 -1
  8. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/utils.py +13 -1
  9. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/add.py +4 -3
  10. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/children_hotkeys.py +16 -14
  11. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/move.py +6 -4
  12. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/remove.py +5 -4
  13. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/subnets/price.py +126 -30
  14. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/subnets/subnets.py +3 -2
  15. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/sudo.py +13 -11
  16. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/wallets.py +68 -16
  17. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/weights.py +2 -1
  18. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/PKG-INFO +13 -5
  19. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/requires.txt +3 -3
  20. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/pyproject.toml +4 -4
  21. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/MANIFEST.in +0 -0
  22. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/__init__.py +0 -0
  23. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/doc_generation_helper.py +0 -0
  24. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/__init__.py +0 -0
  25. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/__init__.py +0 -0
  26. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/balances.py +0 -0
  27. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/chain_data.py +0 -0
  28. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/extrinsics/__init__.py +0 -0
  29. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/minigraph.py +0 -0
  30. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/networking.py +0 -0
  31. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/main-filters.j2 +0 -0
  32. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/main-header.j2 +0 -0
  33. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/neuron-details.j2 +0 -0
  34. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/price-multi.j2 +0 -0
  35. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/price-single.j2 +0 -0
  36. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/subnet-details-header.j2 +0 -0
  37. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/subnet-details.j2 +0 -0
  38. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/subnet-metrics.j2 +0 -0
  39. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/subnets-table.j2 +0 -0
  40. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/table.j2 +0 -0
  41. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/view.css +0 -0
  42. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/view.j2 +0 -0
  43. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/bittensor/templates/view.js +0 -0
  44. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/__init__.py +0 -0
  45. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/liquidity/__init__.py +0 -0
  46. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/liquidity/liquidity.py +0 -0
  47. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/liquidity/utils.py +0 -0
  48. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/__init__.py +0 -0
  49. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/stake/list.py +0 -0
  50. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/subnets/__init__.py +0 -0
  51. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/src/commands/view.py +0 -0
  52. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli/version.py +0 -0
  53. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/SOURCES.txt +0 -0
  54. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/dependency_links.txt +0 -0
  55. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/entry_points.txt +0 -0
  56. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/bittensor_cli.egg-info/top_level.txt +0 -0
  57. {bittensor_cli-9.9.0 → bittensor_cli-9.10.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bittensor-cli
3
- Version: 9.9.0
3
+ Version: 9.10.0
4
4
  Summary: Bittensor CLI
5
5
  Author: bittensor.com
6
6
  Project-URL: homepage, https://github.com/opentensor/btcli
@@ -11,7 +11,6 @@ Requires-Dist: wheel
11
11
  Requires-Dist: async-substrate-interface>=1.4.2
12
12
  Requires-Dist: aiohttp~=3.10.2
13
13
  Requires-Dist: backoff~=2.2.1
14
- Requires-Dist: click<8.2.0
15
14
  Requires-Dist: GitPython>=3.0.0
16
15
  Requires-Dist: netaddr~=1.3.0
17
16
  Requires-Dist: numpy<3.0.0,>=2.0.1
@@ -20,8 +19,9 @@ Requires-Dist: pycryptodome<4.0.0,>=3.0.0
20
19
  Requires-Dist: PyYAML~=6.0.1
21
20
  Requires-Dist: rich<15.0,>=13.7
22
21
  Requires-Dist: scalecodec==1.2.11
23
- Requires-Dist: typer<0.16,>=0.12
24
- Requires-Dist: bittensor-wallet>=3.0.7
22
+ Requires-Dist: typer>=0.16
23
+ Requires-Dist: bittensor-wallet>=4.0.0
24
+ Requires-Dist: packaging
25
25
  Requires-Dist: plotille>=5.0.0
26
26
  Requires-Dist: plotly>=6.0.0
27
27
  Provides-Extra: cuda
@@ -71,7 +71,15 @@ Installation steps are described below. For a full documentation on how to use `
71
71
 
72
72
  ## Install on macOS and Linux
73
73
 
74
- You can install `btcli` on your local machine directly from source, PyPI, or Homebrew. **Make sure you verify your installation after you install**:
74
+ You can install `btcli` on your local machine directly from source, PyPI, or Homebrew.
75
+ **Make sure you verify your installation after you install**.
76
+
77
+ ### For macOS users
78
+ Note that the macOS preinstalled CPython installation is compiled with LibreSSL instead of OpenSSL. There are a number
79
+ of issues with LibreSSL, and as such is not fully supported by the libraries used by btcli. Thus we highly recommend, if
80
+ you are using a Mac, to first install Python from [Homebrew](https://brew.sh/). Additionally, the Rust FFI bindings
81
+ [if installing from precompiled wheels (default)] require the Homebrew-installed OpenSSL pacakge. If you choose to use
82
+ the preinstalled Python version from macOS, things may not work completely.
75
83
 
76
84
 
77
85
  ### Install from [PyPI](https://pypi.org/project/bittensor/)
@@ -38,7 +38,15 @@ Installation steps are described below. For a full documentation on how to use `
38
38
 
39
39
  ## Install on macOS and Linux
40
40
 
41
- You can install `btcli` on your local machine directly from source, PyPI, or Homebrew. **Make sure you verify your installation after you install**:
41
+ You can install `btcli` on your local machine directly from source, PyPI, or Homebrew.
42
+ **Make sure you verify your installation after you install**.
43
+
44
+ ### For macOS users
45
+ Note that the macOS preinstalled CPython installation is compiled with LibreSSL instead of OpenSSL. There are a number
46
+ of issues with LibreSSL, and as such is not fully supported by the libraries used by btcli. Thus we highly recommend, if
47
+ you are using a Mac, to first install Python from [Homebrew](https://brew.sh/). Additionally, the Rust FFI bindings
48
+ [if installing from precompiled wheels (default)] require the Homebrew-installed OpenSSL pacakge. If you choose to use
49
+ the preinstalled Python version from macOS, things may not work completely.
42
50
 
43
51
 
44
52
  ### Install from [PyPI](https://pypi.org/project/bittensor/)
@@ -58,6 +58,7 @@ from bittensor_cli.src.bittensor.utils import (
58
58
  validate_uri,
59
59
  prompt_for_subnet_identity,
60
60
  validate_rate_tolerance,
61
+ get_hotkey_pub_ss58,
61
62
  )
62
63
  from bittensor_cli.src.commands import sudo, wallets, view
63
64
  from bittensor_cli.src.commands import weights as weights_cmds
@@ -250,7 +251,7 @@ class Options:
250
251
  True,
251
252
  "--prompt/--no-prompt",
252
253
  " /--yes",
253
- "--prompt/--no_prompt",
254
+ " /--no_prompt",
254
255
  " /-y",
255
256
  help="Enable or disable interactive prompts.",
256
257
  )
@@ -643,8 +644,21 @@ class CLIManager:
643
644
  # },
644
645
  }
645
646
  self.subtensor = None
647
+
648
+ if sys.version_info < (3, 10):
649
+ # For Python 3.9 or lower
650
+ self.event_loop = asyncio.new_event_loop()
651
+ else:
652
+ try:
653
+ uvloop = importlib.import_module("uvloop")
654
+ self.event_loop = uvloop.new_event_loop()
655
+ except ModuleNotFoundError:
656
+ self.event_loop = asyncio.new_event_loop()
657
+
646
658
  self.config_base_path = os.path.expanduser(defaults.config.base_path)
647
- self.config_path = os.path.expanduser(defaults.config.path)
659
+ self.config_path = os.getenv("BTCLI_CONFIG_PATH") or os.path.expanduser(
660
+ defaults.config.path
661
+ )
648
662
 
649
663
  self.app = typer.Typer(
650
664
  rich_markup_mode="rich",
@@ -652,7 +666,12 @@ class CLIManager:
652
666
  epilog=_epilog,
653
667
  no_args_is_help=True,
654
668
  )
655
- self.config_app = typer.Typer(epilog=_epilog)
669
+ self.config_app = typer.Typer(
670
+ epilog=_epilog,
671
+ help=f"Allows for getting/setting the config. "
672
+ f"Default path for the config file is [{COLORS.G.ARG}]{defaults.config.path}[/{COLORS.G.ARG}]. "
673
+ f"You can set your own with the env var [{COLORS.G.ARG}]BTCLI_CONFIG_PATH[/{COLORS.G.ARG}]",
674
+ )
656
675
  self.wallet_app = typer.Typer(epilog=_epilog)
657
676
  self.stake_app = typer.Typer(epilog=_epilog)
658
677
  self.sudo_app = typer.Typer(epilog=_epilog)
@@ -773,6 +792,9 @@ class CLIManager:
773
792
  self.wallet_app.command(
774
793
  "regen-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
775
794
  )(self.wallet_regen_hotkey)
795
+ self.wallet_app.command(
796
+ "regen-hotkeypub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
797
+ )(self.wallet_regen_hotkey_pub)
776
798
  self.wallet_app.command(
777
799
  "new-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
778
800
  )(self.wallet_new_hotkey)
@@ -955,6 +977,10 @@ class CLIManager:
955
977
  "regen_hotkey",
956
978
  hidden=True,
957
979
  )(self.wallet_regen_hotkey)
980
+ self.wallet_app.command(
981
+ "regen_hotkeypub",
982
+ hidden=True,
983
+ )(self.wallet_regen_hotkey_pub)
958
984
  self.wallet_app.command(
959
985
  "new_hotkey",
960
986
  hidden=True,
@@ -1079,11 +1105,11 @@ class CLIManager:
1079
1105
 
1080
1106
  self.subtensor = SubtensorInterface(network_)
1081
1107
  elif self.config["network"]:
1082
- self.subtensor = SubtensorInterface(self.config["network"])
1083
1108
  console.print(
1084
1109
  f"Using the specified network [{COLORS.G.LINKS}]{self.config['network']}"
1085
1110
  f"[/{COLORS.G.LINKS}] from config"
1086
1111
  )
1112
+ self.subtensor = SubtensorInterface(self.config["network"])
1087
1113
  else:
1088
1114
  self.subtensor = SubtensorInterface(defaults.subtensor.network)
1089
1115
  return self.subtensor
@@ -1097,12 +1123,9 @@ class CLIManager:
1097
1123
  initiated = False
1098
1124
  try:
1099
1125
  if self.subtensor:
1100
- async with self.subtensor:
1101
- initiated = True
1102
- result = await cmd
1103
- else:
1104
- initiated = True
1105
- result = await cmd
1126
+ await self.subtensor.substrate.initialize()
1127
+ initiated = True
1128
+ result = await cmd
1106
1129
  return result
1107
1130
  except (ConnectionRefusedError, ssl.SSLError, InvalidHandshake):
1108
1131
  err_console.print(f"Unable to connect to the chain: {self.subtensor}")
@@ -1128,12 +1151,14 @@ class CLIManager:
1128
1151
  exit_early is True
1129
1152
  ): # temporarily to handle multiple run commands in one session
1130
1153
  try:
1154
+ if self.subtensor:
1155
+ await self.subtensor.substrate.close()
1131
1156
  raise typer.Exit()
1132
1157
  except Exception as e: # ensures we always exit cleanly
1133
1158
  if not isinstance(e, (typer.Exit, RuntimeError)):
1134
1159
  err_console.print(f"An unknown error has occurred: {e}")
1135
1160
 
1136
- return self.asyncio_runner(_run())
1161
+ return self.event_loop.run_until_complete(_run())
1137
1162
 
1138
1163
  def main_callback(
1139
1164
  self,
@@ -1184,20 +1209,6 @@ class CLIManager:
1184
1209
  if k in self.config.keys():
1185
1210
  self.config[k] = v
1186
1211
 
1187
- if sys.version_info < (3, 10):
1188
- # For Python 3.9 or lower
1189
- self.asyncio_runner = asyncio.get_event_loop().run_until_complete
1190
- else:
1191
- try:
1192
- uvloop = importlib.import_module("uvloop")
1193
- if sys.version_info >= (3, 11):
1194
- self.asyncio_runner = uvloop.run
1195
- else:
1196
- uvloop.install()
1197
- self.asyncio_runner = asyncio.run
1198
- except ModuleNotFoundError:
1199
- self.asyncio_runner = asyncio.run
1200
-
1201
1212
  def verbosity_handler(
1202
1213
  self, quiet: bool, verbose: bool, json_output: bool = False
1203
1214
  ) -> None:
@@ -1502,6 +1513,8 @@ class CLIManager:
1502
1513
  Column("[bold white]Value", style="gold1"),
1503
1514
  Column("", style="medium_purple"),
1504
1515
  box=box.SIMPLE_HEAD,
1516
+ title=f"[{COLORS.G.HEADER}]BTCLI Config[/{COLORS.G.HEADER}]: "
1517
+ f"[{COLORS.G.ARG}]{self.config_path}[/{COLORS.G.ARG}]",
1505
1518
  )
1506
1519
 
1507
1520
  for key, value in self.config.items():
@@ -1722,7 +1735,7 @@ class CLIManager:
1722
1735
  if return_wallet_and_hotkey:
1723
1736
  valid = utils.is_valid_wallet(wallet)
1724
1737
  if valid[1]:
1725
- return wallet, wallet.hotkey.ss58_address
1738
+ return wallet, get_hotkey_pub_ss58(wallet)
1726
1739
  else:
1727
1740
  if wallet_hotkey and is_valid_ss58_address(wallet_hotkey):
1728
1741
  return wallet, wallet_hotkey
@@ -2229,14 +2242,15 @@ class CLIManager:
2229
2242
 
2230
2243
  if not wallet_path:
2231
2244
  wallet_path = Prompt.ask(
2232
- "Enter the path for the wallets directory", default=defaults.wallet.path
2245
+ "Enter the path for the wallets directory",
2246
+ default=self.config.get("wallet_path") or defaults.wallet.path,
2233
2247
  )
2234
2248
  wallet_path = os.path.expanduser(wallet_path)
2235
2249
 
2236
2250
  if not wallet_name:
2237
2251
  wallet_name = Prompt.ask(
2238
2252
  f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2239
- default=defaults.wallet.name,
2253
+ default=self.config.get("wallet_name") or defaults.wallet.name,
2240
2254
  )
2241
2255
 
2242
2256
  wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
@@ -2280,7 +2294,7 @@ class CLIManager:
2280
2294
 
2281
2295
  EXAMPLE
2282
2296
 
2283
- [green]$[/green] btcli wallet regen_coldkeypub --ss58_address 5DkQ4...
2297
+ [green]$[/green] btcli wallet regen-coldkeypub --ss58_address 5DkQ4...
2284
2298
 
2285
2299
  [bold]Note[/bold]: This command is particularly useful for users who need to regenerate their coldkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old coldkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
2286
2300
  """
@@ -2288,13 +2302,14 @@ class CLIManager:
2288
2302
 
2289
2303
  if not wallet_path:
2290
2304
  wallet_path = Prompt.ask(
2291
- "Enter the path to the wallets directory", default=defaults.wallet.path
2305
+ "Enter the path to the wallets directory",
2306
+ default=self.config.get("wallet_path") or defaults.wallet.path,
2292
2307
  )
2293
2308
  wallet_path = os.path.expanduser(wallet_path)
2294
2309
 
2295
2310
  if not wallet_name:
2296
2311
  wallet_name = Prompt.ask(
2297
- f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2312
+ f"Enter the name of the [{COLORS.G.CK}]wallet for the new coldkeypub",
2298
2313
  default=defaults.wallet.name,
2299
2314
  )
2300
2315
  wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
@@ -2311,7 +2326,7 @@ class CLIManager:
2311
2326
  address=ss58_address if ss58_address else public_key_hex
2312
2327
  ):
2313
2328
  rich.print("[red]Error: Invalid SS58 address or public key![/red]")
2314
- raise typer.Exit()
2329
+ return
2315
2330
  return self._run_command(
2316
2331
  wallets.regen_coldkey_pub(
2317
2332
  wallet, ss58_address, public_key_hex, overwrite, json_output
@@ -2377,6 +2392,68 @@ class CLIManager:
2377
2392
  )
2378
2393
  )
2379
2394
 
2395
+ def wallet_regen_hotkey_pub(
2396
+ self,
2397
+ wallet_name: Optional[str] = Options.wallet_name,
2398
+ wallet_path: Optional[str] = Options.wallet_path,
2399
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
2400
+ public_key_hex: Optional[str] = Options.public_hex_key,
2401
+ ss58_address: Optional[str] = Options.ss58_address,
2402
+ overwrite: bool = Options.overwrite,
2403
+ quiet: bool = Options.quiet,
2404
+ verbose: bool = Options.verbose,
2405
+ json_output: bool = Options.json_output,
2406
+ ):
2407
+ """
2408
+ Regenerates the public part of a hotkey (hotkeypub.txt) for a wallet.
2409
+
2410
+ Use this command when you need to move machine for subnet mining. Use the public key or SS58 address from your hotkeypub.txt that you have on another machine to regenerate the hotkeypub.txt on this new machine.
2411
+
2412
+ USAGE
2413
+
2414
+ The command requires either a public key in hexadecimal format or an ``SS58`` address from the existing hotkeypub.txt from old machine to regenerate the coldkeypub on the new machine.
2415
+
2416
+ EXAMPLE
2417
+
2418
+ [green]$[/green] btcli wallet regen-hotkeypub --ss58_address 5DkQ4...
2419
+
2420
+ [bold]Note[/bold]: This command is particularly useful for users who need to regenerate their hotkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old hotkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
2421
+ """
2422
+ self.verbosity_handler(quiet, verbose, json_output)
2423
+
2424
+ if not wallet_path:
2425
+ wallet_path = Prompt.ask(
2426
+ "Enter the path to the wallets directory",
2427
+ default=self.config.get("wallet_path") or defaults.wallet.path,
2428
+ )
2429
+ wallet_path = os.path.expanduser(wallet_path)
2430
+
2431
+ if not wallet_name:
2432
+ wallet_name = Prompt.ask(
2433
+ f"Enter the name of the [{COLORS.G.CK}]wallet for the new hotkeypub",
2434
+ default=defaults.wallet.name,
2435
+ )
2436
+ wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
2437
+
2438
+ if not ss58_address and not public_key_hex:
2439
+ prompt_answer = typer.prompt(
2440
+ "Enter the ss58_address or the public key in hex"
2441
+ )
2442
+ if prompt_answer.startswith("0x"):
2443
+ public_key_hex = prompt_answer
2444
+ else:
2445
+ ss58_address = prompt_answer
2446
+ if not utils.is_valid_bittensor_address_or_public_key(
2447
+ address=ss58_address if ss58_address else public_key_hex
2448
+ ):
2449
+ rich.print("[red]Error: Invalid SS58 address or public key![/red]")
2450
+ return False
2451
+ return self._run_command(
2452
+ wallets.regen_hotkey_pub(
2453
+ wallet, ss58_address, public_key_hex, overwrite, json_output
2454
+ )
2455
+ )
2456
+
2380
2457
  def wallet_new_hotkey(
2381
2458
  self,
2382
2459
  wallet_name: Optional[str] = Options.wallet_name,
@@ -2417,7 +2494,7 @@ class CLIManager:
2417
2494
  if not wallet_name:
2418
2495
  wallet_name = Prompt.ask(
2419
2496
  f"Enter the [{COLORS.G.CK}]wallet name",
2420
- default=defaults.wallet.name,
2497
+ default=self.config.get("wallet_name") or defaults.wallet.name,
2421
2498
  )
2422
2499
 
2423
2500
  if not wallet_hotkey:
@@ -2472,11 +2549,11 @@ class CLIManager:
2472
2549
  if not wallet_hotkey:
2473
2550
  wallet_hotkey = Prompt.ask(
2474
2551
  "Enter the [blue]hotkey[/blue] name or "
2475
- "[blue]hotkey ss58 address[/blue] [dim](to associate with your coldkey)[/dim]"
2552
+ "[blue]hotkey ss58 address[/blue] [dim](to associate with your coldkey)[/dim]",
2553
+ default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
2476
2554
  )
2477
2555
 
2478
- hotkey_display = None
2479
- if is_valid_ss58_address(wallet_hotkey):
2556
+ if wallet_hotkey and is_valid_ss58_address(wallet_hotkey):
2480
2557
  hotkey_ss58 = wallet_hotkey
2481
2558
  wallet = self.wallet_ask(
2482
2559
  wallet_name,
@@ -2496,8 +2573,11 @@ class CLIManager:
2496
2573
  ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
2497
2574
  validate=WV.WALLET_AND_HOTKEY,
2498
2575
  )
2499
- hotkey_ss58 = wallet.hotkey.ss58_address
2500
- hotkey_display = f"hotkey [blue]{wallet_hotkey}[/blue] [{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
2576
+ hotkey_ss58 = get_hotkey_pub_ss58(wallet)
2577
+ hotkey_display = (
2578
+ f"hotkey [blue]{wallet_hotkey}[/blue] "
2579
+ f"[{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
2580
+ )
2501
2581
 
2502
2582
  return self._run_command(
2503
2583
  wallets.associate_hotkey(
@@ -2544,13 +2624,14 @@ class CLIManager:
2544
2624
 
2545
2625
  if not wallet_path:
2546
2626
  wallet_path = Prompt.ask(
2547
- "Enter the path to the wallets directory", default=defaults.wallet.path
2627
+ "Enter the path to the wallets directory",
2628
+ default=self.config.get("wallet_path") or defaults.wallet.path,
2548
2629
  )
2549
2630
 
2550
2631
  if not wallet_name:
2551
2632
  wallet_name = Prompt.ask(
2552
2633
  f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2553
- default=defaults.wallet.name,
2634
+ default=self.config.get("wallet_name") or defaults.wallet.name,
2554
2635
  )
2555
2636
 
2556
2637
  wallet = self.wallet_ask(
@@ -2623,7 +2704,8 @@ class CLIManager:
2623
2704
 
2624
2705
  if not wallet_ss58_address:
2625
2706
  wallet_ss58_address = Prompt.ask(
2626
- "Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim](leave blank to show all pending swaps)[/dim]"
2707
+ "Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim]"
2708
+ "(leave blank to show all pending swaps)[/dim]"
2627
2709
  )
2628
2710
  if not wallet_ss58_address:
2629
2711
  return self._run_command(
@@ -2687,18 +2769,18 @@ class CLIManager:
2687
2769
  self.verbosity_handler(quiet, verbose, json_output)
2688
2770
  if not wallet_path:
2689
2771
  wallet_path = Prompt.ask(
2690
- "Enter the path of wallets directory", default=defaults.wallet.path
2772
+ "Enter the path of wallets directory",
2773
+ default=self.config.get("wallet_path") or defaults.wallet.path,
2691
2774
  )
2692
2775
 
2693
2776
  if not wallet_name:
2694
2777
  wallet_name = Prompt.ask(
2695
2778
  f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2696
- default=defaults.wallet.name,
2697
2779
  )
2698
2780
  if not wallet_hotkey:
2699
2781
  wallet_hotkey = Prompt.ask(
2700
2782
  f"Enter the the name of the [{COLORS.G.HK}]new hotkey",
2701
- default=defaults.wallet.hotkey,
2783
+ default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
2702
2784
  )
2703
2785
 
2704
2786
  wallet = self.wallet_ask(
@@ -3507,7 +3589,7 @@ class CLIManager:
3507
3589
  ask_for=[WO.NAME, WO.HOTKEY, WO.PATH],
3508
3590
  validate=WV.WALLET_AND_HOTKEY,
3509
3591
  )
3510
- include_hotkeys = wallet.hotkey.ss58_address
3592
+ include_hotkeys = get_hotkey_pub_ss58(wallet)
3511
3593
 
3512
3594
  elif all_hotkeys or include_hotkeys or exclude_hotkeys:
3513
3595
  wallet = self.wallet_ask(
@@ -3971,7 +4053,7 @@ class CLIManager:
3971
4053
  ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3972
4054
  validate=WV.WALLET_AND_HOTKEY,
3973
4055
  )
3974
- destination_hotkey = destination_wallet.hotkey.ss58_address
4056
+ destination_hotkey = get_hotkey_pub_ss58(destination_wallet)
3975
4057
  else:
3976
4058
  if is_valid_ss58_address(destination_hotkey):
3977
4059
  destination_hotkey = destination_hotkey
@@ -4010,7 +4092,7 @@ class CLIManager:
4010
4092
  ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
4011
4093
  validate=WV.WALLET_AND_HOTKEY,
4012
4094
  )
4013
- origin_hotkey = wallet.hotkey.ss58_address
4095
+ origin_hotkey = get_hotkey_pub_ss58(wallet)
4014
4096
  else:
4015
4097
  if is_valid_ss58_address(wallet_hotkey):
4016
4098
  origin_hotkey = wallet_hotkey
@@ -4022,7 +4104,7 @@ class CLIManager:
4022
4104
  ask_for=[],
4023
4105
  validate=WV.WALLET_AND_HOTKEY,
4024
4106
  )
4025
- origin_hotkey = wallet.hotkey.ss58_address
4107
+ origin_hotkey = get_hotkey_pub_ss58(wallet)
4026
4108
 
4027
4109
  if not interactive_selection:
4028
4110
  if origin_netuid is None:
@@ -4158,7 +4240,8 @@ class CLIManager:
4158
4240
  interactive_selection = False
4159
4241
  if not wallet_hotkey:
4160
4242
  origin_hotkey = Prompt.ask(
4161
- "Enter the [blue]origin hotkey[/blue] name or ss58 address [bold](stake will be transferred FROM here)[/bold] "
4243
+ "Enter the [blue]origin hotkey[/blue] name or ss58 address [bold]"
4244
+ "(stake will be transferred FROM here)[/bold] "
4162
4245
  "[dim](or press Enter to select from existing stakes)[/dim]"
4163
4246
  )
4164
4247
  if origin_hotkey == "":
@@ -4174,7 +4257,7 @@ class CLIManager:
4174
4257
  ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
4175
4258
  validate=WV.WALLET_AND_HOTKEY,
4176
4259
  )
4177
- origin_hotkey = wallet.hotkey.ss58_address
4260
+ origin_hotkey = get_hotkey_pub_ss58(wallet)
4178
4261
  else:
4179
4262
  if is_valid_ss58_address(wallet_hotkey):
4180
4263
  origin_hotkey = wallet_hotkey
@@ -4186,7 +4269,7 @@ class CLIManager:
4186
4269
  ask_for=[],
4187
4270
  validate=WV.WALLET_AND_HOTKEY,
4188
4271
  )
4189
- origin_hotkey = wallet.hotkey.ss58_address
4272
+ origin_hotkey = get_hotkey_pub_ss58(wallet)
4190
4273
 
4191
4274
  if not interactive_selection:
4192
4275
  if origin_netuid is None:
@@ -5009,7 +5092,7 @@ class CLIManager:
5009
5092
  "Netuids to show the price for. Separate multiple netuids with a comma, for example: `-n 0,1,2`.",
5010
5093
  ),
5011
5094
  interval_hours: int = typer.Option(
5012
- 24,
5095
+ 4,
5013
5096
  "--interval-hours",
5014
5097
  "--interval",
5015
5098
  help="The number of hours to show the historical price for.",
@@ -5026,6 +5109,11 @@ class CLIManager:
5026
5109
  "--log",
5027
5110
  help="Show the price in log scale.",
5028
5111
  ),
5112
+ current_only: bool = typer.Option(
5113
+ False,
5114
+ "--current",
5115
+ help="Show only the current data, and no historical data.",
5116
+ ),
5029
5117
  html_output: bool = Options.html_output,
5030
5118
  quiet: bool = Options.quiet,
5031
5119
  verbose: bool = Options.verbose,
@@ -5048,9 +5136,31 @@ class CLIManager:
5048
5136
  [green]$[/green] btcli subnets price --netuids 1,2,3,4 --html
5049
5137
  """
5050
5138
  if json_output and html_output:
5051
- print_error("Cannot specify both `--json-output` and `--html`")
5139
+ print_error(
5140
+ f"Cannot specify both [{COLORS.G.ARG}]--json-output[/{COLORS.G.ARG}] "
5141
+ f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
5142
+ )
5143
+ return
5144
+ if current_only and html_output:
5145
+ print_error(
5146
+ f"Cannot specify both [{COLORS.G.ARG}]--current[/{COLORS.G.ARG}] "
5147
+ f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
5148
+ )
5052
5149
  return
5053
5150
  self.verbosity_handler(quiet=quiet, verbose=verbose, json_output=json_output)
5151
+
5152
+ subtensor = self.initialize_chain(network)
5153
+ non_archives = ["finney", "latent-lite", "subvortex"]
5154
+ if not current_only and subtensor.network in non_archives + [
5155
+ Constants.network_map[x] for x in non_archives
5156
+ ]:
5157
+ err_console.print(
5158
+ f"[red]Error[/red] Running this command without [{COLORS.G.ARG}]--current[/{COLORS.G.ARG}] requires "
5159
+ "use of an archive node. "
5160
+ f"Try running again with the [{COLORS.G.ARG}]--network archive[/{COLORS.G.ARG}] flag."
5161
+ )
5162
+ return False
5163
+
5054
5164
  if netuids:
5055
5165
  netuids = parse_to_list(
5056
5166
  netuids,
@@ -5080,10 +5190,11 @@ class CLIManager:
5080
5190
 
5081
5191
  return self._run_command(
5082
5192
  price.price(
5083
- self.initialize_chain(network),
5193
+ subtensor,
5084
5194
  netuids,
5085
5195
  all_netuids,
5086
5196
  interval_hours,
5197
+ current_only,
5087
5198
  html_output,
5088
5199
  log_scale,
5089
5200
  json_output,