bittensor-cli 9.0.0rc3__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 +228 -80
- 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 +181 -64
- 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.0rc3.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.0rc3.dist-info/RECORD +0 -34
- {bittensor_cli-9.0.0rc3.dist-info → bittensor_cli-9.0.1.dist-info}/WHEEL +0 -0
- {bittensor_cli-9.0.0rc3.dist-info → bittensor_cli-9.0.1.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.0.0rc3.dist-info → bittensor_cli-9.0.1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
|
|
1
1
|
import ast
|
2
|
+
from collections import namedtuple
|
2
3
|
import math
|
3
4
|
import os
|
4
5
|
import sqlite3
|
@@ -13,7 +14,7 @@ import re
|
|
13
14
|
|
14
15
|
from bittensor_wallet import Wallet, Keypair
|
15
16
|
from bittensor_wallet.utils import SS58_FORMAT
|
16
|
-
from bittensor_wallet.errors import KeyFileError
|
17
|
+
from bittensor_wallet.errors import KeyFileError, PasswordError
|
17
18
|
from bittensor_wallet import utils
|
18
19
|
from jinja2 import Template
|
19
20
|
from markupsafe import Markup
|
@@ -31,12 +32,30 @@ from bittensor_cli.src import defaults, Constants
|
|
31
32
|
|
32
33
|
if TYPE_CHECKING:
|
33
34
|
from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
|
34
|
-
from async_substrate_interface.async_substrate import AsyncSubstrateInterface
|
35
35
|
|
36
36
|
console = Console()
|
37
37
|
err_console = Console(stderr=True)
|
38
38
|
verbose_console = Console(quiet=True)
|
39
39
|
|
40
|
+
UnlockStatus = namedtuple("UnlockStatus", ["success", "message"])
|
41
|
+
|
42
|
+
|
43
|
+
class _Hotkey:
|
44
|
+
def __init__(self, hotkey_ss58=None):
|
45
|
+
self.ss58_address = hotkey_ss58
|
46
|
+
|
47
|
+
|
48
|
+
class WalletLike:
|
49
|
+
def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None):
|
50
|
+
self.name = name
|
51
|
+
self.hotkey_ss58 = hotkey_ss58
|
52
|
+
self.hotkey_str = hotkey_str
|
53
|
+
self._hotkey = _Hotkey(hotkey_ss58)
|
54
|
+
|
55
|
+
@property
|
56
|
+
def hotkey(self):
|
57
|
+
return self._hotkey
|
58
|
+
|
40
59
|
|
41
60
|
def print_console(message: str, colour: str, title: str, console: Console):
|
42
61
|
console.print(
|
@@ -196,13 +215,14 @@ def convert_root_weight_uids_and_vals_to_tensor(
|
|
196
215
|
|
197
216
|
|
198
217
|
def get_hotkey_wallets_for_wallet(
|
199
|
-
wallet: Wallet, show_nulls: bool = False
|
218
|
+
wallet: Wallet, show_nulls: bool = False, show_encrypted: bool = False
|
200
219
|
) -> list[Optional[Wallet]]:
|
201
220
|
"""
|
202
221
|
Returns wallet objects with hotkeys for a single given wallet
|
203
222
|
|
204
223
|
:param wallet: Wallet object to use for the path
|
205
224
|
:param show_nulls: will add `None` into the output if a hotkey is encrypted or not on the device
|
225
|
+
:param show_encrypted: will add some basic info about the encrypted hotkey
|
206
226
|
|
207
227
|
:return: a list of wallets (with Nones included for cases of a hotkey being encrypted or not on the device, if
|
208
228
|
`show_nulls` is set to `True`)
|
@@ -218,12 +238,18 @@ def get_hotkey_wallets_for_wallet(
|
|
218
238
|
hotkey_for_name = Wallet(path=str(wallet_path), name=wallet.name, hotkey=h_name)
|
219
239
|
try:
|
220
240
|
if (
|
221
|
-
hotkey_for_name.hotkey_file.exists_on_device()
|
241
|
+
(exists := hotkey_for_name.hotkey_file.exists_on_device())
|
222
242
|
and not hotkey_for_name.hotkey_file.is_encrypted()
|
223
243
|
# and hotkey_for_name.coldkeypub.ss58_address
|
224
244
|
and hotkey_for_name.hotkey.ss58_address
|
225
245
|
):
|
226
246
|
hotkey_wallets.append(hotkey_for_name)
|
247
|
+
elif (
|
248
|
+
show_encrypted and exists and hotkey_for_name.hotkey_file.is_encrypted()
|
249
|
+
):
|
250
|
+
hotkey_wallets.append(
|
251
|
+
WalletLike(str(wallet_path), "<ENCRYPTED>", h_name)
|
252
|
+
)
|
227
253
|
elif show_nulls:
|
228
254
|
hotkey_wallets.append(None)
|
229
255
|
except (
|
@@ -240,11 +266,14 @@ def get_hotkey_wallets_for_wallet(
|
|
240
266
|
def get_coldkey_wallets_for_path(path: str) -> list[Wallet]:
|
241
267
|
"""Gets all wallets with coldkeys from a given path"""
|
242
268
|
wallet_path = Path(path).expanduser()
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
269
|
+
try:
|
270
|
+
wallets = [
|
271
|
+
Wallet(name=directory.name, path=path)
|
272
|
+
for directory in wallet_path.iterdir()
|
273
|
+
if directory.is_dir()
|
274
|
+
]
|
275
|
+
except FileNotFoundError:
|
276
|
+
wallets = []
|
248
277
|
return wallets
|
249
278
|
|
250
279
|
|
@@ -448,16 +477,13 @@ def get_explorer_url_for_network(
|
|
448
477
|
return explorer_urls
|
449
478
|
|
450
479
|
|
451
|
-
def format_error_message(
|
452
|
-
error_message: Union[dict, Exception], substrate: "AsyncSubstrateInterface"
|
453
|
-
) -> str:
|
480
|
+
def format_error_message(error_message: Union[dict, Exception]) -> str:
|
454
481
|
"""
|
455
482
|
Formats an error message from the Subtensor error information for use in extrinsics.
|
456
483
|
|
457
484
|
Args:
|
458
485
|
error_message: A dictionary containing the error information from Subtensor, or a SubstrateRequestException
|
459
486
|
containing dictionary literal args.
|
460
|
-
substrate: The initialised SubstrateInterface object to use.
|
461
487
|
|
462
488
|
Returns:
|
463
489
|
str: A formatted error message string.
|
@@ -479,7 +505,7 @@ def format_error_message(
|
|
479
505
|
elif all(x in d for x in ["code", "message", "data"]):
|
480
506
|
new_error_message = d
|
481
507
|
break
|
482
|
-
except
|
508
|
+
except ValueError:
|
483
509
|
pass
|
484
510
|
if new_error_message is None:
|
485
511
|
return_val = " ".join(error_message.args)
|
@@ -500,7 +526,10 @@ def format_error_message(
|
|
500
526
|
|
501
527
|
# subtensor custom error marker
|
502
528
|
if err_data.startswith("Custom error:"):
|
503
|
-
err_description =
|
529
|
+
err_description = (
|
530
|
+
f"{err_data} | Please consult "
|
531
|
+
f"https://docs.bittensor.com/subtensor-nodes/subtensor-error-messages"
|
532
|
+
)
|
504
533
|
else:
|
505
534
|
err_description = err_data
|
506
535
|
|
@@ -535,7 +564,8 @@ def decode_hex_identity_dict(info_dictionary) -> dict[str, Any]:
|
|
535
564
|
"""
|
536
565
|
Decodes hex-encoded strings in a dictionary.
|
537
566
|
|
538
|
-
This function traverses the given dictionary, identifies hex-encoded strings, and decodes them into readable
|
567
|
+
This function traverses the given dictionary, identifies hex-encoded strings, and decodes them into readable
|
568
|
+
strings. It handles nested dictionaries and lists within the dictionary.
|
539
569
|
|
540
570
|
Args:
|
541
571
|
info_dictionary (dict): The dictionary containing hex-encoded strings to decode.
|
@@ -557,7 +587,7 @@ def decode_hex_identity_dict(info_dictionary) -> dict[str, Any]:
|
|
557
587
|
def get_decoded(data: str) -> str:
|
558
588
|
"""Decodes a hex-encoded string."""
|
559
589
|
try:
|
560
|
-
return
|
590
|
+
return hex_to_bytes(data).decode()
|
561
591
|
except UnicodeDecodeError:
|
562
592
|
print(f"Could not decode: {key}: {item}")
|
563
593
|
|
@@ -1096,6 +1126,7 @@ def prompt_for_identity(
|
|
1096
1126
|
|
1097
1127
|
|
1098
1128
|
def prompt_for_subnet_identity(
|
1129
|
+
current_identity: dict,
|
1099
1130
|
subnet_name: Optional[str],
|
1100
1131
|
github_repo: Optional[str],
|
1101
1132
|
subnet_contact: Optional[str],
|
@@ -1180,7 +1211,7 @@ def prompt_for_subnet_identity(
|
|
1180
1211
|
prompt,
|
1181
1212
|
rejection=rejection_func,
|
1182
1213
|
rejection_text=rejection_msg,
|
1183
|
-
default=
|
1214
|
+
default=current_identity.get(key, ""),
|
1184
1215
|
show_default=True,
|
1185
1216
|
)
|
1186
1217
|
|
@@ -1262,11 +1293,14 @@ def is_linux():
|
|
1262
1293
|
"""Returns True if the operating system is Linux."""
|
1263
1294
|
return platform.system().lower() == "linux"
|
1264
1295
|
|
1296
|
+
|
1265
1297
|
def validate_rate_tolerance(value: Optional[float]) -> Optional[float]:
|
1266
1298
|
"""Validates rate tolerance input"""
|
1267
1299
|
if value is not None:
|
1268
1300
|
if value < 0:
|
1269
|
-
raise typer.BadParameter(
|
1301
|
+
raise typer.BadParameter(
|
1302
|
+
"Rate tolerance cannot be negative (less than 0%)."
|
1303
|
+
)
|
1270
1304
|
if value > 1:
|
1271
1305
|
raise typer.BadParameter("Rate tolerance cannot be greater than 1 (100%).")
|
1272
1306
|
if value > 0.5:
|
@@ -1275,3 +1309,79 @@ def validate_rate_tolerance(value: Optional[float]) -> Optional[float]:
|
|
1275
1309
|
"This may result in unfavorable transaction execution.[/yellow]"
|
1276
1310
|
)
|
1277
1311
|
return value
|
1312
|
+
|
1313
|
+
|
1314
|
+
def unlock_key(
|
1315
|
+
wallet: Wallet, unlock_type="cold", print_out: bool = True
|
1316
|
+
) -> "UnlockStatus":
|
1317
|
+
"""
|
1318
|
+
Attempts to decrypt a wallet's coldkey or hotkey
|
1319
|
+
Args:
|
1320
|
+
wallet: a Wallet object
|
1321
|
+
unlock_type: the key type, 'cold' or 'hot'
|
1322
|
+
print_out: whether to print out the error message to the err_console
|
1323
|
+
|
1324
|
+
Returns: UnlockStatus for success status of unlock, with error message if unsuccessful
|
1325
|
+
|
1326
|
+
"""
|
1327
|
+
if unlock_type == "cold":
|
1328
|
+
unlocker = "unlock_coldkey"
|
1329
|
+
elif unlock_type == "hot":
|
1330
|
+
unlocker = "unlock_hotkey"
|
1331
|
+
else:
|
1332
|
+
raise ValueError(
|
1333
|
+
f"Invalid unlock type provided: {unlock_type}. Must be 'cold' or 'hot'."
|
1334
|
+
)
|
1335
|
+
try:
|
1336
|
+
getattr(wallet, unlocker)()
|
1337
|
+
return UnlockStatus(True, "")
|
1338
|
+
except PasswordError:
|
1339
|
+
err_msg = f"The password used to decrypt your {unlock_type.capitalize()}key Keyfile is invalid."
|
1340
|
+
if print_out:
|
1341
|
+
err_console.print(f":cross_mark: [red]{err_msg}[/red]")
|
1342
|
+
return UnlockStatus(False, err_msg)
|
1343
|
+
except KeyFileError:
|
1344
|
+
err_msg = f"{unlock_type.capitalize()}key Keyfile is corrupt, non-writable, or non-readable, or non-existent."
|
1345
|
+
if print_out:
|
1346
|
+
err_console.print(f":cross_mark: [red]{err_msg}[/red]")
|
1347
|
+
return UnlockStatus(False, err_msg)
|
1348
|
+
|
1349
|
+
|
1350
|
+
def hex_to_bytes(hex_str: str) -> bytes:
|
1351
|
+
"""
|
1352
|
+
Converts a hex-encoded string into bytes. Handles 0x-prefixed and non-prefixed hex-encoded strings.
|
1353
|
+
"""
|
1354
|
+
if hex_str.startswith("0x"):
|
1355
|
+
bytes_result = bytes.fromhex(hex_str[2:])
|
1356
|
+
else:
|
1357
|
+
bytes_result = bytes.fromhex(hex_str)
|
1358
|
+
return bytes_result
|
1359
|
+
|
1360
|
+
|
1361
|
+
def blocks_to_duration(blocks: int) -> str:
|
1362
|
+
"""Convert blocks to human readable duration string using two largest units.
|
1363
|
+
|
1364
|
+
Args:
|
1365
|
+
blocks (int): Number of blocks (12s per block)
|
1366
|
+
|
1367
|
+
Returns:
|
1368
|
+
str: Duration string like '2d 5h', '3h 45m', '2m 10s', or '0s'
|
1369
|
+
"""
|
1370
|
+
if blocks <= 0:
|
1371
|
+
return "0s"
|
1372
|
+
|
1373
|
+
seconds = blocks * 12
|
1374
|
+
intervals = [
|
1375
|
+
("d", 86400), # 60 * 60 * 24
|
1376
|
+
("h", 3600), # 60 * 60
|
1377
|
+
("m", 60),
|
1378
|
+
("s", 1),
|
1379
|
+
]
|
1380
|
+
results = []
|
1381
|
+
for unit, seconds_per_unit in intervals:
|
1382
|
+
unit_count = seconds // seconds_per_unit
|
1383
|
+
seconds %= seconds_per_unit
|
1384
|
+
if unit_count > 0:
|
1385
|
+
results.append(f"{unit_count}{unit}")
|
1386
|
+
# Return only the first two non-zero units
|
1387
|
+
return " ".join(results[:2]) or "0s"
|
@@ -108,14 +108,14 @@ async def stake_add(
|
|
108
108
|
return
|
109
109
|
else:
|
110
110
|
err_out(
|
111
|
-
f"\n{failure_prelude} with error: {format_error_message(e
|
111
|
+
f"\n{failure_prelude} with error: {format_error_message(e)}"
|
112
112
|
)
|
113
113
|
return
|
114
114
|
else:
|
115
115
|
await response.process_events()
|
116
116
|
if not await response.is_success:
|
117
117
|
err_out(
|
118
|
-
f"\n{failure_prelude} with error: {format_error_message(await response.error_message
|
118
|
+
f"\n{failure_prelude} with error: {format_error_message(await response.error_message)}"
|
119
119
|
)
|
120
120
|
else:
|
121
121
|
block_hash = await subtensor.substrate.get_chain_head()
|
@@ -181,14 +181,14 @@ async def stake_add(
|
|
181
181
|
)
|
182
182
|
except SubstrateRequestException as e:
|
183
183
|
err_out(
|
184
|
-
f"\n{failure_prelude} with error: {format_error_message(e
|
184
|
+
f"\n{failure_prelude} with error: {format_error_message(e)}"
|
185
185
|
)
|
186
186
|
return
|
187
187
|
else:
|
188
188
|
await response.process_events()
|
189
189
|
if not await response.is_success:
|
190
190
|
err_out(
|
191
|
-
f"\n{failure_prelude} with error: {format_error_message(await response.error_message
|
191
|
+
f"\n{failure_prelude} with error: {format_error_message(await response.error_message)}"
|
192
192
|
)
|
193
193
|
else:
|
194
194
|
new_balance, new_stake = await asyncio.gather(
|
@@ -2,7 +2,6 @@ import asyncio
|
|
2
2
|
from typing import Optional
|
3
3
|
|
4
4
|
from bittensor_wallet import Wallet
|
5
|
-
from bittensor_wallet.errors import KeyFileError
|
6
5
|
from rich.prompt import Confirm, Prompt, IntPrompt
|
7
6
|
from rich.table import Table
|
8
7
|
from rich.text import Text
|
@@ -19,6 +18,7 @@ from bittensor_cli.src.bittensor.utils import (
|
|
19
18
|
u64_to_float,
|
20
19
|
is_valid_ss58_address,
|
21
20
|
format_error_message,
|
21
|
+
unlock_key,
|
22
22
|
)
|
23
23
|
|
24
24
|
|
@@ -99,10 +99,8 @@ async def set_children_extrinsic(
|
|
99
99
|
return False, "Operation Cancelled"
|
100
100
|
|
101
101
|
# Decrypt coldkey.
|
102
|
-
|
103
|
-
|
104
|
-
except KeyFileError:
|
105
|
-
return False, "There was an error unlocking your coldkey."
|
102
|
+
if not (unlock_status := unlock_key(wallet, print_out=False)).success:
|
103
|
+
return False, unlock_status.message
|
106
104
|
|
107
105
|
with console.status(
|
108
106
|
f":satellite: {operation} on [white]{subtensor.network}[/white] ..."
|
@@ -185,10 +183,8 @@ async def set_childkey_take_extrinsic(
|
|
185
183
|
return False, "Operation Cancelled"
|
186
184
|
|
187
185
|
# Decrypt coldkey.
|
188
|
-
|
189
|
-
|
190
|
-
except KeyFileError:
|
191
|
-
return False, "There was an error unlocking your coldkey."
|
186
|
+
if not (unlock_status := unlock_key(wallet, print_out=False)).success:
|
187
|
+
return False, unlock_status.message
|
192
188
|
|
193
189
|
with console.status(
|
194
190
|
f":satellite: Setting childkey take on [white]{subtensor.network}[/white] ..."
|
@@ -239,7 +235,7 @@ async def set_childkey_take_extrinsic(
|
|
239
235
|
except SubstrateRequestException as e:
|
240
236
|
return (
|
241
237
|
False,
|
242
|
-
f"Exception occurred while setting childkey take: {format_error_message(e
|
238
|
+
f"Exception occurred while setting childkey take: {format_error_message(e)}",
|
243
239
|
)
|
244
240
|
|
245
241
|
|
@@ -263,9 +259,7 @@ async def get_childkey_take(subtensor, hotkey: str, netuid: int) -> Optional[int
|
|
263
259
|
return int(childkey_take_.value)
|
264
260
|
|
265
261
|
except SubstrateRequestException as e:
|
266
|
-
err_console.print(
|
267
|
-
f"Error querying ChildKeys: {format_error_message(e, subtensor.substrate)}"
|
268
|
-
)
|
262
|
+
err_console.print(f"Error querying ChildKeys: {format_error_message(e)}")
|
269
263
|
return None
|
270
264
|
|
271
265
|
|
@@ -502,7 +496,7 @@ async def set_children(
|
|
502
496
|
subtensor: "SubtensorInterface",
|
503
497
|
children: list[str],
|
504
498
|
proportions: list[float],
|
505
|
-
netuid: Optional[int],
|
499
|
+
netuid: Optional[int] = None,
|
506
500
|
wait_for_inclusion: bool = True,
|
507
501
|
wait_for_finalization: bool = True,
|
508
502
|
prompt: bool = True,
|
@@ -589,8 +583,8 @@ async def revoke_children(
|
|
589
583
|
netuid: Optional[int] = None,
|
590
584
|
wait_for_inclusion: bool = True,
|
591
585
|
wait_for_finalization: bool = True,
|
586
|
+
prompt: bool = True,
|
592
587
|
):
|
593
|
-
# TODO seek clarification on use of asking hotkey vs how we do it now
|
594
588
|
"""
|
595
589
|
Revokes the children hotkeys associated with a given network identifier (netuid).
|
596
590
|
"""
|
@@ -601,7 +595,7 @@ async def revoke_children(
|
|
601
595
|
netuid=netuid,
|
602
596
|
hotkey=wallet.hotkey.ss58_address,
|
603
597
|
children_with_proportions=[],
|
604
|
-
prompt=
|
598
|
+
prompt=prompt,
|
605
599
|
wait_for_inclusion=wait_for_inclusion,
|
606
600
|
wait_for_finalization=wait_for_finalization,
|
607
601
|
)
|
@@ -630,7 +624,7 @@ async def revoke_children(
|
|
630
624
|
netuid=netuid,
|
631
625
|
hotkey=wallet.hotkey.ss58_address,
|
632
626
|
children_with_proportions=[],
|
633
|
-
prompt=
|
627
|
+
prompt=prompt,
|
634
628
|
wait_for_inclusion=True,
|
635
629
|
wait_for_finalization=False,
|
636
630
|
)
|
@@ -790,7 +784,7 @@ async def childkey_take(
|
|
790
784
|
netuid=netuid,
|
791
785
|
hotkey=wallet.hotkey.ss58_address,
|
792
786
|
take=take,
|
793
|
-
prompt=
|
787
|
+
prompt=prompt,
|
794
788
|
wait_for_inclusion=True,
|
795
789
|
wait_for_finalization=False,
|
796
790
|
)
|
@@ -45,7 +45,7 @@ async def stake_list(
|
|
45
45
|
coldkey_ss58=coldkey_address, block_hash=block_hash
|
46
46
|
),
|
47
47
|
subtensor.get_delegate_identities(block_hash=block_hash),
|
48
|
-
subtensor.all_subnets(),
|
48
|
+
subtensor.all_subnets(block_hash=block_hash),
|
49
49
|
)
|
50
50
|
# sub_stakes = substakes[coldkey_address]
|
51
51
|
dynamic_info = {info.netuid: info for info in _dynamic_info}
|
@@ -199,7 +199,7 @@ async def stake_list(
|
|
199
199
|
issuance = pool.alpha_out if pool.is_dynamic else tao_locked
|
200
200
|
|
201
201
|
# Per block emission cell
|
202
|
-
per_block_emission = substake_.emission.tao / pool.tempo
|
202
|
+
per_block_emission = substake_.emission.tao / (pool.tempo or 1)
|
203
203
|
# Alpha ownership and TAO ownership cells
|
204
204
|
if alpha_value.tao > 0.00009:
|
205
205
|
if issuance.tao != 0:
|
@@ -319,7 +319,7 @@ async def stake_list(
|
|
319
319
|
alpha_value = Balance.from_rao(int(substake.stake.rao)).set_unit(netuid)
|
320
320
|
tao_value = pool.alpha_to_tao(alpha_value)
|
321
321
|
total_tao_value += tao_value
|
322
|
-
swapped_tao_value, slippage = pool.alpha_to_tao_with_slippage(
|
322
|
+
swapped_tao_value, slippage, slippage_pct = pool.alpha_to_tao_with_slippage(
|
323
323
|
substake.stake
|
324
324
|
)
|
325
325
|
total_swapped_tao_value += swapped_tao_value
|
@@ -341,7 +341,7 @@ async def stake_list(
|
|
341
341
|
"price": pool.price.tao,
|
342
342
|
"tao_value": tao_value.tao,
|
343
343
|
"swapped_value": swapped_tao_value.tao,
|
344
|
-
"emission": substake.emission.tao / pool.tempo,
|
344
|
+
"emission": substake.emission.tao / (pool.tempo or 1),
|
345
345
|
"tao_ownership": tao_ownership.tao,
|
346
346
|
}
|
347
347
|
|
@@ -376,15 +376,6 @@ async def stake_list(
|
|
376
376
|
millify=True if not verbose else False,
|
377
377
|
)
|
378
378
|
|
379
|
-
if pool.is_dynamic:
|
380
|
-
slippage_pct = (
|
381
|
-
100 * float(slippage) / float(slippage + swapped_tao_value)
|
382
|
-
if slippage + swapped_tao_value != 0
|
383
|
-
else 0
|
384
|
-
)
|
385
|
-
else:
|
386
|
-
slippage_pct = 0
|
387
|
-
|
388
379
|
if netuid != 0:
|
389
380
|
swap_cell = (
|
390
381
|
format_cell(
|
@@ -400,7 +391,7 @@ async def stake_list(
|
|
400
391
|
else:
|
401
392
|
swap_cell = f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]N/A[/{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}] ({slippage_pct}%)"
|
402
393
|
|
403
|
-
emission_value = substake.emission.tao / pool.tempo
|
394
|
+
emission_value = substake.emission.tao / (pool.tempo or 1)
|
404
395
|
emission_cell = format_cell(
|
405
396
|
emission_value,
|
406
397
|
prev.get("emission"),
|
@@ -443,11 +434,12 @@ async def stake_list(
|
|
443
434
|
return table, current_data
|
444
435
|
|
445
436
|
# Main execution
|
437
|
+
block_hash = await subtensor.substrate.get_chain_head()
|
446
438
|
(
|
447
439
|
sub_stakes,
|
448
440
|
registered_delegate_info,
|
449
441
|
dynamic_info,
|
450
|
-
) = await get_stake_data()
|
442
|
+
) = await get_stake_data(block_hash)
|
451
443
|
balance = await subtensor.get_balance(coldkey_address)
|
452
444
|
|
453
445
|
# Iterate over substakes and aggregate them by hotkey.
|
@@ -536,7 +528,7 @@ async def stake_list(
|
|
536
528
|
table, current_data = create_live_table(
|
537
529
|
selected_stakes,
|
538
530
|
registered_delegate_info,
|
539
|
-
|
531
|
+
dynamic_info_,
|
540
532
|
hotkey_name,
|
541
533
|
previous_data,
|
542
534
|
)
|
@@ -812,7 +812,7 @@ async def transfer_stake(
|
|
812
812
|
if not await response.is_success:
|
813
813
|
err_console.print(
|
814
814
|
f":cross_mark: [red]Failed[/red] with error: "
|
815
|
-
f"{format_error_message(await response.error_message
|
815
|
+
f"{format_error_message(await response.error_message)}"
|
816
816
|
)
|
817
817
|
return False
|
818
818
|
|
@@ -971,7 +971,7 @@ async def swap_stake(
|
|
971
971
|
if not await response.is_success:
|
972
972
|
err_console.print(
|
973
973
|
f":cross_mark: [red]Failed[/red] with error: "
|
974
|
-
f"{format_error_message(await response.error_message
|
974
|
+
f"{format_error_message(await response.error_message)}"
|
975
975
|
)
|
976
976
|
return False
|
977
977
|
|
@@ -561,7 +561,7 @@ async def _unstake_extrinsic(
|
|
561
561
|
if not await response.is_success:
|
562
562
|
err_out(
|
563
563
|
f"{failure_prelude} with error: "
|
564
|
-
f"{format_error_message(await response.error_message
|
564
|
+
f"{format_error_message(await response.error_message)}"
|
565
565
|
)
|
566
566
|
return
|
567
567
|
|
@@ -667,14 +667,14 @@ async def _safe_unstake_extrinsic(
|
|
667
667
|
return
|
668
668
|
else:
|
669
669
|
err_out(
|
670
|
-
f"\n{failure_prelude} with error: {format_error_message(e
|
670
|
+
f"\n{failure_prelude} with error: {format_error_message(e)}"
|
671
671
|
)
|
672
672
|
return
|
673
673
|
|
674
674
|
await response.process_events()
|
675
675
|
if not await response.is_success:
|
676
676
|
err_out(
|
677
|
-
f"\n{failure_prelude} with error: {format_error_message(await response.error_message
|
677
|
+
f"\n{failure_prelude} with error: {format_error_message(await response.error_message)}"
|
678
678
|
)
|
679
679
|
return
|
680
680
|
|