bittensor-cli 9.8.7__py3-none-any.whl → 9.10.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 +229 -55
- bittensor_cli/src/bittensor/extrinsics/registration.py +29 -25
- bittensor_cli/src/bittensor/extrinsics/root.py +6 -5
- bittensor_cli/src/bittensor/extrinsics/transfer.py +35 -18
- bittensor_cli/src/bittensor/subtensor_interface.py +34 -15
- bittensor_cli/src/bittensor/utils.py +13 -1
- bittensor_cli/src/commands/stake/add.py +86 -30
- bittensor_cli/src/commands/stake/children_hotkeys.py +16 -14
- bittensor_cli/src/commands/stake/move.py +106 -84
- bittensor_cli/src/commands/stake/remove.py +119 -11
- bittensor_cli/src/commands/subnets/price.py +126 -30
- bittensor_cli/src/commands/subnets/subnets.py +3 -2
- bittensor_cli/src/commands/sudo.py +13 -11
- bittensor_cli/src/commands/wallets.py +159 -19
- bittensor_cli/src/commands/weights.py +2 -1
- {bittensor_cli-9.8.7.dist-info → bittensor_cli-9.10.0.dist-info}/METADATA +14 -6
- {bittensor_cli-9.8.7.dist-info → bittensor_cli-9.10.0.dist-info}/RECORD +20 -20
- {bittensor_cli-9.8.7.dist-info → bittensor_cli-9.10.0.dist-info}/WHEEL +0 -0
- {bittensor_cli-9.8.7.dist-info → bittensor_cli-9.10.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.8.7.dist-info → bittensor_cli-9.10.0.dist-info}/top_level.txt +0 -0
bittensor_cli/cli.py
CHANGED
@@ -58,6 +58,7 @@ from bittensor_cli.src.bittensor.utils import (
|
|
58
58
|
validate_uri,
|
59
59
|
prompt_for_subnet_identity,
|
60
60
|
validate_rate_tolerance,
|
61
|
+
get_hotkey_pub_ss58,
|
61
62
|
)
|
62
63
|
from bittensor_cli.src.commands import sudo, wallets, view
|
63
64
|
from bittensor_cli.src.commands import weights as weights_cmds
|
@@ -250,7 +251,7 @@ class Options:
|
|
250
251
|
True,
|
251
252
|
"--prompt/--no-prompt",
|
252
253
|
" /--yes",
|
253
|
-
"
|
254
|
+
" /--no_prompt",
|
254
255
|
" /-y",
|
255
256
|
help="Enable or disable interactive prompts.",
|
256
257
|
)
|
@@ -643,8 +644,21 @@ class CLIManager:
|
|
643
644
|
# },
|
644
645
|
}
|
645
646
|
self.subtensor = None
|
647
|
+
|
648
|
+
if sys.version_info < (3, 10):
|
649
|
+
# For Python 3.9 or lower
|
650
|
+
self.event_loop = asyncio.new_event_loop()
|
651
|
+
else:
|
652
|
+
try:
|
653
|
+
uvloop = importlib.import_module("uvloop")
|
654
|
+
self.event_loop = uvloop.new_event_loop()
|
655
|
+
except ModuleNotFoundError:
|
656
|
+
self.event_loop = asyncio.new_event_loop()
|
657
|
+
|
646
658
|
self.config_base_path = os.path.expanduser(defaults.config.base_path)
|
647
|
-
self.config_path = os.path.expanduser(
|
659
|
+
self.config_path = os.getenv("BTCLI_CONFIG_PATH") or os.path.expanduser(
|
660
|
+
defaults.config.path
|
661
|
+
)
|
648
662
|
|
649
663
|
self.app = typer.Typer(
|
650
664
|
rich_markup_mode="rich",
|
@@ -652,7 +666,12 @@ class CLIManager:
|
|
652
666
|
epilog=_epilog,
|
653
667
|
no_args_is_help=True,
|
654
668
|
)
|
655
|
-
self.config_app = typer.Typer(
|
669
|
+
self.config_app = typer.Typer(
|
670
|
+
epilog=_epilog,
|
671
|
+
help=f"Allows for getting/setting the config. "
|
672
|
+
f"Default path for the config file is [{COLORS.G.ARG}]{defaults.config.path}[/{COLORS.G.ARG}]. "
|
673
|
+
f"You can set your own with the env var [{COLORS.G.ARG}]BTCLI_CONFIG_PATH[/{COLORS.G.ARG}]",
|
674
|
+
)
|
656
675
|
self.wallet_app = typer.Typer(epilog=_epilog)
|
657
676
|
self.stake_app = typer.Typer(epilog=_epilog)
|
658
677
|
self.sudo_app = typer.Typer(epilog=_epilog)
|
@@ -773,6 +792,9 @@ class CLIManager:
|
|
773
792
|
self.wallet_app.command(
|
774
793
|
"regen-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
|
775
794
|
)(self.wallet_regen_hotkey)
|
795
|
+
self.wallet_app.command(
|
796
|
+
"regen-hotkeypub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
|
797
|
+
)(self.wallet_regen_hotkey_pub)
|
776
798
|
self.wallet_app.command(
|
777
799
|
"new-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
|
778
800
|
)(self.wallet_new_hotkey)
|
@@ -817,6 +839,9 @@ class CLIManager:
|
|
817
839
|
self.wallet_app.command(
|
818
840
|
"sign", rich_help_panel=HELP_PANELS["WALLET"]["OPERATIONS"]
|
819
841
|
)(self.wallet_sign)
|
842
|
+
self.wallet_app.command(
|
843
|
+
"verify", rich_help_panel=HELP_PANELS["WALLET"]["OPERATIONS"]
|
844
|
+
)(self.wallet_verify)
|
820
845
|
|
821
846
|
# stake commands
|
822
847
|
self.stake_app.command(
|
@@ -952,6 +977,10 @@ class CLIManager:
|
|
952
977
|
"regen_hotkey",
|
953
978
|
hidden=True,
|
954
979
|
)(self.wallet_regen_hotkey)
|
980
|
+
self.wallet_app.command(
|
981
|
+
"regen_hotkeypub",
|
982
|
+
hidden=True,
|
983
|
+
)(self.wallet_regen_hotkey_pub)
|
955
984
|
self.wallet_app.command(
|
956
985
|
"new_hotkey",
|
957
986
|
hidden=True,
|
@@ -1076,11 +1105,11 @@ class CLIManager:
|
|
1076
1105
|
|
1077
1106
|
self.subtensor = SubtensorInterface(network_)
|
1078
1107
|
elif self.config["network"]:
|
1079
|
-
self.subtensor = SubtensorInterface(self.config["network"])
|
1080
1108
|
console.print(
|
1081
1109
|
f"Using the specified network [{COLORS.G.LINKS}]{self.config['network']}"
|
1082
1110
|
f"[/{COLORS.G.LINKS}] from config"
|
1083
1111
|
)
|
1112
|
+
self.subtensor = SubtensorInterface(self.config["network"])
|
1084
1113
|
else:
|
1085
1114
|
self.subtensor = SubtensorInterface(defaults.subtensor.network)
|
1086
1115
|
return self.subtensor
|
@@ -1094,12 +1123,9 @@ class CLIManager:
|
|
1094
1123
|
initiated = False
|
1095
1124
|
try:
|
1096
1125
|
if self.subtensor:
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
else:
|
1101
|
-
initiated = True
|
1102
|
-
result = await cmd
|
1126
|
+
await self.subtensor.substrate.initialize()
|
1127
|
+
initiated = True
|
1128
|
+
result = await cmd
|
1103
1129
|
return result
|
1104
1130
|
except (ConnectionRefusedError, ssl.SSLError, InvalidHandshake):
|
1105
1131
|
err_console.print(f"Unable to connect to the chain: {self.subtensor}")
|
@@ -1125,12 +1151,14 @@ class CLIManager:
|
|
1125
1151
|
exit_early is True
|
1126
1152
|
): # temporarily to handle multiple run commands in one session
|
1127
1153
|
try:
|
1154
|
+
if self.subtensor:
|
1155
|
+
await self.subtensor.substrate.close()
|
1128
1156
|
raise typer.Exit()
|
1129
1157
|
except Exception as e: # ensures we always exit cleanly
|
1130
1158
|
if not isinstance(e, (typer.Exit, RuntimeError)):
|
1131
1159
|
err_console.print(f"An unknown error has occurred: {e}")
|
1132
1160
|
|
1133
|
-
return self.
|
1161
|
+
return self.event_loop.run_until_complete(_run())
|
1134
1162
|
|
1135
1163
|
def main_callback(
|
1136
1164
|
self,
|
@@ -1181,20 +1209,6 @@ class CLIManager:
|
|
1181
1209
|
if k in self.config.keys():
|
1182
1210
|
self.config[k] = v
|
1183
1211
|
|
1184
|
-
if sys.version_info < (3, 10):
|
1185
|
-
# For Python 3.9 or lower
|
1186
|
-
self.asyncio_runner = asyncio.get_event_loop().run_until_complete
|
1187
|
-
else:
|
1188
|
-
try:
|
1189
|
-
uvloop = importlib.import_module("uvloop")
|
1190
|
-
if sys.version_info >= (3, 11):
|
1191
|
-
self.asyncio_runner = uvloop.run
|
1192
|
-
else:
|
1193
|
-
uvloop.install()
|
1194
|
-
self.asyncio_runner = asyncio.run
|
1195
|
-
except ModuleNotFoundError:
|
1196
|
-
self.asyncio_runner = asyncio.run
|
1197
|
-
|
1198
1212
|
def verbosity_handler(
|
1199
1213
|
self, quiet: bool, verbose: bool, json_output: bool = False
|
1200
1214
|
) -> None:
|
@@ -1499,6 +1513,8 @@ class CLIManager:
|
|
1499
1513
|
Column("[bold white]Value", style="gold1"),
|
1500
1514
|
Column("", style="medium_purple"),
|
1501
1515
|
box=box.SIMPLE_HEAD,
|
1516
|
+
title=f"[{COLORS.G.HEADER}]BTCLI Config[/{COLORS.G.HEADER}]: "
|
1517
|
+
f"[{COLORS.G.ARG}]{self.config_path}[/{COLORS.G.ARG}]",
|
1502
1518
|
)
|
1503
1519
|
|
1504
1520
|
for key, value in self.config.items():
|
@@ -1719,7 +1735,7 @@ class CLIManager:
|
|
1719
1735
|
if return_wallet_and_hotkey:
|
1720
1736
|
valid = utils.is_valid_wallet(wallet)
|
1721
1737
|
if valid[1]:
|
1722
|
-
return wallet, wallet
|
1738
|
+
return wallet, get_hotkey_pub_ss58(wallet)
|
1723
1739
|
else:
|
1724
1740
|
if wallet_hotkey and is_valid_ss58_address(wallet_hotkey):
|
1725
1741
|
return wallet, wallet_hotkey
|
@@ -1889,6 +1905,12 @@ class CLIManager:
|
|
1889
1905
|
transfer_all: bool = typer.Option(
|
1890
1906
|
False, "--all", prompt=False, help="Transfer all available balance."
|
1891
1907
|
),
|
1908
|
+
allow_death: bool = typer.Option(
|
1909
|
+
False,
|
1910
|
+
"--allow-death",
|
1911
|
+
prompt=False,
|
1912
|
+
help="Transfer balance even if the resulting balance falls below the existential deposit.",
|
1913
|
+
),
|
1892
1914
|
period: int = Options.period,
|
1893
1915
|
wallet_name: str = Options.wallet_name,
|
1894
1916
|
wallet_path: str = Options.wallet_path,
|
@@ -1932,7 +1954,7 @@ class CLIManager:
|
|
1932
1954
|
subtensor = self.initialize_chain(network)
|
1933
1955
|
if transfer_all and amount:
|
1934
1956
|
print_error("Cannot specify an amount and '--all' flag.")
|
1935
|
-
|
1957
|
+
return False
|
1936
1958
|
elif transfer_all:
|
1937
1959
|
amount = 0
|
1938
1960
|
elif not amount:
|
@@ -1944,6 +1966,7 @@ class CLIManager:
|
|
1944
1966
|
destination=destination_ss58_address,
|
1945
1967
|
amount=amount,
|
1946
1968
|
transfer_all=transfer_all,
|
1969
|
+
allow_death=allow_death,
|
1947
1970
|
era=period,
|
1948
1971
|
prompt=prompt,
|
1949
1972
|
json_output=json_output,
|
@@ -2219,14 +2242,15 @@ class CLIManager:
|
|
2219
2242
|
|
2220
2243
|
if not wallet_path:
|
2221
2244
|
wallet_path = Prompt.ask(
|
2222
|
-
"Enter the path for the wallets directory",
|
2245
|
+
"Enter the path for the wallets directory",
|
2246
|
+
default=self.config.get("wallet_path") or defaults.wallet.path,
|
2223
2247
|
)
|
2224
2248
|
wallet_path = os.path.expanduser(wallet_path)
|
2225
2249
|
|
2226
2250
|
if not wallet_name:
|
2227
2251
|
wallet_name = Prompt.ask(
|
2228
2252
|
f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
|
2229
|
-
default=defaults.wallet.name,
|
2253
|
+
default=self.config.get("wallet_name") or defaults.wallet.name,
|
2230
2254
|
)
|
2231
2255
|
|
2232
2256
|
wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
|
@@ -2270,7 +2294,7 @@ class CLIManager:
|
|
2270
2294
|
|
2271
2295
|
EXAMPLE
|
2272
2296
|
|
2273
|
-
[green]$[/green] btcli wallet
|
2297
|
+
[green]$[/green] btcli wallet regen-coldkeypub --ss58_address 5DkQ4...
|
2274
2298
|
|
2275
2299
|
[bold]Note[/bold]: This command is particularly useful for users who need to regenerate their coldkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old coldkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
|
2276
2300
|
"""
|
@@ -2278,13 +2302,14 @@ class CLIManager:
|
|
2278
2302
|
|
2279
2303
|
if not wallet_path:
|
2280
2304
|
wallet_path = Prompt.ask(
|
2281
|
-
"Enter the path to the wallets directory",
|
2305
|
+
"Enter the path to the wallets directory",
|
2306
|
+
default=self.config.get("wallet_path") or defaults.wallet.path,
|
2282
2307
|
)
|
2283
2308
|
wallet_path = os.path.expanduser(wallet_path)
|
2284
2309
|
|
2285
2310
|
if not wallet_name:
|
2286
2311
|
wallet_name = Prompt.ask(
|
2287
|
-
f"Enter the name of the [{COLORS.G.CK}]new
|
2312
|
+
f"Enter the name of the [{COLORS.G.CK}]wallet for the new coldkeypub",
|
2288
2313
|
default=defaults.wallet.name,
|
2289
2314
|
)
|
2290
2315
|
wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
|
@@ -2301,7 +2326,7 @@ class CLIManager:
|
|
2301
2326
|
address=ss58_address if ss58_address else public_key_hex
|
2302
2327
|
):
|
2303
2328
|
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
|
2304
|
-
|
2329
|
+
return
|
2305
2330
|
return self._run_command(
|
2306
2331
|
wallets.regen_coldkey_pub(
|
2307
2332
|
wallet, ss58_address, public_key_hex, overwrite, json_output
|
@@ -2367,6 +2392,68 @@ class CLIManager:
|
|
2367
2392
|
)
|
2368
2393
|
)
|
2369
2394
|
|
2395
|
+
def wallet_regen_hotkey_pub(
|
2396
|
+
self,
|
2397
|
+
wallet_name: Optional[str] = Options.wallet_name,
|
2398
|
+
wallet_path: Optional[str] = Options.wallet_path,
|
2399
|
+
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
|
2400
|
+
public_key_hex: Optional[str] = Options.public_hex_key,
|
2401
|
+
ss58_address: Optional[str] = Options.ss58_address,
|
2402
|
+
overwrite: bool = Options.overwrite,
|
2403
|
+
quiet: bool = Options.quiet,
|
2404
|
+
verbose: bool = Options.verbose,
|
2405
|
+
json_output: bool = Options.json_output,
|
2406
|
+
):
|
2407
|
+
"""
|
2408
|
+
Regenerates the public part of a hotkey (hotkeypub.txt) for a wallet.
|
2409
|
+
|
2410
|
+
Use this command when you need to move machine for subnet mining. Use the public key or SS58 address from your hotkeypub.txt that you have on another machine to regenerate the hotkeypub.txt on this new machine.
|
2411
|
+
|
2412
|
+
USAGE
|
2413
|
+
|
2414
|
+
The command requires either a public key in hexadecimal format or an ``SS58`` address from the existing hotkeypub.txt from old machine to regenerate the coldkeypub on the new machine.
|
2415
|
+
|
2416
|
+
EXAMPLE
|
2417
|
+
|
2418
|
+
[green]$[/green] btcli wallet regen-hotkeypub --ss58_address 5DkQ4...
|
2419
|
+
|
2420
|
+
[bold]Note[/bold]: This command is particularly useful for users who need to regenerate their hotkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old hotkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
|
2421
|
+
"""
|
2422
|
+
self.verbosity_handler(quiet, verbose, json_output)
|
2423
|
+
|
2424
|
+
if not wallet_path:
|
2425
|
+
wallet_path = Prompt.ask(
|
2426
|
+
"Enter the path to the wallets directory",
|
2427
|
+
default=self.config.get("wallet_path") or defaults.wallet.path,
|
2428
|
+
)
|
2429
|
+
wallet_path = os.path.expanduser(wallet_path)
|
2430
|
+
|
2431
|
+
if not wallet_name:
|
2432
|
+
wallet_name = Prompt.ask(
|
2433
|
+
f"Enter the name of the [{COLORS.G.CK}]wallet for the new hotkeypub",
|
2434
|
+
default=defaults.wallet.name,
|
2435
|
+
)
|
2436
|
+
wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
|
2437
|
+
|
2438
|
+
if not ss58_address and not public_key_hex:
|
2439
|
+
prompt_answer = typer.prompt(
|
2440
|
+
"Enter the ss58_address or the public key in hex"
|
2441
|
+
)
|
2442
|
+
if prompt_answer.startswith("0x"):
|
2443
|
+
public_key_hex = prompt_answer
|
2444
|
+
else:
|
2445
|
+
ss58_address = prompt_answer
|
2446
|
+
if not utils.is_valid_bittensor_address_or_public_key(
|
2447
|
+
address=ss58_address if ss58_address else public_key_hex
|
2448
|
+
):
|
2449
|
+
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
|
2450
|
+
return False
|
2451
|
+
return self._run_command(
|
2452
|
+
wallets.regen_hotkey_pub(
|
2453
|
+
wallet, ss58_address, public_key_hex, overwrite, json_output
|
2454
|
+
)
|
2455
|
+
)
|
2456
|
+
|
2370
2457
|
def wallet_new_hotkey(
|
2371
2458
|
self,
|
2372
2459
|
wallet_name: Optional[str] = Options.wallet_name,
|
@@ -2407,7 +2494,7 @@ class CLIManager:
|
|
2407
2494
|
if not wallet_name:
|
2408
2495
|
wallet_name = Prompt.ask(
|
2409
2496
|
f"Enter the [{COLORS.G.CK}]wallet name",
|
2410
|
-
default=defaults.wallet.name,
|
2497
|
+
default=self.config.get("wallet_name") or defaults.wallet.name,
|
2411
2498
|
)
|
2412
2499
|
|
2413
2500
|
if not wallet_hotkey:
|
@@ -2462,11 +2549,11 @@ class CLIManager:
|
|
2462
2549
|
if not wallet_hotkey:
|
2463
2550
|
wallet_hotkey = Prompt.ask(
|
2464
2551
|
"Enter the [blue]hotkey[/blue] name or "
|
2465
|
-
"[blue]hotkey ss58 address[/blue] [dim](to associate with your coldkey)[/dim]"
|
2552
|
+
"[blue]hotkey ss58 address[/blue] [dim](to associate with your coldkey)[/dim]",
|
2553
|
+
default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
|
2466
2554
|
)
|
2467
2555
|
|
2468
|
-
|
2469
|
-
if is_valid_ss58_address(wallet_hotkey):
|
2556
|
+
if wallet_hotkey and is_valid_ss58_address(wallet_hotkey):
|
2470
2557
|
hotkey_ss58 = wallet_hotkey
|
2471
2558
|
wallet = self.wallet_ask(
|
2472
2559
|
wallet_name,
|
@@ -2486,8 +2573,11 @@ class CLIManager:
|
|
2486
2573
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
2487
2574
|
validate=WV.WALLET_AND_HOTKEY,
|
2488
2575
|
)
|
2489
|
-
hotkey_ss58 = wallet
|
2490
|
-
hotkey_display =
|
2576
|
+
hotkey_ss58 = get_hotkey_pub_ss58(wallet)
|
2577
|
+
hotkey_display = (
|
2578
|
+
f"hotkey [blue]{wallet_hotkey}[/blue] "
|
2579
|
+
f"[{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
|
2580
|
+
)
|
2491
2581
|
|
2492
2582
|
return self._run_command(
|
2493
2583
|
wallets.associate_hotkey(
|
@@ -2534,13 +2624,14 @@ class CLIManager:
|
|
2534
2624
|
|
2535
2625
|
if not wallet_path:
|
2536
2626
|
wallet_path = Prompt.ask(
|
2537
|
-
"Enter the path to the wallets directory",
|
2627
|
+
"Enter the path to the wallets directory",
|
2628
|
+
default=self.config.get("wallet_path") or defaults.wallet.path,
|
2538
2629
|
)
|
2539
2630
|
|
2540
2631
|
if not wallet_name:
|
2541
2632
|
wallet_name = Prompt.ask(
|
2542
2633
|
f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
|
2543
|
-
default=defaults.wallet.name,
|
2634
|
+
default=self.config.get("wallet_name") or defaults.wallet.name,
|
2544
2635
|
)
|
2545
2636
|
|
2546
2637
|
wallet = self.wallet_ask(
|
@@ -2613,7 +2704,8 @@ class CLIManager:
|
|
2613
2704
|
|
2614
2705
|
if not wallet_ss58_address:
|
2615
2706
|
wallet_ss58_address = Prompt.ask(
|
2616
|
-
"Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim]
|
2707
|
+
"Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim]"
|
2708
|
+
"(leave blank to show all pending swaps)[/dim]"
|
2617
2709
|
)
|
2618
2710
|
if not wallet_ss58_address:
|
2619
2711
|
return self._run_command(
|
@@ -2677,18 +2769,18 @@ class CLIManager:
|
|
2677
2769
|
self.verbosity_handler(quiet, verbose, json_output)
|
2678
2770
|
if not wallet_path:
|
2679
2771
|
wallet_path = Prompt.ask(
|
2680
|
-
"Enter the path of wallets directory",
|
2772
|
+
"Enter the path of wallets directory",
|
2773
|
+
default=self.config.get("wallet_path") or defaults.wallet.path,
|
2681
2774
|
)
|
2682
2775
|
|
2683
2776
|
if not wallet_name:
|
2684
2777
|
wallet_name = Prompt.ask(
|
2685
2778
|
f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
|
2686
|
-
default=defaults.wallet.name,
|
2687
2779
|
)
|
2688
2780
|
if not wallet_hotkey:
|
2689
2781
|
wallet_hotkey = Prompt.ask(
|
2690
2782
|
f"Enter the the name of the [{COLORS.G.HK}]new hotkey",
|
2691
|
-
default=defaults.wallet.hotkey,
|
2783
|
+
default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
|
2692
2784
|
)
|
2693
2785
|
|
2694
2786
|
wallet = self.wallet_ask(
|
@@ -3091,6 +3183,59 @@ class CLIManager:
|
|
3091
3183
|
|
3092
3184
|
return self._run_command(wallets.sign(wallet, message, use_hotkey, json_output))
|
3093
3185
|
|
3186
|
+
def wallet_verify(
|
3187
|
+
self,
|
3188
|
+
message: Optional[str] = typer.Option(
|
3189
|
+
None, "--message", "-m", help="The message that was signed"
|
3190
|
+
),
|
3191
|
+
signature: Optional[str] = typer.Option(
|
3192
|
+
None, "--signature", "-s", help="The signature to verify (hex format)"
|
3193
|
+
),
|
3194
|
+
public_key_or_ss58: Optional[str] = typer.Option(
|
3195
|
+
None,
|
3196
|
+
"--address",
|
3197
|
+
"-a",
|
3198
|
+
"--public-key",
|
3199
|
+
"-p",
|
3200
|
+
help="SS58 address or public key (hex) of the signer",
|
3201
|
+
),
|
3202
|
+
quiet: bool = Options.quiet,
|
3203
|
+
verbose: bool = Options.verbose,
|
3204
|
+
json_output: bool = Options.json_output,
|
3205
|
+
):
|
3206
|
+
"""
|
3207
|
+
Verify a message signature using the signer's public key or SS58 address.
|
3208
|
+
|
3209
|
+
This command allows you to verify that a message was signed by the owner of a specific address.
|
3210
|
+
|
3211
|
+
USAGE
|
3212
|
+
|
3213
|
+
Provide the original message, the signature (in hex format), and either the SS58 address
|
3214
|
+
or public key of the signer to verify the signature.
|
3215
|
+
|
3216
|
+
EXAMPLES
|
3217
|
+
|
3218
|
+
[green]$[/green] btcli wallet verify --message "Hello world" --signature "0xabc123..." --address "5GrwvaEF..."
|
3219
|
+
|
3220
|
+
[green]$[/green] btcli wallet verify -m "Test message" -s "0xdef456..." -p "0x1234abcd..."
|
3221
|
+
"""
|
3222
|
+
self.verbosity_handler(quiet, verbose, json_output)
|
3223
|
+
|
3224
|
+
if not public_key_or_ss58:
|
3225
|
+
public_key_or_ss58 = Prompt.ask(
|
3226
|
+
"Enter the [blue]address[/blue] (SS58 or hex format)"
|
3227
|
+
)
|
3228
|
+
|
3229
|
+
if not message:
|
3230
|
+
message = Prompt.ask("Enter the [blue]message[/blue]")
|
3231
|
+
|
3232
|
+
if not signature:
|
3233
|
+
signature = Prompt.ask("Enter the [blue]signature[/blue]")
|
3234
|
+
|
3235
|
+
return self._run_command(
|
3236
|
+
wallets.verify(message, signature, public_key_or_ss58, json_output)
|
3237
|
+
)
|
3238
|
+
|
3094
3239
|
def wallet_swap_coldkey(
|
3095
3240
|
self,
|
3096
3241
|
wallet_name: Optional[str] = Options.wallet_name,
|
@@ -3444,7 +3589,7 @@ class CLIManager:
|
|
3444
3589
|
ask_for=[WO.NAME, WO.HOTKEY, WO.PATH],
|
3445
3590
|
validate=WV.WALLET_AND_HOTKEY,
|
3446
3591
|
)
|
3447
|
-
include_hotkeys = wallet
|
3592
|
+
include_hotkeys = get_hotkey_pub_ss58(wallet)
|
3448
3593
|
|
3449
3594
|
elif all_hotkeys or include_hotkeys or exclude_hotkeys:
|
3450
3595
|
wallet = self.wallet_ask(
|
@@ -3908,7 +4053,7 @@ class CLIManager:
|
|
3908
4053
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
3909
4054
|
validate=WV.WALLET_AND_HOTKEY,
|
3910
4055
|
)
|
3911
|
-
destination_hotkey = destination_wallet
|
4056
|
+
destination_hotkey = get_hotkey_pub_ss58(destination_wallet)
|
3912
4057
|
else:
|
3913
4058
|
if is_valid_ss58_address(destination_hotkey):
|
3914
4059
|
destination_hotkey = destination_hotkey
|
@@ -3947,7 +4092,7 @@ class CLIManager:
|
|
3947
4092
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
3948
4093
|
validate=WV.WALLET_AND_HOTKEY,
|
3949
4094
|
)
|
3950
|
-
origin_hotkey = wallet
|
4095
|
+
origin_hotkey = get_hotkey_pub_ss58(wallet)
|
3951
4096
|
else:
|
3952
4097
|
if is_valid_ss58_address(wallet_hotkey):
|
3953
4098
|
origin_hotkey = wallet_hotkey
|
@@ -3959,7 +4104,7 @@ class CLIManager:
|
|
3959
4104
|
ask_for=[],
|
3960
4105
|
validate=WV.WALLET_AND_HOTKEY,
|
3961
4106
|
)
|
3962
|
-
origin_hotkey = wallet
|
4107
|
+
origin_hotkey = get_hotkey_pub_ss58(wallet)
|
3963
4108
|
|
3964
4109
|
if not interactive_selection:
|
3965
4110
|
if origin_netuid is None:
|
@@ -4095,7 +4240,8 @@ class CLIManager:
|
|
4095
4240
|
interactive_selection = False
|
4096
4241
|
if not wallet_hotkey:
|
4097
4242
|
origin_hotkey = Prompt.ask(
|
4098
|
-
"Enter the [blue]origin hotkey[/blue] name or ss58 address [bold]
|
4243
|
+
"Enter the [blue]origin hotkey[/blue] name or ss58 address [bold]"
|
4244
|
+
"(stake will be transferred FROM here)[/bold] "
|
4099
4245
|
"[dim](or press Enter to select from existing stakes)[/dim]"
|
4100
4246
|
)
|
4101
4247
|
if origin_hotkey == "":
|
@@ -4111,7 +4257,7 @@ class CLIManager:
|
|
4111
4257
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
4112
4258
|
validate=WV.WALLET_AND_HOTKEY,
|
4113
4259
|
)
|
4114
|
-
origin_hotkey = wallet
|
4260
|
+
origin_hotkey = get_hotkey_pub_ss58(wallet)
|
4115
4261
|
else:
|
4116
4262
|
if is_valid_ss58_address(wallet_hotkey):
|
4117
4263
|
origin_hotkey = wallet_hotkey
|
@@ -4123,7 +4269,7 @@ class CLIManager:
|
|
4123
4269
|
ask_for=[],
|
4124
4270
|
validate=WV.WALLET_AND_HOTKEY,
|
4125
4271
|
)
|
4126
|
-
origin_hotkey = wallet
|
4272
|
+
origin_hotkey = get_hotkey_pub_ss58(wallet)
|
4127
4273
|
|
4128
4274
|
if not interactive_selection:
|
4129
4275
|
if origin_netuid is None:
|
@@ -4946,7 +5092,7 @@ class CLIManager:
|
|
4946
5092
|
"Netuids to show the price for. Separate multiple netuids with a comma, for example: `-n 0,1,2`.",
|
4947
5093
|
),
|
4948
5094
|
interval_hours: int = typer.Option(
|
4949
|
-
|
5095
|
+
4,
|
4950
5096
|
"--interval-hours",
|
4951
5097
|
"--interval",
|
4952
5098
|
help="The number of hours to show the historical price for.",
|
@@ -4963,6 +5109,11 @@ class CLIManager:
|
|
4963
5109
|
"--log",
|
4964
5110
|
help="Show the price in log scale.",
|
4965
5111
|
),
|
5112
|
+
current_only: bool = typer.Option(
|
5113
|
+
False,
|
5114
|
+
"--current",
|
5115
|
+
help="Show only the current data, and no historical data.",
|
5116
|
+
),
|
4966
5117
|
html_output: bool = Options.html_output,
|
4967
5118
|
quiet: bool = Options.quiet,
|
4968
5119
|
verbose: bool = Options.verbose,
|
@@ -4985,9 +5136,31 @@ class CLIManager:
|
|
4985
5136
|
[green]$[/green] btcli subnets price --netuids 1,2,3,4 --html
|
4986
5137
|
"""
|
4987
5138
|
if json_output and html_output:
|
4988
|
-
print_error(
|
5139
|
+
print_error(
|
5140
|
+
f"Cannot specify both [{COLORS.G.ARG}]--json-output[/{COLORS.G.ARG}] "
|
5141
|
+
f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
|
5142
|
+
)
|
5143
|
+
return
|
5144
|
+
if current_only and html_output:
|
5145
|
+
print_error(
|
5146
|
+
f"Cannot specify both [{COLORS.G.ARG}]--current[/{COLORS.G.ARG}] "
|
5147
|
+
f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
|
5148
|
+
)
|
4989
5149
|
return
|
4990
5150
|
self.verbosity_handler(quiet=quiet, verbose=verbose, json_output=json_output)
|
5151
|
+
|
5152
|
+
subtensor = self.initialize_chain(network)
|
5153
|
+
non_archives = ["finney", "latent-lite", "subvortex"]
|
5154
|
+
if not current_only and subtensor.network in non_archives + [
|
5155
|
+
Constants.network_map[x] for x in non_archives
|
5156
|
+
]:
|
5157
|
+
err_console.print(
|
5158
|
+
f"[red]Error[/red] Running this command without [{COLORS.G.ARG}]--current[/{COLORS.G.ARG}] requires "
|
5159
|
+
"use of an archive node. "
|
5160
|
+
f"Try running again with the [{COLORS.G.ARG}]--network archive[/{COLORS.G.ARG}] flag."
|
5161
|
+
)
|
5162
|
+
return False
|
5163
|
+
|
4991
5164
|
if netuids:
|
4992
5165
|
netuids = parse_to_list(
|
4993
5166
|
netuids,
|
@@ -5017,10 +5190,11 @@ class CLIManager:
|
|
5017
5190
|
|
5018
5191
|
return self._run_command(
|
5019
5192
|
price.price(
|
5020
|
-
|
5193
|
+
subtensor,
|
5021
5194
|
netuids,
|
5022
5195
|
all_netuids,
|
5023
5196
|
interval_hours,
|
5197
|
+
current_only,
|
5024
5198
|
html_output,
|
5025
5199
|
log_scale,
|
5026
5200
|
json_output,
|