bittensor-cli 9.2.0__py3-none-any.whl → 9.4.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.
@@ -749,7 +749,9 @@ class DynamicInfo(InfoBase):
749
749
  self, tao: Balance
750
750
  ) -> tuple[Balance, Balance, float]:
751
751
  """
752
- Returns an estimate of how much Alpha would a staker receive if they stake their tao using the current pool state.
752
+ Returns an estimate of how much Alpha a staker would receive if they stake their tao using the current pool
753
+ state.
754
+
753
755
  Args:
754
756
  tao: Amount of TAO to stake.
755
757
  Returns:
@@ -792,7 +794,9 @@ class DynamicInfo(InfoBase):
792
794
  self, alpha: Balance
793
795
  ) -> tuple[Balance, Balance, float]:
794
796
  """
795
- Returns an estimate of how much TAO would a staker receive if they unstake their alpha using the current pool state.
797
+ Returns an estimate of how much TAO a staker would receive if they unstake their alpha using the current pool
798
+ state.
799
+
796
800
  Args:
797
801
  alpha: Amount of Alpha to stake.
798
802
  Returns:
@@ -524,9 +524,11 @@ async def register_extrinsic(
524
524
  if prompt:
525
525
  if not Confirm.ask(
526
526
  f"Continue Registration?\n"
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"
527
+ f" hotkey [{COLOR_PALETTE.G.HK}]({wallet.hotkey_str})[/{COLOR_PALETTE.G.HK}]:"
528
+ f"\t[{COLOR_PALETTE.G.HK}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n"
529
+ f" coldkey [{COLOR_PALETTE.G.CK}]({wallet.name})[/{COLOR_PALETTE.G.CK}]:"
530
+ f"\t[{COLOR_PALETTE.G.CK}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE.G.CK}]\n"
531
+ f" network:\t\t[{COLOR_PALETTE.G.LINKS}]{subtensor.network}[/{COLOR_PALETTE.G.LINKS}]\n"
530
532
  ):
531
533
  return False
532
534
 
@@ -611,7 +613,6 @@ async def register_extrinsic(
611
613
  if not wait_for_finalization and not wait_for_inclusion:
612
614
  success, err_msg = True, ""
613
615
  else:
614
- await response.process_events()
615
616
  success = await response.is_success
616
617
  if not success:
617
618
  success, err_msg = (
@@ -676,8 +677,9 @@ async def burned_register_extrinsic(
676
677
  old_balance: Balance,
677
678
  wait_for_inclusion: bool = True,
678
679
  wait_for_finalization: bool = True,
680
+ era: Optional[int] = None,
679
681
  prompt: bool = False,
680
- ) -> bool:
682
+ ) -> tuple[bool, str]:
681
683
  """Registers the wallet to chain by recycling TAO.
682
684
 
683
685
  :param subtensor: The SubtensorInterface object to use for the call, initialized
@@ -688,10 +690,11 @@ async def burned_register_extrinsic(
688
690
  `False` if the extrinsic fails to enter the block within the timeout.
689
691
  :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
690
692
  or returns `False` if the extrinsic fails to be finalized within the timeout.
693
+ :param era: the period (in blocks) for which the transaction should remain valid.
691
694
  :param prompt: If `True`, the call waits for confirmation from the user before proceeding.
692
695
 
693
- :return: Flag is `True` if extrinsic was finalized or included in the block. If we did not wait for
694
- finalization/inclusion, the response is `True`.
696
+ :return: (success, msg), where success is `True` if extrinsic was finalized or included in the block. If we did not
697
+ wait for finalization/inclusion, the response is `True`.
695
698
  """
696
699
 
697
700
  if not (unlock_status := unlock_key(wallet, print_out=False)).success:
@@ -704,23 +707,42 @@ async def burned_register_extrinsic(
704
707
  my_uid = await subtensor.query(
705
708
  "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
706
709
  )
710
+ block_hash = await subtensor.substrate.get_chain_head()
707
711
 
708
712
  print_verbose("Checking if already registered", status)
709
713
  neuron = await subtensor.neuron_for_uid(
710
- uid=my_uid,
711
- netuid=netuid,
712
- block_hash=subtensor.substrate.last_block_hash,
714
+ uid=my_uid, netuid=netuid, block_hash=block_hash
713
715
  )
716
+ if not era:
717
+ current_block, tempo, blocks_since_last_step = await asyncio.gather(
718
+ subtensor.substrate.get_block_number(block_hash=block_hash),
719
+ subtensor.get_hyperparameter(
720
+ "Tempo", netuid=netuid, block_hash=block_hash
721
+ ),
722
+ subtensor.query(
723
+ "SubtensorModule",
724
+ "BlocksSinceLastStep",
725
+ [netuid],
726
+ block_hash=block_hash,
727
+ ),
728
+ )
729
+ validity_period = tempo - blocks_since_last_step
730
+ era_ = {
731
+ "period": validity_period,
732
+ "current": current_block,
733
+ }
734
+ else:
735
+ era_ = {"period": era}
714
736
 
715
737
  if not neuron.is_null:
716
738
  console.print(
717
739
  ":white_heavy_check_mark: [dark_sea_green3]Already Registered[/dark_sea_green3]:\n"
718
- f"uid: [{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]{neuron.uid}[/{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]\n"
719
- f"netuid: [{COLOR_PALETTE['GENERAL']['NETUID']}]{neuron.netuid}[/{COLOR_PALETTE['GENERAL']['NETUID']}]\n"
720
- f"hotkey: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]{neuron.hotkey}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
721
- f"coldkey: [{COLOR_PALETTE['GENERAL']['COLDKEY']}]{neuron.coldkey}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]"
740
+ f"uid: [{COLOR_PALETTE.G.NETUID_EXTRA}]{neuron.uid}[/{COLOR_PALETTE.G.NETUID_EXTRA}]\n"
741
+ f"netuid: [{COLOR_PALETTE.G.NETUID}]{neuron.netuid}[/{COLOR_PALETTE.G.NETUID}]\n"
742
+ f"hotkey: [{COLOR_PALETTE.G.HK}]{neuron.hotkey}[/{COLOR_PALETTE.G.HK}]\n"
743
+ f"coldkey: [{COLOR_PALETTE.G.CK}]{neuron.coldkey}[/{COLOR_PALETTE.G.CK}]"
722
744
  )
723
- return True
745
+ return True, "Already registered"
724
746
 
725
747
  with console.status(
726
748
  ":satellite: Recycling TAO for Registration...", spinner="aesthetic"
@@ -734,13 +756,13 @@ async def burned_register_extrinsic(
734
756
  },
735
757
  )
736
758
  success, err_msg = await subtensor.sign_and_send_extrinsic(
737
- call, wallet, wait_for_inclusion, wait_for_finalization
759
+ call, wallet, wait_for_inclusion, wait_for_finalization, era=era_
738
760
  )
739
761
 
740
762
  if not success:
741
763
  err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
742
764
  await asyncio.sleep(0.5)
743
- return False
765
+ return False, err_msg
744
766
  # Successful registration, final check for neuron and pubkey
745
767
  else:
746
768
  with console.status(":satellite: Checking Balance...", spinner="aesthetic"):
@@ -761,20 +783,21 @@ async def burned_register_extrinsic(
761
783
 
762
784
  console.print(
763
785
  "Balance:\n"
764
- f" [blue]{old_balance}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_balance}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
786
+ f" [blue]{old_balance}[/blue] :arrow_right: "
787
+ f"[{COLOR_PALETTE.S.STAKE_AMOUNT}]{new_balance}[/{COLOR_PALETTE.S.STAKE_AMOUNT}]"
765
788
  )
766
789
 
767
790
  if len(netuids_for_hotkey) > 0:
768
791
  console.print(
769
792
  f":white_heavy_check_mark: [green]Registered on netuid {netuid} with UID {my_uid}[/green]"
770
793
  )
771
- return True
794
+ return True, f"Registered on {netuid} with UID {my_uid}"
772
795
  else:
773
796
  # neuron not found, try again
774
797
  err_console.print(
775
798
  ":cross_mark: [red]Unknown error. Neuron not found.[/red]"
776
799
  )
777
- return False
800
+ return False, "Unknown error. Neuron not found."
778
801
 
779
802
 
780
803
  async def run_faucet_extrinsic(
@@ -894,7 +917,6 @@ async def run_faucet_extrinsic(
894
917
  )
895
918
 
896
919
  # process if registration successful, try again if pow is still valid
897
- await response.process_events()
898
920
  if not await response.is_success:
899
921
  err_console.print(
900
922
  f":cross_mark: [red]Failed[/red]: "
@@ -1737,7 +1759,8 @@ async def swap_hotkey_extrinsic(
1737
1759
  )
1738
1760
  if not len(netuids_registered) > 0:
1739
1761
  err_console.print(
1740
- f"Destination hotkey [dark_orange]{new_wallet.hotkey.ss58_address}[/dark_orange] is not registered. Please register and try again"
1762
+ f"Destination hotkey [dark_orange]{new_wallet.hotkey.ss58_address}[/dark_orange] is not registered. "
1763
+ f"Please register and try again"
1741
1764
  )
1742
1765
  return False
1743
1766
 
@@ -1754,7 +1777,8 @@ async def swap_hotkey_extrinsic(
1754
1777
  ):
1755
1778
  return False
1756
1779
  print_verbose(
1757
- f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address}) with {new_wallet.name}s hotkey ({new_wallet.hotkey.ss58_address})"
1780
+ f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address}) with "
1781
+ f"{new_wallet.name}s hotkey ({new_wallet.hotkey.ss58_address})"
1758
1782
  )
1759
1783
  with console.status(":satellite: Swapping hotkeys...", spinner="aesthetic"):
1760
1784
  call = await subtensor.substrate.compose_call(
@@ -291,7 +291,7 @@ async def root_register_extrinsic(
291
291
  wait_for_inclusion: bool = True,
292
292
  wait_for_finalization: bool = True,
293
293
  prompt: bool = False,
294
- ) -> bool:
294
+ ) -> tuple[bool, str]:
295
295
  r"""Registers the wallet to root network.
296
296
 
297
297
  :param subtensor: The SubtensorInterface object
@@ -302,12 +302,12 @@ async def root_register_extrinsic(
302
302
  or returns `False` if the extrinsic fails to be finalized within the timeout.
303
303
  :param prompt: If `True`, the call waits for confirmation from the user before proceeding.
304
304
 
305
- :return: `True` if extrinsic was finalized or included in the block. If we did not wait for finalization/inclusion,
306
- the response is `True`.
305
+ :return: (success, msg), with success being `True` if extrinsic was finalized or included in the block. If we did
306
+ not wait for finalization/inclusion, the response is `True`.
307
307
  """
308
308
 
309
- if not unlock_key(wallet).success:
310
- return False
309
+ if not (unlock := unlock_key(wallet)).success:
310
+ return False, unlock.message
311
311
 
312
312
  print_verbose(f"Checking if hotkey ({wallet.hotkey_str}) is registered on root")
313
313
  is_registered = await is_hotkey_registered(
@@ -317,7 +317,7 @@ async def root_register_extrinsic(
317
317
  console.print(
318
318
  ":white_heavy_check_mark: [green]Already registered on root network.[/green]"
319
319
  )
320
- return True
320
+ return True, "Already registered on root network"
321
321
 
322
322
  with console.status(":satellite: Registering to root network...", spinner="earth"):
323
323
  call = await subtensor.substrate.compose_call(
@@ -334,8 +334,8 @@ async def root_register_extrinsic(
334
334
 
335
335
  if not success:
336
336
  err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
337
- time.sleep(0.5)
338
- return False
337
+ await asyncio.sleep(0.5)
338
+ return False, err_msg
339
339
 
340
340
  # Successful registration, final check for neuron and pubkey
341
341
  else:
@@ -348,13 +348,13 @@ async def root_register_extrinsic(
348
348
  console.print(
349
349
  f":white_heavy_check_mark: [green]Registered with UID {uid}[/green]"
350
350
  )
351
- return True
351
+ return True, f"Registered with UID {uid}"
352
352
  else:
353
353
  # neuron not found, try again
354
354
  err_console.print(
355
355
  ":cross_mark: [red]Unknown error. Neuron not found.[/red]"
356
356
  )
357
- return False
357
+ return False, "Unknown error. Neuron not found."
358
358
 
359
359
 
360
360
  async def set_root_weights_extrinsic(
@@ -410,7 +410,6 @@ async def set_root_weights_extrinsic(
410
410
  if not wait_for_finalization and not wait_for_inclusion:
411
411
  return True, "Not waiting for finalization or inclusion."
412
412
 
413
- await response.process_events()
414
413
  if await response.is_success:
415
414
  return True, "Successfully set weights."
416
415
  else:
@@ -24,6 +24,7 @@ async def transfer_extrinsic(
24
24
  wallet: Wallet,
25
25
  destination: str,
26
26
  amount: Balance,
27
+ era: int = 3,
27
28
  transfer_all: bool = False,
28
29
  wait_for_inclusion: bool = True,
29
30
  wait_for_finalization: bool = False,
@@ -36,6 +37,7 @@ async def transfer_extrinsic(
36
37
  :param wallet: Bittensor wallet object to make transfer from.
37
38
  :param destination: Destination public key address (ss58_address or ed25519) of recipient.
38
39
  :param amount: Amount to stake as Bittensor balance.
40
+ :param era: Length (in blocks) for which the transaction should be valid.
39
41
  :param transfer_all: Whether to transfer all funds from this wallet to the destination address.
40
42
  :param wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`,
41
43
  or returns `False` if the extrinsic fails to enter the block within the timeout.
@@ -84,7 +86,7 @@ async def transfer_extrinsic(
84
86
  call_params={"dest": destination, "value": amount.rao},
85
87
  )
86
88
  extrinsic = await subtensor.substrate.create_signed_extrinsic(
87
- call=call, keypair=wallet.coldkey
89
+ call=call, keypair=wallet.coldkey, era={"period": era}
88
90
  )
89
91
  response = await subtensor.substrate.submit_extrinsic(
90
92
  extrinsic,
@@ -96,7 +98,6 @@ async def transfer_extrinsic(
96
98
  return True, "", ""
97
99
 
98
100
  # Otherwise continue with finalization.
99
- await response.process_events()
100
101
  if await response.is_success:
101
102
  block_hash_ = response.block_hash
102
103
  return True, block_hash_, ""
@@ -155,7 +156,8 @@ async def transfer_extrinsic(
155
156
  if not Confirm.ask(
156
157
  "Do you want to transfer:[bold white]\n"
157
158
  f" amount: [bright_cyan]{amount}[/bright_cyan]\n"
158
- f" from: [light_goldenrod2]{wallet.name}[/light_goldenrod2] : [bright_magenta]{wallet.coldkey.ss58_address}\n[/bright_magenta]"
159
+ f" from: [light_goldenrod2]{wallet.name}[/light_goldenrod2] : "
160
+ f"[bright_magenta]{wallet.coldkey.ss58_address}\n[/bright_magenta]"
159
161
  f" to: [bright_magenta]{destination}[/bright_magenta]\n for fee: [bright_cyan]{fee}[/bright_cyan]"
160
162
  ):
161
163
  return False
@@ -1048,6 +1048,7 @@ class SubtensorInterface:
1048
1048
  wallet: Wallet,
1049
1049
  wait_for_inclusion: bool = True,
1050
1050
  wait_for_finalization: bool = False,
1051
+ era: Optional[dict[str, int]] = None,
1051
1052
  ) -> tuple[bool, str]:
1052
1053
  """
1053
1054
  Helper method to sign and submit an extrinsic call to chain.
@@ -1056,11 +1057,15 @@ class SubtensorInterface:
1056
1057
  :param wallet: the wallet whose coldkey will be used to sign the extrinsic
1057
1058
  :param wait_for_inclusion: whether to wait until the extrinsic call is included on the chain
1058
1059
  :param wait_for_finalization: whether to wait until the extrinsic call is finalized on the chain
1060
+ :param era: The length (in blocks) for which a transaction should be valid.
1059
1061
 
1060
1062
  :return: (success, error message)
1061
1063
  """
1064
+ call_args = {"call": call, "keypair": wallet.coldkey}
1065
+ if era is not None:
1066
+ call_args["era"] = era
1062
1067
  extrinsic = await self.substrate.create_signed_extrinsic(
1063
- call=call, keypair=wallet.coldkey
1068
+ **call_args
1064
1069
  ) # sign with coldkey
1065
1070
  try:
1066
1071
  response = await self.substrate.submit_extrinsic(
@@ -1071,7 +1076,6 @@ class SubtensorInterface:
1071
1076
  # We only wait here if we expect finalization.
1072
1077
  if not wait_for_finalization and not wait_for_inclusion:
1073
1078
  return True, ""
1074
- await response.process_events()
1075
1079
  if await response.is_success:
1076
1080
  return True, ""
1077
1081
  else:
@@ -1368,11 +1372,11 @@ class SubtensorInterface:
1368
1372
  This function is useful for analyzing the stake distribution and delegation patterns of multiple
1369
1373
  accounts simultaneously, offering a broader perspective on network participation and investment strategies.
1370
1374
  """
1371
- BATCH_SIZE = 60
1375
+ batch_size = 60
1372
1376
 
1373
1377
  tasks = []
1374
- for i in range(0, len(coldkey_ss58_list), BATCH_SIZE):
1375
- ss58_chunk = coldkey_ss58_list[i : i + BATCH_SIZE]
1378
+ for i in range(0, len(coldkey_ss58_list), batch_size):
1379
+ ss58_chunk = coldkey_ss58_list[i : i + batch_size]
1376
1380
  tasks.append(
1377
1381
  self.query_runtime_api(
1378
1382
  runtime_api="StakeInfoRuntimeApi",
@@ -1501,3 +1505,53 @@ class SubtensorInterface:
1501
1505
  )
1502
1506
 
1503
1507
  return Balance.from_rao(result)
1508
+
1509
+ async def get_scheduled_coldkey_swap(
1510
+ self,
1511
+ block_hash: Optional[str] = None,
1512
+ reuse_block: bool = False,
1513
+ ) -> Optional[list[str]]:
1514
+ """
1515
+ Queries the chain to fetch the list of coldkeys that are scheduled for a swap.
1516
+
1517
+ :param block_hash: Block hash at which to perform query.
1518
+ :param reuse_block: Whether to reuse the last-used block hash.
1519
+
1520
+ :return: A list of SS58 addresses of the coldkeys that are scheduled for a coldkey swap.
1521
+ """
1522
+ result = await self.substrate.query_map(
1523
+ module="SubtensorModule",
1524
+ storage_function="ColdkeySwapScheduled",
1525
+ block_hash=block_hash,
1526
+ reuse_block_hash=reuse_block,
1527
+ )
1528
+
1529
+ keys_pending_swap = []
1530
+ async for ss58, _ in result:
1531
+ keys_pending_swap.append(decode_account_id(ss58))
1532
+ return keys_pending_swap
1533
+
1534
+ async def get_coldkey_swap_schedule_duration(
1535
+ self,
1536
+ block_hash: Optional[str] = None,
1537
+ reuse_block: bool = False,
1538
+ ) -> int:
1539
+ """
1540
+ Retrieves the duration (in blocks) required for a coldkey swap to be executed.
1541
+
1542
+ Args:
1543
+ block_hash: The hash of the blockchain block number for the query.
1544
+ reuse_block: Whether to reuse the last-used blockchain block hash.
1545
+
1546
+ Returns:
1547
+ int: The number of blocks required for the coldkey swap schedule duration.
1548
+ """
1549
+ result = await self.query(
1550
+ module="SubtensorModule",
1551
+ storage_function="ColdkeySwapScheduleDuration",
1552
+ params=[],
1553
+ block_hash=block_hash,
1554
+ reuse_block_hash=reuse_block,
1555
+ )
1556
+
1557
+ return result
@@ -31,8 +31,10 @@ from bittensor_cli.src import defaults, Constants
31
31
 
32
32
  if TYPE_CHECKING:
33
33
  from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
34
+ from rich.prompt import PromptBase
34
35
 
35
36
  console = Console()
37
+ json_console = Console()
36
38
  err_console = Console(stderr=True)
37
39
  verbose_console = Console(quiet=True)
38
40
 
@@ -1006,7 +1008,7 @@ def retry_prompt(
1006
1008
  rejection_text: str,
1007
1009
  default="",
1008
1010
  show_default=False,
1009
- prompt_type=Prompt.ask,
1011
+ prompt_type: "PromptBase.ask" = Prompt.ask,
1010
1012
  ):
1011
1013
  """
1012
1014
  Allows for asking prompts again if they do not meet a certain criteria (as defined in `rejection`)
@@ -1052,6 +1054,7 @@ def get_effective_network(config, network: Optional[list[str]]) -> str:
1052
1054
  the configuration, and the default.
1053
1055
  """
1054
1056
  if network:
1057
+ network_ = ""
1055
1058
  for item in network:
1056
1059
  if item.startswith("ws"):
1057
1060
  network_ = item
@@ -1308,7 +1311,8 @@ def print_linux_dependency_message():
1308
1311
  "\tAdd this into the file and save: [green]deb http://archive.ubuntu.com/ubuntu jammy main universe[/green]"
1309
1312
  )
1310
1313
  console.print(
1311
- "\tUpdate the repository and install the webkit dependency: [green]sudo apt update && sudo apt install libwebkit2gtk-4.0-dev[/green]"
1314
+ "\tUpdate the repository and install the webkit dependency: [green]sudo apt update && sudo apt install "
1315
+ "libwebkit2gtk-4.0-dev[/green]"
1312
1316
  )
1313
1317
  console.print("\nFedora / CentOS / AlmaLinux:")
1314
1318
  console.print("[green]sudo dnf install gtk3-devel webkit2gtk3-devel[/green]\n\n")