bittensor-cli 8.4.3__py3-none-any.whl → 9.0.0rc2__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.
Files changed (30) hide show
  1. bittensor_cli/__init__.py +2 -2
  2. bittensor_cli/cli.py +1508 -1385
  3. bittensor_cli/src/__init__.py +627 -197
  4. bittensor_cli/src/bittensor/balances.py +41 -8
  5. bittensor_cli/src/bittensor/chain_data.py +557 -428
  6. bittensor_cli/src/bittensor/extrinsics/registration.py +161 -47
  7. bittensor_cli/src/bittensor/extrinsics/root.py +14 -8
  8. bittensor_cli/src/bittensor/extrinsics/transfer.py +14 -21
  9. bittensor_cli/src/bittensor/minigraph.py +46 -8
  10. bittensor_cli/src/bittensor/subtensor_interface.py +572 -253
  11. bittensor_cli/src/bittensor/utils.py +326 -75
  12. bittensor_cli/src/commands/stake/__init__.py +154 -0
  13. bittensor_cli/src/commands/stake/children_hotkeys.py +121 -87
  14. bittensor_cli/src/commands/stake/move.py +1000 -0
  15. bittensor_cli/src/commands/stake/stake.py +1637 -1264
  16. bittensor_cli/src/commands/subnets/__init__.py +0 -0
  17. bittensor_cli/src/commands/subnets/price.py +867 -0
  18. bittensor_cli/src/commands/subnets/subnets.py +2055 -0
  19. bittensor_cli/src/commands/sudo.py +529 -26
  20. bittensor_cli/src/commands/wallets.py +234 -544
  21. bittensor_cli/src/commands/weights.py +15 -11
  22. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/METADATA +7 -4
  23. bittensor_cli-9.0.0rc2.dist-info/RECORD +32 -0
  24. bittensor_cli/src/bittensor/async_substrate_interface.py +0 -2748
  25. bittensor_cli/src/commands/root.py +0 -1752
  26. bittensor_cli/src/commands/subnets.py +0 -897
  27. bittensor_cli-8.4.3.dist-info/RECORD +0 -31
  28. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/WHEEL +0 -0
  29. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/entry_points.txt +0 -0
  30. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/top_level.txt +0 -0
@@ -18,15 +18,19 @@ import typing
18
18
  from typing import Optional
19
19
  import subprocess
20
20
 
21
+ import backoff
21
22
  from bittensor_wallet import Wallet
23
+ from bittensor_wallet.errors import KeyFileError
22
24
  from Crypto.Hash import keccak
23
25
  import numpy as np
24
26
  from rich.prompt import Confirm
25
27
  from rich.console import Console
26
28
  from rich.status import Status
27
- from substrateinterface.exceptions import SubstrateRequestException
29
+ from async_substrate_interface.errors import SubstrateRequestException
28
30
 
31
+ from bittensor_cli.src import COLOR_PALETTE
29
32
  from bittensor_cli.src.bittensor.chain_data import NeuronInfo
33
+ from bittensor_cli.src.bittensor.balances import Balance
30
34
  from bittensor_cli.src.bittensor.utils import (
31
35
  console,
32
36
  err_console,
@@ -35,8 +39,6 @@ from bittensor_cli.src.bittensor.utils import (
35
39
  get_human_readable,
36
40
  print_verbose,
37
41
  print_error,
38
- unlock_key,
39
- hex_to_bytes,
40
42
  )
41
43
 
42
44
  if typing.TYPE_CHECKING:
@@ -436,7 +438,7 @@ async def is_hotkey_registered(
436
438
  subtensor: "SubtensorInterface", netuid: int, hotkey_ss58: str
437
439
  ) -> bool:
438
440
  """Checks to see if the hotkey is registered on a given netuid"""
439
- _result = await subtensor.substrate.query(
441
+ _result = await subtensor.query(
440
442
  module="SubtensorModule",
441
443
  storage_function="Uids",
442
444
  params=[netuid, hotkey_ss58],
@@ -487,22 +489,18 @@ async def register_extrinsic(
487
489
  """
488
490
 
489
491
  async def get_neuron_for_pubkey_and_subnet():
490
- uid = await subtensor.substrate.query(
492
+ uid = await subtensor.query(
491
493
  "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
492
494
  )
493
495
  if uid is None:
494
496
  return NeuronInfo.get_null_neuron()
495
497
 
496
- params = [netuid, uid]
497
- json_body = await subtensor.substrate.rpc_request(
498
- method="neuronInfo_getNeuron",
499
- params=params,
498
+ result = await subtensor.neuron_for_uid(
499
+ uid=uid,
500
+ netuid=netuid,
501
+ block_hash=subtensor.substrate.last_block_hash,
500
502
  )
501
-
502
- if not (result := json_body.get("result", None)):
503
- return NeuronInfo.get_null_neuron()
504
-
505
- return NeuronInfo.from_vec_u8(bytes(result))
503
+ return result
506
504
 
507
505
  print_verbose("Checking subnet status")
508
506
  if not await subtensor.subnet_exists(netuid):
@@ -526,9 +524,9 @@ async def register_extrinsic(
526
524
  if prompt:
527
525
  if not Confirm.ask(
528
526
  f"Continue Registration?\n"
529
- f" hotkey ({wallet.hotkey_str}):\t[bold white]{wallet.hotkey.ss58_address}[/bold white]\n"
530
- f" coldkey ({wallet.name}):\t[bold white]{wallet.coldkeypub.ss58_address}[/bold white]\n"
531
- f" network:\t\t[bold white]{subtensor.network}[/bold white]"
527
+ f" hotkey [{COLOR_PALETTE['GENERAL']['HOTKEY']}]({wallet.hotkey_str})[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]:\t[{COLOR_PALETTE['GENERAL']['HOTKEY']}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
528
+ f" coldkey [{COLOR_PALETTE['GENERAL']['COLDKEY']}]({wallet.name})[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]:\t[{COLOR_PALETTE['GENERAL']['COLDKEY']}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]\n"
529
+ f" network:\t\t[{COLOR_PALETTE['GENERAL']['LINKS']}]{subtensor.network}[/{COLOR_PALETTE['GENERAL']['LINKS']}]\n"
532
530
  ):
533
531
  return False
534
532
 
@@ -581,7 +579,7 @@ async def register_extrinsic(
581
579
  )
582
580
  if is_registered:
583
581
  err_console.print(
584
- f":white_heavy_check_mark: [green]Already registered on netuid:{netuid}[/green]"
582
+ f":white_heavy_check_mark: [dark_sea_green3]Already registered on netuid:{netuid}[/dark_sea_green3]"
585
583
  )
586
584
  return True
587
585
 
@@ -618,15 +616,18 @@ async def register_extrinsic(
618
616
  if not success:
619
617
  success, err_msg = (
620
618
  False,
621
- format_error_message(await response.error_message),
619
+ format_error_message(
620
+ await response.error_message,
621
+ substrate=subtensor.substrate,
622
+ ),
622
623
  )
623
624
  # Look error here
624
625
  # https://github.com/opentensor/subtensor/blob/development/pallets/subtensor/src/errors.rs
625
626
 
626
627
  if "HotKeyAlreadyRegisteredInSubNet" in err_msg:
627
628
  console.print(
628
- f":white_heavy_check_mark: [green]Already Registered on "
629
- f"[bold]subnet:{netuid}[/bold][/green]"
629
+ f":white_heavy_check_mark: [dark_sea_green3]Already Registered on "
630
+ f"[bold]subnet:{netuid}[/bold][/dark_sea_green3]"
630
631
  )
631
632
  return True
632
633
  err_console.print(
@@ -644,7 +645,7 @@ async def register_extrinsic(
644
645
  )
645
646
  if is_registered:
646
647
  console.print(
647
- ":white_heavy_check_mark: [green]Registered[/green]"
648
+ ":white_heavy_check_mark: [dark_sea_green3]Registered[/dark_sea_green3]"
648
649
  )
649
650
  return True
650
651
  else:
@@ -671,6 +672,117 @@ async def register_extrinsic(
671
672
  return False
672
673
 
673
674
 
675
+ async def burned_register_extrinsic(
676
+ subtensor: "SubtensorInterface",
677
+ wallet: Wallet,
678
+ netuid: int,
679
+ old_balance: Balance,
680
+ wait_for_inclusion: bool = True,
681
+ wait_for_finalization: bool = True,
682
+ prompt: bool = False,
683
+ ) -> bool:
684
+ """Registers the wallet to chain by recycling TAO.
685
+
686
+ :param subtensor: The SubtensorInterface object to use for the call, initialized
687
+ :param wallet: Bittensor wallet object.
688
+ :param netuid: The `netuid` of the subnet to register on.
689
+ :param old_balance: The wallet balance prior to the registration burn.
690
+ :param wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`, or returns
691
+ `False` if the extrinsic fails to enter the block within the timeout.
692
+ :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
693
+ or returns `False` if the extrinsic fails to be finalized within the timeout.
694
+ :param prompt: If `True`, the call waits for confirmation from the user before proceeding.
695
+
696
+ :return: Flag is `True` if extrinsic was finalized or included in the block. If we did not wait for
697
+ finalization/inclusion, the response is `True`.
698
+ """
699
+
700
+ try:
701
+ wallet.unlock_coldkey()
702
+ except KeyFileError:
703
+ err_console.print("Error decrypting coldkey (possibly incorrect password)")
704
+ return False
705
+
706
+ with console.status(
707
+ f":satellite: Checking Account on [bold]subnet:{netuid}[/bold]...",
708
+ spinner="aesthetic",
709
+ ) as status:
710
+ my_uid = await subtensor.query(
711
+ "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
712
+ )
713
+
714
+ print_verbose("Checking if already registered", status)
715
+ neuron = await subtensor.neuron_for_uid(
716
+ uid=my_uid,
717
+ netuid=netuid,
718
+ block_hash=subtensor.substrate.last_block_hash,
719
+ )
720
+
721
+ if not neuron.is_null:
722
+ console.print(
723
+ ":white_heavy_check_mark: [dark_sea_green3]Already Registered[/dark_sea_green3]:\n"
724
+ f"uid: [{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]{neuron.uid}[/{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]\n"
725
+ f"netuid: [{COLOR_PALETTE['GENERAL']['NETUID']}]{neuron.netuid}[/{COLOR_PALETTE['GENERAL']['NETUID']}]\n"
726
+ f"hotkey: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]{neuron.hotkey}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
727
+ f"coldkey: [{COLOR_PALETTE['GENERAL']['COLDKEY']}]{neuron.coldkey}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]"
728
+ )
729
+ return True
730
+
731
+ with console.status(
732
+ ":satellite: Recycling TAO for Registration...", spinner="aesthetic"
733
+ ):
734
+ call = await subtensor.substrate.compose_call(
735
+ call_module="SubtensorModule",
736
+ call_function="burned_register",
737
+ call_params={
738
+ "netuid": netuid,
739
+ "hotkey": wallet.hotkey.ss58_address,
740
+ },
741
+ )
742
+ success, err_msg = await subtensor.sign_and_send_extrinsic(
743
+ call, wallet, wait_for_inclusion, wait_for_finalization
744
+ )
745
+
746
+ if not success:
747
+ err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
748
+ await asyncio.sleep(0.5)
749
+ return False
750
+ # Successful registration, final check for neuron and pubkey
751
+ else:
752
+ with console.status(":satellite: Checking Balance...", spinner="aesthetic"):
753
+ block_hash = await subtensor.substrate.get_chain_head()
754
+ new_balance, netuids_for_hotkey, my_uid = await asyncio.gather(
755
+ subtensor.get_balance(
756
+ wallet.coldkeypub.ss58_address,
757
+ block_hash=block_hash,
758
+ reuse_block=False,
759
+ ),
760
+ subtensor.get_netuids_for_hotkey(
761
+ wallet.hotkey.ss58_address, block_hash=block_hash
762
+ ),
763
+ subtensor.query(
764
+ "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
765
+ ),
766
+ )
767
+
768
+ console.print(
769
+ "Balance:\n"
770
+ f" [blue]{old_balance}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_balance}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
771
+ )
772
+
773
+ if len(netuids_for_hotkey) > 0:
774
+ console.print(
775
+ f":white_heavy_check_mark: [green]Registered on netuid {netuid} with UID {my_uid}[/green]"
776
+ )
777
+ return True
778
+ else:
779
+ # neuron not found, try again
780
+ err_console.print(
781
+ ":cross_mark: [red]Unknown error. Neuron not found.[/red]"
782
+ )
783
+ return False
784
+
785
+
674
786
  async def run_faucet_extrinsic(
675
787
  subtensor: "SubtensorInterface",
676
788
  wallet: Wallet,
@@ -684,7 +796,7 @@ async def run_faucet_extrinsic(
684
796
  tpb: int = 256,
685
797
  num_processes: Optional[int] = None,
686
798
  update_interval: Optional[int] = None,
687
- log_verbose: bool = True,
799
+ log_verbose: bool = False,
688
800
  max_successes: int = 3,
689
801
  ) -> tuple[bool, str]:
690
802
  r"""Runs a continual POW to get a faucet of TAO on the test net.
@@ -723,8 +835,10 @@ async def run_faucet_extrinsic(
723
835
  return False, "Requires torch"
724
836
 
725
837
  # Unlock coldkey
726
- if not (unlock_status := unlock_key(wallet, print_out=False)).success:
727
- return False, unlock_status.message
838
+ try:
839
+ wallet.unlock_coldkey()
840
+ except KeyFileError:
841
+ return False, "There was an error unlocking your coldkey"
728
842
 
729
843
  # Get previous balance.
730
844
  old_balance = await subtensor.get_balance(wallet.coldkeypub.ss58_address)
@@ -732,12 +846,8 @@ async def run_faucet_extrinsic(
732
846
  # Attempt rolling registration.
733
847
  attempts = 1
734
848
  successes = 1
735
- pow_result: Optional[POWSolution]
736
849
  while True:
737
850
  try:
738
- account_nonce = await subtensor.substrate.get_account_nonce(
739
- wallet.coldkey.ss58_address
740
- )
741
851
  pow_result = None
742
852
  while pow_result is None or await pow_result.is_stale(subtensor=subtensor):
743
853
  # Solve latest POW.
@@ -746,7 +856,7 @@ async def run_faucet_extrinsic(
746
856
  if prompt:
747
857
  err_console.print("CUDA is not available.")
748
858
  return False, "CUDA is not available."
749
- pow_result = await create_pow(
859
+ pow_result: Optional[POWSolution] = await create_pow(
750
860
  subtensor,
751
861
  wallet,
752
862
  -1,
@@ -759,7 +869,7 @@ async def run_faucet_extrinsic(
759
869
  log_verbose=log_verbose,
760
870
  )
761
871
  else:
762
- pow_result = await create_pow(
872
+ pow_result: Optional[POWSolution] = await create_pow(
763
873
  subtensor,
764
874
  wallet,
765
875
  -1,
@@ -779,7 +889,7 @@ async def run_faucet_extrinsic(
779
889
  },
780
890
  )
781
891
  extrinsic = await subtensor.substrate.create_signed_extrinsic(
782
- call=call, keypair=wallet.coldkey, nonce=account_nonce
892
+ call=call, keypair=wallet.coldkey
783
893
  )
784
894
  response = await subtensor.substrate.submit_extrinsic(
785
895
  extrinsic,
@@ -792,7 +902,7 @@ async def run_faucet_extrinsic(
792
902
  if not await response.is_success:
793
903
  err_console.print(
794
904
  f":cross_mark: [red]Failed[/red]: "
795
- f"{format_error_message(await response.error_message)}"
905
+ f"{format_error_message(await response.error_message, subtensor.substrate)}"
796
906
  )
797
907
  if attempts == max_allowed_attempts:
798
908
  raise MaxAttemptsException
@@ -806,8 +916,8 @@ async def run_faucet_extrinsic(
806
916
  wallet.coldkeypub.ss58_address
807
917
  )
808
918
  console.print(
809
- f"Balance: [blue]{old_balance[wallet.coldkeypub.ss58_address]}[/blue] :arrow_right:"
810
- f" [green]{new_balance[wallet.coldkeypub.ss58_address]}[/green]"
919
+ f"Balance: [blue]{old_balance}[/blue] :arrow_right:"
920
+ f" [green]{new_balance}[/green]"
811
921
  )
812
922
  old_balance = new_balance
813
923
 
@@ -864,7 +974,7 @@ async def _check_for_newest_block_and_update(
864
974
  block_number, difficulty, block_hash = await _get_block_with_retry(
865
975
  subtensor=subtensor, netuid=netuid
866
976
  )
867
- block_bytes = hex_to_bytes(block_hash)
977
+ block_bytes = bytes.fromhex(block_hash[2:])
868
978
 
869
979
  update_curr_block(
870
980
  curr_diff,
@@ -912,14 +1022,11 @@ async def _block_solver(
912
1022
  limit = int(math.pow(2, 256)) - 1
913
1023
 
914
1024
  # Establish communication queues
915
- ## See the _Solver class for more information on the queues.
1025
+ # See the _Solver class for more information on the queues.
916
1026
  stop_event = Event()
917
1027
  stop_event.clear()
918
1028
 
919
1029
  solution_queue = Queue()
920
- if cuda:
921
- num_processes = len(dev_id)
922
-
923
1030
  finished_queues = [Queue() for _ in range(num_processes)]
924
1031
  check_block = Lock()
925
1032
 
@@ -928,7 +1035,8 @@ async def _block_solver(
928
1035
  )
929
1036
 
930
1037
  if cuda:
931
- ## Create a worker per CUDA device
1038
+ # Create a worker per CUDA device
1039
+ num_processes = len(dev_id)
932
1040
  solvers = [
933
1041
  _CUDASolver(
934
1042
  i,
@@ -971,7 +1079,7 @@ async def _block_solver(
971
1079
  subtensor=subtensor, netuid=netuid
972
1080
  )
973
1081
 
974
- block_bytes = hex_to_bytes(block_hash)
1082
+ block_bytes = bytes.fromhex(block_hash[2:])
975
1083
  old_block_number = block_number
976
1084
  # Set to current block
977
1085
  _update_curr_block(
@@ -1246,9 +1354,11 @@ def _terminate_workers_and_wait_for_exit(
1246
1354
  worker.terminate()
1247
1355
 
1248
1356
 
1357
+ # TODO verify this works with async
1358
+ @backoff.on_exception(backoff.constant, Exception, interval=1, max_tries=3)
1249
1359
  async def _get_block_with_retry(
1250
1360
  subtensor: "SubtensorInterface", netuid: int
1251
- ) -> tuple[int, int, str]:
1361
+ ) -> tuple[int, int, bytes]:
1252
1362
  """
1253
1363
  Gets the current block number, difficulty, and block hash from the substrate node.
1254
1364
 
@@ -1260,9 +1370,10 @@ async def _get_block_with_retry(
1260
1370
  :raises Exception: If the block hash is None.
1261
1371
  :raises ValueError: If the difficulty is None.
1262
1372
  """
1263
- block = await subtensor.substrate.get_block()
1264
- block_hash = block["header"]["hash"]
1265
- block_number = block["header"]["number"]
1373
+ block_number = await subtensor.substrate.get_block_number(None)
1374
+ block_hash = await subtensor.substrate.get_block_hash(
1375
+ block_number
1376
+ ) # TODO check if I need to do all this
1266
1377
  try:
1267
1378
  difficulty = (
1268
1379
  1_000_000
@@ -1635,7 +1746,10 @@ async def swap_hotkey_extrinsic(
1635
1746
  )
1636
1747
  return False
1637
1748
 
1638
- if not unlock_key(wallet).success:
1749
+ try:
1750
+ wallet.unlock_coldkey()
1751
+ except KeyFileError:
1752
+ err_console.print("Error decrypting coldkey (possibly incorrect password)")
1639
1753
  return False
1640
1754
 
1641
1755
  if prompt:
@@ -21,12 +21,13 @@ import time
21
21
  from typing import Union, List, TYPE_CHECKING
22
22
 
23
23
  from bittensor_wallet import Wallet, Keypair
24
+ from bittensor_wallet.errors import KeyFileError
24
25
  import numpy as np
25
26
  from numpy.typing import NDArray
26
27
  from rich.prompt import Confirm
27
28
  from rich.table import Table, Column
28
29
  from scalecodec import ScaleBytes, U16, Vec
29
- from substrateinterface.exceptions import SubstrateRequestException
30
+ from async_substrate_interface.errors import SubstrateRequestException
30
31
 
31
32
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
32
33
  from bittensor_cli.src.bittensor.extrinsics.registration import is_hotkey_registered
@@ -36,7 +37,6 @@ from bittensor_cli.src.bittensor.utils import (
36
37
  u16_normalized_float,
37
38
  print_verbose,
38
39
  format_error_message,
39
- unlock_key,
40
40
  )
41
41
 
42
42
  if TYPE_CHECKING:
@@ -306,7 +306,10 @@ async def root_register_extrinsic(
306
306
  the response is `True`.
307
307
  """
308
308
 
309
- if not unlock_key(wallet).success:
309
+ try:
310
+ wallet.unlock_coldkey()
311
+ except KeyFileError:
312
+ err_console.print("Error decrypting coldkey (possibly incorrect password)")
310
313
  return False
311
314
 
312
315
  print_verbose(f"Checking if hotkey ({wallet.hotkey_str}) is registered on root")
@@ -339,7 +342,7 @@ async def root_register_extrinsic(
339
342
 
340
343
  # Successful registration, final check for neuron and pubkey
341
344
  else:
342
- uid = await subtensor.substrate.query(
345
+ uid = await subtensor.query(
343
346
  module="SubtensorModule",
344
347
  storage_function="Uids",
345
348
  params=[0, wallet.hotkey.ss58_address],
@@ -416,7 +419,7 @@ async def set_root_weights_extrinsic(
416
419
  else:
417
420
  return False, await response.error_message
418
421
 
419
- my_uid = await subtensor.substrate.query(
422
+ my_uid = await subtensor.query(
420
423
  "SubtensorModule", "Uids", [0, wallet.hotkey.ss58_address]
421
424
  )
422
425
 
@@ -424,7 +427,10 @@ async def set_root_weights_extrinsic(
424
427
  err_console.print("Your hotkey is not registered to the root network")
425
428
  return False
426
429
 
427
- if not unlock_key(wallet).success:
430
+ try:
431
+ wallet.unlock_coldkey()
432
+ except KeyFileError:
433
+ err_console.print("Error decrypting coldkey (possibly incorrect password)")
428
434
  return False
429
435
 
430
436
  # First convert types.
@@ -486,11 +492,11 @@ async def set_root_weights_extrinsic(
486
492
  console.print(":white_heavy_check_mark: [green]Finalized[/green]")
487
493
  return True
488
494
  else:
489
- fmt_err = format_error_message(error_message)
495
+ fmt_err = format_error_message(error_message, subtensor.substrate)
490
496
  err_console.print(f":cross_mark: [red]Failed[/red]: {fmt_err}")
491
497
  return False
492
498
 
493
499
  except SubstrateRequestException as e:
494
- fmt_err = format_error_message(e)
500
+ fmt_err = format_error_message(e, subtensor.substrate)
495
501
  err_console.print(":cross_mark: [red]Failed[/red]: error:{}".format(fmt_err))
496
502
  return False
@@ -1,8 +1,9 @@
1
1
  import asyncio
2
2
 
3
3
  from bittensor_wallet import Wallet
4
+ from bittensor_wallet.errors import KeyFileError
4
5
  from rich.prompt import Confirm
5
- from substrateinterface.exceptions import SubstrateRequestException
6
+ from async_substrate_interface.errors import SubstrateRequestException
6
7
 
7
8
  from bittensor_cli.src import NETWORK_EXPLORER_MAP
8
9
  from bittensor_cli.src.bittensor.balances import Balance
@@ -14,8 +15,6 @@ from bittensor_cli.src.bittensor.utils import (
14
15
  format_error_message,
15
16
  get_explorer_url_for_network,
16
17
  is_valid_bittensor_address_or_public_key,
17
- print_error,
18
- unlock_key,
19
18
  )
20
19
 
21
20
 
@@ -24,7 +23,6 @@ async def transfer_extrinsic(
24
23
  wallet: Wallet,
25
24
  destination: str,
26
25
  amount: Balance,
27
- transfer_all: bool = False,
28
26
  wait_for_inclusion: bool = True,
29
27
  wait_for_finalization: bool = False,
30
28
  keep_alive: bool = True,
@@ -36,7 +34,6 @@ async def transfer_extrinsic(
36
34
  :param wallet: Bittensor wallet object to make transfer from.
37
35
  :param destination: Destination public key address (ss58_address or ed25519) of recipient.
38
36
  :param amount: Amount to stake as Bittensor balance.
39
- :param transfer_all: Whether to transfer all funds from this wallet to the destination address.
40
37
  :param wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`,
41
38
  or returns `False` if the extrinsic fails to enter the block within the timeout.
42
39
  :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning
@@ -64,14 +61,14 @@ async def transfer_extrinsic(
64
61
  call=call, keypair=wallet.coldkeypub
65
62
  )
66
63
  except SubstrateRequestException as e:
67
- payment_info = {"partialFee": int(2e7)} # assume 0.02 Tao
64
+ payment_info = {"partial_fee": int(2e7)} # assume 0.02 Tao
68
65
  err_console.print(
69
- f":cross_mark: [red]Failed to get payment info[/red]:[bold white]\n"
70
- f" {format_error_message(e)}[/bold white]\n"
71
- f" Defaulting to default transfer fee: {payment_info['partialFee']}"
66
+ f":cross_mark: [red]Failed to get payment info[/red]:\n"
67
+ f" [bold white]{format_error_message(e)}[/bold white]\n"
68
+ f" Defaulting to default transfer fee: {payment_info['partial_fee']}"
72
69
  )
73
70
 
74
- return Balance.from_rao(payment_info["partialFee"])
71
+ return Balance.from_rao(payment_info["partial_fee"])
75
72
 
76
73
  async def do_transfer() -> tuple[bool, str, str]:
77
74
  """
@@ -104,7 +101,7 @@ async def transfer_extrinsic(
104
101
  return (
105
102
  False,
106
103
  "",
107
- format_error_message(await response.error_message),
104
+ format_error_message(await response.error_message, subtensor.substrate),
108
105
  )
109
106
 
110
107
  # Validate destination address.
@@ -115,7 +112,10 @@ async def transfer_extrinsic(
115
112
  return False
116
113
  console.print(f"[dark_orange]Initiating transfer on network: {subtensor.network}")
117
114
  # Unlock wallet coldkey.
118
- if not unlock_key(wallet).success:
115
+ try:
116
+ wallet.unlock_coldkey()
117
+ except KeyFileError:
118
+ err_console.print("Error decrypting coldkey (possibly incorrect password)")
119
119
  return False
120
120
 
121
121
  # Check balance.
@@ -126,13 +126,12 @@ async def transfer_extrinsic(
126
126
  # check existential deposit and fee
127
127
  print_verbose("Fetching existential and fee", status)
128
128
  block_hash = await subtensor.substrate.get_chain_head()
129
- account_balance_, existential_deposit = await asyncio.gather(
129
+ account_balance, existential_deposit = await asyncio.gather(
130
130
  subtensor.get_balance(
131
131
  wallet.coldkeypub.ss58_address, block_hash=block_hash
132
132
  ),
133
133
  subtensor.get_existential_deposit(block_hash=block_hash),
134
134
  )
135
- account_balance = account_balance_[wallet.coldkeypub.ss58_address]
136
135
  fee = await get_transfer_fee()
137
136
 
138
137
  if not keep_alive:
@@ -140,12 +139,6 @@ async def transfer_extrinsic(
140
139
  existential_deposit = Balance(0)
141
140
 
142
141
  # Check if we have enough balance.
143
- if transfer_all is True:
144
- amount = account_balance - fee - existential_deposit
145
- if amount < Balance(0):
146
- print_error("Not enough balance to transfer")
147
- return False
148
-
149
142
  if account_balance < (amount + fee + existential_deposit):
150
143
  err_console.print(
151
144
  ":cross_mark: [bold red]Not enough balance[/bold red]:\n\n"
@@ -194,7 +187,7 @@ async def transfer_extrinsic(
194
187
  )
195
188
  console.print(
196
189
  f"Balance:\n"
197
- f" [blue]{account_balance}[/blue] :arrow_right: [green]{new_balance[wallet.coldkeypub.ss58_address]}[/green]"
190
+ f" [blue]{account_balance}[/blue] :arrow_right: [green]{new_balance}[/green]"
198
191
  )
199
192
  return True
200
193
 
@@ -3,7 +3,7 @@ import asyncio
3
3
  import numpy as np
4
4
  from numpy.typing import NDArray
5
5
 
6
- from bittensor_cli.src.bittensor.chain_data import NeuronInfo
6
+ from bittensor_cli.src.bittensor.chain_data import NeuronInfo, SubnetState
7
7
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
8
8
  from bittensor_cli.src.bittensor.utils import (
9
9
  convert_root_weight_uids_and_vals_to_tensor,
@@ -18,6 +18,7 @@ class MiniGraph:
18
18
  netuid: int,
19
19
  neurons: list[NeuronInfo],
20
20
  subtensor: "SubtensorInterface",
21
+ subnet_state: "SubnetState",
21
22
  block: int,
22
23
  ):
23
24
  self.neurons = neurons
@@ -62,12 +63,14 @@ class MiniGraph:
62
63
  self.validator_trust = self._create_tensor(
63
64
  [neuron.validator_trust for neuron in self.neurons], dtype=np.float32
64
65
  )
65
- self.total_stake = self._create_tensor(
66
- [neuron.total_stake.tao for neuron in self.neurons], dtype=np.float32
67
- )
68
- self.stake = self._create_tensor(
69
- [neuron.stake for neuron in self.neurons], dtype=np.float32
66
+
67
+ # Fetch stakes from subnet_state until we get updated data in NeuronInfo
68
+ global_stake_list, local_stake_list, stake_weights_list = self._process_stakes(
69
+ neurons, subnet_state
70
70
  )
71
+ self.global_stake = self._create_tensor(global_stake_list, dtype=np.float32)
72
+ self.local_stake = self._create_tensor(local_stake_list, dtype=np.float32)
73
+ self.stake_weights = self._create_tensor(stake_weights_list, dtype=np.float32)
71
74
 
72
75
  async def __aenter__(self):
73
76
  if not self.weights:
@@ -120,6 +123,41 @@ class MiniGraph:
120
123
  [neuron.bonds for neuron in self.neurons], "bonds"
121
124
  )
122
125
 
126
+ def _process_stakes(
127
+ self,
128
+ neurons: list[NeuronInfo],
129
+ subnet_state: SubnetState,
130
+ ) -> tuple[list[float], list[float], list[float]]:
131
+ """
132
+ Processes the global_stake, local_stake, and stake_weights based on the neuron's hotkey.
133
+
134
+ Args:
135
+ neurons (List[NeuronInfo]): List of neurons.
136
+ subnet_state (SubnetState): The subnet state containing stake information.
137
+
138
+ Returns:
139
+ tuple[list[float], list[float], list[float]]: Lists of global_stake, local_stake, and stake_weights.
140
+ """
141
+ global_stake_list = []
142
+ local_stake_list = []
143
+ stake_weights_list = []
144
+ hotkey_to_index = {
145
+ hotkey: idx for idx, hotkey in enumerate(subnet_state.hotkeys)
146
+ }
147
+
148
+ for neuron in neurons:
149
+ idx = hotkey_to_index.get(neuron.hotkey)
150
+ if idx is not None:
151
+ global_stake_list.append(subnet_state.global_stake[idx].tao)
152
+ local_stake_list.append(subnet_state.local_stake[idx].tao)
153
+ stake_weights_list.append(subnet_state.stake_weight[idx])
154
+ else:
155
+ global_stake_list.append(0.0)
156
+ local_stake_list.append(0.0)
157
+ stake_weights_list.append(0.0)
158
+
159
+ return global_stake_list, local_stake_list, stake_weights_list
160
+
123
161
  def _process_weights_or_bonds(self, data, attribute: str) -> NDArray:
124
162
  """
125
163
  Processes the raw weights or bonds data and converts it into a structured tensor format. This method handles
@@ -177,7 +215,7 @@ class MiniGraph:
177
215
  """
178
216
 
179
217
  async def get_total_subnets():
180
- _result = await self.subtensor.substrate.query(
218
+ _result = await self.subtensor.query(
181
219
  module="SubtensorModule",
182
220
  storage_function="TotalNetworks",
183
221
  params=[],
@@ -186,7 +224,7 @@ class MiniGraph:
186
224
  return _result
187
225
 
188
226
  async def get_subnets():
189
- _result = await self.subtensor.substrate.query(
227
+ _result = await self.subtensor.query(
190
228
  module="SubtensorModule",
191
229
  storage_function="TotalNetworks",
192
230
  )