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.
- bittensor_cli/cli.py +601 -133
- bittensor_cli/src/__init__.py +444 -465
- bittensor_cli/src/bittensor/chain_data.py +6 -2
- bittensor_cli/src/bittensor/extrinsics/registration.py +47 -23
- bittensor_cli/src/bittensor/extrinsics/root.py +10 -11
- bittensor_cli/src/bittensor/extrinsics/transfer.py +5 -3
- bittensor_cli/src/bittensor/subtensor_interface.py +59 -5
- bittensor_cli/src/bittensor/utils.py +6 -2
- bittensor_cli/src/commands/stake/add.py +127 -98
- bittensor_cli/src/commands/stake/children_hotkeys.py +120 -79
- bittensor_cli/src/commands/stake/list.py +54 -20
- bittensor_cli/src/commands/stake/move.py +15 -12
- bittensor_cli/src/commands/stake/remove.py +101 -80
- bittensor_cli/src/commands/subnets/price.py +11 -9
- bittensor_cli/src/commands/subnets/subnets.py +334 -81
- bittensor_cli/src/commands/sudo.py +76 -22
- bittensor_cli/src/commands/wallets.py +656 -40
- bittensor_cli/src/commands/weights.py +21 -11
- bittensor_cli/version.py +14 -11
- {bittensor_cli-9.2.0.dist-info → bittensor_cli-9.4.0.dist-info}/METADATA +8 -9
- bittensor_cli-9.4.0.dist-info/RECORD +35 -0
- {bittensor_cli-9.2.0.dist-info → bittensor_cli-9.4.0.dist-info}/WHEEL +1 -1
- bittensor_cli-9.2.0.dist-info/RECORD +0 -35
- {bittensor_cli-9.2.0.dist-info → bittensor_cli-9.4.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.2.0.dist-info → bittensor_cli-9.4.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import json
|
2
3
|
from functools import partial
|
3
4
|
|
4
5
|
from typing import TYPE_CHECKING, Optional
|
@@ -20,6 +21,7 @@ from bittensor_cli.src.bittensor.utils import (
|
|
20
21
|
format_error_message,
|
21
22
|
group_subnets,
|
22
23
|
unlock_key,
|
24
|
+
json_console,
|
23
25
|
)
|
24
26
|
|
25
27
|
if TYPE_CHECKING:
|
@@ -41,6 +43,8 @@ async def unstake(
|
|
41
43
|
safe_staking: bool,
|
42
44
|
rate_tolerance: float,
|
43
45
|
allow_partial_stake: bool,
|
46
|
+
json_output: bool,
|
47
|
+
era: int,
|
44
48
|
):
|
45
49
|
"""Unstake from hotkey(s)."""
|
46
50
|
with console.status(
|
@@ -258,8 +262,11 @@ async def unstake(
|
|
258
262
|
base_unstake_op["price_with_tolerance"] = price_with_tolerance
|
259
263
|
base_table_row.extend(
|
260
264
|
[
|
261
|
-
|
262
|
-
f"
|
265
|
+
# Rate with tolerance
|
266
|
+
f"{rate_with_tolerance:.4f} {Balance.get_unit(0)}/{Balance.get_unit(netuid)}",
|
267
|
+
# Partial unstake
|
268
|
+
f"[{'dark_sea_green3' if allow_partial_stake else 'red'}]"
|
269
|
+
f"{allow_partial_stake}[/{'dark_sea_green3' if allow_partial_stake else 'red'}]",
|
263
270
|
]
|
264
271
|
)
|
265
272
|
|
@@ -290,44 +297,45 @@ async def unstake(
|
|
290
297
|
if not unlock_key(wallet).success:
|
291
298
|
return False
|
292
299
|
|
300
|
+
successes = []
|
293
301
|
with console.status("\n:satellite: Performing unstaking operations...") as status:
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
status=status,
|
327
|
-
)
|
302
|
+
for op in unstake_operations:
|
303
|
+
common_args = {
|
304
|
+
"wallet": wallet,
|
305
|
+
"subtensor": subtensor,
|
306
|
+
"netuid": op["netuid"],
|
307
|
+
"amount": op["amount_to_unstake"],
|
308
|
+
"hotkey_ss58": op["hotkey_ss58"],
|
309
|
+
"status": status,
|
310
|
+
"era": era,
|
311
|
+
}
|
312
|
+
|
313
|
+
if safe_staking and op["netuid"] != 0:
|
314
|
+
func = _safe_unstake_extrinsic
|
315
|
+
specific_args = {
|
316
|
+
"price_limit": op["price_with_tolerance"],
|
317
|
+
"allow_partial_stake": allow_partial_stake,
|
318
|
+
}
|
319
|
+
else:
|
320
|
+
func = _unstake_extrinsic
|
321
|
+
specific_args = {"current_stake": op["current_stake_balance"]}
|
322
|
+
|
323
|
+
suc = await func(**common_args, **specific_args)
|
324
|
+
|
325
|
+
successes.append(
|
326
|
+
{
|
327
|
+
"netuid": op["netuid"],
|
328
|
+
"hotkey_ss58": op["hotkey_ss58"],
|
329
|
+
"unstake_amount": op["amount_to_unstake"].tao,
|
330
|
+
"success": suc,
|
331
|
+
}
|
332
|
+
)
|
333
|
+
|
328
334
|
console.print(
|
329
335
|
f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]Unstaking operations completed."
|
330
336
|
)
|
337
|
+
if json_output:
|
338
|
+
json_console.print(json.dumps(successes))
|
331
339
|
|
332
340
|
|
333
341
|
async def unstake_all(
|
@@ -338,7 +346,9 @@ async def unstake_all(
|
|
338
346
|
all_hotkeys: bool = False,
|
339
347
|
include_hotkeys: Optional[list[str]] = None,
|
340
348
|
exclude_hotkeys: Optional[list[str]] = None,
|
349
|
+
era: int = 3,
|
341
350
|
prompt: bool = True,
|
351
|
+
json_output: bool = False,
|
342
352
|
) -> bool:
|
343
353
|
"""Unstakes all stakes from all hotkeys in all subnets."""
|
344
354
|
include_hotkeys = include_hotkeys or []
|
@@ -434,7 +444,7 @@ async def unstake_all(
|
|
434
444
|
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
|
435
445
|
)
|
436
446
|
table.add_column(
|
437
|
-
f"
|
447
|
+
f"Received ({Balance.unit})",
|
438
448
|
justify="center",
|
439
449
|
style=COLOR_PALETTE["POOLS"]["TAO_EQUIV"],
|
440
450
|
)
|
@@ -484,11 +494,16 @@ async def unstake_all(
|
|
484
494
|
slippage_pct,
|
485
495
|
)
|
486
496
|
console.print(table)
|
487
|
-
message = ""
|
488
497
|
if max_slippage > 5:
|
489
|
-
message
|
490
|
-
|
491
|
-
|
498
|
+
message = (
|
499
|
+
f"[{COLOR_PALETTE['STAKE']['SLIPPAGE_TEXT']}]--------------------------------------------------------------"
|
500
|
+
f"-----------------------------------------------------\n"
|
501
|
+
f"[bold]WARNING:[/bold] The slippage on one of your operations is high: "
|
502
|
+
f"[{COLOR_PALETTE['STAKE']['SLIPPAGE_PERCENT']}]{max_slippage:.4f}%"
|
503
|
+
f"[/{COLOR_PALETTE['STAKE']['SLIPPAGE_PERCENT']}], this may result in a loss of funds.\n"
|
504
|
+
"----------------------------------------------------------------------------------------------------------"
|
505
|
+
"---------\n"
|
506
|
+
)
|
492
507
|
console.print(message)
|
493
508
|
|
494
509
|
console.print(
|
@@ -502,17 +517,20 @@ async def unstake_all(
|
|
502
517
|
|
503
518
|
if not unlock_key(wallet).success:
|
504
519
|
return False
|
505
|
-
|
520
|
+
successes = {}
|
506
521
|
with console.status("Unstaking all stakes...") as status:
|
507
522
|
for hotkey_ss58 in hotkey_ss58s:
|
508
|
-
await _unstake_all_extrinsic(
|
523
|
+
successes[hotkey_ss58] = await _unstake_all_extrinsic(
|
509
524
|
wallet=wallet,
|
510
525
|
subtensor=subtensor,
|
511
526
|
hotkey_ss58=hotkey_ss58,
|
512
527
|
hotkey_name=hotkey_names.get(hotkey_ss58, hotkey_ss58),
|
513
528
|
unstake_all_alpha=unstake_all_alpha,
|
514
529
|
status=status,
|
530
|
+
era=era,
|
515
531
|
)
|
532
|
+
if json_output:
|
533
|
+
return json_console.print(json.dumps({"success": successes}))
|
516
534
|
|
517
535
|
|
518
536
|
# Extrinsics
|
@@ -524,7 +542,8 @@ async def _unstake_extrinsic(
|
|
524
542
|
current_stake: Balance,
|
525
543
|
hotkey_ss58: str,
|
526
544
|
status=None,
|
527
|
-
|
545
|
+
era: int = 3,
|
546
|
+
) -> bool:
|
528
547
|
"""Execute a standard unstake extrinsic.
|
529
548
|
|
530
549
|
Args:
|
@@ -535,6 +554,7 @@ async def _unstake_extrinsic(
|
|
535
554
|
wallet: Wallet instance
|
536
555
|
subtensor: Subtensor interface
|
537
556
|
status: Optional status for console updates
|
557
|
+
era: blocks for which the transaction is valid
|
538
558
|
"""
|
539
559
|
err_out = partial(print_error, status=status)
|
540
560
|
failure_prelude = (
|
@@ -546,33 +566,32 @@ async def _unstake_extrinsic(
|
|
546
566
|
f"\n:satellite: Unstaking {amount} from {hotkey_ss58} on netuid: {netuid} ..."
|
547
567
|
)
|
548
568
|
|
549
|
-
current_balance = await
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
569
|
+
current_balance, call = await asyncio.gather(
|
570
|
+
subtensor.get_balance(wallet.coldkeypub.ss58_address),
|
571
|
+
subtensor.substrate.compose_call(
|
572
|
+
call_module="SubtensorModule",
|
573
|
+
call_function="remove_stake",
|
574
|
+
call_params={
|
575
|
+
"hotkey": hotkey_ss58,
|
576
|
+
"netuid": netuid,
|
577
|
+
"amount_unstaked": amount.rao,
|
578
|
+
},
|
579
|
+
),
|
558
580
|
)
|
559
581
|
extrinsic = await subtensor.substrate.create_signed_extrinsic(
|
560
|
-
call=call, keypair=wallet.coldkey
|
582
|
+
call=call, keypair=wallet.coldkey, era={"period": era}
|
561
583
|
)
|
562
584
|
|
563
585
|
try:
|
564
586
|
response = await subtensor.substrate.submit_extrinsic(
|
565
587
|
extrinsic, wait_for_inclusion=True, wait_for_finalization=False
|
566
588
|
)
|
567
|
-
await response.process_events()
|
568
|
-
|
569
589
|
if not await response.is_success:
|
570
590
|
err_out(
|
571
591
|
f"{failure_prelude} with error: "
|
572
592
|
f"{format_error_message(await response.error_message)}"
|
573
593
|
)
|
574
|
-
return
|
575
|
-
|
594
|
+
return False
|
576
595
|
# Fetch latest balance and stake
|
577
596
|
block_hash = await subtensor.substrate.get_chain_head()
|
578
597
|
new_balance, new_stake = await asyncio.gather(
|
@@ -593,9 +612,11 @@ async def _unstake_extrinsic(
|
|
593
612
|
f"Subnet: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
|
594
613
|
f" Stake:\n [blue]{current_stake}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_stake}"
|
595
614
|
)
|
615
|
+
return True
|
596
616
|
|
597
617
|
except Exception as e:
|
598
618
|
err_out(f"{failure_prelude} with error: {str(e)}")
|
619
|
+
return False
|
599
620
|
|
600
621
|
|
601
622
|
async def _safe_unstake_extrinsic(
|
@@ -607,7 +628,8 @@ async def _safe_unstake_extrinsic(
|
|
607
628
|
price_limit: Balance,
|
608
629
|
allow_partial_stake: bool,
|
609
630
|
status=None,
|
610
|
-
|
631
|
+
era: int = 3,
|
632
|
+
) -> bool:
|
611
633
|
"""Execute a safe unstake extrinsic with price limit.
|
612
634
|
|
613
635
|
Args:
|
@@ -632,30 +654,31 @@ async def _safe_unstake_extrinsic(
|
|
632
654
|
|
633
655
|
block_hash = await subtensor.substrate.get_chain_head()
|
634
656
|
|
635
|
-
current_balance, next_nonce, current_stake = await asyncio.gather(
|
657
|
+
current_balance, next_nonce, current_stake, call = await asyncio.gather(
|
636
658
|
subtensor.get_balance(wallet.coldkeypub.ss58_address, block_hash),
|
637
659
|
subtensor.substrate.get_account_next_index(wallet.coldkeypub.ss58_address),
|
638
660
|
subtensor.get_stake(
|
639
661
|
hotkey_ss58=hotkey_ss58,
|
640
662
|
coldkey_ss58=wallet.coldkeypub.ss58_address,
|
641
663
|
netuid=netuid,
|
664
|
+
block_hash=block_hash,
|
665
|
+
),
|
666
|
+
subtensor.substrate.compose_call(
|
667
|
+
call_module="SubtensorModule",
|
668
|
+
call_function="remove_stake_limit",
|
669
|
+
call_params={
|
670
|
+
"hotkey": hotkey_ss58,
|
671
|
+
"netuid": netuid,
|
672
|
+
"amount_unstaked": amount.rao,
|
673
|
+
"limit_price": price_limit,
|
674
|
+
"allow_partial": allow_partial_stake,
|
675
|
+
},
|
676
|
+
block_hash=block_hash,
|
642
677
|
),
|
643
|
-
)
|
644
|
-
|
645
|
-
call = await subtensor.substrate.compose_call(
|
646
|
-
call_module="SubtensorModule",
|
647
|
-
call_function="remove_stake_limit",
|
648
|
-
call_params={
|
649
|
-
"hotkey": hotkey_ss58,
|
650
|
-
"netuid": netuid,
|
651
|
-
"amount_unstaked": amount.rao,
|
652
|
-
"limit_price": price_limit,
|
653
|
-
"allow_partial": allow_partial_stake,
|
654
|
-
},
|
655
678
|
)
|
656
679
|
|
657
680
|
extrinsic = await subtensor.substrate.create_signed_extrinsic(
|
658
|
-
call=call, keypair=wallet.coldkey, nonce=next_nonce
|
681
|
+
call=call, keypair=wallet.coldkey, nonce=next_nonce, era={"period": era}
|
659
682
|
)
|
660
683
|
|
661
684
|
try:
|
@@ -670,17 +693,15 @@ async def _safe_unstake_extrinsic(
|
|
670
693
|
f"Either increase price tolerance or enable partial unstaking.",
|
671
694
|
status=status,
|
672
695
|
)
|
673
|
-
return
|
674
696
|
else:
|
675
697
|
err_out(f"\n{failure_prelude} with error: {format_error_message(e)}")
|
676
|
-
return
|
698
|
+
return False
|
677
699
|
|
678
|
-
await response.process_events()
|
679
700
|
if not await response.is_success:
|
680
701
|
err_out(
|
681
702
|
f"\n{failure_prelude} with error: {format_error_message(await response.error_message)}"
|
682
703
|
)
|
683
|
-
return
|
704
|
+
return False
|
684
705
|
|
685
706
|
block_hash = await subtensor.substrate.get_chain_head()
|
686
707
|
new_balance, new_stake = await asyncio.gather(
|
@@ -711,6 +732,7 @@ async def _safe_unstake_extrinsic(
|
|
711
732
|
f"Subnet: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] "
|
712
733
|
f"Stake:\n [blue]{current_stake}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_stake}"
|
713
734
|
)
|
735
|
+
return True
|
714
736
|
|
715
737
|
|
716
738
|
async def _unstake_all_extrinsic(
|
@@ -720,6 +742,7 @@ async def _unstake_all_extrinsic(
|
|
720
742
|
hotkey_name: str,
|
721
743
|
unstake_all_alpha: bool,
|
722
744
|
status=None,
|
745
|
+
era: int = 3,
|
723
746
|
) -> None:
|
724
747
|
"""Execute an unstake all extrinsic.
|
725
748
|
|
@@ -770,13 +793,11 @@ async def _unstake_all_extrinsic(
|
|
770
793
|
try:
|
771
794
|
response = await subtensor.substrate.submit_extrinsic(
|
772
795
|
extrinsic=await subtensor.substrate.create_signed_extrinsic(
|
773
|
-
call=call,
|
774
|
-
keypair=wallet.coldkey,
|
796
|
+
call=call, keypair=wallet.coldkey, era={"period": era}
|
775
797
|
),
|
776
798
|
wait_for_inclusion=True,
|
777
799
|
wait_for_finalization=False,
|
778
800
|
)
|
779
|
-
await response.process_events()
|
780
801
|
|
781
802
|
if not await response.is_success:
|
782
803
|
err_out(
|
@@ -13,6 +13,7 @@ from bittensor_cli.src.bittensor.utils import (
|
|
13
13
|
err_console,
|
14
14
|
get_subnet_name,
|
15
15
|
print_error,
|
16
|
+
json_console,
|
16
17
|
)
|
17
18
|
|
18
19
|
if TYPE_CHECKING:
|
@@ -26,6 +27,7 @@ async def price(
|
|
26
27
|
interval_hours: int = 24,
|
27
28
|
html_output: bool = False,
|
28
29
|
log_scale: bool = False,
|
30
|
+
json_output: bool = False,
|
29
31
|
):
|
30
32
|
"""
|
31
33
|
Fetch historical price data for subnets and display it in a chart.
|
@@ -60,7 +62,7 @@ async def price(
|
|
60
62
|
all_subnet_infos = await asyncio.gather(*subnet_info_cors)
|
61
63
|
|
62
64
|
subnet_data = _process_subnet_data(
|
63
|
-
block_numbers, all_subnet_infos, netuids, all_netuids
|
65
|
+
block_numbers, all_subnet_infos, netuids, all_netuids
|
64
66
|
)
|
65
67
|
|
66
68
|
if not subnet_data:
|
@@ -71,17 +73,13 @@ async def price(
|
|
71
73
|
await _generate_html_output(
|
72
74
|
subnet_data, block_numbers, interval_hours, log_scale
|
73
75
|
)
|
76
|
+
elif json_output:
|
77
|
+
json_console.print(json.dumps(_generate_json_output(subnet_data)))
|
74
78
|
else:
|
75
79
|
_generate_cli_output(subnet_data, block_numbers, interval_hours, log_scale)
|
76
80
|
|
77
81
|
|
78
|
-
def _process_subnet_data(
|
79
|
-
block_numbers,
|
80
|
-
all_subnet_infos,
|
81
|
-
netuids,
|
82
|
-
all_netuids,
|
83
|
-
interval_hours,
|
84
|
-
):
|
82
|
+
def _process_subnet_data(block_numbers, all_subnet_infos, netuids, all_netuids):
|
85
83
|
"""
|
86
84
|
Process subnet data into a structured format for price analysis.
|
87
85
|
"""
|
@@ -772,6 +770,10 @@ async def _generate_html_output(
|
|
772
770
|
print_error(f"Error generating price chart: {e}")
|
773
771
|
|
774
772
|
|
773
|
+
def _generate_json_output(subnet_data):
|
774
|
+
return {netuid: data for netuid, data in subnet_data.items()}
|
775
|
+
|
776
|
+
|
775
777
|
def _generate_cli_output(subnet_data, block_numbers, interval_hours, log_scale):
|
776
778
|
"""
|
777
779
|
Render the price data in a textual CLI style with plotille ASCII charts.
|
@@ -802,7 +804,7 @@ def _generate_cli_output(subnet_data, block_numbers, interval_hours, log_scale):
|
|
802
804
|
|
803
805
|
fig.plot(
|
804
806
|
block_numbers,
|
805
|
-
|
807
|
+
prices,
|
806
808
|
label=f"Subnet {netuid} Price",
|
807
809
|
interp="linear",
|
808
810
|
lc="bae98f",
|