bittensor-cli 9.0.0rc4__py3-none-any.whl → 9.0.1__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/__init__.py +2 -2
- bittensor_cli/cli.py +217 -78
- bittensor_cli/src/__init__.py +50 -25
- bittensor_cli/src/bittensor/chain_data.py +3 -1
- bittensor_cli/src/bittensor/extrinsics/registration.py +26 -34
- bittensor_cli/src/bittensor/extrinsics/root.py +5 -11
- bittensor_cli/src/bittensor/extrinsics/transfer.py +15 -13
- bittensor_cli/src/bittensor/subtensor_interface.py +4 -6
- bittensor_cli/src/bittensor/utils.py +129 -19
- bittensor_cli/src/commands/stake/add.py +4 -4
- bittensor_cli/src/commands/stake/children_hotkeys.py +12 -18
- bittensor_cli/src/commands/stake/list.py +8 -16
- bittensor_cli/src/commands/stake/move.py +2 -2
- bittensor_cli/src/commands/stake/remove.py +3 -3
- bittensor_cli/src/commands/subnets/subnets.py +148 -4
- bittensor_cli/src/commands/sudo.py +68 -35
- bittensor_cli/src/commands/wallets.py +54 -42
- bittensor_cli/src/commands/weights.py +9 -13
- {bittensor_cli-9.0.0rc4.dist-info → bittensor_cli-9.0.1.dist-info}/METADATA +3 -3
- bittensor_cli-9.0.1.dist-info/RECORD +34 -0
- bittensor_cli-9.0.0rc4.dist-info/RECORD +0 -34
- {bittensor_cli-9.0.0rc4.dist-info → bittensor_cli-9.0.1.dist-info}/WHEEL +0 -0
- {bittensor_cli-9.0.0rc4.dist-info → bittensor_cli-9.0.1.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.0.0rc4.dist-info → bittensor_cli-9.0.1.dist-info}/top_level.txt +0 -0
@@ -35,12 +35,13 @@ from bittensor_cli.src.bittensor.utils import (
|
|
35
35
|
update_metadata_table,
|
36
36
|
prompt_for_identity,
|
37
37
|
get_subnet_name,
|
38
|
+
unlock_key,
|
38
39
|
)
|
39
40
|
|
40
41
|
if TYPE_CHECKING:
|
41
42
|
from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
|
42
43
|
|
43
|
-
TAO_WEIGHT = 0.
|
44
|
+
TAO_WEIGHT = 0.18
|
44
45
|
|
45
46
|
# helpers and extrinsics
|
46
47
|
|
@@ -183,7 +184,7 @@ async def register_subnetwork_extrinsic(
|
|
183
184
|
await response.process_events()
|
184
185
|
if not await response.is_success:
|
185
186
|
err_console.print(
|
186
|
-
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message
|
187
|
+
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message)}"
|
187
188
|
)
|
188
189
|
await asyncio.sleep(0.5)
|
189
190
|
return False
|
@@ -889,7 +890,7 @@ async def show(
|
|
889
890
|
for netuid_ in range(len(all_subnets)):
|
890
891
|
subnet = all_subnets[netuid_]
|
891
892
|
emission_on_subnet = (
|
892
|
-
root_state.emission_history[netuid_][idx] / subnet.tempo
|
893
|
+
root_state.emission_history[netuid_][idx] / (subnet.tempo or 1)
|
893
894
|
)
|
894
895
|
total_emission_per_block += subnet.alpha_to_tao(
|
895
896
|
Balance.from_rao(emission_on_subnet)
|
@@ -1322,7 +1323,7 @@ async def show(
|
|
1322
1323
|
return hotkey
|
1323
1324
|
else:
|
1324
1325
|
console.print(
|
1325
|
-
|
1326
|
+
"[red]Invalid UID. Please enter a valid UID from the table above[/red]"
|
1326
1327
|
)
|
1327
1328
|
except ValueError:
|
1328
1329
|
console.print("[red]Please enter a valid number[/red]")
|
@@ -2026,3 +2027,146 @@ async def metagraph_cmd(
|
|
2026
2027
|
table.add_row(*row)
|
2027
2028
|
|
2028
2029
|
console.print(table)
|
2030
|
+
|
2031
|
+
|
2032
|
+
def create_identity_table(title: str = None):
|
2033
|
+
if not title:
|
2034
|
+
title = "Subnet Identity"
|
2035
|
+
|
2036
|
+
table = Table(
|
2037
|
+
Column(
|
2038
|
+
"Item",
|
2039
|
+
justify="right",
|
2040
|
+
style=COLOR_PALETTE["GENERAL"]["SUBHEADING_MAIN"],
|
2041
|
+
no_wrap=True,
|
2042
|
+
),
|
2043
|
+
Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]),
|
2044
|
+
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]{title}\n",
|
2045
|
+
show_footer=True,
|
2046
|
+
show_edge=False,
|
2047
|
+
header_style="bold white",
|
2048
|
+
border_style="bright_black",
|
2049
|
+
style="bold",
|
2050
|
+
title_justify="center",
|
2051
|
+
show_lines=False,
|
2052
|
+
pad_edge=True,
|
2053
|
+
)
|
2054
|
+
return table
|
2055
|
+
|
2056
|
+
|
2057
|
+
async def set_identity(
|
2058
|
+
wallet: "Wallet",
|
2059
|
+
subtensor: "SubtensorInterface",
|
2060
|
+
netuid: int,
|
2061
|
+
subnet_identity: dict,
|
2062
|
+
prompt: bool = False,
|
2063
|
+
) -> bool:
|
2064
|
+
"""Set identity information for a subnet"""
|
2065
|
+
|
2066
|
+
if not await subtensor.subnet_exists(netuid):
|
2067
|
+
err_console.print(f"Subnet {netuid} does not exist")
|
2068
|
+
return False
|
2069
|
+
|
2070
|
+
identity_data = {
|
2071
|
+
"netuid": netuid,
|
2072
|
+
"subnet_name": subnet_identity.get("subnet_name", ""),
|
2073
|
+
"github_repo": subnet_identity.get("github_repo", ""),
|
2074
|
+
"subnet_contact": subnet_identity.get("subnet_contact", ""),
|
2075
|
+
"subnet_url": subnet_identity.get("subnet_url", ""),
|
2076
|
+
"discord": subnet_identity.get("discord", ""),
|
2077
|
+
"description": subnet_identity.get("description", ""),
|
2078
|
+
"additional": subnet_identity.get("additional", ""),
|
2079
|
+
}
|
2080
|
+
|
2081
|
+
if not unlock_key(wallet).success:
|
2082
|
+
return False
|
2083
|
+
|
2084
|
+
if prompt:
|
2085
|
+
if not Confirm.ask(
|
2086
|
+
"Are you sure you want to set subnet's identity? This is subject to a fee."
|
2087
|
+
):
|
2088
|
+
return False
|
2089
|
+
|
2090
|
+
call = await subtensor.substrate.compose_call(
|
2091
|
+
call_module="SubtensorModule",
|
2092
|
+
call_function="set_subnet_identity",
|
2093
|
+
call_params=identity_data,
|
2094
|
+
)
|
2095
|
+
|
2096
|
+
with console.status(
|
2097
|
+
" :satellite: [dark_sea_green3]Setting subnet identity on-chain...",
|
2098
|
+
spinner="earth",
|
2099
|
+
):
|
2100
|
+
success, err_msg = await subtensor.sign_and_send_extrinsic(call, wallet)
|
2101
|
+
|
2102
|
+
if not success:
|
2103
|
+
err_console.print(f"[red]:cross_mark: Failed![/red] {err_msg}")
|
2104
|
+
return False
|
2105
|
+
|
2106
|
+
console.print(
|
2107
|
+
":white_heavy_check_mark: [dark_sea_green3]Successfully set subnet identity\n"
|
2108
|
+
)
|
2109
|
+
|
2110
|
+
subnet = await subtensor.subnet(netuid)
|
2111
|
+
identity = subnet.subnet_identity if subnet else None
|
2112
|
+
|
2113
|
+
if identity:
|
2114
|
+
table = create_identity_table(title=f"New Subnet {netuid} Identity")
|
2115
|
+
table.add_row("Netuid", str(netuid))
|
2116
|
+
for key in [
|
2117
|
+
"subnet_name",
|
2118
|
+
"github_repo",
|
2119
|
+
"subnet_contact",
|
2120
|
+
"subnet_url",
|
2121
|
+
"discord",
|
2122
|
+
"description",
|
2123
|
+
"additional",
|
2124
|
+
]:
|
2125
|
+
value = getattr(identity, key, None)
|
2126
|
+
table.add_row(key, str(value) if value else "~")
|
2127
|
+
console.print(table)
|
2128
|
+
|
2129
|
+
return True
|
2130
|
+
|
2131
|
+
|
2132
|
+
async def get_identity(subtensor: "SubtensorInterface", netuid: int, title: str = None):
|
2133
|
+
"""Fetch and display existing subnet identity information."""
|
2134
|
+
if not title:
|
2135
|
+
title = "Subnet Identity"
|
2136
|
+
|
2137
|
+
if not await subtensor.subnet_exists(netuid):
|
2138
|
+
print_error(
|
2139
|
+
f"Subnet {netuid} does not exist."
|
2140
|
+
)
|
2141
|
+
raise typer.Exit()
|
2142
|
+
|
2143
|
+
with console.status(
|
2144
|
+
":satellite: [bold green]Querying subnet identity...", spinner="earth"
|
2145
|
+
):
|
2146
|
+
subnet = await subtensor.subnet(netuid)
|
2147
|
+
identity = subnet.subnet_identity if subnet else None
|
2148
|
+
|
2149
|
+
if not identity:
|
2150
|
+
err_console.print(
|
2151
|
+
f"Existing subnet identity not found"
|
2152
|
+
f" for subnet [blue]{netuid}[/blue]"
|
2153
|
+
f" on {subtensor}"
|
2154
|
+
)
|
2155
|
+
return {}
|
2156
|
+
|
2157
|
+
if identity:
|
2158
|
+
table = create_identity_table(title=f"Current Subnet {netuid} Identity")
|
2159
|
+
table.add_row("Netuid", str(netuid))
|
2160
|
+
for key in [
|
2161
|
+
"subnet_name",
|
2162
|
+
"github_repo",
|
2163
|
+
"subnet_contact",
|
2164
|
+
"subnet_url",
|
2165
|
+
"discord",
|
2166
|
+
"description",
|
2167
|
+
"additional",
|
2168
|
+
]:
|
2169
|
+
value = getattr(identity, key, None)
|
2170
|
+
table.add_row(key, str(value) if value else "~")
|
2171
|
+
console.print(table)
|
2172
|
+
return identity
|
@@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, Union, Optional
|
|
3
3
|
|
4
4
|
import typer
|
5
5
|
from bittensor_wallet import Wallet
|
6
|
-
from bittensor_wallet.errors import KeyFileError
|
7
6
|
from rich import box
|
8
7
|
from rich.table import Column, Table
|
9
8
|
from rich.prompt import Confirm
|
@@ -17,6 +16,8 @@ from bittensor_cli.src.bittensor.utils import (
|
|
17
16
|
print_error,
|
18
17
|
print_verbose,
|
19
18
|
normalize_hyperparameters,
|
19
|
+
unlock_key,
|
20
|
+
blocks_to_duration,
|
20
21
|
)
|
21
22
|
|
22
23
|
if TYPE_CHECKING:
|
@@ -106,13 +107,10 @@ async def set_hyperparameter_extrinsic(
|
|
106
107
|
)
|
107
108
|
return False
|
108
109
|
|
109
|
-
|
110
|
-
wallet.unlock_coldkey()
|
111
|
-
except KeyFileError:
|
112
|
-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
|
110
|
+
if not unlock_key(wallet).success:
|
113
111
|
return False
|
114
112
|
|
115
|
-
extrinsic = HYPERPARAMS.get(parameter)
|
113
|
+
extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False))
|
116
114
|
if extrinsic is None:
|
117
115
|
err_console.print(":cross_mark: [red]Invalid hyperparameter specified.[/red]")
|
118
116
|
return False
|
@@ -152,11 +150,17 @@ async def set_hyperparameter_extrinsic(
|
|
152
150
|
call_params[str(value_argument["name"])] = value
|
153
151
|
|
154
152
|
# create extrinsic call
|
155
|
-
|
153
|
+
call_ = await substrate.compose_call(
|
156
154
|
call_module="AdminUtils",
|
157
155
|
call_function=extrinsic,
|
158
156
|
call_params=call_params,
|
159
157
|
)
|
158
|
+
if sudo_:
|
159
|
+
call = await substrate.compose_call(
|
160
|
+
call_module="Sudo", call_function="sudo", call_params={"call": call_}
|
161
|
+
)
|
162
|
+
else:
|
163
|
+
call = call_
|
160
164
|
success, err_msg = await subtensor.sign_and_send_extrinsic(
|
161
165
|
call, wallet, wait_for_inclusion, wait_for_finalization
|
162
166
|
)
|
@@ -266,14 +270,22 @@ def format_call_data(call_data: dict) -> str:
|
|
266
270
|
call_info = call_details[0]
|
267
271
|
call_function, call_args = next(iter(call_info.items()))
|
268
272
|
|
269
|
-
#
|
270
|
-
formatted_args =
|
271
|
-
|
272
|
-
|
273
|
-
|
273
|
+
# Format arguments, handle nested/large payloads
|
274
|
+
formatted_args = []
|
275
|
+
for arg_name, arg_value in call_args.items():
|
276
|
+
if isinstance(arg_value, (tuple, list, dict)):
|
277
|
+
# For large nested, show abbreviated version
|
278
|
+
content_str = str(arg_value)
|
279
|
+
if len(content_str) > 20:
|
280
|
+
formatted_args.append(f"{arg_name}: ... [{len(content_str)}] ...")
|
281
|
+
else:
|
282
|
+
formatted_args.append(f"{arg_name}: {arg_value}")
|
283
|
+
else:
|
284
|
+
formatted_args.append(f"{arg_name}: {arg_value}")
|
274
285
|
|
275
286
|
# Format the final output string
|
276
|
-
|
287
|
+
args_str = ", ".join(formatted_args)
|
288
|
+
return f"{module}.{call_function}({args_str})"
|
277
289
|
|
278
290
|
|
279
291
|
def _validate_proposal_hash(proposal_hash: str) -> bool:
|
@@ -464,19 +476,20 @@ async def sudo_set_hyperparameter(
|
|
464
476
|
|
465
477
|
normalized_value: Union[str, bool]
|
466
478
|
if param_name in [
|
467
|
-
"
|
479
|
+
"registration_allowed",
|
468
480
|
"network_pow_registration_allowed",
|
469
481
|
"commit_reveal_weights_enabled",
|
470
482
|
"liquid_alpha_enabled",
|
471
483
|
]:
|
472
|
-
normalized_value = param_value.lower() in ["true", "1"]
|
484
|
+
normalized_value = param_value.lower() in ["true", "True", "1"]
|
473
485
|
else:
|
474
486
|
normalized_value = param_value
|
475
487
|
|
476
488
|
is_allowed_value, value = allowed_value(param_name, normalized_value)
|
477
489
|
if not is_allowed_value:
|
478
490
|
err_console.print(
|
479
|
-
f"Hyperparameter {param_name} value is not within bounds.
|
491
|
+
f"Hyperparameter [dark_orange]{param_name}[/dark_orange] value is not within bounds. "
|
492
|
+
f"Value is {normalized_value} but must be {value}"
|
480
493
|
)
|
481
494
|
return
|
482
495
|
|
@@ -572,24 +585,30 @@ async def get_senate(subtensor: "SubtensorInterface"):
|
|
572
585
|
return console.print(table)
|
573
586
|
|
574
587
|
|
575
|
-
async def proposals(subtensor: "SubtensorInterface"):
|
588
|
+
async def proposals(subtensor: "SubtensorInterface", verbose: bool):
|
576
589
|
console.print(
|
577
590
|
":satellite: Syncing with chain: [white]{}[/white] ...".format(
|
578
591
|
subtensor.network
|
579
592
|
)
|
580
593
|
)
|
581
|
-
print_verbose("Fetching senate members & proposals")
|
582
594
|
block_hash = await subtensor.substrate.get_chain_head()
|
583
|
-
senate_members, all_proposals = await asyncio.gather(
|
595
|
+
senate_members, all_proposals, current_block = await asyncio.gather(
|
584
596
|
_get_senate_members(subtensor, block_hash),
|
585
597
|
_get_proposals(subtensor, block_hash),
|
598
|
+
subtensor.substrate.get_block_number(block_hash),
|
586
599
|
)
|
587
600
|
|
588
|
-
print_verbose("Fetching member information from Chain")
|
589
601
|
registered_delegate_info: dict[
|
590
602
|
str, DelegatesDetails
|
591
603
|
] = await subtensor.get_delegate_identities()
|
592
604
|
|
605
|
+
title = (
|
606
|
+
f"[bold #4196D6]Bittensor Governance Proposals[/bold #4196D6]\n"
|
607
|
+
f"[steel_blue3]Current Block:[/steel_blue3] {current_block}\t"
|
608
|
+
f"[steel_blue3]Network:[/steel_blue3] {subtensor.network}\n\n"
|
609
|
+
f"[steel_blue3]Active Proposals:[/steel_blue3] {len(all_proposals)}\t"
|
610
|
+
f"[steel_blue3]Senate Size:[/steel_blue3] {len(senate_members)}\n"
|
611
|
+
)
|
593
612
|
table = Table(
|
594
613
|
Column(
|
595
614
|
"[white]HASH",
|
@@ -604,8 +623,8 @@ async def proposals(subtensor: "SubtensorInterface"):
|
|
604
623
|
style="rgb(50,163,219)",
|
605
624
|
),
|
606
625
|
Column("[white]END", style="bright_cyan"),
|
607
|
-
Column("[white]CALLDATA", style="dark_sea_green"),
|
608
|
-
title=
|
626
|
+
Column("[white]CALLDATA", style="dark_sea_green", width=30),
|
627
|
+
title=title,
|
609
628
|
show_footer=True,
|
610
629
|
box=box.SIMPLE_HEAVY,
|
611
630
|
pad_edge=False,
|
@@ -613,16 +632,36 @@ async def proposals(subtensor: "SubtensorInterface"):
|
|
613
632
|
border_style="bright_black",
|
614
633
|
)
|
615
634
|
for hash_, (call_data, vote_data) in all_proposals.items():
|
635
|
+
blocks_remaining = vote_data.end - current_block
|
636
|
+
if blocks_remaining > 0:
|
637
|
+
duration_str = blocks_to_duration(blocks_remaining)
|
638
|
+
vote_end_cell = f"{vote_data.end} [dim](in {duration_str})[/dim]"
|
639
|
+
else:
|
640
|
+
vote_end_cell = f"{vote_data.end} [red](expired)[/red]"
|
641
|
+
|
642
|
+
ayes_threshold = (
|
643
|
+
(len(vote_data.ayes) / vote_data.threshold * 100)
|
644
|
+
if vote_data.threshold > 0
|
645
|
+
else 0
|
646
|
+
)
|
647
|
+
nays_threshold = (
|
648
|
+
(len(vote_data.nays) / vote_data.threshold * 100)
|
649
|
+
if vote_data.threshold > 0
|
650
|
+
else 0
|
651
|
+
)
|
616
652
|
table.add_row(
|
617
|
-
hash_,
|
653
|
+
hash_ if verbose else f"{hash_[:4]}...{hash_[-4:]}",
|
618
654
|
str(vote_data.threshold),
|
619
|
-
|
620
|
-
|
655
|
+
f"{len(vote_data.ayes)} ({ayes_threshold:.2f}%)",
|
656
|
+
f"{len(vote_data.nays)} ({nays_threshold:.2f}%)",
|
621
657
|
display_votes(vote_data, registered_delegate_info),
|
622
|
-
|
658
|
+
vote_end_cell,
|
623
659
|
format_call_data(call_data),
|
624
660
|
)
|
625
|
-
|
661
|
+
console.print(table)
|
662
|
+
console.print(
|
663
|
+
"\n[dim]* Both Ayes and Nays percentages are calculated relative to the proposal's threshold.[/dim]"
|
664
|
+
)
|
626
665
|
|
627
666
|
|
628
667
|
async def senate_vote(
|
@@ -653,10 +692,7 @@ async def senate_vote(
|
|
653
692
|
return False
|
654
693
|
|
655
694
|
# Unlock the wallet.
|
656
|
-
|
657
|
-
wallet.unlock_hotkey()
|
658
|
-
wallet.unlock_coldkey()
|
659
|
-
except KeyFileError:
|
695
|
+
if not unlock_key(wallet, "hot").success and unlock_key(wallet, "cold").success:
|
660
696
|
return False
|
661
697
|
|
662
698
|
console.print(f"Fetching proposals in [dark_orange]network: {subtensor.network}")
|
@@ -732,10 +768,7 @@ async def set_take(
|
|
732
768
|
f"Setting take on [{COLOR_PALETTE['GENERAL']['LINKS']}]network: {subtensor.network}"
|
733
769
|
)
|
734
770
|
|
735
|
-
|
736
|
-
wallet.unlock_hotkey()
|
737
|
-
wallet.unlock_coldkey()
|
738
|
-
except KeyFileError:
|
771
|
+
if not unlock_key(wallet, "hot").success and unlock_key(wallet, "cold").success:
|
739
772
|
return False
|
740
773
|
|
741
774
|
result_ = await _do_set_take()
|
@@ -6,7 +6,7 @@ from typing import Generator, Optional
|
|
6
6
|
|
7
7
|
import aiohttp
|
8
8
|
from bittensor_wallet import Wallet, Keypair
|
9
|
-
from bittensor_wallet.errors import KeyFileError
|
9
|
+
from bittensor_wallet.errors import KeyFileError
|
10
10
|
from bittensor_wallet.keyfile import Keyfile
|
11
11
|
from fuzzywuzzy import fuzz
|
12
12
|
from rich import box
|
@@ -43,16 +43,11 @@ from bittensor_cli.src.bittensor.utils import (
|
|
43
43
|
validate_coldkey_presence,
|
44
44
|
get_subnet_name,
|
45
45
|
millify_tao,
|
46
|
+
unlock_key,
|
47
|
+
WalletLike,
|
46
48
|
)
|
47
49
|
|
48
50
|
|
49
|
-
class WalletLike:
|
50
|
-
def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None):
|
51
|
-
self.name = name
|
52
|
-
self.hotkey_ss58 = hotkey_ss58
|
53
|
-
self.hotkey_str = hotkey_str
|
54
|
-
|
55
|
-
|
56
51
|
async def regen_coldkey(
|
57
52
|
wallet: Wallet,
|
58
53
|
mnemonic: Optional[str],
|
@@ -60,6 +55,7 @@ async def regen_coldkey(
|
|
60
55
|
json_path: Optional[str] = None,
|
61
56
|
json_password: Optional[str] = "",
|
62
57
|
use_password: Optional[bool] = True,
|
58
|
+
overwrite: Optional[bool] = False,
|
63
59
|
):
|
64
60
|
"""Creates a new coldkey under this wallet"""
|
65
61
|
json_str: Optional[str] = None
|
@@ -69,13 +65,21 @@ async def regen_coldkey(
|
|
69
65
|
with open(json_path, "r") as f:
|
70
66
|
json_str = f.read()
|
71
67
|
try:
|
72
|
-
wallet.regenerate_coldkey(
|
68
|
+
new_wallet = wallet.regenerate_coldkey(
|
73
69
|
mnemonic=mnemonic,
|
74
70
|
seed=seed,
|
75
71
|
json=(json_str, json_password) if all([json_str, json_password]) else None,
|
76
72
|
use_password=use_password,
|
77
|
-
overwrite=
|
73
|
+
overwrite=overwrite,
|
78
74
|
)
|
75
|
+
|
76
|
+
if isinstance(new_wallet, Wallet):
|
77
|
+
console.print(
|
78
|
+
"\n✅ [dark_sea_green]Regenerated coldkey successfully!\n",
|
79
|
+
f"[dark_sea_green]Wallet name: ({new_wallet.name}), path: ({new_wallet.path}), coldkey ss58: ({new_wallet.coldkeypub.ss58_address})",
|
80
|
+
)
|
81
|
+
except ValueError:
|
82
|
+
print_error("Mnemonic phrase is invalid")
|
79
83
|
except KeyFileError:
|
80
84
|
print_error("KeyFileError: File is not writable")
|
81
85
|
|
@@ -84,14 +88,20 @@ async def regen_coldkey_pub(
|
|
84
88
|
wallet: Wallet,
|
85
89
|
ss58_address: str,
|
86
90
|
public_key_hex: str,
|
91
|
+
overwrite: Optional[bool] = False,
|
87
92
|
):
|
88
93
|
"""Creates a new coldkeypub under this wallet."""
|
89
94
|
try:
|
90
|
-
wallet.regenerate_coldkeypub(
|
95
|
+
new_coldkeypub = wallet.regenerate_coldkeypub(
|
91
96
|
ss58_address=ss58_address,
|
92
97
|
public_key=public_key_hex,
|
93
|
-
overwrite=
|
98
|
+
overwrite=overwrite,
|
94
99
|
)
|
100
|
+
if isinstance(new_coldkeypub, Wallet):
|
101
|
+
console.print(
|
102
|
+
"\n✅ [dark_sea_green]Regenerated coldkeypub successfully!\n",
|
103
|
+
f"[dark_sea_green]Wallet name: ({new_coldkeypub.name}), path: ({new_coldkeypub.path}), coldkey ss58: ({new_coldkeypub.coldkeypub.ss58_address})",
|
104
|
+
)
|
95
105
|
except KeyFileError:
|
96
106
|
print_error("KeyFileError: File is not writable")
|
97
107
|
|
@@ -103,6 +113,7 @@ async def regen_hotkey(
|
|
103
113
|
json_path: Optional[str],
|
104
114
|
json_password: Optional[str] = "",
|
105
115
|
use_password: Optional[bool] = False,
|
116
|
+
overwrite: Optional[bool] = False,
|
106
117
|
):
|
107
118
|
"""Creates a new hotkey under this wallet."""
|
108
119
|
json_str: Optional[str] = None
|
@@ -114,13 +125,20 @@ async def regen_hotkey(
|
|
114
125
|
json_str = f.read()
|
115
126
|
|
116
127
|
try:
|
117
|
-
wallet.regenerate_hotkey(
|
128
|
+
new_hotkey = wallet.regenerate_hotkey(
|
118
129
|
mnemonic=mnemonic,
|
119
130
|
seed=seed,
|
120
131
|
json=(json_str, json_password) if all([json_str, json_password]) else None,
|
121
132
|
use_password=use_password,
|
122
|
-
overwrite=
|
133
|
+
overwrite=overwrite,
|
123
134
|
)
|
135
|
+
if isinstance(new_hotkey, Wallet):
|
136
|
+
console.print(
|
137
|
+
"\n✅ [dark_sea_green]Regenerated hotkey successfully!\n",
|
138
|
+
f"[dark_sea_green]Wallet name: ({new_hotkey.name}), path: ({new_hotkey.path}), hotkey ss58: ({new_hotkey.hotkey.ss58_address})",
|
139
|
+
)
|
140
|
+
except ValueError:
|
141
|
+
print_error("Mnemonic phrase is invalid")
|
124
142
|
except KeyFileError:
|
125
143
|
print_error("KeyFileError: File is not writable")
|
126
144
|
|
@@ -130,6 +148,7 @@ async def new_hotkey(
|
|
130
148
|
n_words: int,
|
131
149
|
use_password: bool,
|
132
150
|
uri: Optional[str] = None,
|
151
|
+
overwrite: Optional[bool] = False,
|
133
152
|
):
|
134
153
|
"""Creates a new hotkey under this wallet."""
|
135
154
|
try:
|
@@ -146,7 +165,7 @@ async def new_hotkey(
|
|
146
165
|
wallet.create_new_hotkey(
|
147
166
|
n_words=n_words,
|
148
167
|
use_password=use_password,
|
149
|
-
overwrite=
|
168
|
+
overwrite=overwrite,
|
150
169
|
)
|
151
170
|
console.print("[dark_sea_green]Hotkey created[/dark_sea_green]")
|
152
171
|
except KeyFileError:
|
@@ -158,6 +177,7 @@ async def new_coldkey(
|
|
158
177
|
n_words: int,
|
159
178
|
use_password: bool,
|
160
179
|
uri: Optional[str] = None,
|
180
|
+
overwrite: Optional[bool] = False,
|
161
181
|
):
|
162
182
|
"""Creates a new coldkey under this wallet."""
|
163
183
|
try:
|
@@ -175,7 +195,7 @@ async def new_coldkey(
|
|
175
195
|
wallet.create_new_coldkey(
|
176
196
|
n_words=n_words,
|
177
197
|
use_password=use_password,
|
178
|
-
overwrite=
|
198
|
+
overwrite=overwrite,
|
179
199
|
)
|
180
200
|
console.print("[dark_sea_green]Coldkey created[/dark_sea_green]")
|
181
201
|
except KeyFileError:
|
@@ -187,6 +207,7 @@ async def wallet_create(
|
|
187
207
|
n_words: int = 12,
|
188
208
|
use_password: bool = True,
|
189
209
|
uri: Optional[str] = None,
|
210
|
+
overwrite: Optional[bool] = False,
|
190
211
|
):
|
191
212
|
"""Creates a new wallet."""
|
192
213
|
if uri:
|
@@ -205,7 +226,7 @@ async def wallet_create(
|
|
205
226
|
wallet.create_new_coldkey(
|
206
227
|
n_words=n_words,
|
207
228
|
use_password=use_password,
|
208
|
-
overwrite=
|
229
|
+
overwrite=overwrite,
|
209
230
|
)
|
210
231
|
console.print("[dark_sea_green]Coldkey created[/dark_sea_green]")
|
211
232
|
except KeyFileError:
|
@@ -215,7 +236,7 @@ async def wallet_create(
|
|
215
236
|
wallet.create_new_hotkey(
|
216
237
|
n_words=n_words,
|
217
238
|
use_password=False,
|
218
|
-
overwrite=
|
239
|
+
overwrite=overwrite,
|
219
240
|
)
|
220
241
|
console.print("[dark_sea_green]Hotkey created[/dark_sea_green]")
|
221
242
|
except KeyFileError:
|
@@ -487,7 +508,9 @@ async def wallet_list(wallet_path: str):
|
|
487
508
|
wallet_tree = root.add(
|
488
509
|
f"[bold blue]Coldkey[/bold blue] [green]{wallet.name}[/green] ss58_address [green]{coldkeypub_str}[/green]"
|
489
510
|
)
|
490
|
-
hotkeys = utils.get_hotkey_wallets_for_wallet(
|
511
|
+
hotkeys = utils.get_hotkey_wallets_for_wallet(
|
512
|
+
wallet, show_nulls=True, show_encrypted=True
|
513
|
+
)
|
491
514
|
for hkey in hotkeys:
|
492
515
|
data = f"[bold red]Hotkey[/bold red][green] {hkey}[/green] (?)"
|
493
516
|
if hkey:
|
@@ -1047,11 +1070,17 @@ async def transfer(
|
|
1047
1070
|
subtensor: SubtensorInterface,
|
1048
1071
|
destination: str,
|
1049
1072
|
amount: float,
|
1073
|
+
transfer_all: bool,
|
1050
1074
|
prompt: bool,
|
1051
1075
|
):
|
1052
1076
|
"""Transfer token of amount to destination."""
|
1053
1077
|
await transfer_extrinsic(
|
1054
|
-
subtensor,
|
1078
|
+
subtensor=subtensor,
|
1079
|
+
wallet=wallet,
|
1080
|
+
destination=destination,
|
1081
|
+
amount=Balance.from_tao(amount),
|
1082
|
+
transfer_all=transfer_all,
|
1083
|
+
prompt=prompt,
|
1055
1084
|
)
|
1056
1085
|
|
1057
1086
|
|
@@ -1211,13 +1240,14 @@ async def faucet(
|
|
1211
1240
|
output_in_place: bool,
|
1212
1241
|
log_verbose: bool,
|
1213
1242
|
max_successes: int = 3,
|
1243
|
+
prompt: bool = True,
|
1214
1244
|
):
|
1215
1245
|
# TODO: - work out prompts to be passed through the cli
|
1216
1246
|
success = await run_faucet_extrinsic(
|
1217
1247
|
subtensor,
|
1218
1248
|
wallet,
|
1219
1249
|
tpb=threads_per_block,
|
1220
|
-
prompt=
|
1250
|
+
prompt=prompt,
|
1221
1251
|
update_interval=update_interval,
|
1222
1252
|
num_processes=processes,
|
1223
1253
|
cuda=use_cuda,
|
@@ -1303,10 +1333,7 @@ async def set_id(
|
|
1303
1333
|
)
|
1304
1334
|
return False
|
1305
1335
|
|
1306
|
-
|
1307
|
-
wallet.unlock_coldkey()
|
1308
|
-
except KeyFileError:
|
1309
|
-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
|
1336
|
+
if not unlock_key(wallet).success:
|
1310
1337
|
return False
|
1311
1338
|
|
1312
1339
|
call = await subtensor.substrate.compose_call(
|
@@ -1398,30 +1425,15 @@ async def check_coldkey_swap(wallet: Wallet, subtensor: SubtensorInterface):
|
|
1398
1425
|
async def sign(wallet: Wallet, message: str, use_hotkey: str):
|
1399
1426
|
"""Sign a message using the provided wallet or hotkey."""
|
1400
1427
|
|
1401
|
-
def _unlock(key: str):
|
1402
|
-
try:
|
1403
|
-
getattr(wallet, f"unlock_{key}")()
|
1404
|
-
return True
|
1405
|
-
except PasswordError:
|
1406
|
-
err_console.print(
|
1407
|
-
":cross_mark: [red]The password used to decrypt your keyfile is invalid[/red]"
|
1408
|
-
)
|
1409
|
-
return False
|
1410
|
-
except KeyFileError:
|
1411
|
-
err_console.print(
|
1412
|
-
":cross_mark: [red]Keyfile is corrupt, non-writable, or non-readable[/red]:"
|
1413
|
-
)
|
1414
|
-
return False
|
1415
|
-
|
1416
1428
|
if not use_hotkey:
|
1417
|
-
if not
|
1429
|
+
if not unlock_key(wallet, "cold").success:
|
1418
1430
|
return False
|
1419
1431
|
keypair = wallet.coldkey
|
1420
1432
|
print_verbose(
|
1421
1433
|
f"Signing using [{COLOR_PALETTE['GENERAL']['COLDKEY']}]coldkey: {wallet.name}"
|
1422
1434
|
)
|
1423
1435
|
else:
|
1424
|
-
if not
|
1436
|
+
if not unlock_key(wallet, "hot").success:
|
1425
1437
|
return False
|
1426
1438
|
keypair = wallet.hotkey
|
1427
1439
|
print_verbose(
|