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.
@@ -43,7 +43,6 @@ async def unstake(
43
43
  allow_partial_stake: bool,
44
44
  ):
45
45
  """Unstake from hotkey(s)."""
46
- unstake_all_from_hk = False
47
46
  with console.status(
48
47
  f"Retrieving subnet data & identities from {subtensor.network}...",
49
48
  spinner="earth",
@@ -145,7 +144,7 @@ async def unstake(
145
144
  staking_address_name, staking_address_ss58, netuid = hotkey
146
145
  netuids_to_process = [netuid]
147
146
  else:
148
- staking_address_name, staking_address_ss58 = hotkey
147
+ staking_address_name, staking_address_ss58, _ = hotkey
149
148
  netuids_to_process = netuids
150
149
 
151
150
  initial_amount = amount
@@ -179,7 +178,6 @@ async def unstake(
179
178
  if staking_address_name
180
179
  else staking_address_ss58,
181
180
  staking_address_ss58,
182
- interactive,
183
181
  )
184
182
  if amount_to_unstake_as_balance is None:
185
183
  skip_remaining_subnets = True
@@ -189,14 +187,32 @@ async def unstake(
189
187
  amount_to_unstake_as_balance.set_unit(netuid)
190
188
  if amount_to_unstake_as_balance > current_stake_balance:
191
189
  err_console.print(
192
- f"[red]Not enough stake to remove[/red]:\n Stake balance: [dark_orange]{current_stake_balance}[/dark_orange]"
193
- f" < Unstaking amount: [dark_orange]{amount_to_unstake_as_balance}[/dark_orange] on netuid: {netuid}"
190
+ f"[red]Not enough stake to remove[/red]:\n"
191
+ f" Stake balance: [dark_orange]{current_stake_balance}[/dark_orange]"
192
+ f" < Unstaking amount: [dark_orange]{amount_to_unstake_as_balance}[/dark_orange]"
193
+ f" on netuid: {netuid}"
194
194
  )
195
195
  continue # Skip to the next subnet - useful when single amount is specified for all subnets
196
196
 
197
- received_amount, slippage_pct, slippage_pct_float = _calculate_slippage(
198
- subnet_info=subnet_info, amount=amount_to_unstake_as_balance
197
+ stake_fee = await subtensor.get_stake_fee(
198
+ origin_hotkey_ss58=staking_address_ss58,
199
+ origin_netuid=netuid,
200
+ origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
201
+ destination_hotkey_ss58=None,
202
+ destination_netuid=None,
203
+ destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
204
+ amount=amount_to_unstake_as_balance.rao,
199
205
  )
206
+
207
+ try:
208
+ received_amount, slippage_pct, slippage_pct_float = _calculate_slippage(
209
+ subnet_info=subnet_info,
210
+ amount=amount_to_unstake_as_balance,
211
+ stake_fee=stake_fee,
212
+ )
213
+ except ValueError:
214
+ continue
215
+
200
216
  total_received_amount += received_amount
201
217
  max_float_slippage = max(max_float_slippage, slippage_pct_float)
202
218
 
@@ -220,6 +236,7 @@ async def unstake(
220
236
  str(amount_to_unstake_as_balance), # Amount to Unstake
221
237
  str(subnet_info.price.tao)
222
238
  + f"({Balance.get_unit(0)}/{Balance.get_unit(netuid)})", # Rate
239
+ str(stake_fee), # Fee
223
240
  str(received_amount), # Received Amount
224
241
  slippage_pct, # Slippage Percent
225
242
  ]
@@ -292,7 +309,6 @@ async def unstake(
292
309
  subtensor=subtensor,
293
310
  netuid=op["netuid"],
294
311
  amount=op["amount_to_unstake"],
295
- current_stake=op["current_stake_balance"],
296
312
  hotkey_ss58=op["hotkey_ss58"],
297
313
  price_limit=op["price_with_tolerance"],
298
314
  allow_partial_stake=allow_partial_stake,
@@ -320,12 +336,13 @@ async def unstake_all(
320
336
  hotkey_ss58_address: str,
321
337
  unstake_all_alpha: bool = False,
322
338
  all_hotkeys: bool = False,
323
- include_hotkeys: list[str] = [],
324
- exclude_hotkeys: list[str] = [],
339
+ include_hotkeys: Optional[list[str]] = None,
340
+ exclude_hotkeys: Optional[list[str]] = None,
325
341
  prompt: bool = True,
326
342
  ) -> bool:
327
343
  """Unstakes all stakes from all hotkeys in all subnets."""
328
-
344
+ include_hotkeys = include_hotkeys or []
345
+ exclude_hotkeys = exclude_hotkeys or []
329
346
  with console.status(
330
347
  f"Retrieving stake information & identities from {subtensor.network}...",
331
348
  spinner="earth",
@@ -356,12 +373,12 @@ async def unstake_all(
356
373
  old_identities=old_identities,
357
374
  )
358
375
  elif not hotkey_ss58_address:
359
- hotkeys = [(wallet.hotkey_str, wallet.hotkey.ss58_address)]
376
+ hotkeys = [(wallet.hotkey_str, wallet.hotkey.ss58_address, None)]
360
377
  else:
361
- hotkeys = [(None, hotkey_ss58_address)]
378
+ hotkeys = [(None, hotkey_ss58_address, None)]
362
379
 
363
- hotkey_names = {ss58: name for name, ss58 in hotkeys if name is not None}
364
- hotkey_ss58s = [ss58 for _, ss58 in hotkeys]
380
+ hotkey_names = {ss58: name for name, ss58, _ in hotkeys if name is not None}
381
+ hotkey_ss58s = [item[1] for item in hotkeys]
365
382
  stake_info = [
366
383
  stake for stake in stake_info if stake.hotkey_ss58 in hotkey_ss58s
367
384
  ]
@@ -411,6 +428,11 @@ async def unstake_all(
411
428
  justify="center",
412
429
  style=COLOR_PALETTE["POOLS"]["RATE"],
413
430
  )
431
+ table.add_column(
432
+ f"Fee ({Balance.unit})",
433
+ justify="center",
434
+ style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
435
+ )
414
436
  table.add_column(
415
437
  f"Recieved ({Balance.unit})",
416
438
  justify="center",
@@ -432,9 +454,22 @@ async def unstake_all(
432
454
  hotkey_display = hotkey_names.get(stake.hotkey_ss58, stake.hotkey_ss58)
433
455
  subnet_info = all_sn_dynamic_info.get(stake.netuid)
434
456
  stake_amount = stake.stake
435
- received_amount, slippage_pct, slippage_pct_float = _calculate_slippage(
436
- subnet_info=subnet_info, amount=stake_amount
457
+ stake_fee = await subtensor.get_stake_fee(
458
+ origin_hotkey_ss58=stake.hotkey_ss58,
459
+ origin_netuid=stake.netuid,
460
+ origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
461
+ destination_hotkey_ss58=None,
462
+ destination_netuid=None,
463
+ destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
464
+ amount=stake_amount.rao,
437
465
  )
466
+ try:
467
+ received_amount, slippage_pct, slippage_pct_float = _calculate_slippage(
468
+ subnet_info=subnet_info, amount=stake_amount, stake_fee=stake_fee
469
+ )
470
+ except ValueError:
471
+ continue
472
+
438
473
  max_slippage = max(max_slippage, slippage_pct_float)
439
474
  total_received_value += received_amount
440
475
 
@@ -444,6 +479,7 @@ async def unstake_all(
444
479
  str(stake_amount),
445
480
  str(float(subnet_info.price))
446
481
  + f"({Balance.get_unit(0)}/{Balance.get_unit(stake.netuid)})",
482
+ str(stake_fee),
447
483
  str(received_amount),
448
484
  slippage_pct,
449
485
  )
@@ -567,7 +603,6 @@ async def _safe_unstake_extrinsic(
567
603
  subtensor: "SubtensorInterface",
568
604
  netuid: int,
569
605
  amount: Balance,
570
- current_stake: Balance,
571
606
  hotkey_ss58: str,
572
607
  price_limit: Balance,
573
608
  allow_partial_stake: bool,
@@ -578,7 +613,6 @@ async def _safe_unstake_extrinsic(
578
613
  Args:
579
614
  netuid: The subnet ID
580
615
  amount: Amount to unstake
581
- current_stake: Current stake balance
582
616
  hotkey_ss58: Hotkey SS58 address
583
617
  price_limit: Maximum acceptable price
584
618
  wallet: Wallet instance
@@ -724,6 +758,7 @@ async def _unstake_all_extrinsic(
724
758
  current_balance = await subtensor.get_balance(
725
759
  wallet.coldkeypub.ss58_address, block_hash=block_hash
726
760
  )
761
+ previous_root_stake = None
727
762
 
728
763
  call_function = "unstake_all_alpha" if unstake_all_alpha else "unstake_all"
729
764
  call = await subtensor.substrate.compose_call(
@@ -768,6 +803,7 @@ async def _unstake_all_extrinsic(
768
803
  new_balance = await subtensor.get_balance(
769
804
  wallet.coldkeypub.ss58_address, block_hash=block_hash
770
805
  )
806
+ new_root_stake = None
771
807
 
772
808
  success_message = (
773
809
  ":white_heavy_check_mark: [green]Finalized: Successfully unstaked all stakes[/green]"
@@ -781,7 +817,9 @@ async def _unstake_all_extrinsic(
781
817
 
782
818
  if unstake_all_alpha:
783
819
  console.print(
784
- f"Root Stake for {hotkey_name}:\n [blue]{previous_root_stake}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_root_stake}"
820
+ f"Root Stake for {hotkey_name}:\n "
821
+ f"[blue]{previous_root_stake}[/blue] :arrow_right: "
822
+ f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_root_stake}"
785
823
  )
786
824
 
787
825
  except Exception as e:
@@ -789,28 +827,47 @@ async def _unstake_all_extrinsic(
789
827
 
790
828
 
791
829
  # Helpers
792
- def _calculate_slippage(subnet_info, amount: Balance) -> tuple[Balance, str, float]:
830
+ def _calculate_slippage(
831
+ subnet_info, amount: Balance, stake_fee: Balance
832
+ ) -> tuple[Balance, str, float]:
793
833
  """Calculate slippage and received amount for unstaking operation.
794
834
 
795
835
  Args:
796
- dynamic_info: Subnet information containing price data
836
+ subnet_info: Subnet information containing price data
797
837
  amount: Amount being unstaked
838
+ stake_fee: Stake fee to include in slippage calculation
798
839
 
799
840
  Returns:
800
841
  tuple containing:
801
- - received_amount: Balance after slippage
842
+ - received_amount: Balance after slippage deduction
802
843
  - slippage_pct: Formatted string of slippage percentage
803
844
  - slippage_pct_float: Float value of slippage percentage
804
845
  """
805
- received_amount, _, slippage_pct_float = subnet_info.alpha_to_tao_with_slippage(
806
- amount
807
- )
846
+ received_amount, _, _ = subnet_info.alpha_to_tao_with_slippage(amount)
847
+ received_amount -= stake_fee
848
+
849
+ if received_amount < Balance.from_tao(0):
850
+ print_error("Not enough Alpha to pay the transaction fee.")
851
+ raise ValueError
808
852
 
809
853
  if subnet_info.is_dynamic:
854
+ # Ideal amount w/o slippage
855
+ ideal_amount = subnet_info.alpha_to_tao(amount)
856
+
857
+ # Total slippage including fees
858
+ total_slippage = ideal_amount - received_amount
859
+ slippage_pct_float = (
860
+ 100 * (float(total_slippage.tao) / float(ideal_amount.tao))
861
+ if ideal_amount.tao != 0
862
+ else 0
863
+ )
810
864
  slippage_pct = f"{slippage_pct_float:.4f} %"
811
865
  else:
812
- slippage_pct_float = 0
813
- slippage_pct = "[red]N/A[/red]"
866
+ # Root will only have fee-based slippage
867
+ slippage_pct_float = (
868
+ 100 * float(stake_fee.tao) / float(amount.tao) if amount.tao != 0 else 0
869
+ )
870
+ slippage_pct = f"{slippage_pct_float:.4f} %"
814
871
 
815
872
  return received_amount, slippage_pct, slippage_pct_float
816
873
 
@@ -821,7 +878,7 @@ async def _unstake_selection(
821
878
  old_identities,
822
879
  stake_infos,
823
880
  netuid: Optional[int] = None,
824
- ):
881
+ ) -> tuple[list[tuple[str, str, int]], bool]:
825
882
  if not stake_infos:
826
883
  print_error("You have no stakes to unstake.")
827
884
  raise ValueError
@@ -899,7 +956,9 @@ async def _unstake_selection(
899
956
 
900
957
  # Display hotkey's staked netuids with amount.
901
958
  table = Table(
902
- title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Stakes for hotkey \n[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{selected_hotkey_name}\n{selected_hotkey_ss58}\n",
959
+ title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Stakes for hotkey \n"
960
+ f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{selected_hotkey_name}\n"
961
+ f"{selected_hotkey_ss58}\n",
903
962
  show_footer=True,
904
963
  show_edge=False,
905
964
  header_style="bold white",
@@ -925,19 +984,20 @@ async def _unstake_selection(
925
984
  console.print("\n", table, "\n")
926
985
 
927
986
  # Ask which netuids to unstake from for the selected hotkey.
928
- unstake_all = False
987
+ unstake_all_ = False
929
988
  if netuid is not None:
930
989
  selected_netuids = [netuid]
931
990
  else:
932
991
  while True:
933
992
  netuid_input = Prompt.ask(
934
- "\nEnter the netuids of the [blue]subnets to unstake[/blue] from (comma-separated), or '[blue]all[/blue]' to unstake from all",
993
+ "\nEnter the netuids of the [blue]subnets to unstake[/blue] from (comma-separated), or "
994
+ "'[blue]all[/blue]' to unstake from all",
935
995
  default="all",
936
996
  )
937
997
 
938
998
  if netuid_input.lower() == "all":
939
999
  selected_netuids = list(netuid_stakes.keys())
940
- unstake_all = True
1000
+ unstake_all_ = True
941
1001
  break
942
1002
  else:
943
1003
  try:
@@ -960,7 +1020,7 @@ async def _unstake_selection(
960
1020
  hotkeys_to_unstake_from.append(
961
1021
  (selected_hotkey_name, selected_hotkey_ss58, netuid_)
962
1022
  )
963
- return hotkeys_to_unstake_from, unstake_all
1023
+ return hotkeys_to_unstake_from, unstake_all_
964
1024
 
965
1025
 
966
1026
  def _ask_unstake_amount(
@@ -968,7 +1028,6 @@ def _ask_unstake_amount(
968
1028
  netuid: int,
969
1029
  staking_address_name: str,
970
1030
  staking_address_ss58: str,
971
- interactive: bool,
972
1031
  ) -> Optional[Balance]:
973
1032
  """Prompt the user to decide the amount to unstake.
974
1033
 
@@ -977,7 +1036,6 @@ def _ask_unstake_amount(
977
1036
  netuid: The subnet ID
978
1037
  staking_address_name: Display name of the staking address
979
1038
  staking_address_ss58: SS58 address of the staking address
980
- interactive: Whether in interactive mode (affects default choice)
981
1039
 
982
1040
  Returns:
983
1041
  Balance amount to unstake, or None if user chooses to quit
@@ -1055,7 +1113,7 @@ def _get_hotkeys_to_unstake(
1055
1113
  stake_infos: list,
1056
1114
  identities: dict,
1057
1115
  old_identities: dict,
1058
- ) -> list[tuple[Optional[str], str]]:
1116
+ ) -> list[tuple[Optional[str], str, None]]:
1059
1117
  """Get list of hotkeys to unstake from based on input parameters.
1060
1118
 
1061
1119
  Args:
@@ -1066,26 +1124,28 @@ def _get_hotkeys_to_unstake(
1066
1124
  exclude_hotkeys: List of hotkey names to exclude
1067
1125
 
1068
1126
  Returns:
1069
- List of tuples containing (hotkey_name, hotkey_ss58) pairs to unstake from
1127
+ List of tuples containing (hotkey_name, hotkey_ss58, None) pairs to unstake from. The final None is important
1128
+ for compatibility with the `_unstake_selection` function.
1070
1129
  """
1071
1130
  if hotkey_ss58_address:
1072
1131
  print_verbose(f"Unstaking from ss58 ({hotkey_ss58_address})")
1073
- return [(None, hotkey_ss58_address)]
1132
+ return [(None, hotkey_ss58_address, None)]
1074
1133
 
1075
1134
  if all_hotkeys:
1076
1135
  print_verbose("Unstaking from all hotkeys")
1077
1136
  all_hotkeys_ = get_hotkey_wallets_for_wallet(wallet=wallet)
1078
1137
  wallet_hotkeys = [
1079
- (wallet.hotkey_str, wallet.hotkey.ss58_address)
1138
+ (wallet.hotkey_str, wallet.hotkey.ss58_address, None)
1080
1139
  for wallet in all_hotkeys_
1081
1140
  if wallet.hotkey_str not in exclude_hotkeys
1082
1141
  ]
1083
1142
 
1084
- wallet_hotkey_addresses = {addr for _, addr in wallet_hotkeys}
1143
+ wallet_hotkey_addresses = {hk[1] for hk in wallet_hotkeys}
1085
1144
  chain_hotkeys = [
1086
1145
  (
1087
1146
  get_hotkey_identity(stake_info.hotkey_ss58, identities, old_identities),
1088
1147
  stake_info.hotkey_ss58,
1148
+ None,
1089
1149
  )
1090
1150
  for stake_info in stake_infos
1091
1151
  if (
@@ -1100,14 +1160,14 @@ def _get_hotkeys_to_unstake(
1100
1160
  result = []
1101
1161
  for hotkey_identifier in include_hotkeys:
1102
1162
  if is_valid_ss58_address(hotkey_identifier):
1103
- result.append((None, hotkey_identifier))
1163
+ result.append((None, hotkey_identifier, None))
1104
1164
  else:
1105
1165
  wallet_ = Wallet(
1106
1166
  name=wallet.name,
1107
1167
  path=wallet.path,
1108
1168
  hotkey=hotkey_identifier,
1109
1169
  )
1110
- result.append((wallet_.hotkey_str, wallet_.hotkey.ss58_address))
1170
+ result.append((wallet_.hotkey_str, wallet_.hotkey.ss58_address, None))
1111
1171
  return result
1112
1172
 
1113
1173
  # Only cli.config.wallet.hotkey is specified
@@ -1115,7 +1175,7 @@ def _get_hotkeys_to_unstake(
1115
1175
  f"Unstaking from wallet: ({wallet.name}) from hotkey: ({wallet.hotkey_str})"
1116
1176
  )
1117
1177
  assert wallet.hotkey is not None
1118
- return [(wallet.hotkey_str, wallet.hotkey.ss58_address)]
1178
+ return [(wallet.hotkey_str, wallet.hotkey.ss58_address, None)]
1119
1179
 
1120
1180
 
1121
1181
  def _create_unstake_table(
@@ -1169,6 +1229,11 @@ def _create_unstake_table(
1169
1229
  justify="center",
1170
1230
  style=COLOR_PALETTE["POOLS"]["RATE"],
1171
1231
  )
1232
+ table.add_column(
1233
+ f"Fee ({Balance.get_unit(0)})",
1234
+ justify="center",
1235
+ style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
1236
+ )
1172
1237
  table.add_column(
1173
1238
  f"Received ({Balance.get_unit(0)})",
1174
1239
  justify="center",
@@ -1222,7 +1287,8 @@ The columns are as follows:
1222
1287
  - [bold white]Hotkey[/bold white]: The ss58 address or identity of the hotkey you are unstaking from.
1223
1288
  - [bold white]Amount to Unstake[/bold white]: The stake amount you are removing from this key.
1224
1289
  - [bold white]Rate[/bold white]: The rate of exchange between TAO and the subnet's stake.
1225
- - [bold white]Received[/bold white]: The amount of free balance TAO you will receive on this subnet after slippage.
1290
+ - [bold white]Fee[/bold white]: The transaction fee for this unstake operation.
1291
+ - [bold white]Received[/bold white]: The amount of free balance TAO you will receive on this subnet after slippage and fees.
1226
1292
  - [bold white]Slippage[/bold white]: The slippage percentage of the unstake operation. (0% if the subnet is not dynamic i.e. root)."""
1227
1293
 
1228
1294
  safe_staking_description = """
@@ -111,6 +111,12 @@ async def register_subnetwork_extrinsic(
111
111
  ):
112
112
  return False
113
113
 
114
+ call_params = {
115
+ "hotkey": wallet.hotkey.ss58_address,
116
+ "mechid": 1,
117
+ }
118
+ call_function = "register_network"
119
+
114
120
  has_identity = any(subnet_identity.values())
115
121
  if has_identity:
116
122
  identity_data = {
@@ -136,6 +142,8 @@ async def register_subnetwork_extrinsic(
136
142
  if subnet_identity.get("additional")
137
143
  else b"",
138
144
  }
145
+ call_params["identity"] = identity_data
146
+ call_function = "register_network_with_identity"
139
147
  for field, value in identity_data.items():
140
148
  max_size = 64 # bytes
141
149
  if len(value) > max_size:
@@ -149,15 +157,6 @@ async def register_subnetwork_extrinsic(
149
157
  return False
150
158
 
151
159
  with console.status(":satellite: Registering subnet...", spinner="earth"):
152
- call_params = {
153
- "hotkey": wallet.hotkey.ss58_address,
154
- "mechid": 1,
155
- }
156
- call_function = "register_network"
157
- if has_identity:
158
- call_params["identity"] = identity_data
159
- call_function = "register_network_with_identity"
160
-
161
160
  substrate = subtensor.substrate
162
161
  # create extrinsic call
163
162
  call = await substrate.compose_call(
@@ -1341,12 +1340,12 @@ async def burn_cost(subtensor: "SubtensorInterface") -> Optional[Balance]:
1341
1340
  f":satellite:Retrieving lock cost from {subtensor.network}...",
1342
1341
  spinner="aesthetic",
1343
1342
  ):
1344
- burn_cost = await subtensor.burn_cost()
1345
- if burn_cost:
1343
+ current_burn_cost = await subtensor.burn_cost()
1344
+ if current_burn_cost:
1346
1345
  console.print(
1347
- f"Subnet burn cost: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{burn_cost}"
1346
+ f"Subnet burn cost: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{current_burn_cost}"
1348
1347
  )
1349
- return burn_cost
1348
+ return current_burn_cost
1350
1349
  else:
1351
1350
  err_console.print(
1352
1351
  "Subnet burn cost: [red]Failed to get subnet burn cost[/red]"
@@ -1417,7 +1416,7 @@ async def pow_register(
1417
1416
  use_cuda,
1418
1417
  dev_id,
1419
1418
  threads_per_block,
1420
- prompt: bool
1419
+ prompt: bool,
1421
1420
  ):
1422
1421
  """Register neuron."""
1423
1422
 
@@ -155,7 +155,6 @@ async def set_hyperparameter_extrinsic(
155
155
  `False` if the extrinsic fails to enter the block within the timeout.
156
156
  :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
157
157
  or returns `False` if the extrinsic fails to be finalized within the timeout.
158
- :param prompt: If `True`, the call waits for confirmation from the user before proceeding.
159
158
 
160
159
  :return: success: `True` if extrinsic was finalized or included in the block. If we did not wait for
161
160
  finalization/inclusion, the response is `True`.
@@ -178,6 +177,7 @@ async def set_hyperparameter_extrinsic(
178
177
  arbitrary_extrinsic = False
179
178
 
180
179
  extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False))
180
+ call_params = {"netuid": netuid}
181
181
  if not extrinsic:
182
182
  arbitrary_extrinsic, call_params = search_metadata(
183
183
  parameter, value, netuid, subtensor.substrate.metadata
@@ -207,7 +207,6 @@ async def set_hyperparameter_extrinsic(
207
207
  extrinsic_params = await substrate.get_metadata_call_function(
208
208
  "AdminUtils", extrinsic
209
209
  )
210
- call_params = {"netuid": netuid}
211
210
 
212
211
  # if input value is a list, iterate through the list and assign values
213
212
  if isinstance(value, list):
@@ -124,17 +124,18 @@ async def regen_hotkey(
124
124
  json_str = f.read()
125
125
 
126
126
  try:
127
- new_hotkey = wallet.regenerate_hotkey(
127
+ new_hotkey_ = wallet.regenerate_hotkey(
128
128
  mnemonic=mnemonic,
129
129
  seed=seed,
130
130
  json=(json_str, json_password) if all([json_str, json_password]) else None,
131
131
  use_password=use_password,
132
132
  overwrite=overwrite,
133
133
  )
134
- if isinstance(new_hotkey, Wallet):
134
+ if isinstance(new_hotkey_, Wallet):
135
135
  console.print(
136
136
  "\n✅ [dark_sea_green]Regenerated hotkey successfully!\n",
137
- f"[dark_sea_green]Wallet name: ({new_hotkey.name}), path: ({new_hotkey.path}), hotkey ss58: ({new_hotkey.hotkey.ss58_address})",
137
+ f"[dark_sea_green]Wallet name: "
138
+ f"({new_hotkey_.name}), path: ({new_hotkey_.path}), hotkey ss58: ({new_hotkey_.hotkey.ss58_address})",
138
139
  )
139
140
  except ValueError:
140
141
  print_error("Mnemonic phrase is invalid")
bittensor_cli/version.py CHANGED
@@ -16,5 +16,5 @@ def version_as_int(version):
16
16
  return __version_as_int__
17
17
 
18
18
 
19
- __version__ = "9.1.3"
19
+ __version__ = "9.1.4"
20
20
  __version_as_int__ = version_as_int(__version__)
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bittensor-cli
3
- Version: 9.1.3
3
+ Version: 9.2.0
4
4
  Summary: Bittensor CLI
5
5
  Author: bittensor.com
6
6
  Project-URL: homepage, https://github.com/opentensor/btcli
7
7
  Project-URL: Repository, https://github.com/opentensor/btcli
8
- Requires-Python: <3.13,>=3.9
8
+ Requires-Python: <3.14,>=3.9
9
9
  Description-Content-Type: text/markdown
10
10
  Requires-Dist: wheel
11
11
  Requires-Dist: async-property==0.2.2
12
- Requires-Dist: async-substrate-interface>=1.0.5
12
+ Requires-Dist: async-substrate-interface>=1.0.8
13
13
  Requires-Dist: aiohttp~=3.10.2
14
14
  Requires-Dist: backoff~=2.2.1
15
15
  Requires-Dist: GitPython>=3.0.0
@@ -31,7 +31,6 @@ Requires-Dist: pywry>=0.6.2
31
31
  Requires-Dist: plotly>=6.0.0
32
32
  Provides-Extra: cuda
33
33
  Requires-Dist: torch<2.6.0,>=1.13.1; extra == "cuda"
34
- Requires-Dist: cubit>=1.1.0; extra == "cuda"
35
34
 
36
35
  <div align="center">
37
36
 
@@ -74,7 +73,20 @@ Installation steps are described below. For a full documentation on how to use `
74
73
 
75
74
  ## Install on macOS and Linux
76
75
 
77
- You can install `btcli` on your local machine directly from source. **Make sure you verify your installation after you install**:
76
+ You can install `btcli` on your local machine directly from source, or from from PyPI. **Make sure you verify your installation after you install**:
77
+
78
+
79
+ ### Install from PyPI
80
+
81
+ Run
82
+ ```
83
+ pip install -U bittensor-cli
84
+ ```
85
+
86
+ Alternatively, if you prefer to use [uv](https://pypi.org/project/uv/):
87
+ ```
88
+ uv pip install bittensor-cli
89
+ ```
78
90
 
79
91
  ### Install from source
80
92
 
@@ -104,6 +116,14 @@ cd btcli
104
116
  pip3 install .
105
117
  ```
106
118
 
119
+ ### Also install bittensor (SDK)
120
+
121
+ If you prefer to install the btcli alongside the bittensor SDK, you can do this in a single command with
122
+
123
+ ```
124
+ pip install -U bittensor[cli]
125
+ ```
126
+
107
127
  ---
108
128
 
109
129
  ## Install on Windows
@@ -0,0 +1,35 @@
1
+ bittensor_cli/__init__.py,sha256=Lpv4NkbAQgwrfqFOnTMuR_S-fqGdaWCSLhxnFnGTHM0,1232
2
+ bittensor_cli/cli.py,sha256=HbU3AOCiAmicOLA9U-7q92NC9Cmf0p_8qjlabSscaWc,197905
3
+ bittensor_cli/doc_generation_helper.py,sha256=GexqjEIKulWg84hpNBEchJ840oOgOi7DWpt447nsdNI,91
4
+ bittensor_cli/version.py,sha256=laVzyT8eo7SMikK5aTb16S3zsLEpmIzwpNLCcb_IU1w,623
5
+ bittensor_cli/src/__init__.py,sha256=gSRsPtIDWe5FM93ItTjLDp3ZRwS6szo44sOYyMyFlso,27679
6
+ bittensor_cli/src/bittensor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ bittensor_cli/src/bittensor/balances.py,sha256=q5KkxF8wmUguWAFddEKstfDKTxPe5ISHpT6br8x32rc,11148
8
+ bittensor_cli/src/bittensor/chain_data.py,sha256=IPgimCD3US5xZqoIBvH4jQza4LDbfUIpFfl_Orgok1Q,41637
9
+ bittensor_cli/src/bittensor/minigraph.py,sha256=BIzmSVLfBYiRAeGD_i1LAC8Cw7zxp38a91SIFEPMqYc,10479
10
+ bittensor_cli/src/bittensor/networking.py,sha256=pZLMs8YXpZzDMLXWMBb_Bj6TVkm_q9khyY-lnbwVMuE,462
11
+ bittensor_cli/src/bittensor/subtensor_interface.py,sha256=FM3wiKPIDeclHQNFvzLlvCfLrncPPSYIUtU8HYFEXmE,56982
12
+ bittensor_cli/src/bittensor/utils.py,sha256=6oJmqiW-ECEobs0z37Eyzu__MfvEU0DyAD_j3FCfzmI,47530
13
+ bittensor_cli/src/bittensor/extrinsics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ bittensor_cli/src/bittensor/extrinsics/registration.py,sha256=3mJZ3hw_wZEa-8I0R8WVuKjMQi4Y9EV5FjTCvbY37Iw,63780
15
+ bittensor_cli/src/bittensor/extrinsics/root.py,sha256=N9Fg4VaveRRP1ZN4EZjIWCe04FpTNBKWFqx8USKp9uQ,19062
16
+ bittensor_cli/src/bittensor/extrinsics/transfer.py,sha256=FyrRo3yk-065toN4f-1Xes23CE5tqP5KU0dBJkKofUc,8476
17
+ bittensor_cli/src/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ bittensor_cli/src/commands/sudo.py,sha256=bSS9nIWeCYf4nqqBYuoTkVDDA2Fm2Di3UG5xlUMJ6yM,31372
19
+ bittensor_cli/src/commands/view.py,sha256=2MdhWWbY9rwGqDilzs8r2ioa0l2GzrYxe8pKkavEVWs,109517
20
+ bittensor_cli/src/commands/wallets.py,sha256=AGV8JFCvRE_OOJv6NozxmyO4Cvf4y5HYXVfI_1kl70M,50736
21
+ bittensor_cli/src/commands/weights.py,sha256=uI7aACKD90JOtYt61VdKL76z7Fe_wh4WtdwMXL6ydD4,16269
22
+ bittensor_cli/src/commands/stake/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ bittensor_cli/src/commands/stake/add.py,sha256=xJLVcU7RZmksxU29gNh22WLiL5ZWcIm1dKEeYo4IfMc,25816
24
+ bittensor_cli/src/commands/stake/children_hotkeys.py,sha256=Eg0Rq_R2DYBsjEBqqNHElJchQ6MlZePkW_oWlifXfSY,29782
25
+ bittensor_cli/src/commands/stake/list.py,sha256=G7YLP68sq-qmWKPuIy2s6cMYK7XTz0oaMDK4JWR7aBE,28577
26
+ bittensor_cli/src/commands/stake/move.py,sha256=T9sP3CnZW2hWB2gI0J5mVvT_CGooFMjJQoB95otiS2w,35821
27
+ bittensor_cli/src/commands/stake/remove.py,sha256=huHinuNYCZx9fLwYcYELGS13X3rDG3OsKMsqICOtXDM,49486
28
+ bittensor_cli/src/commands/subnets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ bittensor_cli/src/commands/subnets/price.py,sha256=TWcRXUFeS_Q-pfyv0YIluAL8SE7d2gzTODK-9M2J5pw,29878
30
+ bittensor_cli/src/commands/subnets/subnets.py,sha256=d41oWtxOfr4a2QxW3v_P2weELtUOr1vRx4Vi0HzN87s,83935
31
+ bittensor_cli-9.2.0.dist-info/METADATA,sha256=yi6Yd5E8dLmt9UeUcmhewA7GOITtGkLufezrn2tuS78,6475
32
+ bittensor_cli-9.2.0.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
33
+ bittensor_cli-9.2.0.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
34
+ bittensor_cli-9.2.0.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
35
+ bittensor_cli-9.2.0.dist-info/RECORD,,
@@ -1,35 +0,0 @@
1
- bittensor_cli/__init__.py,sha256=Lpv4NkbAQgwrfqFOnTMuR_S-fqGdaWCSLhxnFnGTHM0,1232
2
- bittensor_cli/cli.py,sha256=b74SuigzFMoGItVfdkpWoIOktTBLx1ALc-oHb7nprvs,198453
3
- bittensor_cli/doc_generation_helper.py,sha256=GexqjEIKulWg84hpNBEchJ840oOgOi7DWpt447nsdNI,91
4
- bittensor_cli/version.py,sha256=rEVJnYbpsCLoerFYGs5hlQWusewL7n5JfAa3G1B_BeQ,623
5
- bittensor_cli/src/__init__.py,sha256=9JLmK4Z-auboWXX74sMkJiFSvcjw3jcRUUw5lRRABy8,26553
6
- bittensor_cli/src/bittensor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- bittensor_cli/src/bittensor/balances.py,sha256=q5KkxF8wmUguWAFddEKstfDKTxPe5ISHpT6br8x32rc,11148
8
- bittensor_cli/src/bittensor/chain_data.py,sha256=hG61nRpp_4A1NkmEQcbmL89Z1UqL1IF1F9om896Pp-g,41616
9
- bittensor_cli/src/bittensor/minigraph.py,sha256=BIzmSVLfBYiRAeGD_i1LAC8Cw7zxp38a91SIFEPMqYc,10479
10
- bittensor_cli/src/bittensor/networking.py,sha256=pZLMs8YXpZzDMLXWMBb_Bj6TVkm_q9khyY-lnbwVMuE,462
11
- bittensor_cli/src/bittensor/subtensor_interface.py,sha256=tOhQEkjO03J7YJNYdUOmmH333SR5wNybmgYNZ7aoygk,54507
12
- bittensor_cli/src/bittensor/utils.py,sha256=z3KsDpOVgL1O16aXYJWDspaK1UFgei-eXxX2biZZ98s,47539
13
- bittensor_cli/src/bittensor/extrinsics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- bittensor_cli/src/bittensor/extrinsics/registration.py,sha256=3mJZ3hw_wZEa-8I0R8WVuKjMQi4Y9EV5FjTCvbY37Iw,63780
15
- bittensor_cli/src/bittensor/extrinsics/root.py,sha256=N9Fg4VaveRRP1ZN4EZjIWCe04FpTNBKWFqx8USKp9uQ,19062
16
- bittensor_cli/src/bittensor/extrinsics/transfer.py,sha256=FyrRo3yk-065toN4f-1Xes23CE5tqP5KU0dBJkKofUc,8476
17
- bittensor_cli/src/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- bittensor_cli/src/commands/sudo.py,sha256=GICsjDYvaoJpq5zAUHb3gIcXvD0t1VNOkz8hghz_AUs,31475
19
- bittensor_cli/src/commands/view.py,sha256=2MdhWWbY9rwGqDilzs8r2ioa0l2GzrYxe8pKkavEVWs,109517
20
- bittensor_cli/src/commands/wallets.py,sha256=DuG3LQx75NRsi-f0-8Y-FriOSqj57nViNf1xryHHFV0,50711
21
- bittensor_cli/src/commands/weights.py,sha256=uI7aACKD90JOtYt61VdKL76z7Fe_wh4WtdwMXL6ydD4,16269
22
- bittensor_cli/src/commands/stake/__init__.py,sha256=uxomMv_QrYt5Qn3_X5UWFFh45ISjB0JmDmCFxVyX8nQ,6495
23
- bittensor_cli/src/commands/stake/add.py,sha256=aVdBEdrfJ5-IK9MpQ00lYQylw_e6BgimCsxMFJZe75E,24911
24
- bittensor_cli/src/commands/stake/children_hotkeys.py,sha256=udpomkjeNb8MTEFm2p2BxHG1RSunOUamHSdWpQWvvXY,29631
25
- bittensor_cli/src/commands/stake/list.py,sha256=TfoFrXsYRTQeTiDd6pHu-f6rZ2ev0VK9fMybQ295X7Q,28600
26
- bittensor_cli/src/commands/stake/move.py,sha256=RSFtMgpBlK82U9CtCcijeZWBOABABnaPzyIgC2ug_Tc,34635
27
- bittensor_cli/src/commands/stake/remove.py,sha256=iEVV79RmhA2mCL2UGydc98pcCNTO6dpP7gJeq6OfbG0,46884
28
- bittensor_cli/src/commands/subnets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- bittensor_cli/src/commands/subnets/price.py,sha256=TWcRXUFeS_Q-pfyv0YIluAL8SE7d2gzTODK-9M2J5pw,29878
30
- bittensor_cli/src/commands/subnets/subnets.py,sha256=e2QeuaAQZg0S-uHvDUejy82wJPe1_njb9_qeoLcrKf0,83955
31
- bittensor_cli-9.1.3.dist-info/METADATA,sha256=Z7pEVMLdBIfcdSPMijRgi1SsA1zIXKcaJ6KB526tzsw,6145
32
- bittensor_cli-9.1.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
33
- bittensor_cli-9.1.3.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
34
- bittensor_cli-9.1.3.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
35
- bittensor_cli-9.1.3.dist-info/RECORD,,