bittensor-cli 9.1.3__py3-none-any.whl → 9.2.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
@@ -25,7 +25,7 @@ from bittensor_cli.src import (
25
25
  WalletOptions as WO,
26
26
  WalletValidationTypes as WV,
27
27
  Constants,
28
- COLOR_PALETTE,
28
+ COLORS,
29
29
  HYPERPARAMS,
30
30
  )
31
31
  from bittensor_cli.version import __version__, __version_as_int__
@@ -241,6 +241,7 @@ class Options:
241
241
  "--slippage",
242
242
  "--slippage-tolerance",
243
243
  "--tolerance",
244
+ "--rate-tolerance",
244
245
  help="Set the rate tolerance percentage for transactions (default: 0.05%).",
245
246
  callback=validate_rate_tolerance,
246
247
  )
@@ -341,8 +342,8 @@ def get_optional_netuid(netuid: Optional[int], all_netuids: bool) -> Optional[in
341
342
  return None
342
343
  elif netuid is None and all_netuids is False:
343
344
  answer = Prompt.ask(
344
- f"Enter the [{COLOR_PALETTE['GENERAL']['SUBHEADING_MAIN']}]netuid"
345
- f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING_MAIN']}] to use. Leave blank for all netuids",
345
+ f"Enter the [{COLORS.G.SUBHEAD_MAIN}]netuid"
346
+ f"[/{COLORS.G.SUBHEAD_MAIN}] to use. Leave blank for all netuids",
346
347
  default=None,
347
348
  show_default=False,
348
349
  )
@@ -950,7 +951,8 @@ class CLIManager:
950
951
  elif self.config["network"]:
951
952
  self.subtensor = SubtensorInterface(self.config["network"])
952
953
  console.print(
953
- f"Using the specified network [{COLOR_PALETTE['GENERAL']['LINKS']}]{self.config['network']}[/{COLOR_PALETTE['GENERAL']['LINKS']}] from config"
954
+ f"Using the specified network [{COLORS.G.LINKS}]{self.config['network']}"
955
+ f"[/{COLORS.G.LINKS}] from config"
954
956
  )
955
957
  else:
956
958
  self.subtensor = SubtensorInterface(defaults.subtensor.network)
@@ -1523,7 +1525,7 @@ class CLIManager:
1523
1525
  else:
1524
1526
  wallet_name = Prompt.ask(
1525
1527
  "Enter the [blue]wallet name[/blue]"
1526
- + f" [{COLOR_PALETTE['GENERAL']['HINT']} italic](Hint: You can set this with `btcli config set --wallet-name`)",
1528
+ + f" [{COLORS.G.HINT} italic](Hint: You can set this with `btcli config set --wallet-name`)",
1527
1529
  default=defaults.wallet.name,
1528
1530
  )
1529
1531
 
@@ -2049,7 +2051,7 @@ class CLIManager:
2049
2051
 
2050
2052
  if not wallet_name:
2051
2053
  wallet_name = Prompt.ask(
2052
- f"Enter the name of the [{COLOR_PALETTE['GENERAL']['COLDKEY']}]new wallet (coldkey)",
2054
+ f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2053
2055
  default=defaults.wallet.name,
2054
2056
  )
2055
2057
 
@@ -2106,7 +2108,7 @@ class CLIManager:
2106
2108
 
2107
2109
  if not wallet_name:
2108
2110
  wallet_name = Prompt.ask(
2109
- f"Enter the name of the [{COLOR_PALETTE['GENERAL']['COLDKEY']}]new wallet (coldkey)",
2111
+ f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2110
2112
  default=defaults.wallet.name,
2111
2113
  )
2112
2114
  wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
@@ -2223,13 +2225,13 @@ class CLIManager:
2223
2225
 
2224
2226
  if not wallet_name:
2225
2227
  wallet_name = Prompt.ask(
2226
- f"Enter the [{COLOR_PALETTE['GENERAL']['COLDKEY']}]wallet name",
2228
+ f"Enter the [{COLORS.G.CK}]wallet name",
2227
2229
  default=defaults.wallet.name,
2228
2230
  )
2229
2231
 
2230
2232
  if not wallet_hotkey:
2231
2233
  wallet_hotkey = Prompt.ask(
2232
- f"Enter the name of the [{COLOR_PALETTE['GENERAL']['HOTKEY']}]new hotkey",
2234
+ f"Enter the name of the [{COLORS.G.HK}]new hotkey",
2233
2235
  default=defaults.wallet.hotkey,
2234
2236
  )
2235
2237
 
@@ -2285,7 +2287,7 @@ class CLIManager:
2285
2287
 
2286
2288
  if not wallet_name:
2287
2289
  wallet_name = Prompt.ask(
2288
- f"Enter the name of the [{COLOR_PALETTE['GENERAL']['COLDKEY']}]new wallet (coldkey)",
2290
+ f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2289
2291
  default=defaults.wallet.name,
2290
2292
  )
2291
2293
 
@@ -2359,12 +2361,12 @@ class CLIManager:
2359
2361
 
2360
2362
  if not wallet_name:
2361
2363
  wallet_name = Prompt.ask(
2362
- f"Enter the name of the [{COLOR_PALETTE['GENERAL']['COLDKEY']}]new wallet (coldkey)",
2364
+ f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
2363
2365
  default=defaults.wallet.name,
2364
2366
  )
2365
2367
  if not wallet_hotkey:
2366
2368
  wallet_hotkey = Prompt.ask(
2367
- f"Enter the the name of the [{COLOR_PALETTE['GENERAL']['HOTKEY']}]new hotkey",
2369
+ f"Enter the the name of the [{COLORS.G.HK}]new hotkey",
2368
2370
  default=defaults.wallet.hotkey,
2369
2371
  )
2370
2372
 
@@ -2742,9 +2744,10 @@ class CLIManager:
2742
2744
  self.verbosity_handler(quiet, verbose)
2743
2745
  if use_hotkey is None:
2744
2746
  use_hotkey = Confirm.ask(
2745
- f"Would you like to sign the transaction using your [{COLOR_PALETTE['GENERAL']['HOTKEY']}]hotkey[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]?"
2746
- f"\n[Type [{COLOR_PALETTE['GENERAL']['HOTKEY']}]y[/{COLOR_PALETTE['GENERAL']['HOTKEY']}] for [{COLOR_PALETTE['GENERAL']['HOTKEY']}]hotkey[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]"
2747
- f" and [{COLOR_PALETTE['GENERAL']['COLDKEY']}]n[/{COLOR_PALETTE['GENERAL']['COLDKEY']}] for [{COLOR_PALETTE['GENERAL']['COLDKEY']}]coldkey[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]] (default is [{COLOR_PALETTE['GENERAL']['COLDKEY']}]coldkey[/{COLOR_PALETTE['GENERAL']['COLDKEY']}])",
2747
+ f"Would you like to sign the transaction using your [{COLORS.G.HK}]hotkey[/{COLORS.G.HK}]?"
2748
+ f"\n[Type [{COLORS.G.HK}]y[/{COLORS.G.HK}] for [{COLORS.G.HK}]hotkey[/{COLORS.G.HK}]"
2749
+ f" and [{COLORS.G.CK}]n[/{COLORS.G.CK}] for [{COLORS.G.CK}]coldkey[/{COLORS.G.CK}]] "
2750
+ f"(default is [{COLORS.G.CK}]coldkey[/{COLORS.G.CK}])",
2748
2751
  default=False,
2749
2752
  )
2750
2753
 
@@ -3035,11 +3038,11 @@ class CLIManager:
3035
3038
  raise typer.Exit()
3036
3039
  if netuid is not None:
3037
3040
  amount = FloatPrompt.ask(
3038
- f"Amount to [{COLOR_PALETTE['GENERAL']['SUBHEADING_MAIN']}]stake (TAO τ)"
3041
+ f"Amount to [{COLORS.G.SUBHEAD_MAIN}]stake (TAO τ)"
3039
3042
  )
3040
3043
  else:
3041
3044
  amount = FloatPrompt.ask(
3042
- f"Amount to [{COLOR_PALETTE['GENERAL']['SUBHEADING_MAIN']}]stake to each netuid (TAO τ)"
3045
+ f"Amount to [{COLORS.G.SUBHEAD_MAIN}]stake to each netuid (TAO τ)"
3043
3046
  )
3044
3047
 
3045
3048
  if amount <= 0:
@@ -4112,7 +4115,8 @@ class CLIManager:
4112
4115
  if not param_value:
4113
4116
  if HYPERPARAMS.get(param_name):
4114
4117
  param_value = Prompt.ask(
4115
- f"Enter the new value for [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{param_name}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] in the VALUE column format"
4118
+ f"Enter the new value for [{COLORS.G.SUBHEAD}]{param_name}[/{COLORS.G.SUBHEAD}] "
4119
+ f"in the VALUE column format"
4116
4120
  )
4117
4121
  else:
4118
4122
  param_value = None
@@ -721,64 +721,111 @@ HELP_PANELS = {
721
721
  },
722
722
  }
723
723
 
724
- COLOR_PALETTE = {
725
- "GENERAL": {
726
- "HEADER": "#4196D6", # Light Blue
727
- "LINKS": "#8CB9E9", # Sky Blue
728
- "HINT": "#A2E5B8", # Mint Green
729
- "COLDKEY": "#9EF5E4", # Aqua
730
- "HOTKEY": "#ECC39D", # Light Orange/Peach
731
- "SUBHEADING_MAIN": "#7ECFEC", # Light Cyan
732
- "SUBHEADING": "#AFEFFF", # Pale Blue
733
- "SUBHEADING_EXTRA_1": "#96A3C5", # Grayish Blue
734
- "SUBHEADING_EXTRA_2": "#6D7BAF", # Slate Blue
735
- "CONFIRMATION_Y_N_Q": "#EE8DF8", # Light Purple/Pink
736
- "SYMBOL": "#E7CC51", # Gold
737
- "BALANCE": "#4F91C6", # Medium Blue
738
- "COST": "#53B5A0", # Teal
739
- "SUCCESS": "#53B5A0", # Teal
740
- "NETUID": "#CBA880", # Tan
741
- "NETUID_EXTRA": "#DDD5A9", # Light Khaki
742
- "TEMPO": "#67A3A5", # Grayish Teal
743
- },
744
- "STAKE": {
745
- "STAKE_AMOUNT": "#53B5A0", # Teal
746
- "STAKE_ALPHA": "#53B5A0", # Teal
747
- "STAKE_SWAP": "#67A3A5", # Grayish Teal
748
- "TAO": "#4F91C6", # Medium Blue
749
- "SLIPPAGE_TEXT": "#C25E7C", # Rose
750
- "SLIPPAGE_PERCENT": "#E7B195", # Light Coral
751
- "NOT_REGISTERED": "#EB6A6C", # Salmon Red
752
- "EXTRA_1": "#D781BB", # Pink
753
- },
754
- "POOLS": {
755
- "TAO": "#4F91C6", # Medium Blue
756
- "ALPHA_IN": "#D09FE9", # Light Purple
757
- "ALPHA_OUT": "#AB7CC8", # Medium Purple
758
- "RATE": "#F8D384", # Light Orange
759
- "TAO_EQUIV": "#8CB9E9", # Sky Blue
760
- "EMISSION": "#F8D384", # Light Orange
761
- "EXTRA_1": "#CAA8FB", # Lavender
762
- "EXTRA_2": "#806DAF", # Dark Purple
763
- },
764
- "GREY": {
765
- "GREY_100": "#F8F9FA", # Almost White
766
- "GREY_200": "#F1F3F4", # Very Light Grey
767
- "GREY_300": "#DBDDE1", # Light Grey
768
- "GREY_400": "#BDC1C6", # Medium Light Grey
769
- "GREY_500": "#5F6368", # Medium Grey
770
- "GREY_600": "#2E3134", # Medium Dark Grey
771
- "GREY_700": "#282A2D", # Dark Grey
772
- "GREY_800": "#17181B", # Very Dark Grey
773
- "GREY_900": "#0E1013", # Almost Black
774
- "BLACK": "#000000", # Pure Black
775
- },
776
- "SUDO": {
777
- "HYPERPARAMETER": "#4F91C6", # Medium Blue
778
- "VALUE": "#D09FE9", # Light Purple
779
- "NORMALIZED": "#AB7CC8", # Medium Purple
780
- },
781
- }
724
+
725
+ class Gettable:
726
+ def __getitem__(self, item):
727
+ return getattr(self, item)
728
+
729
+
730
+ class ColorPalette(Gettable):
731
+ def __init__(self):
732
+ self.GENERAL = self.General()
733
+ self.STAKE = self.Stake()
734
+ self.POOLS = self.Pools()
735
+ self.GREY = self.Grey()
736
+ self.SUDO = self.Sudo()
737
+ # aliases
738
+ self.G = self.GENERAL
739
+ self.S = self.STAKE
740
+ self.P = self.POOLS
741
+ self.GR = self.GREY
742
+ self.SU = self.SUDO
743
+
744
+ class General(Gettable):
745
+ HEADER = "#4196D6" # Light Blue
746
+ LINKS = "#8CB9E9" # Sky Blue
747
+ HINT = "#A2E5B8" # Mint Green
748
+ COLDKEY = "#9EF5E4" # Aqua
749
+ HOTKEY = "#ECC39D" # Light Orange/Peach
750
+ SUBHEADING_MAIN = "#7ECFEC" # Light Cyan
751
+ SUBHEADING = "#AFEFFF" # Pale Blue
752
+ SUBHEADING_EXTRA_1 = "#96A3C5" # Grayish Blue
753
+ SUBHEADING_EXTRA_2 = "#6D7BAF" # Slate Blue
754
+ CONFIRMATION_Y_N_Q = "#EE8DF8" # Light Purple/Pink
755
+ SYMBOL = "#E7CC51" # Gold
756
+ BALANCE = "#4F91C6" # Medium Blue
757
+ COST = "#53B5A0" # Teal
758
+ SUCCESS = "#53B5A0" # Teal
759
+ NETUID = "#CBA880" # Tan
760
+ NETUID_EXTRA = "#DDD5A9" # Light Khaki
761
+ TEMPO = "#67A3A5" # Grayish Teal
762
+ # aliases
763
+ CK = COLDKEY
764
+ HK = HOTKEY
765
+ SUBHEAD_MAIN = SUBHEADING_MAIN
766
+ SUBHEAD = SUBHEADING
767
+ SUBHEAD_EX_1 = SUBHEADING_EXTRA_1
768
+ SUBHEAD_EX_2 = SUBHEADING_EXTRA_2
769
+ SYM = SYMBOL
770
+ BAL = BALANCE
771
+
772
+ class Stake(Gettable):
773
+ STAKE_AMOUNT = "#53B5A0" # Teal
774
+ STAKE_ALPHA = "#53B5A0" # Teal
775
+ STAKE_SWAP = "#67A3A5" # Grayish Teal
776
+ TAO = "#4F91C6" # Medium Blue
777
+ SLIPPAGE_TEXT = "#C25E7C" # Rose
778
+ SLIPPAGE_PERCENT = "#E7B195" # Light Coral
779
+ NOT_REGISTERED = "#EB6A6C" # Salmon Red
780
+ EXTRA_1 = "#D781BB" # Pink
781
+ # aliases
782
+ AMOUNT = STAKE_AMOUNT
783
+ ALPHA = STAKE_ALPHA
784
+ SWAP = STAKE_SWAP
785
+
786
+ class Pools(Gettable):
787
+ TAO = "#4F91C6" # Medium Blue
788
+ ALPHA_IN = "#D09FE9" # Light Purple
789
+ ALPHA_OUT = "#AB7CC8" # Medium Purple
790
+ RATE = "#F8D384" # Light Orange
791
+ TAO_EQUIV = "#8CB9E9" # Sky Blue
792
+ EMISSION = "#F8D384" # Light Orange
793
+ EXTRA_1 = "#CAA8FB" # Lavender
794
+ EXTRA_2 = "#806DAF" # Dark Purple
795
+
796
+ class Grey(Gettable):
797
+ GREY_100 = "#F8F9FA" # Almost White
798
+ GREY_200 = "#F1F3F4" # Very Light Grey
799
+ GREY_300 = "#DBDDE1" # Light Grey
800
+ GREY_400 = "#BDC1C6" # Medium Light Grey
801
+ GREY_500 = "#5F6368" # Medium Grey
802
+ GREY_600 = "#2E3134" # Medium Dark Grey
803
+ GREY_700 = "#282A2D" # Dark Grey
804
+ GREY_800 = "#17181B" # Very Dark Grey
805
+ GREY_900 = "#0E1013" # Almost Black
806
+ BLACK = "#000000" # Pure Black
807
+ # aliases
808
+ G_100 = GREY_100
809
+ G_200 = GREY_200
810
+ G_300 = GREY_300
811
+ G_400 = GREY_400
812
+ G_500 = GREY_500
813
+ G_600 = GREY_600
814
+ G_700 = GREY_700
815
+ G_800 = GREY_800
816
+ G_900 = GREY_900
817
+
818
+ class Sudo(Gettable):
819
+ HYPERPARAMETER = "#4F91C6" # Medium Blue
820
+ VALUE = "#D09FE9" # Light Purple
821
+ NORMALIZED = "#AB7CC8" # Medium Purple
822
+ # aliases
823
+ HYPERPARAM = HYPERPARAMETER
824
+ NORMAL = NORMALIZED
825
+
826
+
827
+ COLOR_PALETTE = ColorPalette()
828
+ COLORS = COLOR_PALETTE
782
829
 
783
830
 
784
831
  SUBNETS = {
@@ -745,7 +745,9 @@ class DynamicInfo(InfoBase):
745
745
  def alpha_to_tao(self, alpha: Balance) -> Balance:
746
746
  return Balance.from_tao(alpha.tao * self.price.tao)
747
747
 
748
- def tao_to_alpha_with_slippage(self, tao: Balance) -> tuple[Balance, Balance]:
748
+ def tao_to_alpha_with_slippage(
749
+ self, tao: Balance
750
+ ) -> tuple[Balance, Balance, float]:
749
751
  """
750
752
  Returns an estimate of how much Alpha would a staker receive if they stake their tao using the current pool state.
751
753
  Args:
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import os
2
3
  from typing import Optional, Any, Union, TypedDict, Iterable
3
4
 
4
5
  import aiohttp
@@ -9,7 +10,10 @@ from async_substrate_interface.errors import SubstrateRequestException
9
10
  import typer
10
11
 
11
12
 
12
- from async_substrate_interface.async_substrate import AsyncSubstrateInterface
13
+ from async_substrate_interface.async_substrate import (
14
+ DiskCachedAsyncSubstrateInterface,
15
+ AsyncSubstrateInterface,
16
+ )
13
17
  from bittensor_cli.src.bittensor.chain_data import (
14
18
  DelegateInfo,
15
19
  StakeInfo,
@@ -34,6 +38,12 @@ from bittensor_cli.src.bittensor.utils import (
34
38
  u16_normalized_float,
35
39
  )
36
40
 
41
+ SubstrateClass = (
42
+ DiskCachedAsyncSubstrateInterface
43
+ if os.getenv("DISK_CACHE", "0") == "1"
44
+ else AsyncSubstrateInterface
45
+ )
46
+
37
47
 
38
48
  class ParamWithTypes(TypedDict):
39
49
  name: str # Name of the parameter.
@@ -98,7 +108,7 @@ class SubtensorInterface:
98
108
  self.chain_endpoint = Constants.network_map[defaults.subtensor.network]
99
109
  self.network = defaults.subtensor.network
100
110
 
101
- self.substrate = AsyncSubstrateInterface(
111
+ self.substrate = SubstrateClass(
102
112
  url=self.chain_endpoint,
103
113
  ss58_format=SS58_FORMAT,
104
114
  type_registry=TYPE_REGISTRY,
@@ -207,7 +217,7 @@ class SubtensorInterface:
207
217
 
208
218
  if result is None:
209
219
  return []
210
- stakes = StakeInfo.list_from_any(result)
220
+ stakes: list[StakeInfo] = StakeInfo.list_from_any(result)
211
221
  return [stake for stake in stakes if stake.stake > 0]
212
222
 
213
223
  async def get_stake_for_coldkey_and_hotkey(
@@ -352,14 +362,12 @@ class SubtensorInterface:
352
362
  self,
353
363
  *ss58_addresses,
354
364
  block_hash: Optional[str] = None,
355
- reuse_block: bool = False,
356
365
  ) -> dict[str, tuple[Balance, Balance]]:
357
366
  """
358
367
  Returns the total stake held on a coldkey.
359
368
 
360
369
  :param ss58_addresses: The SS58 address(es) of the coldkey(s)
361
370
  :param block_hash: The hash of the block number to retrieve the stake from.
362
- :param reuse_block: Whether to reuse the last-used block hash when retrieving info.
363
371
 
364
372
  :return: {address: Balance objects}
365
373
  """
@@ -1427,3 +1435,69 @@ class SubtensorInterface:
1427
1435
  )
1428
1436
 
1429
1437
  return [decode_account_id(hotkey[0]) for hotkey in owned_hotkeys or []]
1438
+
1439
+ async def get_stake_fee(
1440
+ self,
1441
+ origin_hotkey_ss58: Optional[str],
1442
+ origin_netuid: Optional[int],
1443
+ origin_coldkey_ss58: str,
1444
+ destination_hotkey_ss58: Optional[str],
1445
+ destination_netuid: Optional[int],
1446
+ destination_coldkey_ss58: str,
1447
+ amount: int,
1448
+ block_hash: Optional[str] = None,
1449
+ ) -> Balance:
1450
+ """
1451
+ Calculates the fee for a staking operation.
1452
+
1453
+ :param origin_hotkey_ss58: SS58 address of source hotkey (None for new stake)
1454
+ :param origin_netuid: Netuid of source subnet (None for new stake)
1455
+ :param origin_coldkey_ss58: SS58 address of source coldkey
1456
+ :param destination_hotkey_ss58: SS58 address of destination hotkey (None for removing stake)
1457
+ :param destination_netuid: Netuid of destination subnet (None for removing stake)
1458
+ :param destination_coldkey_ss58: SS58 address of destination coldkey
1459
+ :param amount: Amount of stake to transfer in RAO
1460
+ :param block_hash: Optional block hash at which to perform the calculation
1461
+
1462
+ :return: The calculated stake fee as a Balance object
1463
+
1464
+ When to use None:
1465
+
1466
+ 1. Adding new stake (default fee):
1467
+ - origin_hotkey_ss58 = None
1468
+ - origin_netuid = None
1469
+ - All other fields required
1470
+
1471
+ 2. Removing stake (default fee):
1472
+ - destination_hotkey_ss58 = None
1473
+ - destination_netuid = None
1474
+ - All other fields required
1475
+
1476
+ For all other operations, no None values - provide all parameters:
1477
+ 3. Moving between subnets
1478
+ 4. Moving between hotkeys
1479
+ 5. Moving between coldkeys
1480
+ """
1481
+
1482
+ origin = None
1483
+ if origin_hotkey_ss58 is not None and origin_netuid is not None:
1484
+ origin = (origin_hotkey_ss58, origin_netuid)
1485
+
1486
+ destination = None
1487
+ if destination_hotkey_ss58 is not None and destination_netuid is not None:
1488
+ destination = (destination_hotkey_ss58, destination_netuid)
1489
+
1490
+ result = await self.query_runtime_api(
1491
+ runtime_api="StakeInfoRuntimeApi",
1492
+ method="get_stake_fee",
1493
+ params=[
1494
+ origin,
1495
+ origin_coldkey_ss58,
1496
+ destination,
1497
+ destination_coldkey_ss58,
1498
+ amount,
1499
+ ],
1500
+ block_hash=block_hash,
1501
+ )
1502
+
1503
+ return Balance.from_rao(result)
@@ -5,7 +5,6 @@ import os
5
5
  import sqlite3
6
6
  import platform
7
7
  import webbrowser
8
- import sys
9
8
  from pathlib import Path
10
9
  from typing import TYPE_CHECKING, Any, Collection, Optional, Union, Callable
11
10
  from urllib.parse import urlparse
@@ -73,8 +72,8 @@ class WalletLike:
73
72
  return self._coldkeypub
74
73
 
75
74
 
76
- def print_console(message: str, colour: str, title: str, console: Console):
77
- console.print(
75
+ def print_console(message: str, colour: str, title: str, console_: Console):
76
+ console_.print(
78
77
  f"[bold {colour}][{title}]:[/bold {colour}] [{colour}]{message}[/{colour}]\n"
79
78
  )
80
79
 
@@ -1,154 +0,0 @@
1
- from typing import Optional, TYPE_CHECKING
2
-
3
- import rich.prompt
4
- from rich.table import Table
5
-
6
- from bittensor_cli.src.bittensor.chain_data import DelegateInfoLite
7
- from bittensor_cli.src.bittensor.utils import console
8
-
9
- if TYPE_CHECKING:
10
- from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
11
-
12
-
13
- async def select_delegate(subtensor: "SubtensorInterface", netuid: int):
14
- # Get a list of delegates and sort them by total stake in descending order
15
- delegates: list[DelegateInfoLite] = (
16
- await subtensor.get_delegates_by_netuid_light(netuid)
17
- ).sort(key=lambda x: x.total_stake, reverse=True)
18
-
19
- # Get registered delegates details.
20
- registered_delegate_info = await subtensor.get_delegate_identities()
21
-
22
- # Create a table to display delegate information
23
- table = Table(
24
- show_header=True,
25
- header_style="bold",
26
- border_style="rgb(7,54,66)",
27
- style="rgb(0,43,54)",
28
- )
29
-
30
- # Add columns to the table with specific styles
31
- table.add_column("Index", style="rgb(253,246,227)", no_wrap=True)
32
- table.add_column("Delegate Name", no_wrap=True)
33
- table.add_column("Hotkey SS58", style="rgb(211,54,130)", no_wrap=True)
34
- table.add_column("Owner SS58", style="rgb(133,153,0)", no_wrap=True)
35
- table.add_column("Take", style="rgb(181,137,0)", no_wrap=True)
36
- table.add_column(
37
- "Total Stake", style="rgb(38,139,210)", no_wrap=True, justify="right"
38
- )
39
- table.add_column(
40
- "Owner Stake", style="rgb(220,50,47)", no_wrap=True, justify="right"
41
- )
42
- # table.add_column("Return per 1000", style="rgb(108,113,196)", no_wrap=True, justify="right")
43
- # table.add_column("Total Daily Return", style="rgb(42,161,152)", no_wrap=True, justify="right")
44
-
45
- # List to store visible delegates
46
- visible_delegates = []
47
-
48
- def get_user_input() -> str:
49
- return rich.prompt.Prompt.ask(
50
- 'Press Enter to scroll, enter a number (1-N) to select, or type "h" for help: ',
51
- choices=["", "h"] + [str(x) for x in range(1, len(delegates) - 1)],
52
- show_choices=True,
53
- )
54
-
55
- # TODO: Add pagination to handle large number of delegates more efficiently
56
- # Iterate through delegates and display their information
57
-
58
- def loop_selections() -> Optional[int]:
59
- idx = 0
60
- selected_idx = None
61
- while idx < len(delegates):
62
- if idx < len(delegates):
63
- delegate = delegates[idx]
64
-
65
- # Add delegate to visible list
66
- visible_delegates.append(delegate)
67
-
68
- # Add a row to the table with delegate information
69
- table.add_row(
70
- str(idx),
71
- registered_delegate_info[delegate.hotkey_ss58].name
72
- if delegate.hotkey_ss58 in registered_delegate_info
73
- else "",
74
- delegate.hotkey_ss58[:5]
75
- + "..."
76
- + delegate.hotkey_ss58[-5:], # Show truncated hotkey
77
- delegate.owner_ss58[:5]
78
- + "..."
79
- + delegate.owner_ss58[-5:], # Show truncated owner address
80
- f"{delegate.take:.6f}",
81
- f"τ{delegate.total_stake.tao:,.4f}",
82
- f"τ{delegate.owner_stake.tao:,.4f}",
83
- # f"τ{delegate.return_per_1000.tao:,.4f}",
84
- # f"τ{delegate.total_daily_return.tao:,.4f}",
85
- )
86
-
87
- # Clear console and print updated table
88
- console.clear()
89
- console.print(table)
90
-
91
- # Prompt user for input
92
- user_input: str = get_user_input()
93
-
94
- # Add a help option to display information about each column
95
- if user_input == "h":
96
- console.print("\nColumn Information:")
97
- console.print(
98
- "[rgb(253,246,227)]Index:[/rgb(253,246,227)] Position in the list of delegates"
99
- )
100
- console.print(
101
- "[rgb(211,54,130)]Hotkey SS58:[/rgb(211,54,130)] Truncated public key of the delegate's hotkey"
102
- )
103
- console.print(
104
- "[rgb(133,153,0)]Owner SS58:[/rgb(133,153,0)] Truncated public key of the delegate's owner"
105
- )
106
- console.print(
107
- "[rgb(181,137,0)]Take:[/rgb(181,137,0)] Percentage of rewards the delegate takes"
108
- )
109
- console.print(
110
- "[rgb(38,139,210)]Total Stake:[/rgb(38,139,210)] Total amount staked to this delegate"
111
- )
112
- console.print(
113
- "[rgb(220,50,47)]Owner Stake:[/rgb(220,50,47)] Amount staked by the delegate owner"
114
- )
115
- console.print(
116
- "[rgb(108,113,196)]Return per 1000:[/rgb(108,113,196)] Estimated return for 1000 Tao staked"
117
- )
118
- console.print(
119
- "[rgb(42,161,152)]Total Daily Return:[/rgb(42,161,152)] Estimated total daily return for all stake"
120
- )
121
- user_input = get_user_input()
122
-
123
- # If user presses Enter, continue to next delegate
124
- if user_input and user_input != "h":
125
- selected_idx = int(user_input)
126
- break
127
-
128
- if idx < len(delegates):
129
- idx += 1
130
-
131
- return selected_idx
132
-
133
- # TODO( const ): uncomment for check
134
- # Add a confirmation step before returning the selected delegate
135
- # console.print(f"\nSelected delegate: [rgb(211,54,130)]{visible_delegates[selected_idx].hotkey_ss58}[/rgb(211,54,130)]")
136
- # console.print(f"Take: [rgb(181,137,0)]{visible_delegates[selected_idx].take:.6f}[/rgb(181,137,0)]")
137
- # console.print(f"Total Stake: [rgb(38,139,210)]{visible_delegates[selected_idx].total_stake}[/rgb(38,139,210)]")
138
-
139
- # confirmation = Prompt.ask("Do you want to proceed with this delegate? (y/n)")
140
- # if confirmation.lower() != 'yes' and confirmation.lower() != 'y':
141
- # return select_delegate( subtensor, netuid )
142
-
143
- # Return the selected delegate
144
- while True:
145
- selected_idx_ = loop_selections()
146
- if selected_idx_ is None:
147
- if not rich.prompt.Confirm.ask(
148
- "You've reached the end of the list. You must make a selection. Loop through again?"
149
- ):
150
- raise IndexError
151
- else:
152
- continue
153
- else:
154
- return delegates[selected_idx_]