bittensor-cli 8.2.0rc9__tar.gz → 8.2.0rc11__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 (35) hide show
  1. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/PKG-INFO +1 -1
  2. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/__init__.py +1 -1
  3. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/cli.py +34 -16
  4. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/chain_data.py +12 -6
  5. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/subtensor_interface.py +2 -1
  6. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/stake/stake.py +9 -7
  7. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/subnets.py +144 -36
  8. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/sudo.py +13 -7
  9. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/wallets.py +63 -174
  10. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/PKG-INFO +1 -1
  11. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/README.md +0 -0
  12. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/doc_generation_helper.py +0 -0
  13. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/__init__.py +0 -0
  14. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/__init__.py +0 -0
  15. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/async_substrate_interface.py +0 -0
  16. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/balances.py +0 -0
  17. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/extrinsics/__init__.py +0 -0
  18. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/extrinsics/registration.py +0 -0
  19. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/extrinsics/root.py +0 -0
  20. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/extrinsics/transfer.py +0 -0
  21. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/minigraph.py +0 -0
  22. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/networking.py +0 -0
  23. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/templates/table.j2 +0 -0
  24. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/bittensor/utils.py +0 -0
  25. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/__init__.py +0 -0
  26. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/stake/__init__.py +0 -0
  27. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/stake/children_hotkeys.py +0 -0
  28. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli/src/commands/weights.py +0 -0
  29. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/SOURCES.txt +0 -0
  30. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/dependency_links.txt +0 -0
  31. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/entry_points.txt +0 -0
  32. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/requires.txt +0 -0
  33. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/bittensor_cli.egg-info/top_level.txt +0 -0
  34. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/setup.cfg +0 -0
  35. {bittensor-cli-8.2.0rc9 → bittensor-cli-8.2.0rc11}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bittensor-cli
3
- Version: 8.2.0rc9
3
+ Version: 8.2.0rc11
4
4
  Summary: Bittensor CLI
5
5
  Home-page: https://github.com/opentensor/btcli
6
6
  Author: bittensor.com
@@ -18,6 +18,6 @@
18
18
  from .cli import CLIManager
19
19
 
20
20
 
21
- __version__ = "8.2.0rc9"
21
+ __version__ = "8.2.0rc11"
22
22
 
23
23
  __all__ = ["CLIManager", "__version__"]
@@ -62,7 +62,7 @@ except ImportError:
62
62
  pass
63
63
 
64
64
 
65
- __version__ = "8.2.0rc9"
65
+ __version__ = "8.2.0rc11"
66
66
 
67
67
 
68
68
  _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0)
@@ -645,12 +645,13 @@ class CLIManager:
645
645
  "balance", rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"]
646
646
  )(self.wallet_balance)
647
647
  self.wallet_app.command(
648
- "history", rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"]
648
+ "history",
649
+ rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"],
650
+ hidden=True,
649
651
  )(self.wallet_history)
650
652
  self.wallet_app.command(
651
653
  "overview",
652
654
  rich_help_panel=HELP_PANELS["WALLET"]["INFORMATION"],
653
- hidden=True,
654
655
  )(self.wallet_overview)
655
656
  self.wallet_app.command(
656
657
  "transfer", rich_help_panel=HELP_PANELS["WALLET"]["OPERATIONS"]
@@ -748,10 +749,13 @@ class CLIManager:
748
749
  )(self.subnets_register)
749
750
  self.subnets_app.command(
750
751
  "metagraph", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"], hidden=True
751
- )(self.subnets_show) #Aliased to `s show` for now
752
+ )(self.subnets_show) # Aliased to `s show` for now
752
753
  self.subnets_app.command(
753
754
  "show", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
754
755
  )(self.subnets_show)
756
+ self.subnets_app.command(
757
+ "price", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"], hidden=True
758
+ )(self.subnets_price)
755
759
 
756
760
  # weights commands
757
761
  self.weights_app.command(
@@ -1409,12 +1413,6 @@ class CLIManager:
1409
1413
  "Hotkeys names must be a comma-separated list, e.g., `--exclude-hotkeys hk1,hk2`.",
1410
1414
  )
1411
1415
 
1412
- # For Rao games
1413
- effective_network = get_effective_network(self.config, network)
1414
- if is_rao_network(effective_network):
1415
- print_error("This command is disabled on the 'rao' network.")
1416
- raise typer.Exit()
1417
-
1418
1416
  return self._run_command(
1419
1417
  wallets.overview(
1420
1418
  wallet,
@@ -1425,6 +1423,7 @@ class CLIManager:
1425
1423
  include_hotkeys,
1426
1424
  exclude_hotkeys,
1427
1425
  netuids_filter=netuids,
1426
+ verbose=verbose,
1428
1427
  )
1429
1428
  )
1430
1429
 
@@ -1600,6 +1599,8 @@ class CLIManager:
1600
1599
 
1601
1600
  [bold]Note[/bold]: The `inspect` command is for displaying information only and does not perform any transactions or state changes on the blockchain. It is intended to be used with Bittensor CLI and not as a standalone function in user code.
1602
1601
  """
1602
+ print_error("This command is disabled on the 'rao' network.")
1603
+ raise typer.Exit()
1603
1604
  self.verbosity_handler(quiet, verbose)
1604
1605
 
1605
1606
  if netuids:
@@ -1615,11 +1616,6 @@ class CLIManager:
1615
1616
  wallet = self.wallet_ask(
1616
1617
  wallet_name, wallet_path, wallet_hotkey, ask_for=ask_for, validate=validate
1617
1618
  )
1618
- # For Rao games
1619
- effective_network = get_effective_network(self.config, network)
1620
- if is_rao_network(effective_network):
1621
- print_error("This command is disabled on the 'rao' network.")
1622
- raise typer.Exit()
1623
1619
 
1624
1620
  self.initialize_chain(network)
1625
1621
  return self._run_command(
@@ -2791,7 +2787,7 @@ class CLIManager:
2791
2787
  [blue bold]Note[/blue bold]: This command is for users who wish to reallocate their stake or withdraw them from the network. It allows for flexible management of TAO stake across different neurons (hotkeys) on the network.
2792
2788
  """
2793
2789
  self.verbosity_handler(quiet, verbose)
2794
- # TODO: Coldkey related unstakes need to be updated. Patching for now.
2790
+ # TODO: Coldkey related unstakes need to be updated. Patching for now.
2795
2791
  unstake_all_alpha = False
2796
2792
  unstake_all = False
2797
2793
 
@@ -3562,6 +3558,28 @@ class CLIManager:
3562
3558
  )
3563
3559
  )
3564
3560
 
3561
+ def subnets_price(
3562
+ self,
3563
+ network: Optional[list[str]] = Options.network,
3564
+ netuid: int = Options.netuid,
3565
+ interval_hours: int = typer.Option(
3566
+ 24,
3567
+ "--interval-hours",
3568
+ "--interval",
3569
+ help="The number of hours to show the historical price for.",
3570
+ ),
3571
+ ):
3572
+ """
3573
+ Shows the historical price of a subnet for the past 24 hours.
3574
+
3575
+ EXAMPLE
3576
+
3577
+ [green]$[/green] btcli subnets price --netuid 1
3578
+ """
3579
+ return self._run_command(
3580
+ subnets.price(self.initialize_chain(network), netuid, interval_hours)
3581
+ )
3582
+
3565
3583
  def subnets_show(
3566
3584
  self,
3567
3585
  network: Optional[list[str]] = Options.network,
@@ -97,11 +97,13 @@ def decode_hex_identity(info_dictionary):
97
97
  return decoded_info
98
98
 
99
99
 
100
- def process_stake_data(stake_data):
100
+ def process_stake_data(stake_data, netuid):
101
101
  decoded_stake_data = {}
102
102
  for account_id_bytes, stake_ in stake_data:
103
103
  account_id = decode_account_id(account_id_bytes)
104
- decoded_stake_data.update({account_id: Balance.from_rao(stake_)})
104
+ decoded_stake_data.update(
105
+ {account_id: Balance.from_rao(stake_).set_unit(netuid)}
106
+ )
105
107
  return decoded_stake_data
106
108
 
107
109
 
@@ -371,7 +373,7 @@ class NeuronInfo:
371
373
  @classmethod
372
374
  def from_vec_u8(cls, vec_u8: bytes) -> "NeuronInfo":
373
375
  n = bt_decode.NeuronInfo.decode(vec_u8)
374
- stake_dict = process_stake_data(n.stake)
376
+ stake_dict = process_stake_data(n.stake, n.netuid)
375
377
  total_stake = sum(stake_dict.values()) if stake_dict else Balance(0)
376
378
  axon_info = n.axon_info
377
379
  coldkey = decode_account_id(n.coldkey)
@@ -491,8 +493,12 @@ class NeuronInfoLite:
491
493
  prometheus_info = item.prometheus_info
492
494
  pruning_score = item.pruning_score
493
495
  rank = item.rank
494
- stake_dict = process_stake_data(item.stake)
495
- stake = sum(stake_dict.values()) if stake_dict else Balance(0)
496
+ stake_dict = process_stake_data(item.stake, item.netuid)
497
+ stake = (
498
+ sum(stake_dict.values())
499
+ if stake_dict
500
+ else Balance(0).set_unit(item.netuid)
501
+ )
496
502
  trust = item.trust
497
503
  uid = item.uid
498
504
  validator_permit = item.validator_permit
@@ -899,7 +905,7 @@ class DynamicInfo:
899
905
  def from_vec_u8(cls, vec_u8: list[int]) -> Optional["DynamicInfo"]:
900
906
  if len(vec_u8) == 0:
901
907
  return None
902
- decoded = from_scale_encoding(vec_u8, ChainDataType.DynamicInfo, is_option=True)
908
+ decoded = from_scale_encoding(vec_u8, ChainDataType.DynamicInfo)
903
909
  if decoded is None:
904
910
  return None
905
911
  return DynamicInfo.fix_decoded_values(decoded)
@@ -1392,10 +1392,11 @@ class SubtensorInterface:
1392
1392
 
1393
1393
  return StakeInfo.list_of_tuple_from_vec_u8(bytes_result) # type: ignore
1394
1394
 
1395
- async def get_all_subnet_dynamic_info(self) -> list["DynamicInfo"]:
1395
+ async def get_all_subnet_dynamic_info(self, block_hash: Optional[str] = None) -> list["DynamicInfo"]:
1396
1396
  query = await self.substrate.runtime_call(
1397
1397
  "SubnetInfoRuntimeApi",
1398
1398
  "get_all_dynamic_info",
1399
+ block_hash=block_hash,
1399
1400
  )
1400
1401
  subnets = DynamicInfo.list_from_vec_u8(bytes.fromhex(query.decode()[2:]))
1401
1402
  return subnets
@@ -10,11 +10,11 @@ from rich.prompt import Confirm, FloatPrompt, Prompt
10
10
  from rich.table import Table
11
11
  from rich import box
12
12
  from rich.progress import Progress, BarColumn, TextColumn
13
- from rich.console import Console, Group
13
+ from rich.console import Group
14
14
  from rich.live import Live
15
15
  from substrateinterface.exceptions import SubstrateRequestException
16
16
 
17
- from bittensor_cli.src import COLOR_PALETTE, SUBNETS
17
+ from bittensor_cli.src import COLOR_PALETTE
18
18
  from bittensor_cli.src.bittensor.balances import Balance
19
19
  from bittensor_cli.src.bittensor.chain_data import StakeInfo
20
20
  from bittensor_cli.src.bittensor.utils import (
@@ -1999,7 +1999,7 @@ async def stake_list(
1999
1999
  (
2000
2000
  substakes,
2001
2001
  registered_delegate_info,
2002
- dynamic_info,
2002
+ _dynamic_info,
2003
2003
  ) = await asyncio.gather(
2004
2004
  subtensor.get_stake_info_for_coldkeys(
2005
2005
  coldkey_ss58_list=[coldkey_address], block_hash=block_hash
@@ -2008,6 +2008,7 @@ async def stake_list(
2008
2008
  subtensor.get_all_subnet_dynamic_info(),
2009
2009
  )
2010
2010
  sub_stakes = substakes[coldkey_address]
2011
+ dynamic_info = {info.netuid: info for info in _dynamic_info}
2011
2012
  return (
2012
2013
  sub_stakes,
2013
2014
  registered_delegate_info,
@@ -2195,9 +2196,7 @@ async def stake_list(
2195
2196
  f"{stake_value} {symbol}"
2196
2197
  if netuid != 0
2197
2198
  else f"{symbol} {stake_value}", # Stake (a)
2198
- f"{millify_tao(pool.price.tao)} τ/{symbol}"
2199
- if not verbose
2200
- else f"{pool.price.tao:.4f} τ/{symbol}", # Rate (t/a)
2199
+ f"{pool.price.tao:.4f} τ/{symbol}", # Rate (t/a)
2201
2200
  # f"τ {millify_tao(tao_ownership.tao)}" if not verbose else f"{tao_ownership}", # TAO equiv
2202
2201
  swap_value, # Swap(α) -> τ
2203
2202
  "YES"
@@ -2425,6 +2424,10 @@ async def stake_list(
2425
2424
  hotkeys_to_substakes[hotkey] = []
2426
2425
  hotkeys_to_substakes[hotkey].append(substake)
2427
2426
 
2427
+ if not hotkeys_to_substakes:
2428
+ print_error(f"No stakes found for coldkey ss58: ({coldkey_address})")
2429
+ raise typer.Exit()
2430
+
2428
2431
  if live:
2429
2432
  # Select one hokkey for live monitoring
2430
2433
  if len(hotkeys_to_substakes) > 1:
@@ -2483,7 +2486,6 @@ async def stake_list(
2483
2486
  if stake.hotkey_ss58 == selected_hotkey
2484
2487
  ]
2485
2488
 
2486
- dynamic_info = {info.netuid: info for info in dynamic_info_}
2487
2489
  block_number = await subtensor.substrate.get_block_number(None)
2488
2490
 
2489
2491
  previous_block = current_block
@@ -3,18 +3,17 @@ import json
3
3
  import sqlite3
4
4
  from typing import TYPE_CHECKING, Optional, cast
5
5
  import typer
6
+ import plotille
6
7
 
7
8
  from bittensor_wallet import Wallet
8
9
  from bittensor_wallet.errors import KeyFileError
9
10
  from rich.prompt import Confirm, Prompt
10
- from rich.console import Console, Group
11
- from rich.spinner import Spinner
12
- from rich.text import Text
11
+ from rich.console import Group
13
12
  from rich.progress import Progress, BarColumn, TextColumn
14
13
  from rich.table import Column, Table
15
14
  from rich import box
16
15
 
17
- from bittensor_cli.src import COLOR_PALETTE, SUBNETS
16
+ from bittensor_cli.src import COLOR_PALETTE
18
17
  from bittensor_cli.src.bittensor.balances import Balance
19
18
  from bittensor_cli.src.bittensor.chain_data import SubnetState
20
19
  from bittensor_cli.src.bittensor.extrinsics.registration import (
@@ -26,7 +25,6 @@ from rich.live import Live
26
25
  from bittensor_cli.src.bittensor.minigraph import MiniGraph
27
26
  from bittensor_cli.src.commands.wallets import set_id, get_id
28
27
  from bittensor_cli.src.bittensor.utils import (
29
- RAO_PER_TAO,
30
28
  console,
31
29
  create_table,
32
30
  err_console,
@@ -228,7 +226,9 @@ async def subnets_list(
228
226
  if not verbose:
229
227
  percentage_string = f"τ {millify_tao(total_tao_emitted)}/{millify_tao(block_number)} ({formatted_percentage})"
230
228
  else:
231
- percentage_string = f"τ {total_tao_emitted:.1f}/{block_number} ({formatted_percentage})"
229
+ percentage_string = (
230
+ f"τ {total_tao_emitted:.1f}/{block_number} ({formatted_percentage})"
231
+ )
232
232
  return total_tao_emitted, percentage_string
233
233
 
234
234
  def define_table(
@@ -323,11 +323,7 @@ async def subnets_list(
323
323
  if not verbose
324
324
  else f"{subnet.alpha_out.tao:,.4f}"
325
325
  )
326
- price_value = (
327
- f"{millify_tao(subnet.price.tao)}"
328
- if not verbose
329
- else f"{subnet.price.tao:,.4f}"
330
- )
326
+ price_value = f"{subnet.price.tao:,.4f}"
331
327
 
332
328
  # Market Cap
333
329
  market_cap = (subnet.alpha_in.tao + subnet.alpha_out.tao) * subnet.price.tao
@@ -345,8 +341,8 @@ async def subnets_list(
345
341
  if netuid != 0
346
342
  else "-"
347
343
  )
348
-
349
344
  alpha_in_cell = f"{alpha_in_value} {symbol}" if netuid != 0 else "-"
345
+ liquidity_cell = f"{tao_in_cell}, {alpha_in_cell}"
350
346
 
351
347
  # Supply
352
348
  supply = subnet.alpha_in.tao + subnet.alpha_out.tao
@@ -360,7 +356,6 @@ async def subnets_list(
360
356
  )
361
357
  emission_cell = f"τ {emission_tao:,.4f}"
362
358
  price_cell = f"{price_value} τ/{symbol}"
363
- liquidity_cell = f"{tao_in_cell}, {alpha_in_cell}"
364
359
  alpha_out_cell = (
365
360
  f"{alpha_out_value} {symbol}"
366
361
  if netuid != 0
@@ -534,7 +529,7 @@ async def subnets_list(
534
529
  "supply": supply,
535
530
  "blocks_since_last_step": subnet.blocks_since_last_step,
536
531
  }
537
- prev = previous_data.get(netuid) if previous_data else {}
532
+ prev = previous_data.get(netuid, {}) if previous_data else {}
538
533
 
539
534
  # Prepare cells
540
535
  if netuid == 0:
@@ -559,7 +554,7 @@ async def subnets_list(
559
554
  prev.get("price"),
560
555
  unit=f"τ/{symbol}",
561
556
  precision=4,
562
- millify=True if not verbose else False,
557
+ millify=False,
563
558
  )
564
559
 
565
560
  alpha_out_cell = format_cell(
@@ -1055,9 +1050,7 @@ async def show(
1055
1050
  print_error(f"Subnet {netuid_} does not exist")
1056
1051
  raise typer.Exit()
1057
1052
  elif len(subnet_state.hotkeys) == 0:
1058
- print_error(
1059
- f"Subnet {netuid_} is currently empty with 0 UIDs registered."
1060
- )
1053
+ print_error(f"Subnet {netuid_} is currently empty with 0 UIDs registered.")
1061
1054
  raise typer.Exit()
1062
1055
 
1063
1056
  # Define table properties
@@ -1158,7 +1151,7 @@ async def show(
1158
1151
  ):
1159
1152
  if uid_identity == "~":
1160
1153
  uid_identity = (
1161
- f"[dark_sea_green3](*Owner controlled)[/dark_sea_green3]"
1154
+ "[dark_sea_green3](*Owner controlled)[/dark_sea_green3]"
1162
1155
  )
1163
1156
  else:
1164
1157
  uid_identity = (
@@ -1176,7 +1169,9 @@ async def show(
1176
1169
  f"{subnet_state.alpha_stake[idx].tao:.4f} {subnet_info.symbol}"
1177
1170
  if verbose
1178
1171
  else f"{millify_tao(subnet_state.alpha_stake[idx])} {subnet_info.symbol}", # Alpha Stake
1179
- f"τ {tao_stake.tao:.4f}" if verbose else f"τ {millify_tao(tao_stake)}", # Tao Stake
1172
+ f"τ {tao_stake.tao:.4f}"
1173
+ if verbose
1174
+ else f"τ {millify_tao(tao_stake)}", # Tao Stake
1180
1175
  # str(subnet_state.dividends[idx]),
1181
1176
  f"{Balance.from_tao(hotkey_block_emission).set_unit(netuid_).tao:.5f}", # Dividends
1182
1177
  f"{subnet_state.incentives[idx]:.4f}", # Incentive
@@ -1302,22 +1297,22 @@ async def show(
1302
1297
  # f"\n Stake: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]{subnet_info.alpha_out.tao:,.5f} {subnet_info.symbol}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
1303
1298
  f"\n Tempo: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]{subnet_info.blocks_since_last_step}/{subnet_info.tempo}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
1304
1299
  )
1305
- # console.print(
1306
- # """
1307
- # Description:
1308
- # The table displays the subnet participants and their metrics.
1309
- # The columns are as follows:
1310
- # - UID: The hotkey index in the subnet.
1311
- # - TAO: The sum of all TAO balances for this hotkey accross all subnets.
1312
- # - Stake: The stake balance of this hotkey on this subnet.
1313
- # - Weight: The stake-weight of this hotkey on this subnet. Computed as an average of the normalized TAO and Stake columns of this subnet.
1314
- # - Dividends: Validating dividends earned by the hotkey.
1315
- # - Incentives: Mining incentives earned by the hotkey (always zero in the RAO demo.)
1316
- # - Emission: The emission accrued to this hokey on this subnet every block (in staking units).
1317
- # - Hotkey: The hotkey ss58 address.
1318
- # - Coldkey: The coldkey ss58 address.
1319
- # """
1320
- # )
1300
+ # console.print(
1301
+ # """
1302
+ # Description:
1303
+ # The table displays the subnet participants and their metrics.
1304
+ # The columns are as follows:
1305
+ # - UID: The hotkey index in the subnet.
1306
+ # - TAO: The sum of all TAO balances for this hotkey accross all subnets.
1307
+ # - Stake: The stake balance of this hotkey on this subnet.
1308
+ # - Weight: The stake-weight of this hotkey on this subnet. Computed as an average of the normalized TAO and Stake columns of this subnet.
1309
+ # - Dividends: Validating dividends earned by the hotkey.
1310
+ # - Incentives: Mining incentives earned by the hotkey (always zero in the RAO demo.)
1311
+ # - Emission: The emission accrued to this hokey on this subnet every block (in staking units).
1312
+ # - Hotkey: The hotkey ss58 address.
1313
+ # - Coldkey: The coldkey ss58 address.
1314
+ # """
1315
+ # )
1321
1316
 
1322
1317
  if delegate_selection:
1323
1318
  while True:
@@ -2056,3 +2051,116 @@ async def metagraph_cmd(
2056
2051
  table.add_row(*row)
2057
2052
 
2058
2053
  console.print(table)
2054
+
2055
+
2056
+ async def price(
2057
+ subtensor: "SubtensorInterface",
2058
+ netuid: int,
2059
+ interval_hours: int = 24,
2060
+ ):
2061
+ """Plot historical subnet price data in the CLI."""
2062
+
2063
+ blocks_per_hour = int(3600 / 12) # ~300 blocks per hour
2064
+ total_blocks = blocks_per_hour * interval_hours
2065
+
2066
+ with console.status(":chart_increasing: Fetching historical price data..."):
2067
+ current_block_hash = await subtensor.substrate.get_chain_head()
2068
+ current_block = await subtensor.substrate.get_block_number(current_block_hash)
2069
+
2070
+ # Block range
2071
+ step = 300
2072
+ start_block = max(0, current_block - total_blocks)
2073
+ block_numbers = range(start_block, current_block + 1, step)
2074
+
2075
+ # Fetch all block hashes
2076
+ block_hash_cors = [
2077
+ subtensor.substrate.get_block_hash(bn) for bn in block_numbers
2078
+ ]
2079
+ block_hashes = await asyncio.gather(*block_hash_cors)
2080
+
2081
+ # Fetch subnet data for each block
2082
+ subnet_info_cors = [
2083
+ subtensor.get_subnet_dynamic_info(netuid, bh) for bh in block_hashes
2084
+ ]
2085
+ subnet_infos = await asyncio.gather(*subnet_info_cors)
2086
+
2087
+ prices = []
2088
+ for subnet_info in subnet_infos:
2089
+ prices.append(subnet_info.price.tao)
2090
+
2091
+ if not prices:
2092
+ err_console.print(f"[red]No price data found for subnet {netuid}[/red]")
2093
+ return
2094
+
2095
+ fig = plotille.Figure()
2096
+ fig.width = 60
2097
+ fig.height = 20
2098
+ fig.color_mode = "rgb"
2099
+ fig.background = None
2100
+
2101
+ block_numbers = list(range(current_block - total_blocks, current_block + 1, step))
2102
+
2103
+ def color_label(text):
2104
+ return plotille.color(text, fg=(186, 233, 143), mode="rgb") # Green
2105
+
2106
+ fig.x_label = color_label("Block")
2107
+ fig.y_label = color_label(f"Price ({Balance.get_unit(netuid)})")
2108
+
2109
+ fig.set_x_limits(min_=min(block_numbers), max_=max(block_numbers))
2110
+ fig.set_y_limits(min_=min(prices) * 0.95, max_=max(prices) * 1.05)
2111
+
2112
+ fig.plot(
2113
+ block_numbers,
2114
+ prices,
2115
+ label=f"Subnet {netuid} Price",
2116
+ interp="linear",
2117
+ lc="bae98f", # Green hex
2118
+ )
2119
+
2120
+ subnet = subnet_infos[-1]
2121
+ console.print(
2122
+ f"\n[{COLOR_PALETTE['GENERAL']['SYMBOL']}]Subnet {netuid} - {subnet.symbol} [cyan]{get_subnet_name(subnet)}"
2123
+ )
2124
+ console.print(
2125
+ f"Current: [blue]{prices[-1]:.6f}{Balance.get_unit(netuid)}"
2126
+ if netuid != 0
2127
+ else f"Current: [blue]{Balance.get_unit(netuid)} {prices[-1]:.6f}"
2128
+ )
2129
+ console.print(
2130
+ f"{interval_hours}h High: [dark_sea_green3]{max(prices):.6f}{Balance.get_unit(netuid)}"
2131
+ if netuid != 0
2132
+ else f"{interval_hours}h High: [dark_sea_green3]{Balance.get_unit(netuid)} {max(prices):.6f}"
2133
+ )
2134
+ console.print(
2135
+ f"{interval_hours}h Low: [red]{min(prices):.6f}{Balance.get_unit(netuid)}"
2136
+ if netuid != 0
2137
+ else f"{interval_hours}h Low: [red]{Balance.get_unit(netuid)} {min(prices):.6f}"
2138
+ )
2139
+
2140
+ change_color = "dark_sea_green3" if prices[-1] > prices[0] else "red"
2141
+ console.print(
2142
+ f"{interval_hours}h Change: "
2143
+ f"[{change_color}]{((prices[-1] - prices[0]) / prices[0] * 100):.2f}%\n"
2144
+ )
2145
+ print(fig.show())
2146
+ console.print("\nLatest stats:")
2147
+ console.print(
2148
+ f"Supply: [{COLOR_PALETTE['POOLS']['ALPHA_IN']}]{subnet.alpha_in.tao + subnet.alpha_out.tao:,.2f} {Balance.get_unit(netuid)}"
2149
+ if netuid != 0
2150
+ else f"Supply: [{COLOR_PALETTE['POOLS']['ALPHA_IN']}]{Balance.get_unit(netuid)} {subnet.alpha_in.tao + subnet.alpha_out.tao:,.2f}"
2151
+ )
2152
+ console.print(
2153
+ f"Market Cap: [steel_blue3]{subnet.price.tao * (subnet.alpha_in.tao + subnet.alpha_out.tao):,.2f} {Balance.get_unit(netuid)} / 21M"
2154
+ if netuid != 0
2155
+ else f"Market Cap: [steel_blue3]{Balance.get_unit(netuid)} {subnet.price.tao * (subnet.alpha_in.tao + subnet.alpha_out.tao):,.2f} / 21M"
2156
+ )
2157
+ console.print(
2158
+ f"Emission: [{COLOR_PALETTE['POOLS']['EMISSION']}]{subnet.emission.tao:,.2f} {Balance.get_unit(netuid)}"
2159
+ if netuid != 0
2160
+ else f"Emission: [{COLOR_PALETTE['POOLS']['EMISSION']}]{Balance.get_unit(netuid)} {subnet.emission.tao:,.2f}"
2161
+ )
2162
+ console.print(
2163
+ f"Stake: [{COLOR_PALETTE['STAKE']['TAO']}]{subnet.alpha_out.tao:,.2f} {Balance.get_unit(netuid)}"
2164
+ if netuid != 0
2165
+ else f"Stake: [{COLOR_PALETTE['STAKE']['TAO']}]{Balance.get_unit(netuid)} {subnet.alpha_out.tao:,.2f}"
2166
+ )
@@ -9,7 +9,7 @@ from rich.table import Column, Table
9
9
  from rich.prompt import Confirm
10
10
  from scalecodec import GenericCall
11
11
 
12
- from bittensor_cli.src import HYPERPARAMS, DelegatesDetails, COLOR_PALETTE, SUBNETS
12
+ from bittensor_cli.src import HYPERPARAMS, DelegatesDetails, COLOR_PALETTE
13
13
  from bittensor_cli.src.bittensor.chain_data import decode_account_id
14
14
  from bittensor_cli.src.bittensor.utils import (
15
15
  console,
@@ -445,7 +445,9 @@ async def set_take_extrinsic(
445
445
  if not success:
446
446
  err_console.print(err)
447
447
  else:
448
- console.print(":white_heavy_check_mark: [dark_sea_green_3]Finalized[/dark_sea_green_3]")
448
+ console.print(
449
+ ":white_heavy_check_mark: [dark_sea_green_3]Finalized[/dark_sea_green_3]"
450
+ )
449
451
  return success
450
452
 
451
453
 
@@ -502,9 +504,9 @@ async def get_hyperparameters(subtensor: "SubtensorInterface", netuid: int):
502
504
  raise typer.Exit()
503
505
 
504
506
  table = Table(
505
- Column("[white]HYPERPARAMETER", style=COLOR_PALETTE['SUDO']['HYPERPARAMETER']),
506
- Column("[white]VALUE", style=COLOR_PALETTE['SUDO']['VALUE']),
507
- Column("[white]NORMALIZED", style=COLOR_PALETTE['SUDO']['NORMALIZED']),
507
+ Column("[white]HYPERPARAMETER", style=COLOR_PALETTE["SUDO"]["HYPERPARAMETER"]),
508
+ Column("[white]VALUE", style=COLOR_PALETTE["SUDO"]["VALUE"]),
509
+ Column("[white]NORMALIZED", style=COLOR_PALETTE["SUDO"]["NORMALIZED"]),
508
510
  title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]\nSubnet Hyperparameters\n NETUID: "
509
511
  f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid}"
510
512
  f"{f' ({subnet_info.subnet_name})' if subnet_info.subnet_name is not None else ''}"
@@ -716,10 +718,14 @@ async def set_take(
716
718
  return False
717
719
  else:
718
720
  new_take = await get_current_take(subtensor, wallet)
719
- console.print(f"New take is [{COLOR_PALETTE['POOLS']['RATE']}]{new_take * 100.:.2f}%")
721
+ console.print(
722
+ f"New take is [{COLOR_PALETTE['POOLS']['RATE']}]{new_take * 100.:.2f}%"
723
+ )
720
724
  return True
721
725
 
722
- console.print(f"Setting take on [{COLOR_PALETTE['GENERAL']['LINKS']}]network: {subtensor.network}")
726
+ console.print(
727
+ f"Setting take on [{COLOR_PALETTE['GENERAL']['LINKS']}]network: {subtensor.network}"
728
+ )
723
729
 
724
730
  try:
725
731
  wallet.unlock_hotkey()
@@ -1,12 +1,7 @@
1
1
  import asyncio
2
- import binascii
3
2
  import itertools
4
3
  import os
5
- import sys
6
4
  from collections import defaultdict
7
- from concurrent.futures import ProcessPoolExecutor
8
- from functools import partial
9
- from sys import getsizeof
10
5
  from typing import Any, Collection, Generator, Optional
11
6
 
12
7
  import aiohttp
@@ -16,29 +11,23 @@ from bittensor_wallet.keyfile import Keyfile
16
11
  from fuzzywuzzy import fuzz
17
12
  from rich import box
18
13
  from rich.align import Align
19
- from rich.prompt import Confirm, Prompt
20
14
  from rich.table import Column, Table
21
15
  from rich.tree import Tree
22
16
  from rich.padding import Padding
23
- from rich.prompt import IntPrompt
24
17
  from scalecodec import ScaleBytes
25
- import scalecodec
26
18
  import typer
27
19
 
28
- from bittensor_cli.src import TYPE_REGISTRY, COLOR_PALETTE
20
+ from bittensor_cli.src import COLOR_PALETTE
29
21
  from bittensor_cli.src.bittensor import utils
30
22
  from bittensor_cli.src.bittensor.balances import Balance
31
23
  from bittensor_cli.src.bittensor.chain_data import (
32
24
  DelegateInfo,
33
25
  NeuronInfoLite,
34
26
  StakeInfo,
35
- custom_rpc_type_registry,
36
- decode_account_id,
37
27
  )
38
28
  from bittensor_cli.src.bittensor.extrinsics.registration import (
39
29
  run_faucet_extrinsic,
40
30
  swap_hotkey_extrinsic,
41
- is_hotkey_registered,
42
31
  )
43
32
  from bittensor_cli.src.bittensor.extrinsics.transfer import transfer_extrinsic
44
33
  from bittensor_cli.src.bittensor.networking import int_to_ip
@@ -47,7 +36,6 @@ from bittensor_cli.src.bittensor.utils import (
47
36
  RAO_PER_TAO,
48
37
  console,
49
38
  convert_blocks_to_time,
50
- decode_scale_bytes,
51
39
  err_console,
52
40
  print_error,
53
41
  print_verbose,
@@ -55,10 +43,18 @@ from bittensor_cli.src.bittensor.utils import (
55
43
  get_hotkey_wallets_for_wallet,
56
44
  is_valid_ss58_address,
57
45
  validate_coldkey_presence,
58
- retry_prompt,
46
+ get_subnet_name,
47
+ millify_tao,
59
48
  )
60
49
 
61
50
 
51
+ class WalletLike:
52
+ def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None):
53
+ self.name = name
54
+ self.hotkey_ss58 = hotkey_ss58
55
+ self.hotkey_str = hotkey_str
56
+
57
+
62
58
  async def regen_coldkey(
63
59
  wallet: Wallet,
64
60
  mnemonic: Optional[str],
@@ -603,17 +599,19 @@ async def overview(
603
599
  include_hotkeys: Optional[list[str]] = None,
604
600
  exclude_hotkeys: Optional[list[str]] = None,
605
601
  netuids_filter: Optional[list[int]] = None,
602
+ verbose: bool = False,
606
603
  ):
607
604
  """Prints an overview for the wallet's coldkey."""
608
605
 
609
606
  total_balance = Balance(0)
610
607
 
611
608
  # We are printing for every coldkey.
612
- print_verbose("Fetching total balance for coldkey/s")
613
609
  block_hash = await subtensor.substrate.get_chain_head()
614
610
  all_hotkeys, total_balance = await _get_total_balance(
615
611
  total_balance, subtensor, wallet, all_wallets, block_hash=block_hash
616
612
  )
613
+ _dynamic_info = await subtensor.get_all_subnet_dynamic_info()
614
+ dynamic_info = {info.netuid: info for info in _dynamic_info}
617
615
 
618
616
  with console.status(
619
617
  f":satellite: Synchronizing with chain [white]{subtensor.network}[/white]",
@@ -621,9 +619,6 @@ async def overview(
621
619
  ) as status:
622
620
  # We are printing for a select number of hotkeys from all_hotkeys.
623
621
  if include_hotkeys or exclude_hotkeys:
624
- print_verbose(
625
- "Fetching for select hotkeys passed in 'include_hotkeys'", status
626
- )
627
622
  all_hotkeys = _get_hotkeys(include_hotkeys, exclude_hotkeys, all_hotkeys)
628
623
 
629
624
  # Check we have keys to display.
@@ -633,17 +628,14 @@ async def overview(
633
628
 
634
629
  # Pull neuron info for all keys.
635
630
  neurons: dict[str, list[NeuronInfoLite]] = {}
636
- print_verbose("Fetching subnet netuids", status)
637
631
  block, all_netuids = await asyncio.gather(
638
632
  subtensor.substrate.get_block_number(None),
639
633
  subtensor.get_all_subnet_netuids(),
640
634
  )
641
635
 
642
- print_verbose("Filtering netuids by registered hotkeys", status)
643
636
  netuids = await subtensor.filter_netuids_by_registered_hotkeys(
644
637
  all_netuids, netuids_filter, all_hotkeys, reuse_block=True
645
638
  )
646
- # bittensor.logging.debug(f"Netuids to check: {netuids}")
647
639
 
648
640
  for netuid in netuids:
649
641
  neurons[str(netuid)] = []
@@ -664,104 +656,17 @@ async def overview(
664
656
  )
665
657
  all_hotkeys, _ = validate_coldkey_presence(all_hotkeys)
666
658
 
667
- print_verbose("Fetching key addresses", status)
668
659
  all_hotkey_addresses, hotkey_coldkey_to_hotkey_wallet = _get_key_address(
669
660
  all_hotkeys
670
661
  )
671
662
 
672
- print_verbose("Pulling and processing neuron information for all keys", status)
673
663
  results = await _get_neurons_for_netuids(
674
664
  subtensor, netuids, all_hotkey_addresses
675
665
  )
676
666
  neurons = _process_neuron_results(results, neurons, netuids)
677
- total_coldkey_stake_from_metagraph = await _calculate_total_coldkey_stake(
678
- neurons
679
- )
680
-
681
- alerts_table = Table(show_header=True, header_style="bold magenta")
682
- alerts_table.add_column("🥩 alert!")
683
-
684
- coldkeys_to_check = []
685
- ck_stakes = await subtensor.get_total_stake_for_coldkey(
686
- *(
687
- coldkey_wallet.coldkeypub.ss58_address
688
- for coldkey_wallet in all_coldkey_wallets
689
- if coldkey_wallet.coldkeypub
690
- ),
691
- block_hash=block_hash,
692
- )
693
- for coldkey_wallet in all_coldkey_wallets:
694
- if coldkey_wallet.coldkeypub:
695
- # Check if we have any stake with hotkeys that are not registered.
696
- difference = (
697
- ck_stakes[coldkey_wallet.coldkeypub.ss58_address]
698
- - total_coldkey_stake_from_metagraph[
699
- coldkey_wallet.coldkeypub.ss58_address
700
- ]
701
- )
702
- if difference == 0:
703
- continue # We have all our stake registered.
704
-
705
- coldkeys_to_check.append(coldkey_wallet)
706
- alerts_table.add_row(
707
- "Found [light_goldenrod2]{}[/light_goldenrod2] stake with coldkey [bright_magenta]{}[/bright_magenta] that is not registered.".format(
708
- abs(difference), coldkey_wallet.coldkeypub.ss58_address
709
- )
710
- )
711
-
712
- if coldkeys_to_check:
713
- # We have some stake that is not with a registered hotkey.
714
- if "-1" not in neurons:
715
- neurons["-1"] = []
716
-
717
- print_verbose("Checking coldkeys for de-registered stake", status)
718
- results = await asyncio.gather(
719
- *[
720
- _get_de_registered_stake_for_coldkey_wallet(
721
- subtensor, all_hotkey_addresses, coldkey_wallet
722
- )
723
- for coldkey_wallet in coldkeys_to_check
724
- ]
725
- )
726
-
727
- for result in results:
728
- coldkey_wallet, de_registered_stake, err_msg = result
729
- if err_msg is not None:
730
- err_console.print(err_msg)
731
-
732
- if len(de_registered_stake) == 0:
733
- continue # We have no de-registered stake with this coldkey.
734
-
735
- de_registered_neurons = []
736
- for hotkey_addr, our_stake in de_registered_stake:
737
- # Make a neuron info lite for this hotkey and coldkey.
738
- de_registered_neuron = NeuronInfoLite.get_null_neuron()
739
- de_registered_neuron.hotkey = hotkey_addr
740
- de_registered_neuron.coldkey = coldkey_wallet.coldkeypub.ss58_address
741
- de_registered_neuron.total_stake = Balance(our_stake)
742
- de_registered_neurons.append(de_registered_neuron)
743
-
744
- # Add this hotkey to the wallets dict
745
- wallet_ = Wallet(name=wallet)
746
- wallet_.hotkey_ss58 = hotkey_addr
747
- wallet.hotkey_str = hotkey_addr[:5] # Max length of 5 characters
748
- # Indicates a hotkey not on local machine but exists in stake_info obj on-chain
749
- if hotkey_coldkey_to_hotkey_wallet.get(hotkey_addr) is None:
750
- hotkey_coldkey_to_hotkey_wallet[hotkey_addr] = {}
751
- hotkey_coldkey_to_hotkey_wallet[hotkey_addr][
752
- coldkey_wallet.coldkeypub.ss58_address
753
- ] = wallet_
754
-
755
- # Add neurons to overview.
756
- neurons["-1"].extend(de_registered_neurons)
757
-
758
667
  # Setup outer table.
759
668
  grid = Table.grid(pad_edge=True)
760
669
 
761
- # If there are any alerts, add them to the grid
762
- if len(alerts_table.rows) > 0:
763
- grid.add_row(alerts_table)
764
-
765
670
  # Add title
766
671
  if not all_wallets:
767
672
  title = "[underline dark_orange]Wallet[/underline dark_orange]\n"
@@ -780,9 +685,6 @@ async def overview(
780
685
  )
781
686
  )
782
687
  # Generate rows per netuid
783
- hotkeys_seen = set()
784
- total_neurons = 0
785
- total_stake = 0.0
786
688
  tempos = await asyncio.gather(
787
689
  *[
788
690
  subtensor.get_hyperparameter("Tempo", netuid, block_hash)
@@ -790,7 +692,6 @@ async def overview(
790
692
  ]
791
693
  )
792
694
  for netuid, subnet_tempo in zip(netuids, tempos):
793
- last_subnet = netuid == netuids[-1]
794
695
  table_data = []
795
696
  total_rank = 0.0
796
697
  total_trust = 0.0
@@ -799,6 +700,8 @@ async def overview(
799
700
  total_incentive = 0.0
800
701
  total_dividends = 0.0
801
702
  total_emission = 0
703
+ total_stake = 0
704
+ total_neurons = 0
802
705
 
803
706
  for nn in neurons[str(netuid)]:
804
707
  hotwallet = hotkey_coldkey_to_hotkey_wallet.get(nn.hotkey, {}).get(
@@ -807,8 +710,7 @@ async def overview(
807
710
  if not hotwallet:
808
711
  # Indicates a mismatch between what the chain says the coldkey
809
712
  # is for this hotkey and the local wallet coldkey-hotkey pair
810
- hotwallet = Wallet(name=nn.coldkey[:7])
811
- hotwallet.hotkey_str = nn.hotkey[:7]
713
+ hotwallet = WalletLike(name=nn.coldkey[:7], hotkey_str=nn.hotkey[:7])
812
714
 
813
715
  nn: NeuronInfoLite
814
716
  uid = nn.uid
@@ -820,7 +722,7 @@ async def overview(
820
722
  validator_trust = nn.validator_trust
821
723
  incentive = nn.incentive
822
724
  dividends = nn.dividends
823
- emission = int(nn.emission / (subnet_tempo + 1) * 1e9)
725
+ emission = int(nn.emission / (subnet_tempo + 1) * 1e9) # Per block
824
726
  last_update = int(block - nn.last_update)
825
727
  validator_permit = nn.validator_permit
826
728
  row = [
@@ -828,14 +730,14 @@ async def overview(
828
730
  hotwallet.hotkey_str,
829
731
  str(uid),
830
732
  str(active),
831
- "{:.5f}".format(stake),
832
- "{:.5f}".format(rank),
833
- "{:.5f}".format(trust),
834
- "{:.5f}".format(consensus),
835
- "{:.5f}".format(incentive),
836
- "{:.5f}".format(dividends),
837
- "{:_}".format(emission),
838
- "{:.5f}".format(validator_trust),
733
+ f"{stake:.4f}" if verbose else millify_tao(stake),
734
+ f"{rank:.4f}" if verbose else millify_tao(rank),
735
+ f"{trust:.4f}" if verbose else millify_tao(trust),
736
+ f"{consensus:.4f}" if verbose else millify_tao(consensus),
737
+ f"{incentive:.4f}" if verbose else millify_tao(incentive),
738
+ f"{dividends:.4f}" if verbose else millify_tao(dividends),
739
+ f"{emission:.4f}",
740
+ f"{validator_trust:.4f}" if verbose else millify_tao(validator_trust),
839
741
  "*" if validator_permit else "",
840
742
  str(last_update),
841
743
  (
@@ -853,23 +755,15 @@ async def overview(
853
755
  total_dividends += dividends
854
756
  total_emission += emission
855
757
  total_validator_trust += validator_trust
856
-
857
- if (nn.hotkey, nn.coldkey) not in hotkeys_seen:
858
- # Don't double count stake on hotkey-coldkey pairs.
859
- hotkeys_seen.add((nn.hotkey, nn.coldkey))
860
- total_stake += stake
861
-
862
- # netuid -1 are neurons that are de-registered.
863
- if netuid != "-1":
864
- total_neurons += 1
758
+ total_stake += stake
759
+ total_neurons += 1
865
760
 
866
761
  table_data.append(row)
867
762
 
868
763
  # Add subnet header
869
- if netuid == "-1":
870
- grid.add_row("Deregistered Neurons")
871
- else:
872
- grid.add_row(f"Subnet: [dark_orange]{netuid}[/dark_orange]")
764
+ grid.add_row(
765
+ f"Subnet: [dark_orange]{netuid}: {get_subnet_name(dynamic_info[netuid])} {dynamic_info[netuid].symbol}[/dark_orange]"
766
+ )
873
767
  width = console.width
874
768
  table = Table(
875
769
  show_footer=False,
@@ -878,45 +772,34 @@ async def overview(
878
772
  expand=True,
879
773
  width=width - 5,
880
774
  )
881
- if last_subnet:
882
- table.add_column(
883
- "[white]COLDKEY", str(total_neurons), style="bold bright_cyan", ratio=2
884
- )
885
- table.add_column(
886
- "[white]HOTKEY", str(total_neurons), style="bright_cyan", ratio=2
887
- )
888
- else:
889
- # No footer for non-last subnet.
890
- table.add_column("[white]COLDKEY", style="bold bright_cyan", ratio=2)
891
- table.add_column("[white]HOTKEY", style="bright_cyan", ratio=2)
775
+
776
+ table.add_column("[white]COLDKEY", style="bold bright_cyan", ratio=2)
777
+ table.add_column("[white]HOTKEY", style="bright_cyan", ratio=2)
892
778
  table.add_column(
893
779
  "[white]UID", str(total_neurons), style="rgb(42,161,152)", ratio=1
894
780
  )
895
781
  table.add_column(
896
782
  "[white]ACTIVE", justify="right", style="#8787ff", no_wrap=True, ratio=1
897
783
  )
898
- if last_subnet:
899
- table.add_column(
900
- "[white]STAKE(\u03c4)",
901
- "\u03c4{:.5f}".format(total_stake),
902
- footer_style="bold white",
903
- justify="right",
904
- style="dark_orange",
905
- no_wrap=True,
906
- ratio=1,
907
- )
908
- else:
909
- # No footer for non-last subnet.
910
- table.add_column(
911
- "[white]STAKE(\u03c4)",
912
- justify="right",
913
- style="dark_orange",
914
- no_wrap=True,
915
- ratio=1.5,
916
- )
784
+
785
+ _total_stake_formatted = (
786
+ f"{total_stake:.4f}" if verbose else millify_tao(total_stake)
787
+ )
788
+ table.add_column(
789
+ "[white]STAKE(\u03c4)"
790
+ if netuid == 0
791
+ else f"[white]STAKE({Balance.get_unit(netuid)})",
792
+ f"{_total_stake_formatted} {Balance.get_unit(netuid)}"
793
+ if netuid != 0
794
+ else f"{Balance.get_unit(netuid)} {_total_stake_formatted}",
795
+ justify="right",
796
+ style="dark_orange",
797
+ no_wrap=True,
798
+ ratio=1.5,
799
+ )
917
800
  table.add_column(
918
801
  "[white]RANK",
919
- "{:.5f}".format(total_rank),
802
+ f"{total_rank:.4f}",
920
803
  justify="right",
921
804
  style="medium_purple",
922
805
  no_wrap=True,
@@ -924,7 +807,7 @@ async def overview(
924
807
  )
925
808
  table.add_column(
926
809
  "[white]TRUST",
927
- "{:.5f}".format(total_trust),
810
+ f"{total_trust:.4f}",
928
811
  justify="right",
929
812
  style="green",
930
813
  no_wrap=True,
@@ -932,7 +815,7 @@ async def overview(
932
815
  )
933
816
  table.add_column(
934
817
  "[white]CONSENSUS",
935
- "{:.5f}".format(total_consensus),
818
+ f"{total_consensus:.4f}",
936
819
  justify="right",
937
820
  style="rgb(42,161,152)",
938
821
  no_wrap=True,
@@ -940,7 +823,7 @@ async def overview(
940
823
  )
941
824
  table.add_column(
942
825
  "[white]INCENTIVE",
943
- "{:.5f}".format(total_incentive),
826
+ f"{total_incentive:.4f}",
944
827
  justify="right",
945
828
  style="#5fd7ff",
946
829
  no_wrap=True,
@@ -948,7 +831,7 @@ async def overview(
948
831
  )
949
832
  table.add_column(
950
833
  "[white]DIVIDENDS",
951
- "{:.5f}".format(total_dividends),
834
+ f"{total_dividends:.4f}",
952
835
  justify="right",
953
836
  style="#8787d7",
954
837
  no_wrap=True,
@@ -956,7 +839,7 @@ async def overview(
956
839
  )
957
840
  table.add_column(
958
841
  "[white]EMISSION(\u03c1)",
959
- "\u03c1{:_}".format(total_emission),
842
+ f"\u03c1{total_emission}",
960
843
  justify="right",
961
844
  style="#d7d7ff",
962
845
  no_wrap=True,
@@ -964,7 +847,7 @@ async def overview(
964
847
  )
965
848
  table.add_column(
966
849
  "[white]VTRUST",
967
- "{:.5f}".format(total_validator_trust),
850
+ f"{total_validator_trust:.4f}",
968
851
  justify="right",
969
852
  style="magenta",
970
853
  no_wrap=True,
@@ -1283,6 +1166,8 @@ async def inspect(
1283
1166
  delegates_: list[tuple[DelegateInfo, Balance]],
1284
1167
  ) -> Generator[list[str], None, None]:
1285
1168
  for d_, staked in delegates_:
1169
+ if not staked.tao > 0:
1170
+ continue
1286
1171
  if d_.hotkey_ss58 in registered_delegate_info:
1287
1172
  delegate_name = registered_delegate_info[d_.hotkey_ss58].display
1288
1173
  else:
@@ -1292,7 +1177,11 @@ async def inspect(
1292
1177
  + [
1293
1178
  str(delegate_name),
1294
1179
  str(staked),
1295
- str(d_.total_daily_return.tao * (staked.tao / d_.total_stake.tao)),
1180
+ str(
1181
+ d_.total_daily_return.tao * (staked.tao / d_.total_stake.tao)
1182
+ if d_.total_stake.tao != 0
1183
+ else 0
1184
+ ),
1296
1185
  ]
1297
1186
  + [""] * 4
1298
1187
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bittensor-cli
3
- Version: 8.2.0rc9
3
+ Version: 8.2.0rc11
4
4
  Summary: Bittensor CLI
5
5
  Home-page: https://github.com/opentensor/btcli
6
6
  Author: bittensor.com