bittensor-cli 9.2.0__py3-none-any.whl → 9.3.0__py3-none-any.whl

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.
bittensor_cli/cli.py CHANGED
@@ -2,6 +2,7 @@
2
2
  import asyncio
3
3
  import curses
4
4
  import importlib
5
+ import json
5
6
  import os.path
6
7
  import re
7
8
  import ssl
@@ -14,11 +15,19 @@ from dataclasses import fields
14
15
  import rich
15
16
  import typer
16
17
  import numpy as np
18
+ from async_substrate_interface.errors import (
19
+ SubstrateRequestException,
20
+ ConnectionClosed,
21
+ InvalidHandshake,
22
+ )
17
23
  from bittensor_wallet import Wallet
18
24
  from rich import box
19
25
  from rich.prompt import Confirm, FloatPrompt, Prompt, IntPrompt
20
26
  from rich.table import Column, Table
21
27
  from rich.tree import Tree
28
+ from typing_extensions import Annotated
29
+ from yaml import safe_dump, safe_load
30
+
22
31
  from bittensor_cli.src import (
23
32
  defaults,
24
33
  HELP_PANELS,
@@ -31,7 +40,6 @@ from bittensor_cli.src import (
31
40
  from bittensor_cli.version import __version__, __version_as_int__
32
41
  from bittensor_cli.src.bittensor import utils
33
42
  from bittensor_cli.src.bittensor.balances import Balance
34
- from async_substrate_interface.errors import SubstrateRequestException
35
43
  from bittensor_cli.src.commands import sudo, wallets, view
36
44
  from bittensor_cli.src.commands import weights as weights_cmds
37
45
  from bittensor_cli.src.commands.subnets import price, subnets
@@ -48,6 +56,7 @@ from bittensor_cli.src.bittensor.utils import (
48
56
  console,
49
57
  err_console,
50
58
  verbose_console,
59
+ json_console,
51
60
  is_valid_ss58_address,
52
61
  print_error,
53
62
  validate_chain_endpoint,
@@ -61,9 +70,6 @@ from bittensor_cli.src.bittensor.utils import (
61
70
  is_linux,
62
71
  validate_rate_tolerance,
63
72
  )
64
- from typing_extensions import Annotated
65
- from websockets import ConnectionClosed, InvalidHandshake
66
- from yaml import safe_dump, safe_load
67
73
 
68
74
  try:
69
75
  from git import Repo, GitError
@@ -109,6 +115,17 @@ class Options:
109
115
  "--wallet.hotkey",
110
116
  help="Hotkey of the wallet",
111
117
  )
118
+ wallet_ss58_address = typer.Option(
119
+ None,
120
+ "--wallet-name",
121
+ "--name",
122
+ "--wallet_name",
123
+ "--wallet.name",
124
+ "--address",
125
+ "--ss58",
126
+ "--ss58-address",
127
+ help="SS58 address or wallet name to check. Leave empty to be prompted.",
128
+ )
112
129
  wallet_hotkey_ss58 = typer.Option(
113
130
  None,
114
131
  "--hotkey",
@@ -268,6 +285,15 @@ class Options:
268
285
  "--dashboard.path",
269
286
  help="Path to save the dashboard HTML file. For example: `~/.bittensor/dashboard`.",
270
287
  )
288
+ json_output = typer.Option(
289
+ False,
290
+ "--json-output",
291
+ "--json-out",
292
+ help="Outputs the result of the command as JSON.",
293
+ )
294
+ era: int = typer.Option(
295
+ 3, help="Length (in blocks) for which the transaction should be valid."
296
+ )
271
297
 
272
298
 
273
299
  def list_prompt(init_var: list, list_type: type, help_text: str) -> list:
@@ -313,22 +339,31 @@ def verbosity_console_handler(verbosity_level: int = 1) -> None:
313
339
  :param verbosity_level: int corresponding to verbosity level of console output (0 is quiet, 1 is normal, 2 is
314
340
  verbose)
315
341
  """
316
- if verbosity_level not in range(3):
342
+ if verbosity_level not in range(4):
317
343
  raise ValueError(
318
- f"Invalid verbosity level: {verbosity_level}. Must be one of: 0 (quiet), 1 (normal), 2 (verbose)"
344
+ f"Invalid verbosity level: {verbosity_level}. "
345
+ f"Must be one of: 0 (quiet + json output), 1 (normal), 2 (verbose), 3 (json output + verbose)"
319
346
  )
320
347
  if verbosity_level == 0:
321
348
  console.quiet = True
322
349
  err_console.quiet = True
323
350
  verbose_console.quiet = True
351
+ json_console.quiet = False
324
352
  elif verbosity_level == 1:
325
353
  console.quiet = False
326
354
  err_console.quiet = False
327
355
  verbose_console.quiet = True
356
+ json_console.quiet = True
328
357
  elif verbosity_level == 2:
329
358
  console.quiet = False
330
359
  err_console.quiet = False
331
360
  verbose_console.quiet = False
361
+ json_console.quiet = True
362
+ elif verbosity_level == 3:
363
+ console.quiet = True
364
+ err_console.quiet = True
365
+ verbose_console.quiet = False
366
+ json_console.quiet = False
332
367
 
333
368
 
334
369
  def get_optional_netuid(netuid: Optional[int], all_netuids: bool) -> Optional[int]:
@@ -684,6 +719,12 @@ class CLIManager:
684
719
  self.wallet_app.command(
685
720
  "swap-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
686
721
  )(self.wallet_swap_hotkey)
722
+ self.wallet_app.command(
723
+ "swap-coldkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
724
+ )(self.wallet_swap_coldkey)
725
+ self.wallet_app.command(
726
+ "swap-check", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
727
+ )(self.wallet_check_ck_swap)
687
728
  self.wallet_app.command(
688
729
  "regen-coldkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
689
730
  )(self.wallet_regen_coldkey)
@@ -699,6 +740,9 @@ class CLIManager:
699
740
  self.wallet_app.command(
700
741
  "new-coldkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
701
742
  )(self.wallet_new_coldkey)
743
+ self.wallet_app.command(
744
+ "associate-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
745
+ )(self.wallet_associate_hotkey)
702
746
  self.wallet_app.command(
703
747
  "create", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
704
748
  )(self.wallet_create_wallet)
@@ -934,6 +978,7 @@ class CLIManager:
934
978
  """
935
979
  if not self.subtensor:
936
980
  if network:
981
+ network_ = None
937
982
  for item in network:
938
983
  if item.startswith("ws"):
939
984
  network_ = item
@@ -1068,12 +1113,15 @@ class CLIManager:
1068
1113
  except ModuleNotFoundError:
1069
1114
  self.asyncio_runner = asyncio.run
1070
1115
 
1071
- def verbosity_handler(self, quiet: bool, verbose: bool):
1116
+ def verbosity_handler(
1117
+ self, quiet: bool, verbose: bool, json_output: bool = False
1118
+ ) -> None:
1072
1119
  if quiet and verbose:
1073
1120
  err_console.print("Cannot specify both `--quiet` and `--verbose`")
1074
1121
  raise typer.Exit()
1075
-
1076
- if quiet:
1122
+ if json_output and verbose:
1123
+ verbosity_console_handler(3)
1124
+ elif json_output or quiet:
1077
1125
  verbosity_console_handler(0)
1078
1126
  elif verbose:
1079
1127
  verbosity_console_handler(2)
@@ -1203,7 +1251,8 @@ class CLIManager:
1203
1251
  elif arg == "rate_tolerance":
1204
1252
  while True:
1205
1253
  val = FloatPrompt.ask(
1206
- f"What percentage would you like to set for [red]{arg}[/red]?\nValues are percentages (e.g. 0.05 for 5%)",
1254
+ f"What percentage would you like to set for [red]{arg}[/red]?\n"
1255
+ f"Values are percentages (e.g. 0.05 for 5%)",
1207
1256
  default=0.05,
1208
1257
  )
1209
1258
  try:
@@ -1503,7 +1552,7 @@ class CLIManager:
1503
1552
  wallet_name: Optional[str],
1504
1553
  wallet_path: Optional[str],
1505
1554
  wallet_hotkey: Optional[str],
1506
- ask_for: list[str] = [],
1555
+ ask_for: Optional[list[str]] = None,
1507
1556
  validate: WV = WV.WALLET,
1508
1557
  ) -> Wallet:
1509
1558
  """
@@ -1512,9 +1561,10 @@ class CLIManager:
1512
1561
  :param wallet_path: root path of the wallets
1513
1562
  :param wallet_hotkey: name of the wallet hotkey file
1514
1563
  :param validate: flag whether to check for the wallet's validity
1515
- :param ask_type: aspect of the wallet (name, path, hotkey) to prompt the user for
1564
+ :param ask_for: aspect of the wallet (name, path, hotkey) to prompt the user for
1516
1565
  :return: created Wallet object
1517
1566
  """
1567
+ ask_for = ask_for or []
1518
1568
  # Prompt for missing attributes specified in ask_for
1519
1569
  if WO.NAME in ask_for and not wallet_name:
1520
1570
  if self.config.get("wallet_name"):
@@ -1587,6 +1637,7 @@ class CLIManager:
1587
1637
  wallet_path: str = Options.wallet_path,
1588
1638
  quiet: bool = Options.quiet,
1589
1639
  verbose: bool = Options.verbose,
1640
+ json_output: bool = Options.json_output,
1590
1641
  ):
1591
1642
  """
1592
1643
  Displays all the wallets and their corresponding hotkeys that are located in the wallet path specified in the config.
@@ -1602,11 +1653,11 @@ class CLIManager:
1602
1653
 
1603
1654
  [bold]NOTE[/bold]: This command is read-only and does not modify the filesystem or the blockchain state. It is intended for use with the Bittensor CLI to provide a quick overview of the user's wallets.
1604
1655
  """
1605
- self.verbosity_handler(quiet, verbose)
1656
+ self.verbosity_handler(quiet, verbose, json_output)
1606
1657
  wallet = self.wallet_ask(
1607
1658
  None, wallet_path, None, ask_for=[WO.PATH], validate=WV.NONE
1608
1659
  )
1609
- return self._run_command(wallets.wallet_list(wallet.path))
1660
+ return self._run_command(wallets.wallet_list(wallet.path, json_output))
1610
1661
 
1611
1662
  def wallet_overview(
1612
1663
  self,
@@ -1646,6 +1697,7 @@ class CLIManager:
1646
1697
  network: Optional[list[str]] = Options.network,
1647
1698
  quiet: bool = Options.quiet,
1648
1699
  verbose: bool = Options.verbose,
1700
+ json_output: bool = Options.json_output,
1649
1701
  ):
1650
1702
  """
1651
1703
  Displays a detailed overview of the user's registered accounts on the Bittensor network.
@@ -1662,7 +1714,7 @@ class CLIManager:
1662
1714
  It provides a quick and comprehensive view of the user's network presence, making it useful for monitoring account status,
1663
1715
  stake distribution, and overall contribution to the Bittensor network.
1664
1716
  """
1665
- self.verbosity_handler(quiet, verbose)
1717
+ self.verbosity_handler(quiet, verbose, json_output)
1666
1718
  if include_hotkeys and exclude_hotkeys:
1667
1719
  utils.err_console.print(
1668
1720
  "[red]You have specified both the inclusion and exclusion options. Only one of these options is allowed currently."
@@ -1707,6 +1759,7 @@ class CLIManager:
1707
1759
  exclude_hotkeys,
1708
1760
  netuids_filter=netuids,
1709
1761
  verbose=verbose,
1762
+ json_output=json_output,
1710
1763
  )
1711
1764
  )
1712
1765
 
@@ -1729,6 +1782,7 @@ class CLIManager:
1729
1782
  transfer_all: bool = typer.Option(
1730
1783
  False, "--all", prompt=False, help="Transfer all available balance."
1731
1784
  ),
1785
+ era: int = Options.era,
1732
1786
  wallet_name: str = Options.wallet_name,
1733
1787
  wallet_path: str = Options.wallet_path,
1734
1788
  wallet_hotkey: str = Options.wallet_hotkey,
@@ -1736,6 +1790,7 @@ class CLIManager:
1736
1790
  prompt: bool = Options.prompt,
1737
1791
  quiet: bool = Options.quiet,
1738
1792
  verbose: bool = Options.verbose,
1793
+ json_output: bool = Options.json_output,
1739
1794
  ):
1740
1795
  """
1741
1796
  Send TAO tokens from one wallet to another wallet on the Bittensor network.
@@ -1759,7 +1814,7 @@ class CLIManager:
1759
1814
  print_error("You have entered an incorrect ss58 address. Please try again.")
1760
1815
  raise typer.Exit()
1761
1816
 
1762
- self.verbosity_handler(quiet, verbose)
1817
+ self.verbosity_handler(quiet, verbose, json_output)
1763
1818
  wallet = self.wallet_ask(
1764
1819
  wallet_name,
1765
1820
  wallet_path,
@@ -1777,12 +1832,14 @@ class CLIManager:
1777
1832
  amount = FloatPrompt.ask("Enter amount (in TAO) to transfer.")
1778
1833
  return self._run_command(
1779
1834
  wallets.transfer(
1780
- wallet,
1781
- subtensor,
1782
- destination_ss58_address,
1783
- amount,
1784
- transfer_all,
1785
- prompt,
1835
+ wallet=wallet,
1836
+ subtensor=subtensor,
1837
+ destination=destination_ss58_address,
1838
+ amount=amount,
1839
+ transfer_all=transfer_all,
1840
+ era=era,
1841
+ prompt=prompt,
1842
+ json_output=json_output,
1786
1843
  )
1787
1844
  )
1788
1845
 
@@ -1798,6 +1855,7 @@ class CLIManager:
1798
1855
  quiet: bool = Options.quiet,
1799
1856
  verbose: bool = Options.verbose,
1800
1857
  prompt: bool = Options.prompt,
1858
+ json_output: bool = Options.json_output,
1801
1859
  ):
1802
1860
  """
1803
1861
  Swap hotkeys of a given wallet on the blockchain. For a registered key pair, for example, a (coldkeyA, hotkeyA) pair, this command swaps the hotkeyA with a new, unregistered, hotkeyB to move the original registration to the (coldkeyA, hotkeyB) pair.
@@ -1816,7 +1874,7 @@ class CLIManager:
1816
1874
 
1817
1875
  [green]$[/green] btcli wallet swap_hotkey destination_hotkey_name --wallet-name your_wallet_name --wallet-hotkey original_hotkey
1818
1876
  """
1819
- self.verbosity_handler(quiet, verbose)
1877
+ self.verbosity_handler(quiet, verbose, json_output)
1820
1878
  original_wallet = self.wallet_ask(
1821
1879
  wallet_name,
1822
1880
  wallet_path,
@@ -1838,7 +1896,9 @@ class CLIManager:
1838
1896
  )
1839
1897
  self.initialize_chain(network)
1840
1898
  return self._run_command(
1841
- wallets.swap_hotkey(original_wallet, new_wallet, self.subtensor, prompt)
1899
+ wallets.swap_hotkey(
1900
+ original_wallet, new_wallet, self.subtensor, prompt, json_output
1901
+ )
1842
1902
  )
1843
1903
 
1844
1904
  def wallet_inspect(
@@ -1857,6 +1917,7 @@ class CLIManager:
1857
1917
  netuids: str = Options.netuids,
1858
1918
  quiet: bool = Options.quiet,
1859
1919
  verbose: bool = Options.verbose,
1920
+ json_output: bool = Options.json_output,
1860
1921
  ):
1861
1922
  """
1862
1923
  Displays the details of the user's wallet pairs (coldkey, hotkey) on the Bittensor network.
@@ -1891,7 +1952,7 @@ class CLIManager:
1891
1952
  """
1892
1953
  print_error("This command is disabled on the 'rao' network.")
1893
1954
  raise typer.Exit()
1894
- self.verbosity_handler(quiet, verbose)
1955
+ self.verbosity_handler(quiet, verbose, json_output)
1895
1956
 
1896
1957
  if netuids:
1897
1958
  netuids = parse_to_list(
@@ -1988,6 +2049,7 @@ class CLIManager:
1988
2049
 
1989
2050
  [bold]Note[/bold]: This command is meant for used in local environments where users can experiment with the blockchain without using real TAO tokens. Users must have the necessary hardware setup, especially when opting for CUDA-based GPU calculations. It is currently disabled on testnet and mainnet (finney). You can only use this command on a local blockchain.
1990
2051
  """
2052
+ # TODO should we add json_output?
1991
2053
  wallet = self.wallet_ask(
1992
2054
  wallet_name,
1993
2055
  wallet_path,
@@ -2024,6 +2086,7 @@ class CLIManager:
2024
2086
  overwrite: bool = Options.overwrite,
2025
2087
  quiet: bool = Options.quiet,
2026
2088
  verbose: bool = Options.verbose,
2089
+ json_output: bool = Options.json_output,
2027
2090
  ):
2028
2091
  """
2029
2092
  Regenerate a coldkey for a wallet on the Bittensor blockchain network.
@@ -2041,7 +2104,7 @@ class CLIManager:
2041
2104
 
2042
2105
  [bold]Note[/bold]: This command is critical for users who need to regenerate their coldkey either for recovery or for security reasons.
2043
2106
  """
2044
- self.verbosity_handler(quiet, verbose)
2107
+ self.verbosity_handler(quiet, verbose, json_output)
2045
2108
 
2046
2109
  if not wallet_path:
2047
2110
  wallet_path = Prompt.ask(
@@ -2069,6 +2132,7 @@ class CLIManager:
2069
2132
  json_password,
2070
2133
  use_password,
2071
2134
  overwrite,
2135
+ json_output,
2072
2136
  )
2073
2137
  )
2074
2138
 
@@ -2082,6 +2146,7 @@ class CLIManager:
2082
2146
  overwrite: bool = Options.overwrite,
2083
2147
  quiet: bool = Options.quiet,
2084
2148
  verbose: bool = Options.verbose,
2149
+ json_output: bool = Options.json_output,
2085
2150
  ):
2086
2151
  """
2087
2152
  Regenerates the public part of a coldkey (coldkeypub.txt) for a wallet.
@@ -2098,7 +2163,7 @@ class CLIManager:
2098
2163
 
2099
2164
  [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.
2100
2165
  """
2101
- self.verbosity_handler(quiet, verbose)
2166
+ self.verbosity_handler(quiet, verbose, json_output)
2102
2167
 
2103
2168
  if not wallet_path:
2104
2169
  wallet_path = Prompt.ask(
@@ -2127,7 +2192,9 @@ class CLIManager:
2127
2192
  rich.print("[red]Error: Invalid SS58 address or public key![/red]")
2128
2193
  raise typer.Exit()
2129
2194
  return self._run_command(
2130
- wallets.regen_coldkey_pub(wallet, ss58_address, public_key_hex, overwrite)
2195
+ wallets.regen_coldkey_pub(
2196
+ wallet, ss58_address, public_key_hex, overwrite, json_output
2197
+ )
2131
2198
  )
2132
2199
 
2133
2200
  def wallet_regen_hotkey(
@@ -2146,6 +2213,7 @@ class CLIManager:
2146
2213
  overwrite: bool = Options.overwrite,
2147
2214
  quiet: bool = Options.quiet,
2148
2215
  verbose: bool = Options.verbose,
2216
+ json_output: bool = Options.json_output,
2149
2217
  ):
2150
2218
  """
2151
2219
  Regenerates a hotkey for a wallet.
@@ -2164,7 +2232,7 @@ class CLIManager:
2164
2232
  [bold]Note[/bold]: This command is essential for users who need to regenerate their hotkey, possibly for security upgrades or key recovery.
2165
2233
  It should be used with caution to avoid accidental overwriting of existing keys.
2166
2234
  """
2167
- self.verbosity_handler(quiet, verbose)
2235
+ self.verbosity_handler(quiet, verbose, json_output)
2168
2236
  wallet = self.wallet_ask(
2169
2237
  wallet_name,
2170
2238
  wallet_path,
@@ -2184,6 +2252,7 @@ class CLIManager:
2184
2252
  json_password,
2185
2253
  use_password,
2186
2254
  overwrite,
2255
+ json_output,
2187
2256
  )
2188
2257
  )
2189
2258
 
@@ -2206,6 +2275,7 @@ class CLIManager:
2206
2275
  overwrite: bool = Options.overwrite,
2207
2276
  quiet: bool = Options.quiet,
2208
2277
  verbose: bool = Options.verbose,
2278
+ json_output: bool = Options.json_output,
2209
2279
  ):
2210
2280
  """
2211
2281
  Create a new hotkey for a wallet.
@@ -2221,7 +2291,7 @@ class CLIManager:
2221
2291
 
2222
2292
  [italic]Note[/italic]: This command is useful to create additional hotkeys for different purposes, such as running multiple subnet miners or subnet validators or separating operational roles within the Bittensor network.
2223
2293
  """
2224
- self.verbosity_handler(quiet, verbose)
2294
+ self.verbosity_handler(quiet, verbose, json_output)
2225
2295
 
2226
2296
  if not wallet_name:
2227
2297
  wallet_name = Prompt.ask(
@@ -2245,7 +2315,77 @@ class CLIManager:
2245
2315
  if not uri:
2246
2316
  n_words = get_n_words(n_words)
2247
2317
  return self._run_command(
2248
- wallets.new_hotkey(wallet, n_words, use_password, uri, overwrite)
2318
+ wallets.new_hotkey(
2319
+ wallet, n_words, use_password, uri, overwrite, json_output
2320
+ )
2321
+ )
2322
+
2323
+ def wallet_associate_hotkey(
2324
+ self,
2325
+ wallet_name: Optional[str] = Options.wallet_name,
2326
+ wallet_path: Optional[str] = Options.wallet_path,
2327
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey_ss58,
2328
+ network: Optional[list[str]] = Options.network,
2329
+ prompt: bool = Options.prompt,
2330
+ quiet: bool = Options.quiet,
2331
+ verbose: bool = Options.verbose,
2332
+ ):
2333
+ """
2334
+ Associate a hotkey with a wallet(coldkey).
2335
+
2336
+ USAGE
2337
+
2338
+ This command is used to associate a hotkey with a wallet(coldkey).
2339
+
2340
+ EXAMPLE
2341
+
2342
+ [green]$[/green] btcli wallet associate-hotkey --hotkey-name hotkey_name
2343
+ [green]$[/green] btcli wallet associate-hotkey --hotkey-ss58 5DkQ4...
2344
+ """
2345
+ self.verbosity_handler(quiet, verbose)
2346
+ if not wallet_name:
2347
+ wallet_name = Prompt.ask(
2348
+ "Enter the [blue]wallet name[/blue] [dim](which you want to associate with the hotkey)[/dim]",
2349
+ default=self.config.get("wallet_name") or defaults.wallet.name,
2350
+ )
2351
+ if not wallet_hotkey:
2352
+ wallet_hotkey = Prompt.ask(
2353
+ "Enter the [blue]hotkey[/blue] name or "
2354
+ "[blue]hotkey ss58 address[/blue] [dim](to associate with your coldkey)[/dim]"
2355
+ )
2356
+
2357
+ hotkey_display = None
2358
+ if is_valid_ss58_address(wallet_hotkey):
2359
+ hotkey_ss58 = wallet_hotkey
2360
+ wallet = self.wallet_ask(
2361
+ wallet_name,
2362
+ wallet_path,
2363
+ None,
2364
+ ask_for=[WO.NAME, WO.PATH],
2365
+ validate=WV.WALLET,
2366
+ )
2367
+ hotkey_display = (
2368
+ f"hotkey [{COLORS.GENERAL.HK}]{hotkey_ss58}[/{COLORS.GENERAL.HK}]"
2369
+ )
2370
+ else:
2371
+ wallet = self.wallet_ask(
2372
+ wallet_name,
2373
+ wallet_path,
2374
+ wallet_hotkey,
2375
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
2376
+ validate=WV.WALLET_AND_HOTKEY,
2377
+ )
2378
+ hotkey_ss58 = wallet.hotkey.ss58_address
2379
+ hotkey_display = f"hotkey [blue]{wallet_hotkey}[/blue] [{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
2380
+
2381
+ return self._run_command(
2382
+ wallets.associate_hotkey(
2383
+ wallet,
2384
+ self.initialize_chain(network),
2385
+ hotkey_ss58,
2386
+ hotkey_display,
2387
+ prompt,
2388
+ )
2249
2389
  )
2250
2390
 
2251
2391
  def wallet_new_coldkey(
@@ -2264,6 +2404,7 @@ class CLIManager:
2264
2404
  overwrite: bool = Options.overwrite,
2265
2405
  quiet: bool = Options.quiet,
2266
2406
  verbose: bool = Options.verbose,
2407
+ json_output: bool = Options.json_output,
2267
2408
  ):
2268
2409
  """
2269
2410
  Create a new coldkey. A coldkey is required for holding TAO balances and performing high-value transactions.
@@ -2278,7 +2419,7 @@ class CLIManager:
2278
2419
 
2279
2420
  [bold]Note[/bold]: This command is crucial for users who need to create a new coldkey for enhanced security or as part of setting up a new wallet. It is a foundational step in establishing a secure presence on the Bittensor network.
2280
2421
  """
2281
- self.verbosity_handler(quiet, verbose)
2422
+ self.verbosity_handler(quiet, verbose, json_output)
2282
2423
 
2283
2424
  if not wallet_path:
2284
2425
  wallet_path = Prompt.ask(
@@ -2301,33 +2442,100 @@ class CLIManager:
2301
2442
  if not uri:
2302
2443
  n_words = get_n_words(n_words)
2303
2444
  return self._run_command(
2304
- wallets.new_coldkey(wallet, n_words, use_password, uri, overwrite)
2445
+ wallets.new_coldkey(
2446
+ wallet, n_words, use_password, uri, overwrite, json_output
2447
+ )
2305
2448
  )
2306
2449
 
2307
2450
  def wallet_check_ck_swap(
2308
2451
  self,
2309
- wallet_name: Optional[str] = Options.wallet_name,
2452
+ wallet_ss58_address: Optional[str] = Options.wallet_ss58_address,
2310
2453
  wallet_path: Optional[str] = Options.wallet_path,
2311
2454
  wallet_hotkey: Optional[str] = Options.wallet_hotkey,
2455
+ scheduled_block: Optional[int] = typer.Option(
2456
+ None,
2457
+ "--block",
2458
+ help="Block number where the swap was scheduled",
2459
+ ),
2460
+ show_all: bool = typer.Option(
2461
+ False,
2462
+ "--all",
2463
+ "-a",
2464
+ help="Show all pending coldkey swaps",
2465
+ ),
2312
2466
  network: Optional[list[str]] = Options.network,
2313
2467
  quiet: bool = Options.quiet,
2314
2468
  verbose: bool = Options.verbose,
2315
2469
  ):
2316
2470
  """
2317
- Check the status of your scheduled coldkey swap.
2471
+ Check the status of scheduled coldkey swaps.
2318
2472
 
2319
2473
  USAGE
2320
2474
 
2321
- Users should provide the old coldkey wallet to check the swap status.
2475
+ This command can be used in three ways:
2476
+ 1. Show all pending swaps (--all)
2477
+ 2. Check status of a specific wallet's swap or SS58 address
2478
+ 3. Check detailed swap status with block number (--block)
2322
2479
 
2323
- EXAMPLE
2480
+ EXAMPLES
2481
+
2482
+ Show all pending swaps:
2483
+ [green]$[/green] btcli wallet swap-check --all
2324
2484
 
2325
- [green]$[/green] btcli wallet check_coldkey_swap
2485
+ Check specific wallet's swap:
2486
+ [green]$[/green] btcli wallet swap-check --wallet-name my_wallet
2487
+
2488
+ Check swap using SS58 address:
2489
+ [green]$[/green] btcli wallet swap-check --ss58 5DkQ4...
2490
+
2491
+ Check swap details with block number:
2492
+ [green]$[/green] btcli wallet swap-check --wallet-name my_wallet --block 12345
2326
2493
  """
2494
+ # TODO add json_output if this ever gets used again (doubtful)
2327
2495
  self.verbosity_handler(quiet, verbose)
2328
- wallet = self.wallet_ask(wallet_name, wallet_path, wallet_hotkey)
2329
2496
  self.initialize_chain(network)
2330
- return self._run_command(wallets.check_coldkey_swap(wallet, self.subtensor))
2497
+
2498
+ if show_all:
2499
+ return self._run_command(
2500
+ wallets.check_swap_status(self.subtensor, None, None)
2501
+ )
2502
+
2503
+ if not wallet_ss58_address:
2504
+ wallet_ss58_address = Prompt.ask(
2505
+ "Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim](leave blank to show all pending swaps)[/dim]"
2506
+ )
2507
+ if not wallet_ss58_address:
2508
+ return self._run_command(
2509
+ wallets.check_swap_status(self.subtensor, None, None)
2510
+ )
2511
+
2512
+ if is_valid_ss58_address(wallet_ss58_address):
2513
+ ss58_address = wallet_ss58_address
2514
+ else:
2515
+ wallet = self.wallet_ask(
2516
+ wallet_ss58_address,
2517
+ wallet_path,
2518
+ wallet_hotkey,
2519
+ ask_for=[WO.NAME, WO.PATH],
2520
+ validate=WV.WALLET,
2521
+ )
2522
+ ss58_address = wallet.coldkeypub.ss58_address
2523
+
2524
+ if not scheduled_block:
2525
+ block_input = Prompt.ask(
2526
+ "[blue]Enter the block number[/blue] where the swap was scheduled [dim](optional, press enter to skip)[/dim]",
2527
+ default="",
2528
+ )
2529
+ if block_input:
2530
+ try:
2531
+ scheduled_block = int(block_input)
2532
+ except ValueError:
2533
+ print_error("Invalid block number")
2534
+ raise typer.Exit()
2535
+
2536
+ return self._run_command(
2537
+ wallets.check_swap_status(self.subtensor, ss58_address, scheduled_block)
2538
+ )
2331
2539
 
2332
2540
  def wallet_create_wallet(
2333
2541
  self,
@@ -2340,6 +2548,7 @@ class CLIManager:
2340
2548
  overwrite: bool = Options.overwrite,
2341
2549
  quiet: bool = Options.quiet,
2342
2550
  verbose: bool = Options.verbose,
2551
+ json_output: bool = Options.json_output,
2343
2552
  ):
2344
2553
  """
2345
2554
  Create a complete wallet by setting up both coldkey and hotkeys.
@@ -2354,6 +2563,7 @@ class CLIManager:
2354
2563
 
2355
2564
  [bold]Note[/bold]: This command is for new users setting up their wallet for the first time, or for those who wish to completely renew their wallet keys. It ensures a fresh start with new keys for secure and effective participation in the Bittensor network.
2356
2565
  """
2566
+ self.verbosity_handler(quiet, verbose, json_output)
2357
2567
  if not wallet_path:
2358
2568
  wallet_path = Prompt.ask(
2359
2569
  "Enter the path of wallets directory", default=defaults.wallet.path
@@ -2370,7 +2580,6 @@ class CLIManager:
2370
2580
  default=defaults.wallet.hotkey,
2371
2581
  )
2372
2582
 
2373
- self.verbosity_handler(quiet, verbose)
2374
2583
  wallet = self.wallet_ask(
2375
2584
  wallet_name,
2376
2585
  wallet_path,
@@ -2381,7 +2590,9 @@ class CLIManager:
2381
2590
  if not uri:
2382
2591
  n_words = get_n_words(n_words)
2383
2592
  return self._run_command(
2384
- wallets.wallet_create(wallet, n_words, use_password, uri, overwrite)
2593
+ wallets.wallet_create(
2594
+ wallet, n_words, use_password, uri, overwrite, json_output
2595
+ )
2385
2596
  )
2386
2597
 
2387
2598
  def wallet_balance(
@@ -2399,6 +2610,7 @@ class CLIManager:
2399
2610
  network: Optional[list[str]] = Options.network,
2400
2611
  quiet: bool = Options.quiet,
2401
2612
  verbose: bool = Options.verbose,
2613
+ json_output: bool = Options.json_output,
2402
2614
  ):
2403
2615
  """
2404
2616
  Check the balance of the wallet. This command shows a detailed view of the wallet's coldkey balances, including free and staked balances.
@@ -2424,7 +2636,7 @@ class CLIManager:
2424
2636
  [green]$[/green] btcli w balance --ss58 <ss58_address> --ss58 <ss58_address>
2425
2637
 
2426
2638
  """
2427
- self.verbosity_handler(quiet, verbose)
2639
+ self.verbosity_handler(quiet, verbose, json_output)
2428
2640
  wallet = None
2429
2641
  if all_balances:
2430
2642
  ask_for = [WO.PATH]
@@ -2487,7 +2699,9 @@ class CLIManager:
2487
2699
  )
2488
2700
  subtensor = self.initialize_chain(network)
2489
2701
  return self._run_command(
2490
- wallets.wallet_balance(wallet, subtensor, all_balances, ss58_addresses)
2702
+ wallets.wallet_balance(
2703
+ wallet, subtensor, all_balances, ss58_addresses, json_output
2704
+ )
2491
2705
  )
2492
2706
 
2493
2707
  def wallet_history(
@@ -2511,6 +2725,7 @@ class CLIManager:
2511
2725
 
2512
2726
  """
2513
2727
  # TODO: Fetch effective network and redirect users accordingly - this only works on finney
2728
+ # TODO: Add json_output if this gets re-enabled
2514
2729
  # no_use_config_str = "Using the network [dark_orange]finney[/dark_orange] and ignoring network/chain configs"
2515
2730
 
2516
2731
  # if self.config.get("network"):
@@ -2577,6 +2792,7 @@ class CLIManager:
2577
2792
  quiet: bool = Options.quiet,
2578
2793
  verbose: bool = Options.verbose,
2579
2794
  prompt: bool = Options.prompt,
2795
+ json_output: bool = Options.json_output,
2580
2796
  ):
2581
2797
  """
2582
2798
  Create or update the on-chain identity of a coldkey or a hotkey on the Bittensor network. [bold]Incurs a 1 TAO transaction fee.[/bold]
@@ -2595,7 +2811,7 @@ class CLIManager:
2595
2811
 
2596
2812
  [bold]Note[/bold]: This command should only be used if the user is willing to incur the a recycle fee associated with setting an identity on the blockchain. It is a high-level command that makes changes to the blockchain state and should not be used programmatically as part of other scripts or applications.
2597
2813
  """
2598
- self.verbosity_handler(quiet, verbose)
2814
+ self.verbosity_handler(quiet, verbose, json_output)
2599
2815
  wallet = self.wallet_ask(
2600
2816
  wallet_name,
2601
2817
  wallet_path,
@@ -2644,6 +2860,7 @@ class CLIManager:
2644
2860
  identity["additional"],
2645
2861
  identity["github_repo"],
2646
2862
  prompt,
2863
+ json_output,
2647
2864
  )
2648
2865
  )
2649
2866
 
@@ -2665,6 +2882,7 @@ class CLIManager:
2665
2882
  network: Optional[list[str]] = Options.network,
2666
2883
  quiet: bool = Options.quiet,
2667
2884
  verbose: bool = Options.verbose,
2885
+ json_output: bool = Options.json_output,
2668
2886
  ):
2669
2887
  """
2670
2888
  Shows the identity details of a user's coldkey or hotkey.
@@ -2683,7 +2901,7 @@ class CLIManager:
2683
2901
 
2684
2902
  [bold]Note[/bold]: This command is primarily used for informational purposes and has no side effects on the blockchain network state.
2685
2903
  """
2686
- wallet = None
2904
+ self.verbosity_handler(quiet, verbose, json_output)
2687
2905
  if not wallet_name:
2688
2906
  if coldkey_ss58:
2689
2907
  if not is_valid_ss58_address(coldkey_ss58):
@@ -2708,9 +2926,8 @@ class CLIManager:
2708
2926
  )
2709
2927
  coldkey_ss58 = wallet.coldkeypub.ss58_address
2710
2928
 
2711
- self.verbosity_handler(quiet, verbose)
2712
2929
  return self._run_command(
2713
- wallets.get_id(self.initialize_chain(network), coldkey_ss58)
2930
+ wallets.get_id(self.initialize_chain(network), coldkey_ss58, json_output)
2714
2931
  )
2715
2932
 
2716
2933
  def wallet_sign(
@@ -2726,6 +2943,7 @@ class CLIManager:
2726
2943
  message: str = typer.Option("", help="The message to encode and sign"),
2727
2944
  quiet: bool = Options.quiet,
2728
2945
  verbose: bool = Options.verbose,
2946
+ json_output: bool = Options.json_output,
2729
2947
  ):
2730
2948
  """
2731
2949
  Allows users to sign a message with the provided wallet or wallet hotkey. Use this command to easily prove your ownership of a coldkey or a hotkey.
@@ -2741,7 +2959,7 @@ class CLIManager:
2741
2959
  [green]$[/green] btcli wallet sign --wallet-name default --wallet-hotkey hotkey --message
2742
2960
  '{"something": "here", "timestamp": 1719908486}'
2743
2961
  """
2744
- self.verbosity_handler(quiet, verbose)
2962
+ self.verbosity_handler(quiet, verbose, json_output)
2745
2963
  if use_hotkey is None:
2746
2964
  use_hotkey = Confirm.ask(
2747
2965
  f"Would you like to sign the transaction using your [{COLORS.G.HK}]hotkey[/{COLORS.G.HK}]?"
@@ -2760,7 +2978,92 @@ class CLIManager:
2760
2978
  if not message:
2761
2979
  message = Prompt.ask("Enter the [blue]message[/blue] to encode and sign")
2762
2980
 
2763
- return self._run_command(wallets.sign(wallet, message, use_hotkey))
2981
+ return self._run_command(wallets.sign(wallet, message, use_hotkey, json_output))
2982
+
2983
+ def wallet_swap_coldkey(
2984
+ self,
2985
+ wallet_name: Optional[str] = Options.wallet_name,
2986
+ wallet_path: Optional[str] = Options.wallet_path,
2987
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
2988
+ new_wallet_or_ss58: Optional[str] = typer.Option(
2989
+ None,
2990
+ "--new-coldkey",
2991
+ "--new-coldkey-ss58",
2992
+ "--new-wallet",
2993
+ "--new",
2994
+ help="SS58 address of the new coldkey that will replace the current one.",
2995
+ ),
2996
+ network: Optional[list[str]] = Options.network,
2997
+ quiet: bool = Options.quiet,
2998
+ verbose: bool = Options.verbose,
2999
+ force_swap: bool = typer.Option(
3000
+ False,
3001
+ "--force",
3002
+ "-f",
3003
+ "--force-swap",
3004
+ help="Force the swap even if the new coldkey is already scheduled for a swap.",
3005
+ ),
3006
+ ):
3007
+ """
3008
+ Schedule a coldkey swap for a wallet.
3009
+
3010
+ This command allows you to schedule a coldkey swap for a wallet. You can either provide a new wallet name, or SS58 address.
3011
+
3012
+ EXAMPLES
3013
+
3014
+ [green]$[/green] btcli wallet schedule-coldkey-swap --new-wallet my_new_wallet
3015
+
3016
+ [green]$[/green] btcli wallet schedule-coldkey-swap --new-coldkey-ss58 5Dk...X3q
3017
+ """
3018
+ self.verbosity_handler(quiet, verbose)
3019
+
3020
+ if not wallet_name:
3021
+ wallet_name = Prompt.ask(
3022
+ "Enter the [blue]wallet name[/blue] which you want to swap the coldkey for",
3023
+ default=self.config.get("wallet_name") or defaults.wallet.name,
3024
+ )
3025
+ wallet = self.wallet_ask(
3026
+ wallet_name,
3027
+ wallet_path,
3028
+ wallet_hotkey,
3029
+ ask_for=[WO.NAME],
3030
+ validate=WV.WALLET,
3031
+ )
3032
+ console.print(
3033
+ f"\nWallet selected to swap the [blue]coldkey[/blue] from: \n"
3034
+ f"[dark_sea_green3]{wallet}[/dark_sea_green3]\n"
3035
+ )
3036
+
3037
+ if not new_wallet_or_ss58:
3038
+ new_wallet_or_ss58 = Prompt.ask(
3039
+ "Enter the [blue]new wallet name[/blue] or [blue]SS58 address[/blue] of the new coldkey",
3040
+ )
3041
+
3042
+ if is_valid_ss58_address(new_wallet_or_ss58):
3043
+ new_wallet_coldkey_ss58 = new_wallet_or_ss58
3044
+ else:
3045
+ new_wallet_name = new_wallet_or_ss58
3046
+ new_wallet = self.wallet_ask(
3047
+ new_wallet_name,
3048
+ wallet_path,
3049
+ wallet_hotkey,
3050
+ ask_for=[WO.NAME],
3051
+ validate=WV.WALLET,
3052
+ )
3053
+ console.print(
3054
+ f"\nNew wallet to swap the [blue]coldkey[/blue] to: \n"
3055
+ f"[dark_sea_green3]{new_wallet}[/dark_sea_green3]\n"
3056
+ )
3057
+ new_wallet_coldkey_ss58 = new_wallet.coldkeypub.ss58_address
3058
+
3059
+ return self._run_command(
3060
+ wallets.schedule_coldkey_swap(
3061
+ wallet=wallet,
3062
+ subtensor=self.initialize_chain(network),
3063
+ new_coldkey_ss58=new_wallet_coldkey_ss58,
3064
+ force_swap=force_swap,
3065
+ )
3066
+ )
2764
3067
 
2765
3068
  def stake_list(
2766
3069
  self,
@@ -2780,6 +3083,7 @@ class CLIManager:
2780
3083
  quiet: bool = Options.quiet,
2781
3084
  verbose: bool = Options.verbose,
2782
3085
  no_prompt: bool = Options.prompt,
3086
+ json_output: bool = Options.json_output,
2783
3087
  # TODO add: all-wallets, reuse_last, html_output
2784
3088
  ):
2785
3089
  """
@@ -2801,7 +3105,7 @@ class CLIManager:
2801
3105
  4. Verbose output with full values:
2802
3106
  [green]$[/green] btcli stake list --wallet.name my_wallet --verbose
2803
3107
  """
2804
- self.verbosity_handler(quiet, verbose)
3108
+ self.verbosity_handler(quiet, verbose, json_output)
2805
3109
 
2806
3110
  wallet = None
2807
3111
  if coldkey_ss58:
@@ -2832,6 +3136,7 @@ class CLIManager:
2832
3136
  live,
2833
3137
  verbose,
2834
3138
  no_prompt,
3139
+ json_output,
2835
3140
  )
2836
3141
  )
2837
3142
 
@@ -2875,9 +3180,11 @@ class CLIManager:
2875
3180
  rate_tolerance: Optional[float] = Options.rate_tolerance,
2876
3181
  safe_staking: Optional[bool] = Options.safe_staking,
2877
3182
  allow_partial_stake: Optional[bool] = Options.allow_partial_stake,
3183
+ era: int = Options.era,
2878
3184
  prompt: bool = Options.prompt,
2879
3185
  quiet: bool = Options.quiet,
2880
3186
  verbose: bool = Options.verbose,
3187
+ json_output: bool = Options.json_output,
2881
3188
  ):
2882
3189
  """
2883
3190
  Stake TAO to one or more hotkeys on specific netuids with your coldkey.
@@ -2910,7 +3217,7 @@ class CLIManager:
2910
3217
  • [blue]--partial[/blue]: Complete partial stake if rates exceed tolerance
2911
3218
 
2912
3219
  """
2913
- self.verbosity_handler(quiet, verbose)
3220
+ self.verbosity_handler(quiet, verbose, json_output)
2914
3221
  safe_staking = self.ask_safe_staking(safe_staking)
2915
3222
  if safe_staking:
2916
3223
  rate_tolerance = self.ask_rate_tolerance(rate_tolerance)
@@ -3068,6 +3375,8 @@ class CLIManager:
3068
3375
  safe_staking,
3069
3376
  rate_tolerance,
3070
3377
  allow_partial_stake,
3378
+ json_output,
3379
+ era,
3071
3380
  )
3072
3381
  )
3073
3382
 
@@ -3119,6 +3428,7 @@ class CLIManager:
3119
3428
  rate_tolerance: Optional[float] = Options.rate_tolerance,
3120
3429
  safe_staking: Optional[bool] = Options.safe_staking,
3121
3430
  allow_partial_stake: Optional[bool] = Options.allow_partial_stake,
3431
+ era: int = Options.era,
3122
3432
  prompt: bool = Options.prompt,
3123
3433
  interactive: bool = typer.Option(
3124
3434
  False,
@@ -3128,6 +3438,7 @@ class CLIManager:
3128
3438
  ),
3129
3439
  quiet: bool = Options.quiet,
3130
3440
  verbose: bool = Options.verbose,
3441
+ json_output: bool = Options.json_output,
3131
3442
  ):
3132
3443
  """
3133
3444
  Unstake TAO from one or more hotkeys and transfer them back to the user's coldkey wallet.
@@ -3159,7 +3470,7 @@ class CLIManager:
3159
3470
  • [blue]--tolerance[/blue]: Max allowed rate change (0.05 = 5%)
3160
3471
  • [blue]--partial[/blue]: Complete partial unstake if rates exceed tolerance
3161
3472
  """
3162
- self.verbosity_handler(quiet, verbose)
3473
+ self.verbosity_handler(quiet, verbose, json_output)
3163
3474
  if not unstake_all and not unstake_all_alpha:
3164
3475
  safe_staking = self.ask_safe_staking(safe_staking)
3165
3476
  if safe_staking:
@@ -3171,7 +3482,8 @@ class CLIManager:
3171
3482
  [hotkey_ss58_address, include_hotkeys, exclude_hotkeys, all_hotkeys]
3172
3483
  ):
3173
3484
  print_error(
3174
- "Interactive mode cannot be used with hotkey selection options like --include-hotkeys, --exclude-hotkeys, --all-hotkeys, or --hotkey."
3485
+ "Interactive mode cannot be used with hotkey selection options like "
3486
+ "--include-hotkeys, --exclude-hotkeys, --all-hotkeys, or --hotkey."
3175
3487
  )
3176
3488
  raise typer.Exit()
3177
3489
 
@@ -3308,6 +3620,8 @@ class CLIManager:
3308
3620
  include_hotkeys=include_hotkeys,
3309
3621
  exclude_hotkeys=exclude_hotkeys,
3310
3622
  prompt=prompt,
3623
+ json_output=json_output,
3624
+ era=era,
3311
3625
  )
3312
3626
  )
3313
3627
  elif (
@@ -3362,6 +3676,8 @@ class CLIManager:
3362
3676
  safe_staking=safe_staking,
3363
3677
  rate_tolerance=rate_tolerance,
3364
3678
  allow_partial_stake=allow_partial_stake,
3679
+ json_output=json_output,
3680
+ era=era,
3365
3681
  )
3366
3682
  )
3367
3683
 
@@ -3389,9 +3705,11 @@ class CLIManager:
3389
3705
  stake_all: bool = typer.Option(
3390
3706
  False, "--stake-all", "--all", help="Stake all", prompt=False
3391
3707
  ),
3708
+ era: int = Options.era,
3392
3709
  prompt: bool = Options.prompt,
3393
3710
  quiet: bool = Options.quiet,
3394
3711
  verbose: bool = Options.verbose,
3712
+ json_output: bool = Options.json_output,
3395
3713
  ):
3396
3714
  """
3397
3715
  Move staked TAO between hotkeys while keeping the same coldkey ownership.
@@ -3413,13 +3731,14 @@ class CLIManager:
3413
3731
 
3414
3732
  [green]$[/green] btcli stake move
3415
3733
  """
3416
- self.verbosity_handler(quiet, verbose)
3734
+ self.verbosity_handler(quiet, verbose, json_output)
3417
3735
  console.print(
3418
3736
  "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]"
3419
3737
  )
3420
3738
  if not destination_hotkey:
3421
3739
  dest_wallet_or_ss58 = Prompt.ask(
3422
- "Enter the [blue]destination wallet[/blue] where destination hotkey is located or [blue]ss58 address[/blue]"
3740
+ "Enter the [blue]destination wallet[/blue] where destination hotkey is located or "
3741
+ "[blue]ss58 address[/blue]"
3423
3742
  )
3424
3743
  if is_valid_ss58_address(dest_wallet_or_ss58):
3425
3744
  destination_hotkey = dest_wallet_or_ss58
@@ -3506,7 +3825,7 @@ class CLIManager:
3506
3825
  "Enter the [blue]destination subnet[/blue] (netuid) to move stake to"
3507
3826
  )
3508
3827
 
3509
- return self._run_command(
3828
+ result = self._run_command(
3510
3829
  move_stake.move_stake(
3511
3830
  subtensor=self.initialize_chain(network),
3512
3831
  wallet=wallet,
@@ -3516,10 +3835,14 @@ class CLIManager:
3516
3835
  destination_hotkey=destination_hotkey,
3517
3836
  amount=amount,
3518
3837
  stake_all=stake_all,
3838
+ era=era,
3519
3839
  interactive_selection=interactive_selection,
3520
3840
  prompt=prompt,
3521
3841
  )
3522
3842
  )
3843
+ if json_output:
3844
+ json_console.print(json.dumps({"success": result}))
3845
+ return result
3523
3846
 
3524
3847
  def stake_transfer(
3525
3848
  self,
@@ -3553,9 +3876,11 @@ class CLIManager:
3553
3876
  stake_all: bool = typer.Option(
3554
3877
  False, "--stake-all", "--all", help="Stake all", prompt=False
3555
3878
  ),
3879
+ era: int = Options.era,
3556
3880
  prompt: bool = Options.prompt,
3557
3881
  quiet: bool = Options.quiet,
3558
3882
  verbose: bool = Options.verbose,
3883
+ json_output: bool = Options.json_output,
3559
3884
  ):
3560
3885
  """
3561
3886
  Transfer stake between coldkeys while keeping the same hotkey ownership.
@@ -3589,10 +3914,10 @@ class CLIManager:
3589
3914
  Transfer all available stake from origin hotkey:
3590
3915
  [green]$[/green] btcli stake transfer --all --origin-netuid 1 --dest-netuid 2
3591
3916
  """
3917
+ self.verbosity_handler(quiet, verbose, json_output)
3592
3918
  console.print(
3593
3919
  "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]"
3594
3920
  )
3595
- self.verbosity_handler(quiet, verbose)
3596
3921
 
3597
3922
  if not dest_ss58:
3598
3923
  dest_ss58 = Prompt.ask(
@@ -3664,7 +3989,7 @@ class CLIManager:
3664
3989
  "Enter the [blue]destination subnet[/blue] (netuid)"
3665
3990
  )
3666
3991
 
3667
- return self._run_command(
3992
+ result = self._run_command(
3668
3993
  move_stake.transfer_stake(
3669
3994
  wallet=wallet,
3670
3995
  subtensor=self.initialize_chain(network),
@@ -3673,11 +3998,15 @@ class CLIManager:
3673
3998
  dest_netuid=dest_netuid,
3674
3999
  dest_coldkey_ss58=dest_ss58,
3675
4000
  amount=amount,
4001
+ era=era,
3676
4002
  interactive_selection=interactive_selection,
3677
4003
  stake_all=stake_all,
3678
4004
  prompt=prompt,
3679
4005
  )
3680
4006
  )
4007
+ if json_output:
4008
+ json_console.print(json.dumps({"success": result}))
4009
+ return result
3681
4010
 
3682
4011
  def stake_swap(
3683
4012
  self,
@@ -3711,11 +4040,13 @@ class CLIManager:
3711
4040
  "--all",
3712
4041
  help="Swap all available stake",
3713
4042
  ),
4043
+ era: int = Options.era,
3714
4044
  prompt: bool = Options.prompt,
3715
4045
  wait_for_inclusion: bool = Options.wait_for_inclusion,
3716
4046
  wait_for_finalization: bool = Options.wait_for_finalization,
3717
4047
  quiet: bool = Options.quiet,
3718
4048
  verbose: bool = Options.verbose,
4049
+ json_output: bool = Options.json_output,
3719
4050
  ):
3720
4051
  """
3721
4052
  Swap stake between different subnets while keeping the same coldkey-hotkey pair ownership.
@@ -3737,10 +4068,11 @@ class CLIManager:
3737
4068
  Swap 100 TAO from subnet 1 to subnet 2:
3738
4069
  [green]$[/green] btcli stake swap --wallet-name default --wallet-hotkey default --origin-netuid 1 --dest-netuid 2 --amount 100
3739
4070
  """
4071
+ self.verbosity_handler(quiet, verbose, json_output)
3740
4072
  console.print(
3741
- "[dim]This command moves stake from one subnet to another subnet while keeping the same coldkey-hotkey pair.[/dim]"
4073
+ "[dim]This command moves stake from one subnet to another subnet while keeping "
4074
+ "the same coldkey-hotkey pair.[/dim]"
3742
4075
  )
3743
- self.verbosity_handler(quiet, verbose)
3744
4076
 
3745
4077
  wallet = self.wallet_ask(
3746
4078
  wallet_name,
@@ -3765,7 +4097,7 @@ class CLIManager:
3765
4097
  if not amount and not swap_all:
3766
4098
  amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to swap")
3767
4099
 
3768
- return self._run_command(
4100
+ result = self._run_command(
3769
4101
  move_stake.swap_stake(
3770
4102
  wallet=wallet,
3771
4103
  subtensor=self.initialize_chain(network),
@@ -3773,12 +4105,16 @@ class CLIManager:
3773
4105
  destination_netuid=dest_netuid,
3774
4106
  amount=amount,
3775
4107
  swap_all=swap_all,
4108
+ era=era,
3776
4109
  interactive_selection=interactive_selection,
3777
4110
  prompt=prompt,
3778
4111
  wait_for_inclusion=wait_for_inclusion,
3779
4112
  wait_for_finalization=wait_for_finalization,
3780
4113
  )
3781
4114
  )
4115
+ if json_output:
4116
+ json_console.print(json.dumps({"success": result}))
4117
+ return result
3782
4118
 
3783
4119
  def stake_get_children(
3784
4120
  self,
@@ -3800,6 +4136,7 @@ class CLIManager:
3800
4136
  ),
3801
4137
  quiet: bool = Options.quiet,
3802
4138
  verbose: bool = Options.verbose,
4139
+ json_output: bool = Options.json_output,
3803
4140
  ):
3804
4141
  """
3805
4142
  Get all the child hotkeys on a specified subnet.
@@ -3811,7 +4148,7 @@ class CLIManager:
3811
4148
  [green]$[/green] btcli stake child get --netuid 1
3812
4149
  [green]$[/green] btcli stake child get --all-netuids
3813
4150
  """
3814
- self.verbosity_handler(quiet, verbose)
4151
+ self.verbosity_handler(quiet, verbose, json_output)
3815
4152
  wallet = self.wallet_ask(
3816
4153
  wallet_name,
3817
4154
  wallet_path,
@@ -3832,11 +4169,14 @@ class CLIManager:
3832
4169
  "Enter a netuid (leave blank for all)", default=None, show_default=True
3833
4170
  )
3834
4171
 
3835
- return self._run_command(
4172
+ result = self._run_command(
3836
4173
  children_hotkeys.get_children(
3837
4174
  wallet, self.initialize_chain(network), netuid
3838
4175
  )
3839
4176
  )
4177
+ if json_output:
4178
+ json_console.print(json.dumps(result))
4179
+ return result
3840
4180
 
3841
4181
  def stake_set_children(
3842
4182
  self,
@@ -3861,6 +4201,7 @@ class CLIManager:
3861
4201
  quiet: bool = Options.quiet,
3862
4202
  verbose: bool = Options.verbose,
3863
4203
  prompt: bool = Options.prompt,
4204
+ json_output: bool = Options.json_output,
3864
4205
  ):
3865
4206
  """
3866
4207
  Set child hotkeys on a specified subnet (or all). Overrides currently set children.
@@ -3873,7 +4214,7 @@ class CLIManager:
3873
4214
 
3874
4215
  [green]$[/green] btcli stake child set -c 5FCL3gmjtQV4xxxxuEPEFQVhyyyyqYgNwX7drFLw7MSdBnxP -c 5Hp5dxxxxtGg7pu8dN2btyyyyVA1vELmM9dy8KQv3LxV8PA7 --hotkey default --netuid 1 -p 0.3 -p 0.7
3875
4216
  """
3876
- self.verbosity_handler(quiet, verbose)
4217
+ self.verbosity_handler(quiet, verbose, json_output)
3877
4218
  netuid = get_optional_netuid(netuid, all_netuids)
3878
4219
 
3879
4220
  children = list_prompt(
@@ -3885,7 +4226,8 @@ class CLIManager:
3885
4226
  proportions = list_prompt(
3886
4227
  proportions,
3887
4228
  float,
3888
- "Enter comma-separated proportions equal to the number of children (sum not exceeding a total of 1.0)",
4229
+ "Enter comma-separated proportions equal to the number of children "
4230
+ "(sum not exceeding a total of 1.0)",
3889
4231
  )
3890
4232
 
3891
4233
  if len(proportions) != len(children):
@@ -3913,6 +4255,7 @@ class CLIManager:
3913
4255
  wait_for_finalization=wait_for_finalization,
3914
4256
  wait_for_inclusion=wait_for_inclusion,
3915
4257
  prompt=prompt,
4258
+ json_output=json_output,
3916
4259
  )
3917
4260
  )
3918
4261
 
@@ -3939,6 +4282,7 @@ class CLIManager:
3939
4282
  quiet: bool = Options.quiet,
3940
4283
  verbose: bool = Options.verbose,
3941
4284
  prompt: bool = Options.prompt,
4285
+ json_output: bool = Options.json_output,
3942
4286
  ):
3943
4287
  """
3944
4288
  Remove all children hotkeys on a specified subnet (or all).
@@ -3949,7 +4293,7 @@ class CLIManager:
3949
4293
 
3950
4294
  [green]$[/green] btcli stake child revoke --hotkey <parent_hotkey> --netuid 1
3951
4295
  """
3952
- self.verbosity_handler(quiet, verbose)
4296
+ self.verbosity_handler(quiet, verbose, json_output)
3953
4297
  wallet = self.wallet_ask(
3954
4298
  wallet_name,
3955
4299
  wallet_path,
@@ -3974,6 +4318,7 @@ class CLIManager:
3974
4318
  wait_for_inclusion,
3975
4319
  wait_for_finalization,
3976
4320
  prompt=prompt,
4321
+ json_output=json_output,
3977
4322
  )
3978
4323
  )
3979
4324
 
@@ -4000,7 +4345,8 @@ class CLIManager:
4000
4345
  None,
4001
4346
  "--take",
4002
4347
  "-t",
4003
- help="Use to set the take value for your child hotkey. When not used, the command will fetch the current take value.",
4348
+ help="Use to set the take value for your child hotkey. When not used, the command will fetch the current "
4349
+ "take value.",
4004
4350
  prompt=False,
4005
4351
  ),
4006
4352
  wait_for_inclusion: bool = Options.wait_for_inclusion,
@@ -4008,6 +4354,7 @@ class CLIManager:
4008
4354
  prompt: bool = Options.prompt,
4009
4355
  quiet: bool = Options.quiet,
4010
4356
  verbose: bool = Options.verbose,
4357
+ json_output: bool = Options.json_output,
4011
4358
  ):
4012
4359
  """
4013
4360
  Get and set your child hotkey take on a specified subnet.
@@ -4024,7 +4371,7 @@ class CLIManager:
4024
4371
 
4025
4372
  [green]$[/green] btcli stake child take --hotkey <child_hotkey> --take 0.12 --netuid 1
4026
4373
  """
4027
- self.verbosity_handler(quiet, verbose)
4374
+ self.verbosity_handler(quiet, verbose, json_output)
4028
4375
  wallet = self.wallet_ask(
4029
4376
  wallet_name,
4030
4377
  wallet_path,
@@ -4041,7 +4388,7 @@ class CLIManager:
4041
4388
  netuid = IntPrompt.ask(
4042
4389
  "Enter netuid (leave blank for all)", default=None, show_default=True
4043
4390
  )
4044
- return self._run_command(
4391
+ results: list[tuple[Optional[int], bool]] = self._run_command(
4045
4392
  children_hotkeys.childkey_take(
4046
4393
  wallet=wallet,
4047
4394
  subtensor=self.initialize_chain(network),
@@ -4053,6 +4400,12 @@ class CLIManager:
4053
4400
  prompt=prompt,
4054
4401
  )
4055
4402
  )
4403
+ if json_output:
4404
+ output = {}
4405
+ for netuid_, success in results:
4406
+ output[netuid_] = success
4407
+ json_console.print(json.dumps(output))
4408
+ return results
4056
4409
 
4057
4410
  def sudo_set(
4058
4411
  self,
@@ -4069,6 +4422,7 @@ class CLIManager:
4069
4422
  ),
4070
4423
  quiet: bool = Options.quiet,
4071
4424
  verbose: bool = Options.verbose,
4425
+ json_output: bool = Options.json_output,
4072
4426
  ):
4073
4427
  """
4074
4428
  Used to set hyperparameters for a specific subnet.
@@ -4079,7 +4433,7 @@ class CLIManager:
4079
4433
 
4080
4434
  [green]$[/green] btcli sudo set --netuid 1 --param tempo --value 400
4081
4435
  """
4082
- self.verbosity_handler(quiet, verbose)
4436
+ self.verbosity_handler(quiet, verbose, json_output)
4083
4437
 
4084
4438
  if not param_name or not param_value:
4085
4439
  hyperparams = self._run_command(
@@ -4124,15 +4478,19 @@ class CLIManager:
4124
4478
  wallet = self.wallet_ask(
4125
4479
  wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
4126
4480
  )
4127
- return self._run_command(
4481
+ result = self._run_command(
4128
4482
  sudo.sudo_set_hyperparameter(
4129
4483
  wallet,
4130
4484
  self.initialize_chain(network),
4131
4485
  netuid,
4132
4486
  param_name,
4133
4487
  param_value,
4488
+ json_output,
4134
4489
  )
4135
4490
  )
4491
+ if json_output:
4492
+ json_console.print(json.dumps({"success": result}))
4493
+ return result
4136
4494
 
4137
4495
  def sudo_get(
4138
4496
  self,
@@ -4140,6 +4498,7 @@ class CLIManager:
4140
4498
  netuid: int = Options.netuid,
4141
4499
  quiet: bool = Options.quiet,
4142
4500
  verbose: bool = Options.verbose,
4501
+ json_output: bool = Options.json_output,
4143
4502
  ):
4144
4503
  """
4145
4504
  Shows a list of the hyperparameters for the specified subnet.
@@ -4148,9 +4507,11 @@ class CLIManager:
4148
4507
 
4149
4508
  [green]$[/green] btcli sudo get --netuid 1
4150
4509
  """
4151
- self.verbosity_handler(quiet, verbose)
4510
+ self.verbosity_handler(quiet, verbose, json_output)
4152
4511
  return self._run_command(
4153
- sudo.get_hyperparameters(self.initialize_chain(network), netuid)
4512
+ sudo.get_hyperparameters(
4513
+ self.initialize_chain(network), netuid, json_output
4514
+ )
4154
4515
  )
4155
4516
 
4156
4517
  def sudo_senate(
@@ -4158,6 +4519,7 @@ class CLIManager:
4158
4519
  network: Optional[list[str]] = Options.network,
4159
4520
  quiet: bool = Options.quiet,
4160
4521
  verbose: bool = Options.verbose,
4522
+ json_output: bool = Options.json_output,
4161
4523
  ):
4162
4524
  """
4163
4525
  Shows the Senate members of the Bittensor's governance protocol.
@@ -4167,14 +4529,17 @@ class CLIManager:
4167
4529
  EXAMPLE
4168
4530
  [green]$[/green] btcli sudo senate
4169
4531
  """
4170
- self.verbosity_handler(quiet, verbose)
4171
- return self._run_command(sudo.get_senate(self.initialize_chain(network)))
4532
+ self.verbosity_handler(quiet, verbose, json_output)
4533
+ return self._run_command(
4534
+ sudo.get_senate(self.initialize_chain(network), json_output)
4535
+ )
4172
4536
 
4173
4537
  def sudo_proposals(
4174
4538
  self,
4175
4539
  network: Optional[list[str]] = Options.network,
4176
4540
  quiet: bool = Options.quiet,
4177
4541
  verbose: bool = Options.verbose,
4542
+ json_output: bool = Options.json_output,
4178
4543
  ):
4179
4544
  """
4180
4545
  View active proposals for the senate in the Bittensor's governance protocol.
@@ -4184,9 +4549,9 @@ class CLIManager:
4184
4549
  EXAMPLE
4185
4550
  [green]$[/green] btcli sudo proposals
4186
4551
  """
4187
- self.verbosity_handler(quiet, verbose)
4552
+ self.verbosity_handler(quiet, verbose, json_output)
4188
4553
  return self._run_command(
4189
- sudo.proposals(self.initialize_chain(network), verbose)
4554
+ sudo.proposals(self.initialize_chain(network), verbose, json_output)
4190
4555
  )
4191
4556
 
4192
4557
  def sudo_senate_vote(
@@ -4223,6 +4588,7 @@ class CLIManager:
4223
4588
  EXAMPLE
4224
4589
  [green]$[/green] btcli sudo senate_vote --proposal <proposal_hash>
4225
4590
  """
4591
+ # TODO discuss whether this should receive json_output. I don't think it should.
4226
4592
  self.verbosity_handler(quiet, verbose)
4227
4593
  wallet = self.wallet_ask(
4228
4594
  wallet_name,
@@ -4246,6 +4612,7 @@ class CLIManager:
4246
4612
  take: float = typer.Option(None, help="The new take value."),
4247
4613
  quiet: bool = Options.quiet,
4248
4614
  verbose: bool = Options.verbose,
4615
+ json_output: bool = Options.json_output,
4249
4616
  ):
4250
4617
  """
4251
4618
  Allows users to change their delegate take percentage.
@@ -4258,7 +4625,7 @@ class CLIManager:
4258
4625
  """
4259
4626
  max_value = 0.18
4260
4627
  min_value = 0.00
4261
- self.verbosity_handler(quiet, verbose)
4628
+ self.verbosity_handler(quiet, verbose, json_output)
4262
4629
 
4263
4630
  wallet = self.wallet_ask(
4264
4631
  wallet_name,
@@ -4283,9 +4650,12 @@ class CLIManager:
4283
4650
  )
4284
4651
  raise typer.Exit()
4285
4652
 
4286
- return self._run_command(
4653
+ result = self._run_command(
4287
4654
  sudo.set_take(wallet, self.initialize_chain(network), take)
4288
4655
  )
4656
+ if json_output:
4657
+ json_console.print(json.dumps({"success": result}))
4658
+ return result
4289
4659
 
4290
4660
  def sudo_get_take(
4291
4661
  self,
@@ -4295,6 +4665,7 @@ class CLIManager:
4295
4665
  wallet_hotkey: Optional[str] = Options.wallet_hotkey,
4296
4666
  quiet: bool = Options.quiet,
4297
4667
  verbose: bool = Options.verbose,
4668
+ json_output: bool = Options.json_output,
4298
4669
  ):
4299
4670
  """
4300
4671
  Allows users to check their delegate take percentage.
@@ -4304,7 +4675,7 @@ class CLIManager:
4304
4675
  EXAMPLE
4305
4676
  [green]$[/green] btcli sudo get-take --wallet-name my_wallet --wallet-hotkey my_hotkey
4306
4677
  """
4307
- self.verbosity_handler(quiet, verbose)
4678
+ self.verbosity_handler(quiet, verbose, json_output)
4308
4679
 
4309
4680
  wallet = self.wallet_ask(
4310
4681
  wallet_name,
@@ -4313,10 +4684,15 @@ class CLIManager:
4313
4684
  ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
4314
4685
  validate=WV.WALLET_AND_HOTKEY,
4315
4686
  )
4316
-
4317
- self._run_command(
4318
- sudo.display_current_take(self.initialize_chain(network), wallet)
4319
- )
4687
+ if json_output:
4688
+ result = self._run_command(
4689
+ sudo.get_current_take(self.initialize_chain(network), wallet)
4690
+ )
4691
+ json_console.print(json.dumps({"current_take": result}))
4692
+ else:
4693
+ self._run_command(
4694
+ sudo.display_current_take(self.initialize_chain(network), wallet)
4695
+ )
4320
4696
 
4321
4697
  def subnets_list(
4322
4698
  self,
@@ -4324,6 +4700,7 @@ class CLIManager:
4324
4700
  quiet: bool = Options.quiet,
4325
4701
  verbose: bool = Options.verbose,
4326
4702
  live_mode: bool = Options.live,
4703
+ json_output: bool = Options.json_output,
4327
4704
  ):
4328
4705
  """
4329
4706
  List all subnets and their detailed information.
@@ -4351,7 +4728,10 @@ class CLIManager:
4351
4728
 
4352
4729
  [green]$[/green] btcli subnets list
4353
4730
  """
4354
- self.verbosity_handler(quiet, verbose)
4731
+ if json_output and live_mode:
4732
+ print_error("Cannot use `--json-output` and `--live` at the same time.")
4733
+ return
4734
+ self.verbosity_handler(quiet, verbose, json_output)
4355
4735
  subtensor = self.initialize_chain(network)
4356
4736
  return self._run_command(
4357
4737
  subnets.subnets_list(
@@ -4361,6 +4741,7 @@ class CLIManager:
4361
4741
  not self.config.get("use_cache", True),
4362
4742
  verbose,
4363
4743
  live_mode,
4744
+ json_output,
4364
4745
  )
4365
4746
  )
4366
4747
 
@@ -4393,6 +4774,9 @@ class CLIManager:
4393
4774
  help="Show the price in log scale.",
4394
4775
  ),
4395
4776
  html_output: bool = Options.html_output,
4777
+ quiet: bool = Options.quiet,
4778
+ verbose: bool = Options.verbose,
4779
+ json_output: bool = Options.json_output,
4396
4780
  ):
4397
4781
  """
4398
4782
  Shows the historical price of a subnet for the past 24 hours.
@@ -4410,6 +4794,10 @@ class CLIManager:
4410
4794
  [green]$[/green] btcli subnets price --all --html
4411
4795
  [green]$[/green] btcli subnets price --netuids 1,2,3,4 --html
4412
4796
  """
4797
+ if json_output and html_output:
4798
+ print_error("Cannot specify both `--json-output` and `--html`")
4799
+ return
4800
+ self.verbosity_handler(quiet=quiet, verbose=verbose, json_output=json_output)
4413
4801
  if netuids:
4414
4802
  netuids = parse_to_list(
4415
4803
  netuids,
@@ -4418,15 +4806,15 @@ class CLIManager:
4418
4806
  )
4419
4807
  if all_netuids and netuids:
4420
4808
  print_error("Cannot specify both --netuid and --all-netuids")
4421
- raise typer.Exit()
4809
+ return
4422
4810
 
4423
4811
  if not netuids and not all_netuids:
4424
4812
  netuids = Prompt.ask(
4425
- "Enter the [blue]netuid(s)[/blue] to view the price of in comma-separated format [dim](or Press Enter to view all subnets)[/dim]",
4813
+ "Enter the [blue]netuid(s)[/blue] to view the price of in comma-separated format [dim]"
4814
+ "(or Press Enter to view all subnets)[/dim]",
4426
4815
  )
4427
4816
  if not netuids:
4428
4817
  all_netuids = True
4429
- html_output = True
4430
4818
  else:
4431
4819
  netuids = parse_to_list(
4432
4820
  netuids,
@@ -4434,7 +4822,7 @@ class CLIManager:
4434
4822
  "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
4435
4823
  )
4436
4824
 
4437
- if all_netuids:
4825
+ if all_netuids and not json_output:
4438
4826
  html_output = True
4439
4827
 
4440
4828
  if html_output and is_linux():
@@ -4448,6 +4836,7 @@ class CLIManager:
4448
4836
  interval_hours,
4449
4837
  html_output,
4450
4838
  log_scale,
4839
+ json_output,
4451
4840
  )
4452
4841
  )
4453
4842
 
@@ -4463,6 +4852,7 @@ class CLIManager:
4463
4852
  quiet: bool = Options.quiet,
4464
4853
  verbose: bool = Options.verbose,
4465
4854
  prompt: bool = Options.prompt,
4855
+ json_output: bool = Options.json_output,
4466
4856
  ):
4467
4857
  """
4468
4858
  Displays detailed information about a subnet including participants and their state.
@@ -4471,7 +4861,7 @@ class CLIManager:
4471
4861
 
4472
4862
  [green]$[/green] btcli subnets list
4473
4863
  """
4474
- self.verbosity_handler(quiet, verbose)
4864
+ self.verbosity_handler(quiet, verbose, json_output)
4475
4865
  subtensor = self.initialize_chain(network)
4476
4866
  return self._run_command(
4477
4867
  subnets.show(
@@ -4482,6 +4872,7 @@ class CLIManager:
4482
4872
  delegate_selection=False,
4483
4873
  verbose=verbose,
4484
4874
  prompt=prompt,
4875
+ json_output=json_output,
4485
4876
  )
4486
4877
  )
4487
4878
 
@@ -4490,6 +4881,7 @@ class CLIManager:
4490
4881
  network: Optional[list[str]] = Options.network,
4491
4882
  quiet: bool = Options.quiet,
4492
4883
  verbose: bool = Options.verbose,
4884
+ json_output: bool = Options.json_output,
4493
4885
  ):
4494
4886
  """
4495
4887
  Shows the required amount of TAO to be recycled for creating a new subnet, i.e., cost of registering a new subnet.
@@ -4500,8 +4892,10 @@ class CLIManager:
4500
4892
 
4501
4893
  [green]$[/green] btcli subnets burn_cost
4502
4894
  """
4503
- self.verbosity_handler(quiet, verbose)
4504
- return self._run_command(subnets.burn_cost(self.initialize_chain(network)))
4895
+ self.verbosity_handler(quiet, verbose, json_output)
4896
+ return self._run_command(
4897
+ subnets.burn_cost(self.initialize_chain(network), json_output)
4898
+ )
4505
4899
 
4506
4900
  def subnets_create(
4507
4901
  self,
@@ -4510,7 +4904,7 @@ class CLIManager:
4510
4904
  wallet_hotkey: str = Options.wallet_hotkey,
4511
4905
  network: Optional[list[str]] = Options.network,
4512
4906
  subnet_name: Optional[str] = typer.Option(
4513
- None, "--subnet-name", "--name", help="Name of the subnet"
4907
+ None, "--subnet-name", help="Name of the subnet"
4514
4908
  ),
4515
4909
  github_repo: Optional[str] = typer.Option(
4516
4910
  None, "--github-repo", "--repo", help="GitHub repository URL"
@@ -4534,6 +4928,7 @@ class CLIManager:
4534
4928
  additional_info: Optional[str] = typer.Option(
4535
4929
  None, "--additional-info", help="Additional information"
4536
4930
  ),
4931
+ json_output: bool = Options.json_output,
4537
4932
  prompt: bool = Options.prompt,
4538
4933
  quiet: bool = Options.quiet,
4539
4934
  verbose: bool = Options.verbose,
@@ -4552,7 +4947,7 @@ class CLIManager:
4552
4947
  2. Create with GitHub repo and contact email:
4553
4948
  [green]$[/green] btcli subnets create --subnet-name MySubnet --github-repo https://github.com/myorg/mysubnet --subnet-contact team@mysubnet.net
4554
4949
  """
4555
- self.verbosity_handler(quiet, verbose)
4950
+ self.verbosity_handler(quiet, verbose, json_output)
4556
4951
  wallet = self.wallet_ask(
4557
4952
  wallet_name,
4558
4953
  wallet_path,
@@ -4574,34 +4969,19 @@ class CLIManager:
4574
4969
  description=description,
4575
4970
  additional=additional_info,
4576
4971
  )
4577
- success = self._run_command(
4578
- subnets.create(wallet, self.initialize_chain(network), identity, prompt),
4579
- exit_early=False,
4972
+ self._run_command(
4973
+ subnets.create(
4974
+ wallet, self.initialize_chain(network), identity, json_output, prompt
4975
+ )
4580
4976
  )
4581
4977
 
4582
- if success and prompt:
4583
- set_id = Confirm.ask(
4584
- "[dark_sea_green3]Do you want to set/update your identity?",
4585
- default=False,
4586
- show_default=True,
4587
- )
4588
- if set_id:
4589
- self.wallet_set_id(
4590
- wallet_name=wallet.name,
4591
- wallet_hotkey=wallet.hotkey,
4592
- wallet_path=wallet.path,
4593
- network=network,
4594
- prompt=prompt,
4595
- quiet=quiet,
4596
- verbose=verbose,
4597
- )
4598
-
4599
4978
  def subnets_get_identity(
4600
4979
  self,
4601
4980
  network: Optional[list[str]] = Options.network,
4602
4981
  netuid: int = Options.netuid,
4603
4982
  quiet: bool = Options.quiet,
4604
4983
  verbose: bool = Options.verbose,
4984
+ json_output: bool = Options.json_output,
4605
4985
  ):
4606
4986
  """
4607
4987
  Get the identity information for a subnet.
@@ -4610,11 +4990,10 @@ class CLIManager:
4610
4990
 
4611
4991
  [green]$[/green] btcli subnets get-identity --netuid 1
4612
4992
  """
4613
- self.verbosity_handler(quiet, verbose)
4993
+ self.verbosity_handler(quiet, verbose, json_output)
4614
4994
  return self._run_command(
4615
4995
  subnets.get_identity(
4616
- self.initialize_chain(network),
4617
- netuid,
4996
+ self.initialize_chain(network), netuid, json_output=json_output
4618
4997
  )
4619
4998
  )
4620
4999
 
@@ -4650,6 +5029,7 @@ class CLIManager:
4650
5029
  additional_info: Optional[str] = typer.Option(
4651
5030
  None, "--additional-info", help="Additional information"
4652
5031
  ),
5032
+ json_output: bool = Options.json_output,
4653
5033
  prompt: bool = Options.prompt,
4654
5034
  quiet: bool = Options.quiet,
4655
5035
  verbose: bool = Options.verbose,
@@ -4667,7 +5047,7 @@ class CLIManager:
4667
5047
  2. Set subnet identity with specific values:
4668
5048
  [green]$[/green] btcli subnets set-identity --netuid 1 --subnet-name MySubnet --github-repo https://github.com/myorg/mysubnet --subnet-contact team@mysubnet.net
4669
5049
  """
4670
- self.verbosity_handler(quiet, verbose)
5050
+ self.verbosity_handler(quiet, verbose, json_output)
4671
5051
  wallet = self.wallet_ask(
4672
5052
  wallet_name,
4673
5053
  wallet_path,
@@ -4685,7 +5065,9 @@ class CLIManager:
4685
5065
  exit_early=False,
4686
5066
  )
4687
5067
  if current_identity is None:
4688
- raise typer.Exit()
5068
+ if json_output:
5069
+ json_console.print('{"success": false}')
5070
+ return
4689
5071
 
4690
5072
  identity = prompt_for_subnet_identity(
4691
5073
  current_identity=current_identity,
@@ -4698,15 +5080,13 @@ class CLIManager:
4698
5080
  additional=additional_info,
4699
5081
  )
4700
5082
 
4701
- return self._run_command(
5083
+ success = self._run_command(
4702
5084
  subnets.set_identity(
4703
- wallet,
4704
- self.initialize_chain(network),
4705
- netuid,
4706
- identity,
4707
- prompt,
5085
+ wallet, self.initialize_chain(network), netuid, identity, prompt
4708
5086
  )
4709
5087
  )
5088
+ if json_output:
5089
+ json_console.print(json.dumps({"success": success}))
4710
5090
 
4711
5091
  def subnets_pow_register(
4712
5092
  self,
@@ -4804,6 +5184,14 @@ class CLIManager:
4804
5184
  wallet_hotkey: str = Options.wallet_hotkey,
4805
5185
  network: Optional[list[str]] = Options.network,
4806
5186
  netuid: int = Options.netuid,
5187
+ era: Optional[
5188
+ int
5189
+ ] = typer.Option( # Should not be Options.era bc this needs to be an Optional[int]
5190
+ None,
5191
+ help="Length (in blocks) for which the transaction should be valid. Note that it is possible that if you "
5192
+ "use an era for this transaction that you may pay a different fee to register than the one stated.",
5193
+ ),
5194
+ json_output: bool = Options.json_output,
4807
5195
  prompt: bool = Options.prompt,
4808
5196
  quiet: bool = Options.quiet,
4809
5197
  verbose: bool = Options.verbose,
@@ -4819,7 +5207,7 @@ class CLIManager:
4819
5207
 
4820
5208
  [green]$[/green] btcli subnets register --netuid 1
4821
5209
  """
4822
- self.verbosity_handler(quiet, verbose)
5210
+ self.verbosity_handler(quiet, verbose, json_output)
4823
5211
  wallet = self.wallet_ask(
4824
5212
  wallet_name,
4825
5213
  wallet_path,
@@ -4832,6 +5220,8 @@ class CLIManager:
4832
5220
  wallet,
4833
5221
  self.initialize_chain(network),
4834
5222
  netuid,
5223
+ era,
5224
+ json_output,
4835
5225
  prompt,
4836
5226
  )
4837
5227
  )
@@ -4957,6 +5347,7 @@ class CLIManager:
4957
5347
  "-s",
4958
5348
  help="Corresponding salt for the hash function, e.g. -s 163,241,217 ...",
4959
5349
  ),
5350
+ json_output: bool = Options.json_output,
4960
5351
  quiet: bool = Options.quiet,
4961
5352
  verbose: bool = Options.verbose,
4962
5353
  prompt: bool = Options.prompt,
@@ -4970,7 +5361,7 @@ class CLIManager:
4970
5361
 
4971
5362
  [green]$[/green] btcli wt reveal --netuid 1 --uids 1,2,3,4 --weights 0.1,0.2,0.3,0.4 --salt 163,241,217,11,161,142,147,189
4972
5363
  """
4973
- self.verbosity_handler(quiet, verbose)
5364
+ self.verbosity_handler(quiet, verbose, json_output)
4974
5365
  uids = list_prompt(uids, int, "UIDs of interest for the specified netuid")
4975
5366
  weights = list_prompt(
4976
5367
  weights, float, "Corresponding weights for the specified UIDs"
@@ -5003,7 +5394,7 @@ class CLIManager:
5003
5394
  err_console.print(
5004
5395
  "The number of UIDs you specify must match up with the specified number of weights"
5005
5396
  )
5006
- raise typer.Exit()
5397
+ return
5007
5398
 
5008
5399
  if salt:
5009
5400
  salt = parse_to_list(
@@ -5032,6 +5423,7 @@ class CLIManager:
5032
5423
  salt,
5033
5424
  __version_as_int__,
5034
5425
  prompt=prompt,
5426
+ json_output=json_output,
5035
5427
  )
5036
5428
  )
5037
5429
 
@@ -5055,6 +5447,7 @@ class CLIManager:
5055
5447
  "-s",
5056
5448
  help="Corresponding salt for the hash function, e.g. -s 163 -s 241 -s 217 ...",
5057
5449
  ),
5450
+ json_output: bool = Options.json_output,
5058
5451
  quiet: bool = Options.quiet,
5059
5452
  verbose: bool = Options.verbose,
5060
5453
  prompt: bool = Options.prompt,
@@ -5072,7 +5465,7 @@ class CLIManager:
5072
5465
  [italic]Note[/italic]: This command is used to commit weights for a specific subnet and requires the user to have the necessary
5073
5466
  permissions.
5074
5467
  """
5075
- self.verbosity_handler(quiet, verbose)
5468
+ self.verbosity_handler(quiet, verbose, json_output)
5076
5469
 
5077
5470
  if uids:
5078
5471
  uids = parse_to_list(
@@ -5101,7 +5494,7 @@ class CLIManager:
5101
5494
  err_console.print(
5102
5495
  "The number of UIDs you specify must match up with the specified number of weights"
5103
5496
  )
5104
- raise typer.Exit()
5497
+ return
5105
5498
 
5106
5499
  if salt:
5107
5500
  salt = parse_to_list(
@@ -5128,6 +5521,7 @@ class CLIManager:
5128
5521
  weights,
5129
5522
  salt,
5130
5523
  __version_as_int__,
5524
+ json_output=json_output,
5131
5525
  prompt=prompt,
5132
5526
  )
5133
5527
  )