bittensor-cli 9.1.0__py3-none-any.whl → 9.1.1__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
@@ -109,6 +109,18 @@ class Options:
109
109
  "--wallet.hotkey",
110
110
  help="Hotkey of the wallet",
111
111
  )
112
+ wallet_hotkey_ss58 = typer.Option(
113
+ None,
114
+ "--hotkey",
115
+ "--hotkey-ss58",
116
+ "-H",
117
+ "--wallet_hotkey",
118
+ "--wallet_hotkey_ss58",
119
+ "--wallet-hotkey",
120
+ "--wallet-hotkey-ss58",
121
+ "--wallet.hotkey",
122
+ help="Hotkey name or SS58 address of the hotkey",
123
+ )
112
124
  mnemonic = typer.Option(
113
125
  None,
114
126
  help='Mnemonic used to regenerate your key. For example: "horse cart dog ..."',
@@ -246,6 +258,15 @@ class Options:
246
258
  "--allow-partial/--not-partial",
247
259
  help="Enable or disable partial stake mode (default: disabled).",
248
260
  )
261
+ dashboard_path = typer.Option(
262
+ None,
263
+ "--dashboard-path",
264
+ "--dashboard_path",
265
+ "--dash_path",
266
+ "--dash.path",
267
+ "--dashboard.path",
268
+ help="Path to save the dashboard HTML file. For example: `~/.bittensor/dashboard`.",
269
+ )
249
270
 
250
271
 
251
272
  def list_prompt(init_var: list, list_type: type, help_text: str) -> list:
@@ -525,6 +546,7 @@ class CLIManager:
525
546
  "rate_tolerance": None,
526
547
  "safe_staking": True,
527
548
  "allow_partial_stake": False,
549
+ "dashboard_path": None,
528
550
  # Commenting this out as this needs to get updated
529
551
  # "metagraph_cols": {
530
552
  # "UID": True,
@@ -1119,6 +1141,7 @@ class CLIManager:
1119
1141
  "--partial/--no-partial",
1120
1142
  "--allow/--not-allow",
1121
1143
  ),
1144
+ dashboard_path: Optional[str] = Options.dashboard_path,
1122
1145
  ):
1123
1146
  """
1124
1147
  Sets or updates configuration values in the BTCLI config file.
@@ -1148,6 +1171,7 @@ class CLIManager:
1148
1171
  "rate_tolerance": rate_tolerance,
1149
1172
  "safe_staking": safe_staking,
1150
1173
  "allow_partial_stake": allow_partial_stake,
1174
+ "dashboard_path": dashboard_path,
1151
1175
  }
1152
1176
  bools = ["use_cache", "safe_staking", "allow_partial_stake"]
1153
1177
  if all(v is None for v in args.values()):
@@ -1257,6 +1281,7 @@ class CLIManager:
1257
1281
  "--allow/--not-allow",
1258
1282
  ),
1259
1283
  all_items: bool = typer.Option(False, "--all"),
1284
+ dashboard_path: Optional[str] = Options.dashboard_path,
1260
1285
  ):
1261
1286
  """
1262
1287
  Clears the fields in the config file and sets them to 'None'.
@@ -1288,6 +1313,7 @@ class CLIManager:
1288
1313
  "rate_tolerance": rate_tolerance,
1289
1314
  "safe_staking": safe_staking,
1290
1315
  "allow_partial_stake": allow_partial_stake,
1316
+ "dashboard_path": dashboard_path,
1291
1317
  }
1292
1318
 
1293
1319
  # If no specific argument is provided, iterate over all
@@ -2937,7 +2963,7 @@ class CLIManager:
2937
2963
  ),
2938
2964
  exit_early=False,
2939
2965
  )
2940
- if selected_hotkey is None:
2966
+ if not selected_hotkey:
2941
2967
  print_error("No delegate selected. Exiting.")
2942
2968
  raise typer.Exit()
2943
2969
  include_hotkeys = selected_hotkey
@@ -3048,14 +3074,12 @@ class CLIManager:
3048
3074
  False,
3049
3075
  "--unstake-all",
3050
3076
  "--all",
3051
- hidden=True,
3052
3077
  help="When set, this command unstakes all staked TAO + Alpha from the all hotkeys.",
3053
3078
  ),
3054
3079
  unstake_all_alpha: bool = typer.Option(
3055
3080
  False,
3056
3081
  "--unstake-all-alpha",
3057
3082
  "--all-alpha",
3058
- hidden=True,
3059
3083
  help="When set, this command unstakes all staked Alpha from the all hotkeys.",
3060
3084
  ),
3061
3085
  amount: float = typer.Option(
@@ -3337,7 +3361,7 @@ class CLIManager:
3337
3361
  network: Optional[list[str]] = Options.network,
3338
3362
  wallet_name: Optional[str] = Options.wallet_name,
3339
3363
  wallet_path: Optional[str] = Options.wallet_path,
3340
- wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3364
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey_ss58,
3341
3365
  origin_netuid: Optional[int] = typer.Option(
3342
3366
  None, "--origin-netuid", help="Origin netuid"
3343
3367
  ),
@@ -3357,6 +3381,8 @@ class CLIManager:
3357
3381
  False, "--stake-all", "--all", help="Stake all", prompt=False
3358
3382
  ),
3359
3383
  prompt: bool = Options.prompt,
3384
+ quiet: bool = Options.quiet,
3385
+ verbose: bool = Options.verbose,
3360
3386
  ):
3361
3387
  """
3362
3388
  Move staked TAO between hotkeys while keeping the same coldkey ownership.
@@ -3378,6 +3404,7 @@ class CLIManager:
3378
3404
 
3379
3405
  [green]$[/green] btcli stake move
3380
3406
  """
3407
+ self.verbosity_handler(quiet, verbose)
3381
3408
  console.print(
3382
3409
  "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]"
3383
3410
  )
@@ -3490,7 +3517,7 @@ class CLIManager:
3490
3517
  network: Optional[list[str]] = Options.network,
3491
3518
  wallet_name: Optional[str] = Options.wallet_name,
3492
3519
  wallet_path: Optional[str] = Options.wallet_path,
3493
- wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3520
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey_ss58,
3494
3521
  origin_netuid: Optional[int] = typer.Option(
3495
3522
  None,
3496
3523
  "--origin-netuid",
@@ -3514,6 +3541,9 @@ class CLIManager:
3514
3541
  "-a",
3515
3542
  help="Amount of stake to transfer",
3516
3543
  ),
3544
+ stake_all: bool = typer.Option(
3545
+ False, "--stake-all", "--all", help="Stake all", prompt=False
3546
+ ),
3517
3547
  prompt: bool = Options.prompt,
3518
3548
  quiet: bool = Options.quiet,
3519
3549
  verbose: bool = Options.verbose,
@@ -3531,6 +3561,8 @@ class CLIManager:
3531
3561
  - The destination subnet (--dest-netuid)
3532
3562
  - The destination wallet/address (--dest)
3533
3563
  - The amount to transfer (--amount)
3564
+ - The origin wallet (--wallet-name)
3565
+ - The origin hotkey wallet/address (--wallet-hotkey)
3534
3566
 
3535
3567
  If no arguments are provided, an interactive selection menu will be shown.
3536
3568
 
@@ -3539,14 +3571,37 @@ class CLIManager:
3539
3571
  Transfer 100 TAO from subnet 1 to subnet 2:
3540
3572
  [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest wallet2 --amount 100
3541
3573
 
3542
- Using SS58 address:
3574
+ Using Destination SS58 address:
3543
3575
  [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --amount 100
3576
+
3577
+ Using Origin hotkey SS58 address (useful when transferring stake from a delegate):
3578
+ [green]$[/green] btcli stake transfer --wallet-hotkey 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --wallet-name sample_wallet
3579
+
3580
+ Transfer all available stake from origin hotkey:
3581
+ [green]$[/green] btcli stake transfer --all --origin-netuid 1 --dest-netuid 2
3544
3582
  """
3545
3583
  console.print(
3546
3584
  "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]"
3547
3585
  )
3548
3586
  self.verbosity_handler(quiet, verbose)
3549
3587
 
3588
+ if not dest_ss58:
3589
+ dest_ss58 = Prompt.ask(
3590
+ "Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3591
+ )
3592
+
3593
+ if is_valid_ss58_address(dest_ss58):
3594
+ dest_ss58 = dest_ss58
3595
+ else:
3596
+ dest_wallet = self.wallet_ask(
3597
+ dest_ss58,
3598
+ wallet_path,
3599
+ None,
3600
+ ask_for=[WO.NAME, WO.PATH],
3601
+ validate=WV.WALLET,
3602
+ )
3603
+ dest_ss58 = dest_wallet.coldkeypub.ss58_address
3604
+
3550
3605
  if not wallet_name:
3551
3606
  wallet_name = Prompt.ask(
3552
3607
  "Enter the [blue]origin wallet name[/blue]",
@@ -3556,13 +3611,16 @@ class CLIManager:
3556
3611
  wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME]
3557
3612
  )
3558
3613
 
3614
+ interactive_selection = False
3559
3615
  if not wallet_hotkey:
3560
3616
  origin_hotkey = Prompt.ask(
3561
- "Enter the [blue]origin hotkey[/blue] name or "
3562
- "[blue]ss58 address[/blue] where the stake will be moved from",
3563
- default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
3617
+ "Enter the [blue]origin hotkey[/blue] name or ss58 address [bold](stake will be transferred FROM here)[/bold] "
3618
+ "[dim](or press Enter to select from existing stakes)[/dim]"
3564
3619
  )
3565
- if is_valid_ss58_address(origin_hotkey):
3620
+ if origin_hotkey == "":
3621
+ interactive_selection = True
3622
+
3623
+ elif is_valid_ss58_address(origin_hotkey):
3566
3624
  origin_hotkey = origin_hotkey
3567
3625
  else:
3568
3626
  wallet = self.wallet_ask(
@@ -3586,33 +3644,11 @@ class CLIManager:
3586
3644
  )
3587
3645
  origin_hotkey = wallet.hotkey.ss58_address
3588
3646
 
3589
- if not dest_ss58:
3590
- dest_ss58 = Prompt.ask(
3591
- "Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3592
- )
3593
-
3594
- if is_valid_ss58_address(dest_ss58):
3595
- dest_ss58 = dest_ss58
3596
- else:
3597
- dest_wallet = self.wallet_ask(
3598
- dest_ss58,
3599
- wallet_path,
3600
- None,
3601
- ask_for=[WO.NAME, WO.PATH],
3602
- validate=WV.WALLET,
3603
- )
3604
- dest_ss58 = dest_wallet.coldkeypub.ss58_address
3605
-
3606
- interactive_selection = False
3607
- if origin_netuid is None and dest_netuid is None and not amount:
3608
- interactive_selection = True
3609
- else:
3647
+ if not interactive_selection:
3610
3648
  if origin_netuid is None:
3611
3649
  origin_netuid = IntPrompt.ask(
3612
3650
  "Enter the [blue]origin subnet[/blue] (netuid)"
3613
3651
  )
3614
- if not amount:
3615
- amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to transfer")
3616
3652
 
3617
3653
  if dest_netuid is None:
3618
3654
  dest_netuid = IntPrompt.ask(
@@ -3629,6 +3665,7 @@ class CLIManager:
3629
3665
  dest_coldkey_ss58=dest_ss58,
3630
3666
  amount=amount,
3631
3667
  interactive_selection=interactive_selection,
3668
+ stake_all=stake_all,
3632
3669
  prompt=prompt,
3633
3670
  )
3634
3671
  )
@@ -5091,6 +5128,19 @@ class CLIManager:
5091
5128
  wallet_name: str = Options.wallet_name,
5092
5129
  wallet_path: str = Options.wallet_path,
5093
5130
  wallet_hotkey: str = Options.wallet_hotkey,
5131
+ coldkey_ss58: Optional[str] = typer.Option(
5132
+ None,
5133
+ "--coldkey-ss58",
5134
+ "--ss58",
5135
+ help="Coldkey SS58 address to view dashboard for",
5136
+ ),
5137
+ use_wry: bool = typer.Option(
5138
+ False, "--use-wry", help="Use PyWry instead of browser window"
5139
+ ),
5140
+ save_file: bool = typer.Option(
5141
+ False, "--save-file", "--save", help="Save the dashboard HTML file"
5142
+ ),
5143
+ dashboard_path: Optional[str] = Options.dashboard_path,
5094
5144
  quiet: bool = Options.quiet,
5095
5145
  verbose: bool = Options.verbose,
5096
5146
  ):
@@ -5098,13 +5148,40 @@ class CLIManager:
5098
5148
  Display html dashboard with subnets list, stake, and neuron information.
5099
5149
  """
5100
5150
  self.verbosity_handler(quiet, verbose)
5101
- if is_linux():
5151
+ if use_wry and is_linux():
5102
5152
  print_linux_dependency_message()
5103
- wallet = self.wallet_ask(
5104
- wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
5105
- )
5153
+
5154
+ if use_wry and save_file:
5155
+ print_error("Cannot save file when using PyWry.")
5156
+ raise typer.Exit()
5157
+
5158
+ if save_file:
5159
+ if not dashboard_path:
5160
+ dashboard_path = Prompt.ask(
5161
+ "Enter the [blue]path[/blue] where the dashboard HTML file will be saved",
5162
+ default=self.config.get("dashboard_path")
5163
+ or defaults.dashboard.path,
5164
+ )
5165
+
5166
+ if coldkey_ss58:
5167
+ if not is_valid_ss58_address(coldkey_ss58):
5168
+ print_error(f"Invalid SS58 address: {coldkey_ss58}")
5169
+ raise typer.Exit()
5170
+ wallet = None
5171
+ else:
5172
+ wallet = self.wallet_ask(
5173
+ wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
5174
+ )
5175
+
5106
5176
  return self._run_command(
5107
- view.display_network_dashboard(wallet, self.initialize_chain(network))
5177
+ view.display_network_dashboard(
5178
+ wallet=wallet,
5179
+ subtensor=self.initialize_chain(network),
5180
+ use_wry=use_wry,
5181
+ save_file=save_file,
5182
+ dashboard_path=dashboard_path,
5183
+ coldkey_ss58=coldkey_ss58,
5184
+ )
5108
5185
  )
5109
5186
 
5110
5187
  @staticmethod
@@ -138,6 +138,9 @@ class Defaults:
138
138
  record_log = False
139
139
  logging_dir = "~/.bittensor/miners"
140
140
 
141
+ class dashboard:
142
+ path = "~/.bittensor/dashboard/"
143
+
141
144
 
142
145
  defaults = Defaults
143
146
 
@@ -1251,7 +1251,7 @@ class SubtensorInterface:
1251
1251
  if _result is None:
1252
1252
  return Balance(0).set_unit(netuid)
1253
1253
  else:
1254
- return Balance.from_rao(_result).set_unit(int(netuid))
1254
+ return Balance.from_rao(fixed_to_float(_result)).set_unit(int(netuid))
1255
1255
 
1256
1256
  async def get_metagraph_info(
1257
1257
  self, netuid: int, block_hash: Optional[str] = None
@@ -45,17 +45,33 @@ class _Hotkey:
45
45
  self.ss58_address = hotkey_ss58
46
46
 
47
47
 
48
+ class _Coldkeypub:
49
+ def __init__(self, coldkey_ss58=None):
50
+ self.ss58_address = coldkey_ss58
51
+
52
+
48
53
  class WalletLike:
49
- def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None):
54
+ def __init__(
55
+ self,
56
+ name=None,
57
+ hotkey_ss58=None,
58
+ hotkey_str=None,
59
+ coldkeypub_ss58=None,
60
+ ):
50
61
  self.name = name
51
62
  self.hotkey_ss58 = hotkey_ss58
52
63
  self.hotkey_str = hotkey_str
53
64
  self._hotkey = _Hotkey(hotkey_ss58)
65
+ self._coldkeypub = _Coldkeypub(coldkeypub_ss58)
54
66
 
55
67
  @property
56
68
  def hotkey(self):
57
69
  return self._hotkey
58
70
 
71
+ @property
72
+ def coldkeypub(self):
73
+ return self._coldkeypub
74
+
59
75
 
60
76
  def print_console(message: str, colour: str, title: str, console: Console):
61
77
  console.print(
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
2
  from functools import partial
3
3
 
4
- import typer
5
4
  from typing import TYPE_CHECKING, Optional
6
5
  from rich.table import Table
7
6
  from rich.prompt import Confirm, Prompt
@@ -20,7 +19,6 @@ from bittensor_cli.src.bittensor.utils import (
20
19
  unlock_key,
21
20
  )
22
21
  from bittensor_wallet import Wallet
23
- from bittensor_wallet.errors import KeyFileError
24
22
 
25
23
  if TYPE_CHECKING:
26
24
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
@@ -338,7 +336,7 @@ async def stake_add(
338
336
 
339
337
  if prompt:
340
338
  if not Confirm.ask("Would you like to continue?"):
341
- raise typer.Exit()
339
+ return False
342
340
  if not unlock_key(wallet).success:
343
341
  return False
344
342
 
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
2
 
3
3
  from typing import TYPE_CHECKING, Optional
4
- import typer
5
4
 
6
5
  from bittensor_wallet import Wallet
7
6
  from rich.prompt import Prompt
@@ -428,7 +427,7 @@ async def stake_list(
428
427
 
429
428
  if not hotkeys_to_substakes:
430
429
  print_error(f"No stakes found for coldkey ss58: ({coldkey_address})")
431
- raise typer.Exit()
430
+ return
432
431
 
433
432
  if live:
434
433
  # Select one hotkey for live monitoring