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.
- bittensor_cli/cli.py +22 -18
- bittensor_cli/src/__init__.py +105 -58
- bittensor_cli/src/bittensor/chain_data.py +3 -1
- bittensor_cli/src/bittensor/subtensor_interface.py +79 -5
- bittensor_cli/src/bittensor/utils.py +2 -3
- bittensor_cli/src/commands/stake/__init__.py +0 -154
- bittensor_cli/src/commands/stake/add.py +60 -32
- bittensor_cli/src/commands/stake/children_hotkeys.py +17 -14
- bittensor_cli/src/commands/stake/list.py +93 -95
- bittensor_cli/src/commands/stake/move.py +43 -9
- bittensor_cli/src/commands/stake/remove.py +111 -45
- bittensor_cli/src/commands/subnets/subnets.py +13 -14
- bittensor_cli/src/commands/sudo.py +1 -2
- bittensor_cli/src/commands/wallets.py +4 -3
- bittensor_cli/version.py +1 -1
- {bittensor_cli-9.1.3.dist-info → bittensor_cli-9.2.0.dist-info}/METADATA +25 -5
- bittensor_cli-9.2.0.dist-info/RECORD +35 -0
- bittensor_cli-9.1.3.dist-info/RECORD +0 -35
- {bittensor_cli-9.1.3.dist-info → bittensor_cli-9.2.0.dist-info}/WHEEL +0 -0
- {bittensor_cli-9.1.3.dist-info → bittensor_cli-9.2.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.1.3.dist-info → bittensor_cli-9.2.0.dist-info}/top_level.txt +0 -0
@@ -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
|
193
|
-
f"
|
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
|
-
|
198
|
-
|
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 = [
|
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
|
-
|
436
|
-
|
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
|
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(
|
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
|
-
|
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, _,
|
806
|
-
|
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
|
-
|
813
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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,
|
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 = {
|
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]
|
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
|
-
|
1345
|
-
if
|
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']}]{
|
1346
|
+
f"Subnet burn cost: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{current_burn_cost}"
|
1348
1347
|
)
|
1349
|
-
return
|
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
|
-
|
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(
|
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:
|
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
@@ -1,15 +1,15 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: bittensor-cli
|
3
|
-
Version: 9.
|
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.
|
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.
|
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,,
|
File without changes
|
File without changes
|