bittensor-cli 9.5.0__tar.gz → 9.7.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 (54) hide show
  1. bittensor_cli-9.7.0/MANIFEST.in +1 -0
  2. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/PKG-INFO +9 -3
  3. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/README.md +8 -2
  4. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/cli.py +77 -22
  5. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/__init__.py +2 -0
  6. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/chain_data.py +4 -0
  7. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/extrinsics/registration.py +56 -16
  8. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/subtensor_interface.py +15 -7
  9. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/main-filters.j2 +24 -0
  10. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/main-header.j2 +36 -0
  11. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/neuron-details.j2 +111 -0
  12. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/price-multi.j2 +113 -0
  13. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/price-single.j2 +99 -0
  14. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/subnet-details-header.j2 +49 -0
  15. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/subnet-details.j2 +32 -0
  16. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/subnet-metrics.j2 +57 -0
  17. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/subnets-table.j2 +28 -0
  18. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/table.j2 +267 -0
  19. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/view.css +1058 -0
  20. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/view.j2 +43 -0
  21. bittensor_cli-9.7.0/bittensor_cli/src/bittensor/templates/view.js +1053 -0
  22. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/utils.py +30 -10
  23. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/add.py +46 -41
  24. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/subnets/subnets.py +2 -1
  25. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/sudo.py +71 -61
  26. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/wallets.py +2 -0
  27. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/PKG-INFO +9 -3
  28. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/SOURCES.txt +14 -0
  29. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/pyproject.toml +3 -2
  30. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/__init__.py +0 -0
  31. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/doc_generation_helper.py +0 -0
  32. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/__init__.py +0 -0
  33. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/balances.py +0 -0
  34. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/extrinsics/__init__.py +0 -0
  35. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/extrinsics/root.py +0 -0
  36. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/extrinsics/transfer.py +0 -0
  37. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/minigraph.py +0 -0
  38. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/bittensor/networking.py +0 -0
  39. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/__init__.py +0 -0
  40. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/__init__.py +0 -0
  41. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/children_hotkeys.py +0 -0
  42. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/list.py +0 -0
  43. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/move.py +0 -0
  44. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/stake/remove.py +0 -0
  45. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/subnets/__init__.py +0 -0
  46. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/subnets/price.py +0 -0
  47. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/view.py +0 -0
  48. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/src/commands/weights.py +0 -0
  49. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli/version.py +0 -0
  50. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/dependency_links.txt +0 -0
  51. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/entry_points.txt +0 -0
  52. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/requires.txt +0 -0
  53. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/bittensor_cli.egg-info/top_level.txt +0 -0
  54. {bittensor_cli-9.5.0 → bittensor_cli-9.7.0}/setup.cfg +0 -0
@@ -0,0 +1 @@
1
+ recursive-include bittensor_cli/src/bittensor/templates *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bittensor-cli
3
- Version: 9.5.0
3
+ Version: 9.7.0
4
4
  Summary: Bittensor CLI
5
5
  Author: bittensor.com
6
6
  Project-URL: homepage, https://github.com/opentensor/btcli
@@ -71,10 +71,10 @@ 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, or from PyPI. **Make sure you verify your installation after you install**:
74
+ You can install `btcli` on your local machine directly from source, PyPI, or Homebrew. **Make sure you verify your installation after you install**:
75
75
 
76
76
 
77
- ### Install from PyPI
77
+ ### Install from [PyPI](https://pypi.org/project/bittensor/)
78
78
 
79
79
  Run
80
80
  ```
@@ -86,6 +86,12 @@ Alternatively, if you prefer to use [uv](https://pypi.org/project/uv/):
86
86
  uv pip install bittensor-cli
87
87
  ```
88
88
 
89
+ ### Install from [Homebrew](https://formulae.brew.sh/formula/btcli#default)
90
+
91
+ ```shell
92
+ brew install btcli
93
+ ```
94
+
89
95
  ### Install from source
90
96
 
91
97
  1. Create and activate a virtual environment.
@@ -38,10 +38,10 @@ 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, or from PyPI. **Make sure you verify your installation after you install**:
41
+ You can install `btcli` on your local machine directly from source, PyPI, or Homebrew. **Make sure you verify your installation after you install**:
42
42
 
43
43
 
44
- ### Install from PyPI
44
+ ### Install from [PyPI](https://pypi.org/project/bittensor/)
45
45
 
46
46
  Run
47
47
  ```
@@ -53,6 +53,12 @@ Alternatively, if you prefer to use [uv](https://pypi.org/project/uv/):
53
53
  uv pip install bittensor-cli
54
54
  ```
55
55
 
56
+ ### Install from [Homebrew](https://formulae.brew.sh/formula/btcli#default)
57
+
58
+ ```shell
59
+ brew install btcli
60
+ ```
61
+
56
62
  ### Install from source
57
63
 
58
64
  1. Create and activate a virtual environment.
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  import asyncio
3
3
  import curses
4
+ import copy
4
5
  import importlib
5
6
  import json
6
7
  import os.path
@@ -10,7 +11,7 @@ import sys
10
11
  import traceback
11
12
  import warnings
12
13
  from pathlib import Path
13
- from typing import Coroutine, Optional
14
+ from typing import Coroutine, Optional, Union
14
15
  from dataclasses import fields
15
16
 
16
17
  import rich
@@ -89,6 +90,23 @@ class Options:
89
90
  Re-usable typer args
90
91
  """
91
92
 
93
+ @classmethod
94
+ def edit_help(cls, option_name: str, help_text: str):
95
+ """
96
+ Edits the `help` attribute of a copied given Typer option in this class, returning
97
+ the modified Typer option.
98
+
99
+ Args:
100
+ option_name: the name of the option (e.g. "wallet_name")
101
+ help_text: New help text to be used (e.g. "Wallet's name")
102
+
103
+ Returns:
104
+ Modified Typer Option with new help text.
105
+ """
106
+ copied_attr = copy.copy(getattr(cls, option_name))
107
+ setattr(copied_attr, "help", help_text)
108
+ return copied_attr
109
+
92
110
  wallet_name = typer.Option(
93
111
  None,
94
112
  "--wallet-name",
@@ -1879,6 +1897,8 @@ class CLIManager:
1879
1897
  wallet_name: Optional[str] = Options.wallet_name,
1880
1898
  wallet_path: Optional[str] = Options.wallet_path,
1881
1899
  wallet_hotkey: Optional[str] = Options.wallet_hotkey,
1900
+ netuid: Optional[int] = Options.netuid_not_req,
1901
+ all_netuids: bool = Options.all_netuids,
1882
1902
  network: Optional[list[str]] = Options.network,
1883
1903
  destination_hotkey_name: Optional[str] = typer.Argument(
1884
1904
  None, help="Destination hotkey name."
@@ -1899,12 +1919,14 @@ class CLIManager:
1899
1919
 
1900
1920
  - Make sure that your original key pair (coldkeyA, hotkeyA) is already registered.
1901
1921
  - Make sure that you use a newly created hotkeyB in this command. A hotkeyB that is already registered cannot be used in this command.
1922
+ - You can specify the netuid for which you want to swap the hotkey for. If it is not defined, the swap will be initiated for all subnets.
1902
1923
  - Finally, note that this command requires a fee of 1 TAO for recycling and this fee is taken from your wallet (coldkeyA).
1903
1924
 
1904
1925
  EXAMPLE
1905
1926
 
1906
- [green]$[/green] btcli wallet swap_hotkey destination_hotkey_name --wallet-name your_wallet_name --wallet-hotkey original_hotkey
1927
+ [green]$[/green] btcli wallet swap_hotkey destination_hotkey_name --wallet-name your_wallet_name --wallet-hotkey original_hotkey --netuid 1
1907
1928
  """
1929
+ netuid = get_optional_netuid(netuid, all_netuids)
1908
1930
  self.verbosity_handler(quiet, verbose, json_output)
1909
1931
  original_wallet = self.wallet_ask(
1910
1932
  wallet_name,
@@ -1928,7 +1950,7 @@ class CLIManager:
1928
1950
  self.initialize_chain(network)
1929
1951
  return self._run_command(
1930
1952
  wallets.swap_hotkey(
1931
- original_wallet, new_wallet, self.subtensor, prompt, json_output
1953
+ original_wallet, new_wallet, self.subtensor, netuid, prompt, json_output
1932
1954
  )
1933
1955
  )
1934
1956
 
@@ -3202,7 +3224,11 @@ class CLIManager:
3202
3224
  help="When set, this command stakes to all hotkeys associated with the wallet. Do not use if specifying "
3203
3225
  "hotkeys in `--include-hotkeys`.",
3204
3226
  ),
3205
- netuid: Optional[int] = Options.netuid_not_req,
3227
+ netuids: Optional[str] = Options.edit_help(
3228
+ "netuids",
3229
+ "Netuid(s) to for which to add stake. Specify multiple netuids by separating with a comma, e.g."
3230
+ "`btcli st add -n 1,2,3",
3231
+ ),
3206
3232
  all_netuids: bool = Options.all_netuids,
3207
3233
  wallet_name: str = Options.wallet_name,
3208
3234
  wallet_path: str = Options.wallet_path,
@@ -3242,42 +3268,65 @@ class CLIManager:
3242
3268
  6. Stake all balance to a subnet:
3243
3269
  [green]$[/green] btcli stake add --all --netuid 3
3244
3270
 
3271
+ 7. Stake the same amount to multiple subnets:
3272
+ [green]$[/green] btcli stake add --amount 100 --netuids 4,5,6
3273
+
3245
3274
  [bold]Safe Staking Parameters:[/bold]
3246
3275
  • [blue]--safe[/blue]: Enables rate tolerance checks
3247
3276
  • [blue]--tolerance[/blue]: Maximum % rate change allowed (0.05 = 5%)
3248
3277
  • [blue]--partial[/blue]: Complete partial stake if rates exceed tolerance
3249
3278
 
3250
3279
  """
3280
+ netuids = netuids or []
3251
3281
  self.verbosity_handler(quiet, verbose, json_output)
3252
3282
  safe_staking = self.ask_safe_staking(safe_staking)
3253
3283
  if safe_staking:
3254
3284
  rate_tolerance = self.ask_rate_tolerance(rate_tolerance)
3255
3285
  allow_partial_stake = self.ask_partial_stake(allow_partial_stake)
3256
3286
  console.print("\n")
3257
- netuid = get_optional_netuid(netuid, all_netuids)
3287
+
3288
+ if netuids:
3289
+ netuids = parse_to_list(
3290
+ netuids, int, "Netuids must be ints separated by commas", False
3291
+ )
3292
+ else:
3293
+ netuid_ = get_optional_netuid(None, all_netuids)
3294
+ netuids = [netuid_] if netuid_ else None
3295
+ if netuids:
3296
+ for netuid_ in netuids:
3297
+ # ensure no negative netuids make it into our list
3298
+ validate_netuid(netuid_)
3258
3299
 
3259
3300
  if stake_all and amount:
3260
3301
  print_error(
3261
3302
  "Cannot specify an amount and 'stake-all'. Choose one or the other."
3262
3303
  )
3263
- raise typer.Exit()
3304
+ return
3264
3305
 
3265
3306
  if stake_all and not amount:
3266
3307
  if not Confirm.ask("Stake all the available TAO tokens?", default=False):
3267
- raise typer.Exit()
3308
+ return
3309
+
3310
+ if (
3311
+ stake_all
3312
+ and (isinstance(netuids, list) and len(netuids) > 1)
3313
+ or (netuids is None)
3314
+ ):
3315
+ print_error("Cannot stake all to multiple subnets.")
3316
+ return
3268
3317
 
3269
3318
  if all_hotkeys and include_hotkeys:
3270
3319
  print_error(
3271
3320
  "You have specified hotkeys to include and also the `--all-hotkeys` flag. The flag"
3272
3321
  "should only be used standalone (to use all hotkeys) or with `--exclude-hotkeys`."
3273
3322
  )
3274
- raise typer.Exit()
3323
+ return
3275
3324
 
3276
3325
  if include_hotkeys and exclude_hotkeys:
3277
3326
  print_error(
3278
3327
  "You have specified options for both including and excluding hotkeys. Select one or the other."
3279
3328
  )
3280
- raise typer.Exit()
3329
+ return
3281
3330
 
3282
3331
  if not wallet_hotkey and not all_hotkeys and not include_hotkeys:
3283
3332
  if not wallet_name:
@@ -3285,9 +3334,10 @@ class CLIManager:
3285
3334
  "Enter the [blue]wallet name[/blue]",
3286
3335
  default=self.config.get("wallet_name") or defaults.wallet.name,
3287
3336
  )
3288
- if netuid is not None:
3337
+ if netuids is not None:
3289
3338
  hotkey_or_ss58 = Prompt.ask(
3290
- "Enter the [blue]wallet hotkey[/blue] name or [blue]ss58 address[/blue] to stake to [dim](or Press Enter to view delegates)[/dim]",
3339
+ "Enter the [blue]wallet hotkey[/blue] name or [blue]ss58 address[/blue] to stake to [dim]"
3340
+ "(or Press Enter to view delegates)[/dim]",
3291
3341
  )
3292
3342
  else:
3293
3343
  hotkey_or_ss58 = Prompt.ask(
@@ -3299,10 +3349,18 @@ class CLIManager:
3299
3349
  wallet = self.wallet_ask(
3300
3350
  wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
3301
3351
  )
3352
+ if len(netuids) > 1:
3353
+ netuid_ = IntPrompt.ask(
3354
+ "Enter the netuid for which to show delegates",
3355
+ choices=[str(x) for x in netuids],
3356
+ )
3357
+ else:
3358
+ netuid_ = netuids[0]
3359
+
3302
3360
  selected_hotkey = self._run_command(
3303
3361
  subnets.show(
3304
3362
  subtensor=self.initialize_chain(network),
3305
- netuid=netuid,
3363
+ netuid=netuid_,
3306
3364
  sort=False,
3307
3365
  max_rows=12,
3308
3366
  prompt=False,
@@ -3312,7 +3370,7 @@ class CLIManager:
3312
3370
  )
3313
3371
  if not selected_hotkey:
3314
3372
  print_error("No delegate selected. Exiting.")
3315
- raise typer.Exit()
3373
+ return
3316
3374
  include_hotkeys = selected_hotkey
3317
3375
  elif is_valid_ss58_address(hotkey_or_ss58):
3318
3376
  wallet = self.wallet_ask(
@@ -3373,8 +3431,8 @@ class CLIManager:
3373
3431
  )
3374
3432
  if free_balance == Balance.from_tao(0):
3375
3433
  print_error("You dont have any balance to stake.")
3376
- raise typer.Exit()
3377
- if netuid is not None:
3434
+ return
3435
+ if netuids:
3378
3436
  amount = FloatPrompt.ask(
3379
3437
  f"Amount to [{COLORS.G.SUBHEAD_MAIN}]stake (TAO τ)"
3380
3438
  )
@@ -3396,7 +3454,7 @@ class CLIManager:
3396
3454
  add_stake.stake_add(
3397
3455
  wallet,
3398
3456
  self.initialize_chain(network),
3399
- netuid,
3457
+ netuids,
3400
3458
  stake_all,
3401
3459
  amount,
3402
3460
  prompt,
@@ -4796,12 +4854,9 @@ class CLIManager:
4796
4854
  def subnets_price(
4797
4855
  self,
4798
4856
  network: Optional[list[str]] = Options.network,
4799
- netuids: str = typer.Option(
4800
- None,
4801
- "--netuids",
4802
- "--netuid",
4803
- "-n",
4804
- help="Netuid(s) to show the price for.",
4857
+ netuids: str = Options.edit_help(
4858
+ "netuids",
4859
+ "Netuids to show the price for. Separate multiple netuids with a comma, for example: `-n 0,1,2`.",
4805
4860
  ),
4806
4861
  interval_hours: int = typer.Option(
4807
4862
  24,
@@ -658,6 +658,8 @@ HYPERPARAMS = {
658
658
  "sudo_set_network_pow_registration_allowed",
659
659
  False,
660
660
  ),
661
+ "yuma3_enabled": ("sudo_set_yuma3_enabled", False),
662
+ "alpha_sigmoid_steepness": ("sudo_set_alpha_sigmoid_steepness", True),
661
663
  }
662
664
 
663
665
  # Help Panels for cli help
@@ -177,6 +177,8 @@ class SubnetHyperparameters(InfoBase):
177
177
  alpha_high: int
178
178
  alpha_low: int
179
179
  liquid_alpha_enabled: bool
180
+ yuma3_enabled: bool
181
+ alpha_sigmoid_steepness: int
180
182
 
181
183
  @classmethod
182
184
  def _fix_decoded(
@@ -210,6 +212,8 @@ class SubnetHyperparameters(InfoBase):
210
212
  alpha_high=decoded.get("alpha_high"),
211
213
  alpha_low=decoded.get("alpha_low"),
212
214
  liquid_alpha_enabled=decoded.get("liquid_alpha_enabled"),
215
+ yuma3_enabled=decoded.get("yuma3_enabled"),
216
+ alpha_sigmoid_steepness=decoded.get("alpha_sigmoid_steepness"),
213
217
  )
214
218
 
215
219
 
@@ -1611,7 +1611,8 @@ def _update_curr_block(
1611
1611
  """
1612
1612
  Update the current block data with the provided block information and difficulty.
1613
1613
 
1614
- This function updates the current block and its difficulty in a thread-safe manner. It sets the current block
1614
+ This function updates the current block
1615
+ and its difficulty in a thread-safe manner. It sets the current block
1615
1616
  number, hashes the block with the hotkey, updates the current block bytes, and packs the difficulty.
1616
1617
 
1617
1618
  :param curr_diff: Shared array to store the current difficulty.
@@ -1745,6 +1746,7 @@ async def swap_hotkey_extrinsic(
1745
1746
  subtensor: "SubtensorInterface",
1746
1747
  wallet: Wallet,
1747
1748
  new_wallet: Wallet,
1749
+ netuid: Optional[int] = None,
1748
1750
  prompt: bool = False,
1749
1751
  ) -> bool:
1750
1752
  """
@@ -1756,43 +1758,81 @@ async def swap_hotkey_extrinsic(
1756
1758
  netuids_registered = await subtensor.get_netuids_for_hotkey(
1757
1759
  wallet.hotkey.ss58_address, block_hash=block_hash
1758
1760
  )
1759
- if not len(netuids_registered) > 0:
1761
+ netuids_registered_new_hotkey = await subtensor.get_netuids_for_hotkey(
1762
+ new_wallet.hotkey.ss58_address, block_hash=block_hash
1763
+ )
1764
+
1765
+ if netuid is not None and netuid not in netuids_registered:
1766
+ err_console.print(
1767
+ f":cross_mark: [red]Failed[/red]: Original hotkey {wallet.hotkey.ss58_address} is not registered on subnet {netuid}"
1768
+ )
1769
+ return False
1770
+
1771
+ elif not len(netuids_registered) > 0:
1760
1772
  err_console.print(
1761
- f"Destination hotkey [dark_orange]{new_wallet.hotkey.ss58_address}[/dark_orange] is not registered. "
1773
+ f"Original hotkey [dark_orange]{wallet.hotkey.ss58_address}[/dark_orange] is not registered on any subnet. "
1762
1774
  f"Please register and try again"
1763
1775
  )
1764
1776
  return False
1765
1777
 
1778
+ if netuid is not None:
1779
+ if netuid in netuids_registered_new_hotkey:
1780
+ err_console.print(
1781
+ f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
1782
+ f"is already registered on subnet {netuid}"
1783
+ )
1784
+ return False
1785
+ else:
1786
+ if len(netuids_registered_new_hotkey) > 0:
1787
+ err_console.print(
1788
+ f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
1789
+ f"is already registered on subnet(s) {netuids_registered_new_hotkey}"
1790
+ )
1791
+ return False
1792
+
1766
1793
  if not unlock_key(wallet).success:
1767
1794
  return False
1768
1795
 
1769
1796
  if prompt:
1770
1797
  # Prompt user for confirmation.
1771
- if not Confirm.ask(
1772
- f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
1773
- f"[dark_orange]{wallet.hotkey.ss58_address}[/dark_orange] with hotkey \n\t"
1774
- f"[dark_orange]{new_wallet.hotkey.ss58_address}[/dark_orange]\n"
1775
- "This operation will cost [bold cyan]1 TAO t (recycled)[/bold cyan]"
1776
- ):
1798
+ if netuid is not None:
1799
+ confirm_message = (
1800
+ f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
1801
+ f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1802
+ f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n"
1803
+ "This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
1804
+ )
1805
+ else:
1806
+ confirm_message = (
1807
+ f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
1808
+ f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1809
+ f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n"
1810
+ "This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
1811
+ )
1812
+
1813
+ if not Confirm.ask(confirm_message):
1777
1814
  return False
1778
1815
  print_verbose(
1779
- f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address}) with "
1780
- f"{new_wallet.name}s hotkey ({new_wallet.hotkey.ss58_address})"
1816
+ f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address} - {wallet.hotkey_str}) with "
1817
+ f"{new_wallet.name}'s hotkey ({new_wallet.hotkey.ss58_address} - {new_wallet.hotkey_str})"
1781
1818
  )
1782
1819
  with console.status(":satellite: Swapping hotkeys...", spinner="aesthetic"):
1820
+ call_params = {
1821
+ "hotkey": wallet.hotkey.ss58_address,
1822
+ "new_hotkey": new_wallet.hotkey.ss58_address,
1823
+ "netuid": netuid,
1824
+ }
1825
+
1783
1826
  call = await subtensor.substrate.compose_call(
1784
1827
  call_module="SubtensorModule",
1785
1828
  call_function="swap_hotkey",
1786
- call_params={
1787
- "hotkey": wallet.hotkey.ss58_address,
1788
- "new_hotkey": new_wallet.hotkey.ss58_address,
1789
- },
1829
+ call_params=call_params,
1790
1830
  )
1791
1831
  success, err_msg = await subtensor.sign_and_send_extrinsic(call, wallet)
1792
1832
 
1793
1833
  if success:
1794
1834
  console.print(
1795
- f"Hotkey {wallet.hotkey} swapped for new hotkey: {new_wallet.hotkey}"
1835
+ f"Hotkey {wallet.hotkey.ss58_address} ({wallet.hotkey_str}) swapped for new hotkey: {new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})"
1796
1836
  )
1797
1837
  return True
1798
1838
  else:
@@ -1128,14 +1128,22 @@ class SubtensorInterface:
1128
1128
  Understanding the hyperparameters is crucial for comprehending how subnets are configured and
1129
1129
  managed, and how they interact with the network's consensus and incentive mechanisms.
1130
1130
  """
1131
- result = await self.query_runtime_api(
1132
- runtime_api="SubnetInfoRuntimeApi",
1133
- method="get_subnet_hyperparams",
1134
- params=[netuid],
1135
- block_hash=block_hash,
1131
+ main_result, yuma3_result, sigmoid_steepness = await asyncio.gather(
1132
+ self.query_runtime_api(
1133
+ runtime_api="SubnetInfoRuntimeApi",
1134
+ method="get_subnet_hyperparams",
1135
+ params=[netuid],
1136
+ block_hash=block_hash,
1137
+ ),
1138
+ self.query("SubtensorModule", "Yuma3On", [netuid]),
1139
+ self.query("SubtensorModule", "AlphaSigmoidSteepness", [netuid]),
1136
1140
  )
1137
-
1138
- if not result:
1141
+ result = {
1142
+ **main_result,
1143
+ **{"yuma3_enabled": yuma3_result},
1144
+ **{"alpha_sigmoid_steepness": sigmoid_steepness},
1145
+ }
1146
+ if not main_result:
1139
1147
  return []
1140
1148
 
1141
1149
  return SubnetHyperparameters.from_any(result)
@@ -0,0 +1,24 @@
1
+ <div class="filters-section">
2
+ <div class="search-box">
3
+ <input type="text" id="subnet-search" placeholder="search for name, or netuid..." onkeyup="filterSubnets()">
4
+ </div>
5
+ <div class="filter-toggles">
6
+ <label>
7
+ <input type="checkbox" id="show-verbose" onchange="toggleVerboseNumbers()">
8
+ Precise Numbers
9
+ </label>
10
+ <label>
11
+ <input type="checkbox" id="show-staked" onchange="filterSubnets()">
12
+ Show Only Staked
13
+ </label>
14
+ <label>
15
+ <input type="checkbox" id="show-tiles" onchange="toggleTileView()" checked>
16
+ Tile View
17
+ </label>
18
+ <label class="disabled-label" title="Coming soon">
19
+ <input type="checkbox" id="live-mode" disabled>
20
+ Live Mode (coming soon)
21
+ </label>
22
+ </div>
23
+ </div>
24
+ <div id="subnet-tiles-container" class="subnet-tiles-container"></div>
@@ -0,0 +1,36 @@
1
+ {#
2
+ vars:
3
+ wallet_info.coldkey, truncated_coldkey, wallet_info.balance, root_symbol_html, wallet_info.total_ideal_stake_value,
4
+ slippage_percentage, wallet_info.total_slippage_value, block_number
5
+ #}
6
+
7
+ <div class="header">
8
+ <meta charset="UTF-8">
9
+ <div class="wallet-info">
10
+ <span class="wallet-name">{{ wallet_info.name }}</span>
11
+ <div class="wallet-address-container" onclick="copyToClipboard('{{ coldkey }}', this)">
12
+ <span class="wallet-address" title="Click to copy">{{ truncated_coldkey }}}</span>
13
+ <span class="copy-indicator">Copy</span>
14
+ </div>
15
+ </div>
16
+ <div class="stake-metrics">
17
+ <div class="stake-metric">
18
+ <span class="metric-label">Block</span>
19
+ <span class="metric-value" style="color: #FF9900;">{{ block_number }}</span>
20
+ </div>
21
+ <div class="stake-metric">
22
+ <span class="metric-label">Balance</span>
23
+ <span class="metric-value">{{ "%.4f"|format(wallet_info.balance) }} {{ root_symbol_html }}</span>
24
+ </div>
25
+ <div class="stake-metric">
26
+ <span class="metric-label">Total Stake Value</span>
27
+ <span class="metric-value">{{ "%.4f"|format(wallet_info.total_ideal_stake_value) }} {{ root_symbol_html }}</span>
28
+ </div>
29
+ <div class="stake-metric">
30
+ <span class="metric-label">Slippage Impact</span>
31
+ <span class="metric-value slippage-value">
32
+ {{ "%.2f"|format(slippage_percentage) }}% <span class="slippage-detail">({{ "%.4f"|format(wallet_info.total_slippage_value) }} {{ root_symbol_html }})</span>
33
+ </span>
34
+ </div>
35
+ </div>
36
+ </div>
@@ -0,0 +1,111 @@
1
+ <div id="neuron-detail-container" style="display: none;">
2
+ <div class="neuron-detail-header">
3
+ <button class="back-button neuron-detail-back" onclick="closeNeuronDetails()">&larr; Back</button>
4
+ </div>
5
+ <div class="neuron-detail-content">
6
+ <div class="neuron-info-top">
7
+ <h2 class="neuron-name" id="neuron-name"></h2>
8
+ <div class="neuron-keys">
9
+ <div class="hotkey-label">
10
+ <span style="color: #FF9900;">Hotkey:</span>
11
+ <span id="neuron-hotkey" class="truncated-address"></span>
12
+ </div>
13
+ <div class="coldkey-label">
14
+ <span style="color: #FF9900;">Coldkey:</span>
15
+ <span id="neuron-coldkey" class="truncated-address"></span>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <div class="neuron-cards-container">
20
+ <!-- First row: Stakes, Dividends, Incentive, Emissions -->
21
+ <div class="neuron-metrics-row">
22
+ <div class="metric-card">
23
+ <div class="metric-label">Stake Weight</div>
24
+ <div id="neuron-stake-total" class="metric-value formatted-number"
25
+ data-value="0" data-symbol=""></div>
26
+ </div>
27
+
28
+ <div class="metric-card">
29
+ <div class="metric-label">Stake (Alpha)</div>
30
+ <div id="neuron-stake-token" class="metric-value formatted-number"
31
+ data-value="0" data-symbol=""></div>
32
+ </div>
33
+
34
+ <div class="metric-card">
35
+ <div class="metric-label">Stake (Root)</div>
36
+ <div id="neuron-stake-root" class="metric-value formatted-number"
37
+ data-value="0" data-symbol="&#x03C4;"></div>
38
+ </div>
39
+
40
+ <div class="metric-card">
41
+ <div class="metric-label">Dividends</div>
42
+ <div id="neuron-dividends" class="metric-value formatted-number"
43
+ data-value="0" data-symbol=""></div>
44
+ </div>
45
+
46
+ <div class="metric-card">
47
+ <div class="metric-label">Incentive</div>
48
+ <div id="neuron-incentive" class="metric-value formatted-number"
49
+ data-value="0" data-symbol=""></div>
50
+ </div>
51
+
52
+ <div class="metric-card">
53
+ <div class="metric-label">Emissions</div>
54
+ <div id="neuron-emissions" class="metric-value formatted-number"
55
+ data-value="0" data-symbol=""></div>
56
+ </div>
57
+ </div>
58
+
59
+ <!-- Second row: Rank, Trust, Pruning Score, Validator Permit, Consensus, Last Update -->
60
+ <div class="neuron-metrics-row">
61
+ <div class="metric-card">
62
+ <div class="metric-label">Rank</div>
63
+ <div id="neuron-rank" class="metric-value"></div>
64
+ </div>
65
+
66
+ <div class="metric-card">
67
+ <div class="metric-label">Trust</div>
68
+ <div id="neuron-trust" class="metric-value"></div>
69
+ </div>
70
+
71
+ <div class="metric-card">
72
+ <div class="metric-label">Pruning Score</div>
73
+ <div id="neuron-pruning-score" class="metric-value"></div>
74
+ </div>
75
+
76
+ <div class="metric-card">
77
+ <div class="metric-label">Validator Permit</div>
78
+ <div id="neuron-validator-permit" class="metric-value"></div>
79
+ </div>
80
+
81
+ <div class="metric-card">
82
+ <div class="metric-label">Consensus</div>
83
+ <div id="neuron-consensus" class="metric-value"></div>
84
+ </div>
85
+
86
+ <div class="metric-card">
87
+ <div class="metric-label">Last Update</div>
88
+ <div id="neuron-last-update" class="metric-value"></div>
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Third row: Reg Block, IP Info, Active -->
93
+ <div class="neuron-metrics-row last-row">
94
+ <div class="metric-card">
95
+ <div class="metric-label">Reg Block</div>
96
+ <div id="neuron-reg-block" class="metric-value"></div>
97
+ </div>
98
+
99
+ <div class="metric-card">
100
+ <div class="metric-label">IP Info</div>
101
+ <div id="neuron-ipinfo" class="metric-value"></div>
102
+ </div>
103
+
104
+ <div class="metric-card">
105
+ <div class="metric-label">Active</div>
106
+ <div id="neuron-active" class="metric-value"></div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>