bittensor-cli 9.0.2__py3-none-any.whl → 9.1.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.
@@ -20,6 +20,7 @@ from bittensor_cli.src.bittensor.chain_data import (
20
20
  decode_hex_identity,
21
21
  DynamicInfo,
22
22
  SubnetState,
23
+ MetagraphInfo,
23
24
  )
24
25
  from bittensor_cli.src import DelegatesDetails
25
26
  from bittensor_cli.src.bittensor.balances import Balance, fixed_to_float
@@ -1252,6 +1253,38 @@ class SubtensorInterface:
1252
1253
  else:
1253
1254
  return Balance.from_rao(_result).set_unit(int(netuid))
1254
1255
 
1256
+ async def get_metagraph_info(
1257
+ self, netuid: int, block_hash: Optional[str] = None
1258
+ ) -> Optional[MetagraphInfo]:
1259
+ hex_bytes_result = await self.query_runtime_api(
1260
+ runtime_api="SubnetInfoRuntimeApi",
1261
+ method="get_metagraph",
1262
+ params=[netuid],
1263
+ block_hash=block_hash,
1264
+ )
1265
+
1266
+ if hex_bytes_result is None:
1267
+ return None
1268
+
1269
+ try:
1270
+ bytes_result = bytes.fromhex(hex_bytes_result[2:])
1271
+ except ValueError:
1272
+ bytes_result = bytes.fromhex(hex_bytes_result)
1273
+
1274
+ return MetagraphInfo.from_any(bytes_result)
1275
+
1276
+ async def get_all_metagraphs_info(
1277
+ self, block_hash: Optional[str] = None
1278
+ ) -> list[MetagraphInfo]:
1279
+ hex_bytes_result = await self.query_runtime_api(
1280
+ runtime_api="SubnetInfoRuntimeApi",
1281
+ method="get_all_metagraphs",
1282
+ params=[],
1283
+ block_hash=block_hash,
1284
+ )
1285
+
1286
+ return MetagraphInfo.list_from_any(hex_bytes_result)
1287
+
1255
1288
  async def multi_get_stake_for_coldkey_and_hotkey_on_netuid(
1256
1289
  self,
1257
1290
  hotkey_ss58s: list[str],
@@ -1327,20 +1360,29 @@ class SubtensorInterface:
1327
1360
  This function is useful for analyzing the stake distribution and delegation patterns of multiple
1328
1361
  accounts simultaneously, offering a broader perspective on network participation and investment strategies.
1329
1362
  """
1330
- result = await self.query_runtime_api(
1331
- runtime_api="StakeInfoRuntimeApi",
1332
- method="get_stake_info_for_coldkeys",
1333
- params=[coldkey_ss58_list],
1334
- block_hash=block_hash,
1335
- )
1336
- if result is None:
1337
- return None
1363
+ BATCH_SIZE = 60
1338
1364
 
1365
+ tasks = []
1366
+ for i in range(0, len(coldkey_ss58_list), BATCH_SIZE):
1367
+ ss58_chunk = coldkey_ss58_list[i : i + BATCH_SIZE]
1368
+ tasks.append(
1369
+ self.query_runtime_api(
1370
+ runtime_api="StakeInfoRuntimeApi",
1371
+ method="get_stake_info_for_coldkeys",
1372
+ params=[ss58_chunk],
1373
+ block_hash=block_hash,
1374
+ )
1375
+ )
1376
+ results = await asyncio.gather(*tasks)
1339
1377
  stake_info_map = {}
1340
- for coldkey_bytes, stake_info_list in result:
1341
- coldkey_ss58 = decode_account_id(coldkey_bytes)
1342
- stake_info_map[coldkey_ss58] = StakeInfo.list_from_any(stake_info_list)
1343
- return stake_info_map
1378
+ for result in results:
1379
+ if result is None:
1380
+ continue
1381
+ for coldkey_bytes, stake_info_list in result:
1382
+ coldkey_ss58 = decode_account_id(coldkey_bytes)
1383
+ stake_info_map[coldkey_ss58] = StakeInfo.list_from_any(stake_info_list)
1384
+
1385
+ return stake_info_map if stake_info_map else None
1344
1386
 
1345
1387
  async def all_subnets(self, block_hash: Optional[str] = None) -> list[DynamicInfo]:
1346
1388
  result = await self.query_runtime_api(
@@ -1279,14 +1279,25 @@ def print_linux_dependency_message():
1279
1279
  """Prints the WebKit dependency message for Linux systems."""
1280
1280
  console.print("[red]This command requires WebKit dependencies on Linux.[/red]")
1281
1281
  console.print(
1282
- "\nPlease install the required packages using one of the following commands based on your distribution:"
1282
+ "\nPlease make sure these packages are installed on your system for PyWry to work:"
1283
1283
  )
1284
1284
  console.print("\nArch Linux / Manjaro:")
1285
1285
  console.print("[green]sudo pacman -S webkit2gtk[/green]")
1286
1286
  console.print("\nDebian / Ubuntu:")
1287
1287
  console.print("[green]sudo apt install libwebkit2gtk-4.0-dev[/green]")
1288
+ console.print("\nNote for Ubuntu 24.04+ & Debian 13+:")
1289
+ console.print("You may need these additional steps to install libwebkit2gtk:")
1290
+ console.print(
1291
+ "\tCreate a new source file with: [green]sudo vim /etc/apt/sources.list.d/jammy-temp.list[/green]"
1292
+ )
1293
+ console.print(
1294
+ "\tAdd this into the file and save: [green]deb http://archive.ubuntu.com/ubuntu jammy main universe[/green]"
1295
+ )
1296
+ console.print(
1297
+ "\tUpdate the repository and install the webkit dependency: [green]sudo apt update && sudo apt install libwebkit2gtk-4.0-dev[/green]"
1298
+ )
1288
1299
  console.print("\nFedora / CentOS / AlmaLinux:")
1289
- console.print("[green]sudo dnf install gtk3-devel webkit2gtk3-devel[/green]")
1300
+ console.print("[green]sudo dnf install gtk3-devel webkit2gtk3-devel[/green]\n\n")
1290
1301
 
1291
1302
 
1292
1303
  def is_linux():
@@ -17,6 +17,7 @@ from bittensor_cli.src.bittensor.utils import (
17
17
  is_valid_ss58_address,
18
18
  print_error,
19
19
  print_verbose,
20
+ unlock_key,
20
21
  )
21
22
  from bittensor_wallet import Wallet
22
23
  from bittensor_wallet.errors import KeyFileError
@@ -338,10 +339,7 @@ async def stake_add(
338
339
  if prompt:
339
340
  if not Confirm.ask("Would you like to continue?"):
340
341
  raise typer.Exit()
341
- try:
342
- wallet.unlock_coldkey()
343
- except KeyFileError:
344
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
342
+ if not unlock_key(wallet).success:
345
343
  return False
346
344
 
347
345
  if safe_staking:
@@ -671,6 +671,8 @@ async def childkey_take(
671
671
  chk_take = await get_childkey_take(
672
672
  subtensor=subtensor, netuid=netuid, hotkey=ss58
673
673
  )
674
+ if chk_take is None:
675
+ chk_take = 0
674
676
  chk_take = u16_to_float(chk_take)
675
677
  console.print(
676
678
  f"Child take for {ss58} is: {chk_take * 100:.2f}% on netuid {netuid}."
@@ -17,6 +17,7 @@ from bittensor_cli.src.bittensor.utils import (
17
17
  format_error_message,
18
18
  group_subnets,
19
19
  get_subnet_name,
20
+ unlock_key,
20
21
  )
21
22
 
22
23
  if TYPE_CHECKING:
@@ -334,8 +335,7 @@ async def stake_move_selection(
334
335
 
335
336
 
336
337
  async def stake_transfer_selection(
337
- wallet: Wallet,
338
- subtensor: "SubtensorInterface",
338
+ wallet: Wallet, subtensor: "SubtensorInterface", origin_hotkey: str
339
339
  ):
340
340
  """Selection interface for transferring stakes."""
341
341
  (
@@ -352,7 +352,7 @@ async def stake_transfer_selection(
352
352
 
353
353
  available_stakes = {}
354
354
  for stake in stakes:
355
- if stake.stake.tao > 0 and stake.hotkey_ss58 == wallet.hotkey.ss58_address:
355
+ if stake.stake.tao > 0 and stake.hotkey_ss58 == origin_hotkey:
356
356
  available_stakes[stake.netuid] = {
357
357
  "hotkey_ss58": stake.hotkey_ss58,
358
358
  "stake": stake.stake,
@@ -621,10 +621,7 @@ async def move_stake(
621
621
  raise typer.Exit()
622
622
 
623
623
  # Perform moving operation.
624
- try:
625
- wallet.unlock_coldkey()
626
- except KeyFileError:
627
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
624
+ if not unlock_key(wallet).success:
628
625
  return False
629
626
  with console.status(
630
627
  f"\n:satellite: Moving [blue]{amount_to_move_as_balance}[/blue] from [blue]{origin_hotkey}[/blue] on netuid: [blue]{origin_netuid}[/blue] \nto "
@@ -697,6 +694,7 @@ async def transfer_stake(
697
694
  wallet: Wallet,
698
695
  subtensor: "SubtensorInterface",
699
696
  amount: float,
697
+ origin_hotkey: str,
700
698
  origin_netuid: int,
701
699
  dest_netuid: int,
702
700
  dest_coldkey_ss58: str,
@@ -709,6 +707,7 @@ async def transfer_stake(
709
707
  wallet (Wallet): Bittensor wallet object.
710
708
  subtensor (SubtensorInterface): Subtensor interface instance.
711
709
  amount (float): Amount to transfer.
710
+ origin_hotkey (str): The hotkey SS58 to transfer the stake from.
712
711
  origin_netuid (int): The netuid to transfer stake from.
713
712
  dest_netuid (int): The netuid to transfer stake to.
714
713
  dest_coldkey_ss58 (str): The destination coldkey to transfer stake to.
@@ -718,8 +717,9 @@ async def transfer_stake(
718
717
  Returns:
719
718
  bool: True if transfer was successful, False otherwise.
720
719
  """
720
+ origin_hotkey = origin_hotkey or wallet.hotkey.ss58_address
721
721
  if interactive_selection:
722
- selection = await stake_transfer_selection(wallet, subtensor)
722
+ selection = await stake_transfer_selection(wallet, subtensor, origin_hotkey)
723
723
  origin_netuid = selection["origin_netuid"]
724
724
  amount = selection["amount"]
725
725
  dest_netuid = selection["destination_netuid"]
@@ -739,16 +739,15 @@ async def transfer_stake(
739
739
  return False
740
740
 
741
741
  # Get current stake balances
742
- hotkey_ss58 = wallet.hotkey.ss58_address
743
742
  with console.status(f"Retrieving stake data from {subtensor.network}..."):
744
743
  current_stake = await subtensor.get_stake(
745
744
  coldkey_ss58=wallet.coldkeypub.ss58_address,
746
- hotkey_ss58=hotkey_ss58,
745
+ hotkey_ss58=origin_hotkey,
747
746
  netuid=origin_netuid,
748
747
  )
749
748
  current_dest_stake = await subtensor.get_stake(
750
749
  coldkey_ss58=dest_coldkey_ss58,
751
- hotkey_ss58=hotkey_ss58,
750
+ hotkey_ss58=origin_hotkey,
752
751
  netuid=dest_netuid,
753
752
  )
754
753
  amount_to_transfer = Balance.from_tao(amount).set_unit(origin_netuid)
@@ -768,8 +767,8 @@ async def transfer_stake(
768
767
  subtensor=subtensor,
769
768
  origin_netuid=origin_netuid,
770
769
  destination_netuid=dest_netuid,
771
- origin_hotkey=hotkey_ss58,
772
- destination_hotkey=hotkey_ss58,
770
+ origin_hotkey=origin_hotkey,
771
+ destination_hotkey=origin_hotkey,
773
772
  amount_to_move=amount_to_transfer,
774
773
  )
775
774
 
@@ -777,10 +776,7 @@ async def transfer_stake(
777
776
  raise typer.Exit()
778
777
 
779
778
  # Perform transfer operation
780
- try:
781
- wallet.unlock_coldkey()
782
- except KeyFileError:
783
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
779
+ if not unlock_key(wallet).success:
784
780
  return False
785
781
 
786
782
  with console.status("\n:satellite: Transferring stake ..."):
@@ -789,7 +785,7 @@ async def transfer_stake(
789
785
  call_function="transfer_stake",
790
786
  call_params={
791
787
  "destination_coldkey": dest_coldkey_ss58,
792
- "hotkey": hotkey_ss58,
788
+ "hotkey": origin_hotkey,
793
789
  "origin_netuid": origin_netuid,
794
790
  "destination_netuid": dest_netuid,
795
791
  "alpha_amount": amount_to_transfer.rao,
@@ -820,12 +816,12 @@ async def transfer_stake(
820
816
  new_stake, new_dest_stake = await asyncio.gather(
821
817
  subtensor.get_stake(
822
818
  coldkey_ss58=wallet.coldkeypub.ss58_address,
823
- hotkey_ss58=hotkey_ss58,
819
+ hotkey_ss58=origin_hotkey,
824
820
  netuid=origin_netuid,
825
821
  ),
826
822
  subtensor.get_stake(
827
823
  coldkey_ss58=dest_coldkey_ss58,
828
- hotkey_ss58=hotkey_ss58,
824
+ hotkey_ss58=origin_hotkey,
829
825
  netuid=dest_netuid,
830
826
  ),
831
827
  )
@@ -933,10 +929,7 @@ async def swap_stake(
933
929
  raise typer.Exit()
934
930
 
935
931
  # Perform swap operation
936
- try:
937
- wallet.unlock_coldkey()
938
- except KeyFileError:
939
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
932
+ if not unlock_key(wallet).success:
940
933
  return False
941
934
 
942
935
  with console.status(
@@ -21,6 +21,7 @@ from bittensor_cli.src.bittensor.utils import (
21
21
  is_valid_ss58_address,
22
22
  format_error_message,
23
23
  group_subnets,
24
+ unlock_key,
24
25
  )
25
26
 
26
27
  if TYPE_CHECKING:
@@ -268,10 +269,7 @@ async def unstake(
268
269
  raise typer.Exit()
269
270
 
270
271
  # Execute extrinsics
271
- try:
272
- wallet.unlock_coldkey()
273
- except KeyFileError:
274
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
272
+ if not unlock_key(wallet).success:
275
273
  return False
276
274
 
277
275
  with console.status("\n:satellite: Performing unstaking operations...") as status:
@@ -465,10 +463,7 @@ async def unstake_all(
465
463
  ):
466
464
  return False
467
465
 
468
- try:
469
- wallet.unlock_coldkey()
470
- except KeyFileError:
471
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
466
+ if not unlock_key(wallet).success:
472
467
  return False
473
468
 
474
469
  with console.status("Unstaking all stakes...") as status:
@@ -97,8 +97,10 @@ async def register_subnetwork_extrinsic(
97
97
  sn_burn_cost = await burn_cost(subtensor)
98
98
  if sn_burn_cost > your_balance:
99
99
  err_console.print(
100
- f"Your balance of: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}[{COLOR_PALETTE['POOLS']['TAO']}] is not enough to pay the subnet lock cost of: "
101
- f"[{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}[{COLOR_PALETTE['POOLS']['TAO']}]"
100
+ f"Your balance of: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}[{COLOR_PALETTE['POOLS']['TAO']}]"
101
+ f" is not enough to burn "
102
+ f"[{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}[{COLOR_PALETTE['POOLS']['TAO']}] "
103
+ f"to register a subnet."
102
104
  )
103
105
  return False
104
106
 
@@ -107,7 +109,7 @@ async def register_subnetwork_extrinsic(
107
109
  f"Your balance is: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}"
108
110
  )
109
111
  if not Confirm.ask(
110
- f"Do you want to register a subnet for [{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}?"
112
+ f"Do you want to burn [{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost} to register a subnet?"
111
113
  ):
112
114
  return False
113
115
 
@@ -145,10 +147,7 @@ async def register_subnetwork_extrinsic(
145
147
  )
146
148
  return False
147
149
 
148
- try:
149
- wallet.unlock_coldkey()
150
- except KeyFileError:
151
- err_console.print("Error decrypting coldkey (possibly incorrect password)")
150
+ if not unlock_key(wallet).success:
152
151
  return False
153
152
 
154
153
  with console.status(":satellite: Registering subnet...", spinner="earth"):
@@ -189,6 +189,11 @@ async def set_hyperparameter_extrinsic(
189
189
  ":cross_mark: [red]Invalid hyperparameter specified.[/red]"
190
190
  )
191
191
  return False
192
+ if sudo_:
193
+ if not Confirm.ask(
194
+ "This hyperparam is only settable by root sudo users. If you are not, this will fail. Please confirm"
195
+ ):
196
+ return False
192
197
 
193
198
  substrate = subtensor.substrate
194
199
  msg_value = value if not arbitrary_extrinsic else call_params