bittensor-cli 8.4.4__py3-none-any.whl → 9.0.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/__init__.py +1 -1
- bittensor_cli/cli.py +1827 -1394
- bittensor_cli/src/__init__.py +623 -168
- bittensor_cli/src/bittensor/balances.py +41 -8
- bittensor_cli/src/bittensor/chain_data.py +557 -428
- bittensor_cli/src/bittensor/extrinsics/registration.py +129 -23
- bittensor_cli/src/bittensor/extrinsics/root.py +3 -3
- bittensor_cli/src/bittensor/extrinsics/transfer.py +6 -11
- bittensor_cli/src/bittensor/minigraph.py +46 -8
- bittensor_cli/src/bittensor/subtensor_interface.py +567 -250
- bittensor_cli/src/bittensor/utils.py +370 -25
- bittensor_cli/src/commands/stake/__init__.py +154 -0
- bittensor_cli/src/commands/stake/add.py +625 -0
- bittensor_cli/src/commands/stake/children_hotkeys.py +103 -75
- bittensor_cli/src/commands/stake/list.py +687 -0
- bittensor_cli/src/commands/stake/move.py +1000 -0
- bittensor_cli/src/commands/stake/remove.py +1146 -0
- bittensor_cli/src/commands/subnets/__init__.py +0 -0
- bittensor_cli/src/commands/subnets/price.py +867 -0
- bittensor_cli/src/commands/subnets/subnets.py +2028 -0
- bittensor_cli/src/commands/sudo.py +554 -12
- bittensor_cli/src/commands/wallets.py +225 -531
- bittensor_cli/src/commands/weights.py +2 -2
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/METADATA +7 -4
- bittensor_cli-9.0.0.dist-info/RECORD +34 -0
- bittensor_cli/src/bittensor/async_substrate_interface.py +0 -2748
- bittensor_cli/src/commands/root.py +0 -1787
- bittensor_cli/src/commands/stake/stake.py +0 -1448
- bittensor_cli/src/commands/subnets.py +0 -897
- bittensor_cli-8.4.4.dist-info/RECORD +0 -31
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/WHEEL +0 -0
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/top_level.txt +0 -0
@@ -1,39 +1,31 @@
|
|
1
1
|
import asyncio
|
2
|
-
import binascii
|
3
2
|
import itertools
|
4
3
|
import os
|
5
|
-
import sys
|
6
4
|
from collections import defaultdict
|
7
|
-
from
|
8
|
-
from sys import getsizeof
|
9
|
-
from typing import Collection, Generator, Optional
|
5
|
+
from typing import Generator, Optional
|
10
6
|
|
11
7
|
import aiohttp
|
12
|
-
from bittensor_wallet import Wallet
|
8
|
+
from bittensor_wallet import Wallet, Keypair
|
13
9
|
from bittensor_wallet.errors import KeyFileError
|
14
10
|
from bittensor_wallet.keyfile import Keyfile
|
15
11
|
from fuzzywuzzy import fuzz
|
16
12
|
from rich import box
|
17
13
|
from rich.align import Align
|
18
|
-
from rich.prompt import Confirm
|
19
14
|
from rich.table import Column, Table
|
20
15
|
from rich.tree import Tree
|
21
16
|
from rich.padding import Padding
|
22
|
-
from rich.prompt import IntPrompt
|
23
17
|
import typer
|
24
18
|
|
19
|
+
from bittensor_cli.src import COLOR_PALETTE
|
25
20
|
from bittensor_cli.src.bittensor import utils
|
26
21
|
from bittensor_cli.src.bittensor.balances import Balance
|
27
22
|
from bittensor_cli.src.bittensor.chain_data import (
|
28
23
|
DelegateInfo,
|
29
24
|
NeuronInfoLite,
|
30
|
-
StakeInfo,
|
31
|
-
decode_account_id,
|
32
25
|
)
|
33
26
|
from bittensor_cli.src.bittensor.extrinsics.registration import (
|
34
27
|
run_faucet_extrinsic,
|
35
28
|
swap_hotkey_extrinsic,
|
36
|
-
is_hotkey_registered,
|
37
29
|
)
|
38
30
|
from bittensor_cli.src.bittensor.extrinsics.transfer import transfer_extrinsic
|
39
31
|
from bittensor_cli.src.bittensor.networking import int_to_ip
|
@@ -49,19 +41,13 @@ from bittensor_cli.src.bittensor.utils import (
|
|
49
41
|
get_hotkey_wallets_for_wallet,
|
50
42
|
is_valid_ss58_address,
|
51
43
|
validate_coldkey_presence,
|
52
|
-
|
44
|
+
get_subnet_name,
|
45
|
+
millify_tao,
|
53
46
|
unlock_key,
|
54
|
-
|
47
|
+
WalletLike,
|
55
48
|
)
|
56
49
|
|
57
50
|
|
58
|
-
class WalletLike:
|
59
|
-
def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None):
|
60
|
-
self.name = name
|
61
|
-
self.hotkey_ss58 = hotkey_ss58
|
62
|
-
self.hotkey_str = hotkey_str
|
63
|
-
|
64
|
-
|
65
51
|
async def regen_coldkey(
|
66
52
|
wallet: Wallet,
|
67
53
|
mnemonic: Optional[str],
|
@@ -161,15 +147,27 @@ async def new_hotkey(
|
|
161
147
|
wallet: Wallet,
|
162
148
|
n_words: int,
|
163
149
|
use_password: bool,
|
150
|
+
uri: Optional[str] = None,
|
164
151
|
overwrite: Optional[bool] = False,
|
165
152
|
):
|
166
153
|
"""Creates a new hotkey under this wallet."""
|
167
154
|
try:
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
155
|
+
if uri:
|
156
|
+
try:
|
157
|
+
keypair = Keypair.create_from_uri(uri)
|
158
|
+
except Exception as e:
|
159
|
+
print_error(f"Failed to create keypair from URI {uri}: {str(e)}")
|
160
|
+
wallet.set_hotkey(keypair=keypair, encrypt=use_password)
|
161
|
+
console.print(
|
162
|
+
f"[dark_sea_green]Hotkey created from URI: {uri}[/dark_sea_green]"
|
163
|
+
)
|
164
|
+
else:
|
165
|
+
wallet.create_new_hotkey(
|
166
|
+
n_words=n_words,
|
167
|
+
use_password=use_password,
|
168
|
+
overwrite=overwrite,
|
169
|
+
)
|
170
|
+
console.print("[dark_sea_green]Hotkey created[/dark_sea_green]")
|
173
171
|
except KeyFileError:
|
174
172
|
print_error("KeyFileError: File is not writable")
|
175
173
|
|
@@ -178,15 +176,28 @@ async def new_coldkey(
|
|
178
176
|
wallet: Wallet,
|
179
177
|
n_words: int,
|
180
178
|
use_password: bool,
|
179
|
+
uri: Optional[str] = None,
|
181
180
|
overwrite: Optional[bool] = False,
|
182
181
|
):
|
183
182
|
"""Creates a new coldkey under this wallet."""
|
184
183
|
try:
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
184
|
+
if uri:
|
185
|
+
try:
|
186
|
+
keypair = Keypair.create_from_uri(uri)
|
187
|
+
except Exception as e:
|
188
|
+
print_error(f"Failed to create keypair from URI {uri}: {str(e)}")
|
189
|
+
wallet.set_coldkey(keypair=keypair, encrypt=False, overwrite=False)
|
190
|
+
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False)
|
191
|
+
console.print(
|
192
|
+
f"[dark_sea_green]Coldkey created from URI: {uri}[/dark_sea_green]"
|
193
|
+
)
|
194
|
+
else:
|
195
|
+
wallet.create_new_coldkey(
|
196
|
+
n_words=n_words,
|
197
|
+
use_password=use_password,
|
198
|
+
overwrite=overwrite,
|
199
|
+
)
|
200
|
+
console.print("[dark_sea_green]Coldkey created[/dark_sea_green]")
|
190
201
|
except KeyFileError:
|
191
202
|
print_error("KeyFileError: File is not writable")
|
192
203
|
|
@@ -195,26 +206,41 @@ async def wallet_create(
|
|
195
206
|
wallet: Wallet,
|
196
207
|
n_words: int = 12,
|
197
208
|
use_password: bool = True,
|
209
|
+
uri: Optional[str] = None,
|
198
210
|
overwrite: Optional[bool] = False,
|
199
211
|
):
|
200
212
|
"""Creates a new wallet."""
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
overwrite=
|
213
|
+
if uri:
|
214
|
+
try:
|
215
|
+
keypair = Keypair.create_from_uri(uri)
|
216
|
+
wallet.set_coldkey(keypair=keypair, encrypt=False, overwrite=False)
|
217
|
+
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False)
|
218
|
+
wallet.set_hotkey(keypair=keypair, encrypt=False, overwrite=False)
|
219
|
+
except Exception as e:
|
220
|
+
print_error(f"Failed to create keypair from URI: {str(e)}")
|
221
|
+
console.print(
|
222
|
+
f"[dark_sea_green]Wallet created from URI: {uri}[/dark_sea_green]"
|
206
223
|
)
|
207
|
-
|
208
|
-
|
224
|
+
else:
|
225
|
+
try:
|
226
|
+
wallet.create_new_coldkey(
|
227
|
+
n_words=n_words,
|
228
|
+
use_password=use_password,
|
229
|
+
overwrite=overwrite,
|
230
|
+
)
|
231
|
+
console.print("[dark_sea_green]Coldkey created[/dark_sea_green]")
|
232
|
+
except KeyFileError:
|
233
|
+
print_error("KeyFileError: File is not writable")
|
209
234
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
235
|
+
try:
|
236
|
+
wallet.create_new_hotkey(
|
237
|
+
n_words=n_words,
|
238
|
+
use_password=False,
|
239
|
+
overwrite=overwrite,
|
240
|
+
)
|
241
|
+
console.print("[dark_sea_green]Hotkey created[/dark_sea_green]")
|
242
|
+
except KeyFileError:
|
243
|
+
print_error("KeyFileError: File is not writable")
|
218
244
|
|
219
245
|
|
220
246
|
def get_coldkey_wallets_for_path(path: str) -> list[Wallet]:
|
@@ -258,7 +284,11 @@ async def wallet_balance(
|
|
258
284
|
"""Retrieves the current balance of the specified wallet"""
|
259
285
|
if ss58_addresses:
|
260
286
|
coldkeys = ss58_addresses
|
261
|
-
|
287
|
+
identities = await subtensor.query_all_identities()
|
288
|
+
wallet_names = [
|
289
|
+
f"{identities.get(coldkey, {'name': f'Provided address {i}'})['name']}"
|
290
|
+
for i, coldkey in enumerate(coldkeys)
|
291
|
+
]
|
262
292
|
|
263
293
|
elif not all_balances:
|
264
294
|
if not wallet.coldkeypub_file.exists_on_device():
|
@@ -277,16 +307,12 @@ async def wallet_balance(
|
|
277
307
|
wallet_names = [wallet.name]
|
278
308
|
|
279
309
|
block_hash = await subtensor.substrate.get_chain_head()
|
280
|
-
free_balances
|
281
|
-
subtensor.get_balance(*coldkeys, block_hash=block_hash),
|
282
|
-
subtensor.get_total_stake_for_coldkey(*coldkeys, block_hash=block_hash),
|
283
|
-
)
|
310
|
+
free_balances = await subtensor.get_balances(*coldkeys, block_hash=block_hash)
|
284
311
|
|
285
312
|
total_free_balance = sum(free_balances.values())
|
286
|
-
total_staked_balance = sum(staked_balances.values())
|
287
313
|
|
288
314
|
balances = {
|
289
|
-
name: (coldkey, free_balances[coldkey]
|
315
|
+
name: (coldkey, free_balances[coldkey])
|
290
316
|
for (name, coldkey) in zip(wallet_names, coldkeys)
|
291
317
|
}
|
292
318
|
|
@@ -298,28 +324,16 @@ async def wallet_balance(
|
|
298
324
|
),
|
299
325
|
Column(
|
300
326
|
"[white]Coldkey Address",
|
301
|
-
style="
|
327
|
+
style=COLOR_PALETTE["GENERAL"]["COLDKEY"],
|
302
328
|
no_wrap=True,
|
303
329
|
),
|
304
330
|
Column(
|
305
331
|
"[white]Free Balance",
|
306
332
|
justify="right",
|
307
|
-
style="
|
333
|
+
style=COLOR_PALETTE["GENERAL"]["BALANCE"],
|
308
334
|
no_wrap=True,
|
309
335
|
),
|
310
|
-
|
311
|
-
"[white]Staked Balance",
|
312
|
-
justify="right",
|
313
|
-
style="orange1",
|
314
|
-
no_wrap=True,
|
315
|
-
),
|
316
|
-
Column(
|
317
|
-
"[white]Total Balance",
|
318
|
-
justify="right",
|
319
|
-
style="green",
|
320
|
-
no_wrap=True,
|
321
|
-
),
|
322
|
-
title=f"[underline dark_orange]Wallet Coldkey Balance[/underline dark_orange]\n[dark_orange]Network: {subtensor.network}",
|
336
|
+
title=f"\n [{COLOR_PALETTE['GENERAL']['HEADER']}]Wallet Coldkey Balance\nNetwork: {subtensor.network}",
|
323
337
|
show_footer=True,
|
324
338
|
show_edge=False,
|
325
339
|
border_style="bright_black",
|
@@ -329,24 +343,21 @@ async def wallet_balance(
|
|
329
343
|
leading=True,
|
330
344
|
)
|
331
345
|
|
332
|
-
for name, (coldkey, free
|
346
|
+
for name, (coldkey, free) in balances.items():
|
333
347
|
table.add_row(
|
334
348
|
name,
|
335
349
|
coldkey,
|
336
350
|
str(free),
|
337
|
-
str(staked),
|
338
|
-
str(free + staked),
|
339
351
|
)
|
340
352
|
table.add_row()
|
341
353
|
table.add_row(
|
342
354
|
"Total Balance",
|
343
355
|
"",
|
344
356
|
str(total_free_balance),
|
345
|
-
str(total_staked_balance),
|
346
|
-
str(total_free_balance + total_staked_balance),
|
347
357
|
)
|
348
358
|
console.print(Padding(table, (0, 0, 0, 4)))
|
349
359
|
await subtensor.substrate.close()
|
360
|
+
return total_free_balance
|
350
361
|
|
351
362
|
|
352
363
|
async def get_wallet_transfers(wallet_address: str) -> list[dict]:
|
@@ -497,7 +508,9 @@ async def wallet_list(wallet_path: str):
|
|
497
508
|
wallet_tree = root.add(
|
498
509
|
f"[bold blue]Coldkey[/bold blue] [green]{wallet.name}[/green] ss58_address [green]{coldkeypub_str}[/green]"
|
499
510
|
)
|
500
|
-
hotkeys = utils.get_hotkey_wallets_for_wallet(
|
511
|
+
hotkeys = utils.get_hotkey_wallets_for_wallet(
|
512
|
+
wallet, show_nulls=True, show_encrypted=True
|
513
|
+
)
|
501
514
|
for hkey in hotkeys:
|
502
515
|
data = f"[bold red]Hotkey[/bold red][green] {hkey}[/green] (?)"
|
503
516
|
if hkey:
|
@@ -541,7 +554,7 @@ async def _get_total_balance(
|
|
541
554
|
]
|
542
555
|
total_balance += sum(
|
543
556
|
(
|
544
|
-
await subtensor.
|
557
|
+
await subtensor.get_balances(
|
545
558
|
*(x.coldkeypub.ss58_address for x in _balance_cold_wallets),
|
546
559
|
block_hash=block_hash,
|
547
560
|
)
|
@@ -563,7 +576,7 @@ async def _get_total_balance(
|
|
563
576
|
):
|
564
577
|
total_balance = sum(
|
565
578
|
(
|
566
|
-
await subtensor.
|
579
|
+
await subtensor.get_balances(
|
567
580
|
coldkey_wallet.coldkeypub.ss58_address, block_hash=block_hash
|
568
581
|
)
|
569
582
|
).values()
|
@@ -587,17 +600,19 @@ async def overview(
|
|
587
600
|
include_hotkeys: Optional[list[str]] = None,
|
588
601
|
exclude_hotkeys: Optional[list[str]] = None,
|
589
602
|
netuids_filter: Optional[list[int]] = None,
|
603
|
+
verbose: bool = False,
|
590
604
|
):
|
591
605
|
"""Prints an overview for the wallet's coldkey."""
|
592
606
|
|
593
607
|
total_balance = Balance(0)
|
594
608
|
|
595
609
|
# We are printing for every coldkey.
|
596
|
-
print_verbose("Fetching total balance for coldkey/s")
|
597
610
|
block_hash = await subtensor.substrate.get_chain_head()
|
598
611
|
all_hotkeys, total_balance = await _get_total_balance(
|
599
612
|
total_balance, subtensor, wallet, all_wallets, block_hash=block_hash
|
600
613
|
)
|
614
|
+
_dynamic_info = await subtensor.all_subnets()
|
615
|
+
dynamic_info = {info.netuid: info for info in _dynamic_info}
|
601
616
|
|
602
617
|
with console.status(
|
603
618
|
f":satellite: Synchronizing with chain [white]{subtensor.network}[/white]",
|
@@ -605,9 +620,6 @@ async def overview(
|
|
605
620
|
) as status:
|
606
621
|
# We are printing for a select number of hotkeys from all_hotkeys.
|
607
622
|
if include_hotkeys or exclude_hotkeys:
|
608
|
-
print_verbose(
|
609
|
-
"Fetching for select hotkeys passed in 'include_hotkeys'", status
|
610
|
-
)
|
611
623
|
all_hotkeys = _get_hotkeys(include_hotkeys, exclude_hotkeys, all_hotkeys)
|
612
624
|
|
613
625
|
# Check we have keys to display.
|
@@ -617,17 +629,14 @@ async def overview(
|
|
617
629
|
|
618
630
|
# Pull neuron info for all keys.
|
619
631
|
neurons: dict[str, list[NeuronInfoLite]] = {}
|
620
|
-
print_verbose("Fetching subnet netuids", status)
|
621
632
|
block, all_netuids = await asyncio.gather(
|
622
633
|
subtensor.substrate.get_block_number(None),
|
623
634
|
subtensor.get_all_subnet_netuids(),
|
624
635
|
)
|
625
636
|
|
626
|
-
print_verbose("Filtering netuids by registered hotkeys", status)
|
627
637
|
netuids = await subtensor.filter_netuids_by_registered_hotkeys(
|
628
638
|
all_netuids, netuids_filter, all_hotkeys, reuse_block=True
|
629
639
|
)
|
630
|
-
# bittensor.logging.debug(f"Netuids to check: {netuids}")
|
631
640
|
|
632
641
|
for netuid in netuids:
|
633
642
|
neurons[str(netuid)] = []
|
@@ -648,122 +657,17 @@ async def overview(
|
|
648
657
|
)
|
649
658
|
all_hotkeys, _ = validate_coldkey_presence(all_hotkeys)
|
650
659
|
|
651
|
-
print_verbose("Fetching key addresses", status)
|
652
660
|
all_hotkey_addresses, hotkey_coldkey_to_hotkey_wallet = _get_key_address(
|
653
661
|
all_hotkeys
|
654
662
|
)
|
655
663
|
|
656
|
-
print_verbose("Pulling and processing neuron information for all keys", status)
|
657
664
|
results = await _get_neurons_for_netuids(
|
658
665
|
subtensor, netuids, all_hotkey_addresses
|
659
666
|
)
|
660
667
|
neurons = _process_neuron_results(results, neurons, netuids)
|
661
|
-
total_coldkey_stake_from_metagraph = await _calculate_total_coldkey_stake(
|
662
|
-
neurons
|
663
|
-
)
|
664
|
-
|
665
|
-
has_alerts = False
|
666
|
-
alerts_table = Table(show_header=True, header_style="bold magenta")
|
667
|
-
alerts_table.add_column("🥩 alert!")
|
668
|
-
alerts_table.add_row(
|
669
|
-
"[bold]Detected the following stake(s) associated with coldkey(s) that are not linked to any local hotkeys:[/bold]"
|
670
|
-
)
|
671
|
-
alerts_table.add_row("")
|
672
|
-
|
673
|
-
coldkeys_to_check = []
|
674
|
-
ck_stakes = await subtensor.get_total_stake_for_coldkey(
|
675
|
-
*(
|
676
|
-
coldkey_wallet.coldkeypub.ss58_address
|
677
|
-
for coldkey_wallet in all_coldkey_wallets
|
678
|
-
if coldkey_wallet.coldkeypub
|
679
|
-
),
|
680
|
-
block_hash=block_hash,
|
681
|
-
)
|
682
|
-
for coldkey_wallet in all_coldkey_wallets:
|
683
|
-
if coldkey_wallet.coldkeypub:
|
684
|
-
# Check if we have any stake with hotkeys that are not registered.
|
685
|
-
difference = (
|
686
|
-
ck_stakes[coldkey_wallet.coldkeypub.ss58_address]
|
687
|
-
- total_coldkey_stake_from_metagraph[
|
688
|
-
coldkey_wallet.coldkeypub.ss58_address
|
689
|
-
]
|
690
|
-
)
|
691
|
-
if difference == 0:
|
692
|
-
continue # We have all our stake registered.
|
693
|
-
|
694
|
-
has_alerts = True
|
695
|
-
coldkeys_to_check.append(coldkey_wallet)
|
696
|
-
alerts_table.add_row(
|
697
|
-
"[light_goldenrod2]{}[/light_goldenrod2] stake associated with coldkey [bright_magenta]{}[/bright_magenta] (ss58: [bright_magenta]{}[/bright_magenta])".format(
|
698
|
-
abs(difference),
|
699
|
-
coldkey_wallet.name,
|
700
|
-
coldkey_wallet.coldkeypub.ss58_address,
|
701
|
-
)
|
702
|
-
)
|
703
|
-
if has_alerts:
|
704
|
-
alerts_table.add_row("")
|
705
|
-
alerts_table.add_row(
|
706
|
-
"[bold yellow]Note:[/bold yellow] This stake might be delegated, staked to another user's hotkey, or associated with a hotkey not present in your wallet."
|
707
|
-
)
|
708
|
-
alerts_table.add_row(
|
709
|
-
"You can find out more by executing `[bold]btcli wallet inspect[/bold]` command."
|
710
|
-
)
|
711
|
-
|
712
|
-
if coldkeys_to_check:
|
713
|
-
# We have some stake that is not with a registered hotkey.
|
714
|
-
if "-1" not in neurons:
|
715
|
-
neurons["-1"] = []
|
716
|
-
|
717
|
-
print_verbose("Checking coldkeys for de-registered stake", status)
|
718
|
-
results = await asyncio.gather(
|
719
|
-
*[
|
720
|
-
_get_de_registered_stake_for_coldkey_wallet(
|
721
|
-
subtensor, all_hotkey_addresses, coldkey_wallet
|
722
|
-
)
|
723
|
-
for coldkey_wallet in coldkeys_to_check
|
724
|
-
]
|
725
|
-
)
|
726
|
-
|
727
|
-
for result in results:
|
728
|
-
coldkey_wallet, de_registered_stake, err_msg = result
|
729
|
-
if err_msg is not None:
|
730
|
-
err_console.print(err_msg)
|
731
|
-
|
732
|
-
if len(de_registered_stake) == 0:
|
733
|
-
continue # We have no de-registered stake with this coldkey.
|
734
|
-
|
735
|
-
de_registered_neurons = []
|
736
|
-
for hotkey_addr, our_stake in de_registered_stake:
|
737
|
-
# Make a neuron info lite for this hotkey and coldkey.
|
738
|
-
de_registered_neuron = NeuronInfoLite.get_null_neuron()
|
739
|
-
de_registered_neuron.hotkey = hotkey_addr
|
740
|
-
de_registered_neuron.coldkey = coldkey_wallet.coldkeypub.ss58_address
|
741
|
-
de_registered_neuron.total_stake = Balance(our_stake)
|
742
|
-
de_registered_neurons.append(de_registered_neuron)
|
743
|
-
|
744
|
-
# Add this hotkey to the wallets dict
|
745
|
-
wallet_ = WalletLike(
|
746
|
-
name=wallet.name,
|
747
|
-
hotkey_ss58=hotkey_addr,
|
748
|
-
hotkey_str=hotkey_addr[:5],
|
749
|
-
)
|
750
|
-
# Indicates a hotkey not on local machine but exists in stake_info obj on-chain
|
751
|
-
if hotkey_coldkey_to_hotkey_wallet.get(hotkey_addr) is None:
|
752
|
-
hotkey_coldkey_to_hotkey_wallet[hotkey_addr] = {}
|
753
|
-
hotkey_coldkey_to_hotkey_wallet[hotkey_addr][
|
754
|
-
coldkey_wallet.coldkeypub.ss58_address
|
755
|
-
] = wallet_
|
756
|
-
|
757
|
-
# Add neurons to overview.
|
758
|
-
neurons["-1"].extend(de_registered_neurons)
|
759
|
-
|
760
668
|
# Setup outer table.
|
761
669
|
grid = Table.grid(pad_edge=True)
|
762
670
|
|
763
|
-
# If there are any alerts, add them to the grid
|
764
|
-
if has_alerts:
|
765
|
-
grid.add_row(alerts_table)
|
766
|
-
|
767
671
|
# Add title
|
768
672
|
if not all_wallets:
|
769
673
|
title = "[underline dark_orange]Wallet[/underline dark_orange]\n"
|
@@ -782,9 +686,6 @@ async def overview(
|
|
782
686
|
)
|
783
687
|
)
|
784
688
|
# Generate rows per netuid
|
785
|
-
hotkeys_seen = set()
|
786
|
-
total_neurons = 0
|
787
|
-
total_stake = 0.0
|
788
689
|
tempos = await asyncio.gather(
|
789
690
|
*[
|
790
691
|
subtensor.get_hyperparameter("Tempo", netuid, block_hash)
|
@@ -792,7 +693,6 @@ async def overview(
|
|
792
693
|
]
|
793
694
|
)
|
794
695
|
for netuid, subnet_tempo in zip(netuids, tempos):
|
795
|
-
last_subnet = netuid == netuids[-1]
|
796
696
|
table_data = []
|
797
697
|
total_rank = 0.0
|
798
698
|
total_trust = 0.0
|
@@ -801,6 +701,8 @@ async def overview(
|
|
801
701
|
total_incentive = 0.0
|
802
702
|
total_dividends = 0.0
|
803
703
|
total_emission = 0
|
704
|
+
total_stake = 0
|
705
|
+
total_neurons = 0
|
804
706
|
|
805
707
|
for nn in neurons[str(netuid)]:
|
806
708
|
hotwallet = hotkey_coldkey_to_hotkey_wallet.get(nn.hotkey, {}).get(
|
@@ -821,7 +723,7 @@ async def overview(
|
|
821
723
|
validator_trust = nn.validator_trust
|
822
724
|
incentive = nn.incentive
|
823
725
|
dividends = nn.dividends
|
824
|
-
emission = int(nn.emission / (subnet_tempo + 1) * 1e9)
|
726
|
+
emission = int(nn.emission / (subnet_tempo + 1) * 1e9) # Per block
|
825
727
|
last_update = int(block - nn.last_update)
|
826
728
|
validator_permit = nn.validator_permit
|
827
729
|
row = [
|
@@ -829,14 +731,14 @@ async def overview(
|
|
829
731
|
hotwallet.hotkey_str,
|
830
732
|
str(uid),
|
831
733
|
str(active),
|
832
|
-
"{:.
|
833
|
-
"{:.
|
834
|
-
"{:.
|
835
|
-
"{:.
|
836
|
-
"{:.
|
837
|
-
"{:.
|
838
|
-
"{
|
839
|
-
"{:.
|
734
|
+
f"{stake:.4f}" if verbose else millify_tao(stake),
|
735
|
+
f"{rank:.4f}" if verbose else millify_tao(rank),
|
736
|
+
f"{trust:.4f}" if verbose else millify_tao(trust),
|
737
|
+
f"{consensus:.4f}" if verbose else millify_tao(consensus),
|
738
|
+
f"{incentive:.4f}" if verbose else millify_tao(incentive),
|
739
|
+
f"{dividends:.4f}" if verbose else millify_tao(dividends),
|
740
|
+
f"{emission:.4f}",
|
741
|
+
f"{validator_trust:.4f}" if verbose else millify_tao(validator_trust),
|
840
742
|
"*" if validator_permit else "",
|
841
743
|
str(last_update),
|
842
744
|
(
|
@@ -854,23 +756,15 @@ async def overview(
|
|
854
756
|
total_dividends += dividends
|
855
757
|
total_emission += emission
|
856
758
|
total_validator_trust += validator_trust
|
857
|
-
|
858
|
-
|
859
|
-
# Don't double count stake on hotkey-coldkey pairs.
|
860
|
-
hotkeys_seen.add((nn.hotkey, nn.coldkey))
|
861
|
-
total_stake += stake
|
862
|
-
|
863
|
-
# netuid -1 are neurons that are de-registered.
|
864
|
-
if netuid != "-1":
|
865
|
-
total_neurons += 1
|
759
|
+
total_stake += stake
|
760
|
+
total_neurons += 1
|
866
761
|
|
867
762
|
table_data.append(row)
|
868
763
|
|
869
764
|
# Add subnet header
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
grid.add_row(f"Subnet: [dark_orange]{netuid}[/dark_orange]")
|
765
|
+
grid.add_row(
|
766
|
+
f"Subnet: [dark_orange]{netuid}: {get_subnet_name(dynamic_info[netuid])} {dynamic_info[netuid].symbol}[/dark_orange]"
|
767
|
+
)
|
874
768
|
width = console.width
|
875
769
|
table = Table(
|
876
770
|
show_footer=False,
|
@@ -879,45 +773,34 @@ async def overview(
|
|
879
773
|
expand=True,
|
880
774
|
width=width - 5,
|
881
775
|
)
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
)
|
886
|
-
table.add_column(
|
887
|
-
"[white]HOTKEY", str(total_neurons), style="bright_cyan", ratio=2
|
888
|
-
)
|
889
|
-
else:
|
890
|
-
# No footer for non-last subnet.
|
891
|
-
table.add_column("[white]COLDKEY", style="bold bright_cyan", ratio=2)
|
892
|
-
table.add_column("[white]HOTKEY", style="bright_cyan", ratio=2)
|
776
|
+
|
777
|
+
table.add_column("[white]COLDKEY", style="bold bright_cyan", ratio=2)
|
778
|
+
table.add_column("[white]HOTKEY", style="bright_cyan", ratio=2)
|
893
779
|
table.add_column(
|
894
780
|
"[white]UID", str(total_neurons), style="rgb(42,161,152)", ratio=1
|
895
781
|
)
|
896
782
|
table.add_column(
|
897
783
|
"[white]ACTIVE", justify="right", style="#8787ff", no_wrap=True, ratio=1
|
898
784
|
)
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
no_wrap=True,
|
916
|
-
ratio=1.5,
|
917
|
-
)
|
785
|
+
|
786
|
+
_total_stake_formatted = (
|
787
|
+
f"{total_stake:.4f}" if verbose else millify_tao(total_stake)
|
788
|
+
)
|
789
|
+
table.add_column(
|
790
|
+
"[white]STAKE(\u03c4)"
|
791
|
+
if netuid == 0
|
792
|
+
else f"[white]STAKE({Balance.get_unit(netuid)})",
|
793
|
+
f"{_total_stake_formatted} {Balance.get_unit(netuid)}"
|
794
|
+
if netuid != 0
|
795
|
+
else f"{Balance.get_unit(netuid)} {_total_stake_formatted}",
|
796
|
+
justify="right",
|
797
|
+
style="dark_orange",
|
798
|
+
no_wrap=True,
|
799
|
+
ratio=1.5,
|
800
|
+
)
|
918
801
|
table.add_column(
|
919
802
|
"[white]RANK",
|
920
|
-
"{:.
|
803
|
+
f"{total_rank:.4f}",
|
921
804
|
justify="right",
|
922
805
|
style="medium_purple",
|
923
806
|
no_wrap=True,
|
@@ -925,7 +808,7 @@ async def overview(
|
|
925
808
|
)
|
926
809
|
table.add_column(
|
927
810
|
"[white]TRUST",
|
928
|
-
"{:.
|
811
|
+
f"{total_trust:.4f}",
|
929
812
|
justify="right",
|
930
813
|
style="green",
|
931
814
|
no_wrap=True,
|
@@ -933,7 +816,7 @@ async def overview(
|
|
933
816
|
)
|
934
817
|
table.add_column(
|
935
818
|
"[white]CONSENSUS",
|
936
|
-
"{:.
|
819
|
+
f"{total_consensus:.4f}",
|
937
820
|
justify="right",
|
938
821
|
style="rgb(42,161,152)",
|
939
822
|
no_wrap=True,
|
@@ -941,7 +824,7 @@ async def overview(
|
|
941
824
|
)
|
942
825
|
table.add_column(
|
943
826
|
"[white]INCENTIVE",
|
944
|
-
"{:.
|
827
|
+
f"{total_incentive:.4f}",
|
945
828
|
justify="right",
|
946
829
|
style="#5fd7ff",
|
947
830
|
no_wrap=True,
|
@@ -949,7 +832,7 @@ async def overview(
|
|
949
832
|
)
|
950
833
|
table.add_column(
|
951
834
|
"[white]DIVIDENDS",
|
952
|
-
"{:.
|
835
|
+
f"{total_dividends:.4f}",
|
953
836
|
justify="right",
|
954
837
|
style="#8787d7",
|
955
838
|
no_wrap=True,
|
@@ -957,7 +840,7 @@ async def overview(
|
|
957
840
|
)
|
958
841
|
table.add_column(
|
959
842
|
"[white]EMISSION(\u03c1)",
|
960
|
-
"\u03c1{
|
843
|
+
f"\u03c1{total_emission}",
|
961
844
|
justify="right",
|
962
845
|
style="#d7d7ff",
|
963
846
|
no_wrap=True,
|
@@ -965,7 +848,7 @@ async def overview(
|
|
965
848
|
)
|
966
849
|
table.add_column(
|
967
850
|
"[white]VTRUST",
|
968
|
-
"{:.
|
851
|
+
f"{total_validator_trust:.4f}",
|
969
852
|
justify="right",
|
970
853
|
style="magenta",
|
971
854
|
no_wrap=True,
|
@@ -1148,7 +1031,7 @@ def _map_hotkey_to_neurons(
|
|
1148
1031
|
|
1149
1032
|
async def _fetch_neuron_for_netuid(
|
1150
1033
|
netuid: int, subtensor: SubtensorInterface
|
1151
|
-
) -> tuple[int,
|
1034
|
+
) -> tuple[int, list[NeuronInfoLite]]:
|
1152
1035
|
"""
|
1153
1036
|
Retrieves all neurons for a specified netuid
|
1154
1037
|
|
@@ -1157,25 +1040,13 @@ async def _fetch_neuron_for_netuid(
|
|
1157
1040
|
|
1158
1041
|
:return: the original netuid, and a mapping of the neurons to their NeuronInfoLite objects
|
1159
1042
|
"""
|
1160
|
-
|
1161
|
-
async def neurons_lite_for_uid(uid: int) -> Optional[str]:
|
1162
|
-
block_hash = subtensor.substrate.last_block_hash
|
1163
|
-
hex_bytes_result = await subtensor.query_runtime_api(
|
1164
|
-
runtime_api="NeuronInfoRuntimeApi",
|
1165
|
-
method="get_neurons_lite",
|
1166
|
-
params=[uid],
|
1167
|
-
block_hash=block_hash,
|
1168
|
-
)
|
1169
|
-
|
1170
|
-
return hex_bytes_result
|
1171
|
-
|
1172
|
-
neurons = await neurons_lite_for_uid(uid=netuid)
|
1043
|
+
neurons = await subtensor.neurons_lite(netuid=netuid)
|
1173
1044
|
return netuid, neurons
|
1174
1045
|
|
1175
1046
|
|
1176
1047
|
async def _fetch_all_neurons(
|
1177
1048
|
netuids: list[int], subtensor
|
1178
|
-
) -> list[tuple[int,
|
1049
|
+
) -> list[tuple[int, list[NeuronInfoLite]]]:
|
1179
1050
|
"""Retrieves all neurons for each of the specified netuids"""
|
1180
1051
|
return list(
|
1181
1052
|
await asyncio.gather(
|
@@ -1184,85 +1055,16 @@ async def _fetch_all_neurons(
|
|
1184
1055
|
)
|
1185
1056
|
|
1186
1057
|
|
1187
|
-
def _process_neurons_for_netuids(
|
1188
|
-
netuids_with_all_neurons_hex_bytes: list[tuple[int, Optional[str]]],
|
1189
|
-
) -> list[tuple[int, list[NeuronInfoLite]]]:
|
1190
|
-
"""
|
1191
|
-
Decode a list of hex-bytes neurons with their respective netuid
|
1192
|
-
|
1193
|
-
:param netuids_with_all_neurons_hex_bytes: netuids with hex-bytes neurons
|
1194
|
-
:return: netuids mapped to decoded neurons
|
1195
|
-
"""
|
1196
|
-
all_results = [
|
1197
|
-
(netuid, NeuronInfoLite.list_from_vec_u8(hex_to_bytes(result)))
|
1198
|
-
if result
|
1199
|
-
else (netuid, [])
|
1200
|
-
for netuid, result in netuids_with_all_neurons_hex_bytes
|
1201
|
-
]
|
1202
|
-
return all_results
|
1203
|
-
|
1204
|
-
|
1205
1058
|
async def _get_neurons_for_netuids(
|
1206
1059
|
subtensor: SubtensorInterface, netuids: list[int], hot_wallets: list[str]
|
1207
1060
|
) -> list[tuple[int, list["NeuronInfoLite"], Optional[str]]]:
|
1208
|
-
|
1209
|
-
|
1210
|
-
all_processed_neurons = _process_neurons_for_netuids(all_neurons_hex_bytes)
|
1061
|
+
all_neurons = await _fetch_all_neurons(netuids, subtensor)
|
1211
1062
|
return [
|
1212
1063
|
_map_hotkey_to_neurons(neurons, hot_wallets, netuid)
|
1213
|
-
for netuid, neurons in
|
1064
|
+
for netuid, neurons in all_neurons
|
1214
1065
|
]
|
1215
1066
|
|
1216
1067
|
|
1217
|
-
async def _get_de_registered_stake_for_coldkey_wallet(
|
1218
|
-
subtensor: SubtensorInterface,
|
1219
|
-
all_hotkey_addresses: Collection[str],
|
1220
|
-
coldkey_wallet: Wallet,
|
1221
|
-
) -> tuple[Wallet, list[tuple[str, float]], Optional[str]]:
|
1222
|
-
"""
|
1223
|
-
Looks at the total stake of a coldkey, then filters this based on the supplied hotkey addresses
|
1224
|
-
depending on whether the hotkey is a delegate
|
1225
|
-
|
1226
|
-
:param subtensor: SubtensorInterface to make queries with
|
1227
|
-
:param all_hotkey_addresses: collection of hotkey SS58 addresses
|
1228
|
-
:param coldkey_wallet: Wallet containing coldkey
|
1229
|
-
|
1230
|
-
:return: (original wallet, [(hotkey SS58, stake in TAO), ...], error message)
|
1231
|
-
"""
|
1232
|
-
# Pull all stake for our coldkey
|
1233
|
-
all_stake_info_for_coldkey = await subtensor.get_stake_info_for_coldkey(
|
1234
|
-
coldkey_ss58=coldkey_wallet.coldkeypub.ss58_address, reuse_block=True
|
1235
|
-
)
|
1236
|
-
|
1237
|
-
# Filter out hotkeys that are in our wallets
|
1238
|
-
# Filter out hotkeys that are delegates.
|
1239
|
-
async def _filter_stake_info(stake_info: StakeInfo) -> bool:
|
1240
|
-
if stake_info.stake == 0:
|
1241
|
-
return False # Skip hotkeys that we have no stake with.
|
1242
|
-
if stake_info.hotkey_ss58 in all_hotkey_addresses:
|
1243
|
-
return False # Skip hotkeys that are in our wallets.
|
1244
|
-
return not await subtensor.is_hotkey_delegate(
|
1245
|
-
hotkey_ss58=stake_info.hotkey_ss58, reuse_block=True
|
1246
|
-
)
|
1247
|
-
|
1248
|
-
all_staked = await asyncio.gather(
|
1249
|
-
*[_filter_stake_info(stake_info) for stake_info in all_stake_info_for_coldkey]
|
1250
|
-
)
|
1251
|
-
|
1252
|
-
# Collecting all filtered stake info using async for loop
|
1253
|
-
all_staked_hotkeys = []
|
1254
|
-
for stake_info, staked in zip(all_stake_info_for_coldkey, all_staked):
|
1255
|
-
if staked:
|
1256
|
-
all_staked_hotkeys.append(
|
1257
|
-
(
|
1258
|
-
stake_info.hotkey_ss58,
|
1259
|
-
stake_info.stake.tao,
|
1260
|
-
)
|
1261
|
-
)
|
1262
|
-
|
1263
|
-
return coldkey_wallet, all_staked_hotkeys, None
|
1264
|
-
|
1265
|
-
|
1266
1068
|
async def transfer(
|
1267
1069
|
wallet: Wallet,
|
1268
1070
|
subtensor: SubtensorInterface,
|
@@ -1273,11 +1075,11 @@ async def transfer(
|
|
1273
1075
|
):
|
1274
1076
|
"""Transfer token of amount to destination."""
|
1275
1077
|
await transfer_extrinsic(
|
1276
|
-
subtensor,
|
1277
|
-
wallet,
|
1278
|
-
destination,
|
1279
|
-
Balance.from_tao(amount),
|
1280
|
-
transfer_all,
|
1078
|
+
subtensor=subtensor,
|
1079
|
+
wallet=wallet,
|
1080
|
+
destination=destination,
|
1081
|
+
amount=Balance.from_tao(amount),
|
1082
|
+
transfer_all=transfer_all,
|
1281
1083
|
prompt=prompt,
|
1282
1084
|
)
|
1283
1085
|
|
@@ -1292,6 +1094,8 @@ async def inspect(
|
|
1292
1094
|
delegates_: list[tuple[DelegateInfo, Balance]],
|
1293
1095
|
) -> Generator[list[str], None, None]:
|
1294
1096
|
for d_, staked in delegates_:
|
1097
|
+
if not staked.tao > 0:
|
1098
|
+
continue
|
1295
1099
|
if d_.hotkey_ss58 in registered_delegate_info:
|
1296
1100
|
delegate_name = registered_delegate_info[d_.hotkey_ss58].display
|
1297
1101
|
else:
|
@@ -1301,7 +1105,11 @@ async def inspect(
|
|
1301
1105
|
+ [
|
1302
1106
|
str(delegate_name),
|
1303
1107
|
str(staked),
|
1304
|
-
str(
|
1108
|
+
str(
|
1109
|
+
d_.total_daily_return.tao * (staked.tao / d_.total_stake.tao)
|
1110
|
+
if d_.total_stake.tao != 0
|
1111
|
+
else 0
|
1112
|
+
),
|
1305
1113
|
]
|
1306
1114
|
+ [""] * 4
|
1307
1115
|
)
|
@@ -1381,7 +1189,7 @@ async def inspect(
|
|
1381
1189
|
all_delegates: list[list[tuple[DelegateInfo, Balance]]]
|
1382
1190
|
with console.status("Pulling balance data...", spinner="aesthetic"):
|
1383
1191
|
balances, all_neurons, all_delegates = await asyncio.gather(
|
1384
|
-
subtensor.
|
1192
|
+
subtensor.get_balances(
|
1385
1193
|
*[w.coldkeypub.ss58_address for w in wallets_with_ckp_file],
|
1386
1194
|
block_hash=block_hash,
|
1387
1195
|
),
|
@@ -1467,210 +1275,94 @@ async def swap_hotkey(
|
|
1467
1275
|
)
|
1468
1276
|
|
1469
1277
|
|
1470
|
-
def
|
1471
|
-
|
1472
|
-
|
1473
|
-
"""
|
1474
|
-
Used to prompt the user to input their info for setting the ID
|
1475
|
-
:return: (display_name, legal_name, web_url, riot_handle, email,pgp_fingerprint, image_url, info_, twitter_url,
|
1476
|
-
validator_id)
|
1477
|
-
"""
|
1478
|
-
text_rejection = partial(
|
1479
|
-
retry_prompt,
|
1480
|
-
rejection=lambda x: sys.getsizeof(x) > 113,
|
1481
|
-
rejection_text="[red]Error:[/red] Identity field must be <= 64 raw bytes.",
|
1482
|
-
)
|
1278
|
+
def create_identity_table(title: str = None):
|
1279
|
+
if not title:
|
1280
|
+
title = "On-Chain Identity"
|
1483
1281
|
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
"[red]Error:[/red] PGP Fingerprint must be exactly 20 bytes.",
|
1502
|
-
)
|
1503
|
-
image_url = text_rejection("Image URL")
|
1504
|
-
info_ = text_rejection("Enter info")
|
1505
|
-
twitter_url = text_rejection("𝕏 (Twitter) URL")
|
1506
|
-
|
1507
|
-
subnet_netuid = None
|
1508
|
-
if validator is False:
|
1509
|
-
subnet_netuid = IntPrompt.ask("Enter the netuid of the subnet you own")
|
1510
|
-
|
1511
|
-
return (
|
1512
|
-
display_name,
|
1513
|
-
legal_name,
|
1514
|
-
web_url,
|
1515
|
-
pgp_fingerprint,
|
1516
|
-
riot_handle,
|
1517
|
-
email,
|
1518
|
-
image_url,
|
1519
|
-
twitter_url,
|
1520
|
-
info_,
|
1521
|
-
validator,
|
1522
|
-
subnet_netuid,
|
1282
|
+
table = Table(
|
1283
|
+
Column(
|
1284
|
+
"Item",
|
1285
|
+
justify="right",
|
1286
|
+
style=COLOR_PALETTE["GENERAL"]["SUBHEADING_MAIN"],
|
1287
|
+
no_wrap=True,
|
1288
|
+
),
|
1289
|
+
Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]),
|
1290
|
+
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]{title}",
|
1291
|
+
show_footer=True,
|
1292
|
+
show_edge=False,
|
1293
|
+
header_style="bold white",
|
1294
|
+
border_style="bright_black",
|
1295
|
+
style="bold",
|
1296
|
+
title_justify="center",
|
1297
|
+
show_lines=False,
|
1298
|
+
pad_edge=True,
|
1523
1299
|
)
|
1300
|
+
return table
|
1524
1301
|
|
1525
1302
|
|
1526
1303
|
async def set_id(
|
1527
1304
|
wallet: Wallet,
|
1528
1305
|
subtensor: SubtensorInterface,
|
1529
|
-
|
1530
|
-
legal_name: str,
|
1306
|
+
name: str,
|
1531
1307
|
web_url: str,
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
info_: str,
|
1538
|
-
validator_id: bool,
|
1539
|
-
subnet_netuid: int,
|
1308
|
+
image_url: str,
|
1309
|
+
discord: str,
|
1310
|
+
description: str,
|
1311
|
+
additional: str,
|
1312
|
+
github_repo: str,
|
1540
1313
|
prompt: bool,
|
1541
1314
|
):
|
1542
1315
|
"""Create a new or update existing identity on-chain."""
|
1543
1316
|
|
1544
|
-
|
1545
|
-
"
|
1546
|
-
"
|
1547
|
-
"
|
1548
|
-
"
|
1549
|
-
"
|
1550
|
-
"
|
1551
|
-
"
|
1552
|
-
"image": image,
|
1553
|
-
"twitter": twitter,
|
1554
|
-
"info": info_,
|
1317
|
+
identity_data = {
|
1318
|
+
"name": name.encode(),
|
1319
|
+
"url": web_url.encode(),
|
1320
|
+
"image": image_url.encode(),
|
1321
|
+
"discord": discord.encode(),
|
1322
|
+
"description": description.encode(),
|
1323
|
+
"additional": additional.encode(),
|
1324
|
+
"github_repo": github_repo.encode(),
|
1555
1325
|
}
|
1556
1326
|
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
print_error(f"The PGP is not in the correct format: {e}")
|
1561
|
-
raise typer.Exit()
|
1562
|
-
|
1563
|
-
for field, string in id_dict.items():
|
1564
|
-
if (
|
1565
|
-
field == "pgp_fingerprint"
|
1566
|
-
and pgp_fingerprint
|
1567
|
-
and len(pgp_fingerprint_encoded) != 20
|
1568
|
-
):
|
1327
|
+
for field, value in identity_data.items():
|
1328
|
+
max_size = 64 # bytes
|
1329
|
+
if len(value) > max_size:
|
1569
1330
|
err_console.print(
|
1570
|
-
"[red]Error:[/red]
|
1571
|
-
|
1572
|
-
return False
|
1573
|
-
elif (size := getsizeof(string)) > 113: # 64 + 49 overhead bytes for string
|
1574
|
-
err_console.print(
|
1575
|
-
f"[red]Error:[/red] Identity field [white]{field}[/white] must be <= 64 raw bytes.\n"
|
1576
|
-
f"Value: '{string}' currently [white]{size} bytes[/white]."
|
1331
|
+
f"[red]Error:[/red] Identity field [white]{field}[/white] must be <= {max_size} bytes.\n"
|
1332
|
+
f"Value '{value.decode()}' is {len(value)} bytes."
|
1577
1333
|
)
|
1578
1334
|
return False
|
1579
1335
|
|
1580
|
-
identified = (
|
1581
|
-
wallet.hotkey.ss58_address if validator_id else wallet.coldkey.ss58_address
|
1582
|
-
)
|
1583
|
-
encoded_id_dict = {
|
1584
|
-
"info": {
|
1585
|
-
"additional": [[]],
|
1586
|
-
"display": {f"Raw{len(display_name.encode())}": display_name.encode()},
|
1587
|
-
"legal": {f"Raw{len(legal_name.encode())}": legal_name.encode()},
|
1588
|
-
"web": {f"Raw{len(web_url.encode())}": web_url.encode()},
|
1589
|
-
"riot": {f"Raw{len(riot_handle.encode())}": riot_handle.encode()},
|
1590
|
-
"email": {f"Raw{len(email.encode())}": email.encode()},
|
1591
|
-
"pgp_fingerprint": pgp_fingerprint_encoded if pgp_fingerprint else None,
|
1592
|
-
"image": {f"Raw{len(image.encode())}": image.encode()},
|
1593
|
-
"info": {f"Raw{len(info_.encode())}": info_.encode()},
|
1594
|
-
"twitter": {f"Raw{len(twitter.encode())}": twitter.encode()},
|
1595
|
-
},
|
1596
|
-
"identified": identified,
|
1597
|
-
}
|
1598
|
-
|
1599
|
-
if prompt:
|
1600
|
-
if not Confirm.ask(
|
1601
|
-
"Cost to register an Identity is [bold white italic]0.1 Tao[/bold white italic],"
|
1602
|
-
" are you sure you wish to continue?"
|
1603
|
-
):
|
1604
|
-
console.print(":cross_mark: Aborted!")
|
1605
|
-
raise typer.Exit()
|
1606
|
-
|
1607
|
-
if validator_id:
|
1608
|
-
block_hash = await subtensor.substrate.get_chain_head()
|
1609
|
-
|
1610
|
-
is_registered_on_root, hotkey_owner = await asyncio.gather(
|
1611
|
-
is_hotkey_registered(
|
1612
|
-
subtensor, netuid=0, hotkey_ss58=wallet.hotkey.ss58_address
|
1613
|
-
),
|
1614
|
-
subtensor.get_hotkey_owner(
|
1615
|
-
hotkey_ss58=wallet.hotkey.ss58_address, block_hash=block_hash
|
1616
|
-
),
|
1617
|
-
)
|
1618
|
-
|
1619
|
-
if not is_registered_on_root:
|
1620
|
-
print_error("The hotkey is not registered on root. Aborting.")
|
1621
|
-
return False
|
1622
|
-
|
1623
|
-
own_hotkey = wallet.coldkeypub.ss58_address == hotkey_owner
|
1624
|
-
if not own_hotkey:
|
1625
|
-
print_error("The hotkey doesn't belong to the coldkey wallet. Aborting.")
|
1626
|
-
return False
|
1627
|
-
else:
|
1628
|
-
subnet_owner_ = await subtensor.substrate.query(
|
1629
|
-
module="SubtensorModule",
|
1630
|
-
storage_function="SubnetOwner",
|
1631
|
-
params=[subnet_netuid],
|
1632
|
-
)
|
1633
|
-
subnet_owner = decode_account_id(subnet_owner_[0])
|
1634
|
-
if subnet_owner != wallet.coldkeypub.ss58_address:
|
1635
|
-
print_error(f":cross_mark: This wallet doesn't own subnet {subnet_netuid}.")
|
1636
|
-
return False
|
1637
|
-
|
1638
1336
|
if not unlock_key(wallet).success:
|
1639
1337
|
return False
|
1640
1338
|
|
1339
|
+
call = await subtensor.substrate.compose_call(
|
1340
|
+
call_module="SubtensorModule",
|
1341
|
+
call_function="set_identity",
|
1342
|
+
call_params=identity_data,
|
1343
|
+
)
|
1344
|
+
|
1641
1345
|
with console.status(
|
1642
|
-
":satellite: [
|
1346
|
+
" :satellite: [dark_sea_green3]Updating identity on-chain...", spinner="earth"
|
1643
1347
|
):
|
1644
|
-
call = await subtensor.substrate.compose_call(
|
1645
|
-
call_module="Registry",
|
1646
|
-
call_function="set_identity",
|
1647
|
-
call_params=encoded_id_dict,
|
1648
|
-
)
|
1649
1348
|
success, err_msg = await subtensor.sign_and_send_extrinsic(call, wallet)
|
1650
1349
|
|
1651
1350
|
if not success:
|
1652
1351
|
err_console.print(f"[red]:cross_mark: Failed![/red] {err_msg}")
|
1653
1352
|
return
|
1654
1353
|
|
1655
|
-
console.print(":white_heavy_check_mark: Success!")
|
1656
|
-
identity = await subtensor.query_identity(
|
1657
|
-
identified or wallet.coldkey.ss58_address
|
1658
|
-
)
|
1659
|
-
|
1660
|
-
table = Table(
|
1661
|
-
Column("Key", justify="right", style="cyan", no_wrap=True),
|
1662
|
-
Column("Value", style="magenta"),
|
1663
|
-
title="[bold white italic]Updated On-Chain Identity",
|
1664
|
-
)
|
1354
|
+
console.print(":white_heavy_check_mark: [dark_sea_green3]Success!")
|
1355
|
+
identity = await subtensor.query_identity(wallet.coldkeypub.ss58_address)
|
1665
1356
|
|
1666
|
-
table
|
1357
|
+
table = create_identity_table(title="New on-chain Identity")
|
1358
|
+
table.add_row("Address", wallet.coldkeypub.ss58_address)
|
1667
1359
|
for key, value in identity.items():
|
1668
|
-
table.add_row(key, str(value) if value
|
1360
|
+
table.add_row(key, str(value) if value else "~")
|
1669
1361
|
|
1670
1362
|
return console.print(table)
|
1671
1363
|
|
1672
1364
|
|
1673
|
-
async def get_id(subtensor: SubtensorInterface, ss58_address: str):
|
1365
|
+
async def get_id(subtensor: SubtensorInterface, ss58_address: str, title: str = None):
|
1674
1366
|
with console.status(
|
1675
1367
|
":satellite: [bold green]Querying chain identity...", spinner="earth"
|
1676
1368
|
):
|
@@ -1678,40 +1370,37 @@ async def get_id(subtensor: SubtensorInterface, ss58_address: str):
|
|
1678
1370
|
|
1679
1371
|
if not identity:
|
1680
1372
|
err_console.print(
|
1681
|
-
f"[
|
1682
|
-
f" for [
|
1683
|
-
f" on
|
1373
|
+
f"[blue]Existing identity not found[/blue]"
|
1374
|
+
f" for [{COLOR_PALETTE['GENERAL']['COLDKEY']}]{ss58_address}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]"
|
1375
|
+
f" on {subtensor}"
|
1684
1376
|
)
|
1685
|
-
return
|
1686
|
-
table = Table(
|
1687
|
-
Column("Item", justify="right", style="cyan", no_wrap=True),
|
1688
|
-
Column("Value", style="magenta"),
|
1689
|
-
title="[bold white italic]On-Chain Identity",
|
1690
|
-
)
|
1377
|
+
return {}
|
1691
1378
|
|
1379
|
+
table = create_identity_table(title)
|
1692
1380
|
table.add_row("Address", ss58_address)
|
1693
1381
|
for key, value in identity.items():
|
1694
|
-
table.add_row(key, str(value) if value
|
1382
|
+
table.add_row(key, str(value) if value else "~")
|
1695
1383
|
|
1696
|
-
|
1384
|
+
console.print(table)
|
1385
|
+
return identity
|
1697
1386
|
|
1698
1387
|
|
1699
1388
|
async def check_coldkey_swap(wallet: Wallet, subtensor: SubtensorInterface):
|
1700
|
-
arbitration_check = len(
|
1389
|
+
arbitration_check = len( # TODO verify this works
|
1701
1390
|
(
|
1702
|
-
await subtensor.
|
1391
|
+
await subtensor.query(
|
1703
1392
|
module="SubtensorModule",
|
1704
1393
|
storage_function="ColdkeySwapDestinations",
|
1705
1394
|
params=[wallet.coldkeypub.ss58_address],
|
1706
1395
|
)
|
1707
|
-
)
|
1396
|
+
)
|
1708
1397
|
)
|
1709
1398
|
if arbitration_check == 0:
|
1710
1399
|
console.print(
|
1711
1400
|
"[green]There has been no previous key swap initiated for your coldkey.[/green]"
|
1712
1401
|
)
|
1713
1402
|
elif arbitration_check == 1:
|
1714
|
-
arbitration_block = await subtensor.
|
1403
|
+
arbitration_block = await subtensor.query(
|
1715
1404
|
module="SubtensorModule",
|
1716
1405
|
storage_function="ColdkeyArbitrationBlock",
|
1717
1406
|
params=[wallet.coldkeypub.ss58_address],
|
@@ -1735,17 +1424,22 @@ async def check_coldkey_swap(wallet: Wallet, subtensor: SubtensorInterface):
|
|
1735
1424
|
|
1736
1425
|
async def sign(wallet: Wallet, message: str, use_hotkey: str):
|
1737
1426
|
"""Sign a message using the provided wallet or hotkey."""
|
1427
|
+
|
1738
1428
|
if not use_hotkey:
|
1739
|
-
if not unlock_key(wallet).success:
|
1429
|
+
if not unlock_key(wallet, "cold").success:
|
1740
1430
|
return False
|
1741
1431
|
keypair = wallet.coldkey
|
1742
|
-
print_verbose(
|
1432
|
+
print_verbose(
|
1433
|
+
f"Signing using [{COLOR_PALETTE['GENERAL']['COLDKEY']}]coldkey: {wallet.name}"
|
1434
|
+
)
|
1743
1435
|
else:
|
1744
1436
|
if not unlock_key(wallet, "hot").success:
|
1745
1437
|
return False
|
1746
1438
|
keypair = wallet.hotkey
|
1747
|
-
print_verbose(
|
1439
|
+
print_verbose(
|
1440
|
+
f"Signing using [{COLOR_PALETTE['GENERAL']['HOTKEY']}]hotkey: {wallet.hotkey_str}"
|
1441
|
+
)
|
1748
1442
|
|
1749
1443
|
signed_message = keypair.sign(message.encode("utf-8")).hex()
|
1750
|
-
console.print("[
|
1444
|
+
console.print("[dark_sea_green3]Message signed successfully:")
|
1751
1445
|
console.print(signed_message)
|