meshtensor-cli 9.18.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.
- meshtensor_cli/__init__.py +22 -0
- meshtensor_cli/cli.py +10742 -0
- meshtensor_cli/doc_generation_helper.py +4 -0
- meshtensor_cli/src/__init__.py +1085 -0
- meshtensor_cli/src/commands/__init__.py +0 -0
- meshtensor_cli/src/commands/axon/__init__.py +0 -0
- meshtensor_cli/src/commands/axon/axon.py +132 -0
- meshtensor_cli/src/commands/crowd/__init__.py +0 -0
- meshtensor_cli/src/commands/crowd/contribute.py +621 -0
- meshtensor_cli/src/commands/crowd/contributors.py +200 -0
- meshtensor_cli/src/commands/crowd/create.py +783 -0
- meshtensor_cli/src/commands/crowd/dissolve.py +219 -0
- meshtensor_cli/src/commands/crowd/refund.py +233 -0
- meshtensor_cli/src/commands/crowd/update.py +418 -0
- meshtensor_cli/src/commands/crowd/utils.py +124 -0
- meshtensor_cli/src/commands/crowd/view.py +991 -0
- meshtensor_cli/src/commands/governance/__init__.py +0 -0
- meshtensor_cli/src/commands/governance/governance.py +794 -0
- meshtensor_cli/src/commands/liquidity/__init__.py +0 -0
- meshtensor_cli/src/commands/liquidity/liquidity.py +699 -0
- meshtensor_cli/src/commands/liquidity/utils.py +202 -0
- meshtensor_cli/src/commands/proxy.py +700 -0
- meshtensor_cli/src/commands/stake/__init__.py +0 -0
- meshtensor_cli/src/commands/stake/add.py +799 -0
- meshtensor_cli/src/commands/stake/auto_staking.py +306 -0
- meshtensor_cli/src/commands/stake/children_hotkeys.py +865 -0
- meshtensor_cli/src/commands/stake/claim.py +770 -0
- meshtensor_cli/src/commands/stake/list.py +738 -0
- meshtensor_cli/src/commands/stake/move.py +1211 -0
- meshtensor_cli/src/commands/stake/remove.py +1466 -0
- meshtensor_cli/src/commands/stake/wizard.py +323 -0
- meshtensor_cli/src/commands/subnets/__init__.py +0 -0
- meshtensor_cli/src/commands/subnets/mechanisms.py +515 -0
- meshtensor_cli/src/commands/subnets/price.py +733 -0
- meshtensor_cli/src/commands/subnets/subnets.py +2908 -0
- meshtensor_cli/src/commands/sudo.py +1294 -0
- meshtensor_cli/src/commands/tc/__init__.py +0 -0
- meshtensor_cli/src/commands/tc/tc.py +190 -0
- meshtensor_cli/src/commands/treasury/__init__.py +0 -0
- meshtensor_cli/src/commands/treasury/treasury.py +194 -0
- meshtensor_cli/src/commands/view.py +354 -0
- meshtensor_cli/src/commands/wallets.py +2311 -0
- meshtensor_cli/src/commands/weights.py +467 -0
- meshtensor_cli/src/meshtensor/__init__.py +0 -0
- meshtensor_cli/src/meshtensor/balances.py +313 -0
- meshtensor_cli/src/meshtensor/chain_data.py +1263 -0
- meshtensor_cli/src/meshtensor/extrinsics/__init__.py +0 -0
- meshtensor_cli/src/meshtensor/extrinsics/mev_shield.py +174 -0
- meshtensor_cli/src/meshtensor/extrinsics/registration.py +1861 -0
- meshtensor_cli/src/meshtensor/extrinsics/root.py +550 -0
- meshtensor_cli/src/meshtensor/extrinsics/serving.py +255 -0
- meshtensor_cli/src/meshtensor/extrinsics/transfer.py +239 -0
- meshtensor_cli/src/meshtensor/meshtensor_interface.py +2598 -0
- meshtensor_cli/src/meshtensor/minigraph.py +254 -0
- meshtensor_cli/src/meshtensor/networking.py +12 -0
- meshtensor_cli/src/meshtensor/templates/main-filters.j2 +24 -0
- meshtensor_cli/src/meshtensor/templates/main-header.j2 +36 -0
- meshtensor_cli/src/meshtensor/templates/neuron-details.j2 +111 -0
- meshtensor_cli/src/meshtensor/templates/price-multi.j2 +113 -0
- meshtensor_cli/src/meshtensor/templates/price-single.j2 +99 -0
- meshtensor_cli/src/meshtensor/templates/subnet-details-header.j2 +49 -0
- meshtensor_cli/src/meshtensor/templates/subnet-details.j2 +32 -0
- meshtensor_cli/src/meshtensor/templates/subnet-metrics.j2 +57 -0
- meshtensor_cli/src/meshtensor/templates/subnets-table.j2 +28 -0
- meshtensor_cli/src/meshtensor/templates/table.j2 +267 -0
- meshtensor_cli/src/meshtensor/templates/view.css +1058 -0
- meshtensor_cli/src/meshtensor/templates/view.j2 +43 -0
- meshtensor_cli/src/meshtensor/templates/view.js +1053 -0
- meshtensor_cli/src/meshtensor/utils.py +2007 -0
- meshtensor_cli/version.py +23 -0
- meshtensor_cli-9.18.1.dist-info/METADATA +261 -0
- meshtensor_cli-9.18.1.dist-info/RECORD +74 -0
- meshtensor_cli-9.18.1.dist-info/WHEEL +4 -0
- meshtensor_cli-9.18.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
5
|
+
|
|
6
|
+
from meshtensor_wallet import Wallet
|
|
7
|
+
from rich.prompt import Prompt
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from rich import box
|
|
10
|
+
from rich.progress import Progress, BarColumn, TextColumn
|
|
11
|
+
from rich.console import Group
|
|
12
|
+
from rich.live import Live
|
|
13
|
+
|
|
14
|
+
from meshtensor_cli.src import COLOR_PALETTE
|
|
15
|
+
from meshtensor_cli.src.meshtensor.balances import Balance
|
|
16
|
+
from meshtensor_cli.src.meshtensor.chain_data import StakeInfo
|
|
17
|
+
from meshtensor_cli.src.meshtensor.utils import (
|
|
18
|
+
console,
|
|
19
|
+
print_error,
|
|
20
|
+
millify_tao,
|
|
21
|
+
get_subnet_name,
|
|
22
|
+
json_console,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from meshtensor_cli.src.meshtensor.meshtensor_interface import MeshtensorInterface
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def stake_list(
|
|
30
|
+
wallet: Wallet,
|
|
31
|
+
coldkey_ss58: str,
|
|
32
|
+
meshtensor: "MeshtensorInterface",
|
|
33
|
+
live: bool = False,
|
|
34
|
+
verbose: bool = False,
|
|
35
|
+
prompt: bool = False,
|
|
36
|
+
json_output: bool = False,
|
|
37
|
+
):
|
|
38
|
+
coldkey_address = coldkey_ss58 if coldkey_ss58 else wallet.coldkeypub.ss58_address
|
|
39
|
+
|
|
40
|
+
async def get_stake_data(block_hash_: str = None):
|
|
41
|
+
(
|
|
42
|
+
sub_stakes_,
|
|
43
|
+
registered_delegate_info_,
|
|
44
|
+
_dynamic_info,
|
|
45
|
+
) = await asyncio.gather(
|
|
46
|
+
meshtensor.get_stake_for_coldkey(
|
|
47
|
+
coldkey_ss58=coldkey_address, block_hash=block_hash_
|
|
48
|
+
),
|
|
49
|
+
meshtensor.get_delegate_identities(block_hash=block_hash_),
|
|
50
|
+
meshtensor.all_subnets(block_hash=block_hash_),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
claimable_amounts_ = {}
|
|
54
|
+
if sub_stakes_:
|
|
55
|
+
claimable_amounts_ = await meshtensor.get_claimable_stakes_for_coldkey(
|
|
56
|
+
coldkey_ss58=coldkey_address,
|
|
57
|
+
stakes_info=sub_stakes_,
|
|
58
|
+
block_hash=block_hash_,
|
|
59
|
+
)
|
|
60
|
+
# sub_stakes = substakes[coldkey_address]
|
|
61
|
+
dynamic_info__ = {info.netuid: info for info in _dynamic_info}
|
|
62
|
+
return (
|
|
63
|
+
sub_stakes_,
|
|
64
|
+
registered_delegate_info_,
|
|
65
|
+
dynamic_info__,
|
|
66
|
+
claimable_amounts_,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def define_table(
|
|
70
|
+
hotkey_name_: str,
|
|
71
|
+
rows: list[list[str]],
|
|
72
|
+
total_tao_value_: Balance,
|
|
73
|
+
total_swapped_tao_value_: Balance,
|
|
74
|
+
):
|
|
75
|
+
title = f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Hotkey: {hotkey_name_}\nNetwork: {meshtensor.network}\n\n"
|
|
76
|
+
# TODO: Add hint back in after adding columns descriptions
|
|
77
|
+
# if not live:
|
|
78
|
+
# title += f"[{COLOR_PALETTE['GENERAL']['HINT']}]See below for an explanation of the columns\n"
|
|
79
|
+
defined_table = Table(
|
|
80
|
+
title=title,
|
|
81
|
+
show_footer=True,
|
|
82
|
+
show_edge=False,
|
|
83
|
+
header_style="bold white",
|
|
84
|
+
border_style="bright_black",
|
|
85
|
+
style="bold",
|
|
86
|
+
title_justify="center",
|
|
87
|
+
show_lines=False,
|
|
88
|
+
pad_edge=True,
|
|
89
|
+
)
|
|
90
|
+
defined_table.add_column(
|
|
91
|
+
"[white]Netuid",
|
|
92
|
+
footer=f"{len(rows)}",
|
|
93
|
+
footer_style="overline white",
|
|
94
|
+
style="grey89",
|
|
95
|
+
)
|
|
96
|
+
defined_table.add_column(
|
|
97
|
+
"[white]Name",
|
|
98
|
+
style="cyan",
|
|
99
|
+
justify="left",
|
|
100
|
+
no_wrap=True,
|
|
101
|
+
)
|
|
102
|
+
defined_table.add_column(
|
|
103
|
+
f"[white]Value \n({Balance.get_unit(1)} x {Balance.unit}/{Balance.get_unit(1)})",
|
|
104
|
+
footer_style="overline white",
|
|
105
|
+
style=COLOR_PALETTE["STAKE"]["MESH"],
|
|
106
|
+
justify="right",
|
|
107
|
+
footer=f"τ {millify_tao(total_tao_value_.tao)}"
|
|
108
|
+
if not verbose
|
|
109
|
+
else f"{total_tao_value_}",
|
|
110
|
+
)
|
|
111
|
+
defined_table.add_column(
|
|
112
|
+
f"[white]Stake ({Balance.get_unit(1)})",
|
|
113
|
+
footer_style="overline white",
|
|
114
|
+
style=COLOR_PALETTE["STAKE"]["STAKE_ALPHA"],
|
|
115
|
+
justify="center",
|
|
116
|
+
)
|
|
117
|
+
defined_table.add_column(
|
|
118
|
+
f"[white]Price \n({Balance.unit}_in/{Balance.get_unit(1)}_in)",
|
|
119
|
+
footer_style="white",
|
|
120
|
+
style=COLOR_PALETTE["POOLS"]["RATE"],
|
|
121
|
+
justify="center",
|
|
122
|
+
)
|
|
123
|
+
# defined_table.add_column(
|
|
124
|
+
# f"[white]Swap ({Balance.get_unit(1)} -> {Balance.unit})",
|
|
125
|
+
# footer_style="overline white",
|
|
126
|
+
# style=COLOR_PALETTE["STAKE"]["STAKE_SWAP"],
|
|
127
|
+
# justify="right",
|
|
128
|
+
# footer=f"τ {millify_tao(total_swapped_tao_value_.tao)}"
|
|
129
|
+
# if not verbose
|
|
130
|
+
# else f"{total_swapped_tao_value_}",
|
|
131
|
+
# )
|
|
132
|
+
defined_table.add_column(
|
|
133
|
+
"[white]Registered",
|
|
134
|
+
style=COLOR_PALETTE["STAKE"]["STAKE_ALPHA"],
|
|
135
|
+
justify="right",
|
|
136
|
+
)
|
|
137
|
+
defined_table.add_column(
|
|
138
|
+
f"[white]Emission \n({Balance.get_unit(1)}/block)",
|
|
139
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
|
140
|
+
justify="right",
|
|
141
|
+
)
|
|
142
|
+
defined_table.add_column(
|
|
143
|
+
f"[white]Emission \n({Balance.get_unit(0)}/block)",
|
|
144
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
|
145
|
+
justify="right",
|
|
146
|
+
)
|
|
147
|
+
defined_table.add_column(
|
|
148
|
+
f"[white]Claimable \n({Balance.get_unit(1)})",
|
|
149
|
+
style=COLOR_PALETTE["STAKE"]["STAKE_ALPHA"],
|
|
150
|
+
justify="right",
|
|
151
|
+
)
|
|
152
|
+
return defined_table
|
|
153
|
+
|
|
154
|
+
def create_table(
|
|
155
|
+
hotkey_: str,
|
|
156
|
+
substakes_: list[StakeInfo],
|
|
157
|
+
claimable_amounts_: dict[str, dict[int, Balance]],
|
|
158
|
+
):
|
|
159
|
+
name_ = (
|
|
160
|
+
f"{registered_delegate_info[hotkey_].display} ({hotkey_})"
|
|
161
|
+
if hotkey_ in registered_delegate_info
|
|
162
|
+
else hotkey_
|
|
163
|
+
)
|
|
164
|
+
rows = []
|
|
165
|
+
total_tao_value_ = Balance(0)
|
|
166
|
+
total_swapped_tao_value_ = Balance(0)
|
|
167
|
+
root_stakes = [s for s in substakes_ if s.netuid == 0]
|
|
168
|
+
other_stakes = sorted(
|
|
169
|
+
[s for s in substakes_ if s.netuid != 0],
|
|
170
|
+
key=lambda x: dynamic_info[x.netuid]
|
|
171
|
+
.alpha_to_tao(Balance.from_meshlet(int(x.stake.meshlet)).set_unit(x.netuid))
|
|
172
|
+
.tao,
|
|
173
|
+
reverse=True,
|
|
174
|
+
)
|
|
175
|
+
sorted_substakes = root_stakes + other_stakes
|
|
176
|
+
substakes_values = []
|
|
177
|
+
for substake_ in sorted_substakes:
|
|
178
|
+
netuid = substake_.netuid
|
|
179
|
+
pool = dynamic_info[netuid]
|
|
180
|
+
symbol = f"{Balance.get_unit(netuid)}\u200e"
|
|
181
|
+
|
|
182
|
+
# Alpha value cell
|
|
183
|
+
alpha_value = Balance.from_meshlet(int(substake_.stake.meshlet)).set_unit(netuid)
|
|
184
|
+
|
|
185
|
+
# MESH value cell
|
|
186
|
+
tao_value_ = pool.alpha_to_tao(alpha_value)
|
|
187
|
+
total_tao_value_ += tao_value_
|
|
188
|
+
|
|
189
|
+
# MESH value cell
|
|
190
|
+
tao_value_ = pool.alpha_to_tao(substake_.stake)
|
|
191
|
+
total_swapped_tao_value_ += tao_value_
|
|
192
|
+
|
|
193
|
+
if netuid == 0:
|
|
194
|
+
swap_value = f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]N/A[/{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]"
|
|
195
|
+
else:
|
|
196
|
+
swap_value = (
|
|
197
|
+
f"τ {millify_tao(tao_value_.tao)}"
|
|
198
|
+
if not verbose
|
|
199
|
+
else f"{tao_value_}"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Per block emission cell
|
|
203
|
+
per_block_emission = substake_.emission.tao / (pool.tempo or 1)
|
|
204
|
+
per_block_tao_emission = substake_.tao_emission.tao / (pool.tempo or 1)
|
|
205
|
+
# Alpha ownership and MESH ownership cells
|
|
206
|
+
if alpha_value.tao > 0.00009:
|
|
207
|
+
stake_value = (
|
|
208
|
+
millify_tao(substake_.stake.tao)
|
|
209
|
+
if not verbose
|
|
210
|
+
else f"{substake_.stake.tao:,.4f}"
|
|
211
|
+
)
|
|
212
|
+
subnet_name = get_subnet_name(dynamic_info[netuid])
|
|
213
|
+
subnet_name_cell = f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}] {subnet_name}"
|
|
214
|
+
|
|
215
|
+
# Claimable amount cell
|
|
216
|
+
claimable_amount = Balance.from_meshlet(0)
|
|
217
|
+
if (
|
|
218
|
+
hotkey_ in claimable_amounts_
|
|
219
|
+
and netuid in claimable_amounts_[hotkey_]
|
|
220
|
+
):
|
|
221
|
+
claimable_amount = claimable_amounts_[hotkey_][netuid]
|
|
222
|
+
|
|
223
|
+
if claimable_amount.tao > 0.00001:
|
|
224
|
+
claimable_cell = (
|
|
225
|
+
f"{claimable_amount.tao:.5f} {symbol}"
|
|
226
|
+
if not verbose
|
|
227
|
+
else f"{claimable_amount}"
|
|
228
|
+
)
|
|
229
|
+
else:
|
|
230
|
+
claimable_cell = "-"
|
|
231
|
+
|
|
232
|
+
rows.append(
|
|
233
|
+
[
|
|
234
|
+
str(netuid), # Number
|
|
235
|
+
subnet_name_cell, # Symbol + name
|
|
236
|
+
f"τ {millify_tao(tao_value_.tao)}"
|
|
237
|
+
if not verbose
|
|
238
|
+
else f"{tao_value_}", # Value (α x τ/α)
|
|
239
|
+
f"{stake_value} {symbol}"
|
|
240
|
+
if netuid != 0
|
|
241
|
+
else f"{symbol} {stake_value}", # Stake (a)
|
|
242
|
+
f"{pool.price.tao:.4f} τ/{symbol}", # Rate (t/a)
|
|
243
|
+
# f"τ {millify_tao(tao_ownership.tao)}" if not verbose else f"{tao_ownership}", # MESH equiv
|
|
244
|
+
# swap_value, # Swap(α) -> τ
|
|
245
|
+
"YES"
|
|
246
|
+
if substake_.is_registered
|
|
247
|
+
else f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]NO", # Registered
|
|
248
|
+
str(Balance.from_tao(per_block_emission).set_unit(netuid)),
|
|
249
|
+
# Removing this flag for now, TODO: Confirm correct values are here w.r.t CHKs
|
|
250
|
+
# if substake_.is_registered
|
|
251
|
+
# else f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]N/A", # Emission(α/block)
|
|
252
|
+
str(Balance.from_tao(per_block_tao_emission)),
|
|
253
|
+
claimable_cell, # Claimable amount
|
|
254
|
+
]
|
|
255
|
+
)
|
|
256
|
+
substakes_values.append(
|
|
257
|
+
{
|
|
258
|
+
"netuid": netuid,
|
|
259
|
+
"subnet_name": subnet_name,
|
|
260
|
+
"value": tao_value_.tao,
|
|
261
|
+
"stake_value": substake_.stake.tao,
|
|
262
|
+
"rate": pool.price.tao,
|
|
263
|
+
# "swap_value": swap_value,
|
|
264
|
+
"registered": True if substake_.is_registered else False,
|
|
265
|
+
"emission": {
|
|
266
|
+
"alpha": per_block_emission,
|
|
267
|
+
"mesh": per_block_tao_emission,
|
|
268
|
+
},
|
|
269
|
+
"claimable": claimable_amount.tao,
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
created_table = define_table(
|
|
273
|
+
name_, rows, total_tao_value_, total_swapped_tao_value_
|
|
274
|
+
)
|
|
275
|
+
for row in rows:
|
|
276
|
+
created_table.add_row(*row)
|
|
277
|
+
console.print(created_table)
|
|
278
|
+
return total_tao_value_, total_swapped_tao_value_, substakes_values
|
|
279
|
+
|
|
280
|
+
def create_live_table(
|
|
281
|
+
substakes: list,
|
|
282
|
+
dynamic_info_for_lt: dict,
|
|
283
|
+
hotkey_name_: str,
|
|
284
|
+
claimable_amounts_: dict,
|
|
285
|
+
previous_data_: Optional[dict] = None,
|
|
286
|
+
) -> tuple[Table, dict]:
|
|
287
|
+
rows = []
|
|
288
|
+
current_data_ = {}
|
|
289
|
+
|
|
290
|
+
total_tao_value_ = Balance(0)
|
|
291
|
+
total_swapped_tao_value_ = Balance(0)
|
|
292
|
+
|
|
293
|
+
def format_cell(
|
|
294
|
+
value,
|
|
295
|
+
previous_value,
|
|
296
|
+
unit="",
|
|
297
|
+
unit_first_=False,
|
|
298
|
+
precision=4,
|
|
299
|
+
millify=False,
|
|
300
|
+
):
|
|
301
|
+
if previous_value is not None:
|
|
302
|
+
change = value - previous_value
|
|
303
|
+
if abs(change) > 10 ** (-precision):
|
|
304
|
+
formatted_change = (
|
|
305
|
+
f"{change:.{precision}f}"
|
|
306
|
+
if not millify
|
|
307
|
+
else f"{millify_tao(change)}"
|
|
308
|
+
)
|
|
309
|
+
change_text = (
|
|
310
|
+
f" [pale_green3](+{formatted_change})[/pale_green3]"
|
|
311
|
+
if change > 0
|
|
312
|
+
else f" [hot_pink3]({formatted_change})[/hot_pink3]"
|
|
313
|
+
)
|
|
314
|
+
else:
|
|
315
|
+
change_text = ""
|
|
316
|
+
else:
|
|
317
|
+
change_text = ""
|
|
318
|
+
formatted_value = (
|
|
319
|
+
f"{value:,.{precision}f}" if not millify else f"{millify_tao(value)}"
|
|
320
|
+
)
|
|
321
|
+
return (
|
|
322
|
+
f"{formatted_value} {unit}{change_text}"
|
|
323
|
+
if not unit_first_
|
|
324
|
+
else f"{unit} {formatted_value}{change_text}"
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Sort subnets by value
|
|
328
|
+
root_stakes = [s for s in substakes if s.netuid == 0]
|
|
329
|
+
other_stakes = sorted(
|
|
330
|
+
[s for s in substakes if s.netuid != 0],
|
|
331
|
+
key=lambda x: dynamic_info_for_lt[x.netuid]
|
|
332
|
+
.alpha_to_tao(Balance.from_meshlet(int(x.stake.meshlet)).set_unit(x.netuid))
|
|
333
|
+
.tao,
|
|
334
|
+
reverse=True,
|
|
335
|
+
)
|
|
336
|
+
sorted_substakes = root_stakes + other_stakes
|
|
337
|
+
|
|
338
|
+
# Process each stake
|
|
339
|
+
for substake_ in sorted_substakes:
|
|
340
|
+
netuid = substake_.netuid
|
|
341
|
+
pool = dynamic_info_for_lt.get(netuid)
|
|
342
|
+
if substake_.stake.meshlet == 0 or not pool:
|
|
343
|
+
continue
|
|
344
|
+
|
|
345
|
+
# Calculate base values
|
|
346
|
+
symbol = f"{Balance.get_unit(netuid)}\u200e"
|
|
347
|
+
alpha_value = Balance.from_meshlet(int(substake_.stake.meshlet)).set_unit(netuid)
|
|
348
|
+
tao_value_ = pool.alpha_to_tao(alpha_value)
|
|
349
|
+
total_tao_value_ += tao_value_
|
|
350
|
+
swapped_tao_value_ = pool.alpha_to_tao(substake_.stake)
|
|
351
|
+
total_swapped_tao_value_ += swapped_tao_value_
|
|
352
|
+
|
|
353
|
+
# Store current values for future delta tracking
|
|
354
|
+
current_data_[netuid] = {
|
|
355
|
+
"stake": alpha_value.tao,
|
|
356
|
+
"price": pool.price.tao,
|
|
357
|
+
"tao_value": tao_value_.tao,
|
|
358
|
+
"swapped_value": swapped_tao_value_.tao,
|
|
359
|
+
"emission": substake_.emission.tao / (pool.tempo or 1),
|
|
360
|
+
"tao_emission": substake_.tao_emission.tao / (pool.tempo or 1),
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
# Get previous values for delta tracking
|
|
364
|
+
prev = previous_data_.get(netuid, {}) if previous_data_ else {}
|
|
365
|
+
unit_first = True if netuid == 0 else False
|
|
366
|
+
|
|
367
|
+
stake_cell = format_cell(
|
|
368
|
+
alpha_value.tao,
|
|
369
|
+
prev.get("stake"),
|
|
370
|
+
unit=symbol,
|
|
371
|
+
unit_first_=unit_first,
|
|
372
|
+
precision=4,
|
|
373
|
+
millify=True if not verbose else False,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
rate_cell = format_cell(
|
|
377
|
+
pool.price.tao,
|
|
378
|
+
prev.get("price"),
|
|
379
|
+
unit=f"τ/{symbol}",
|
|
380
|
+
unit_first_=False,
|
|
381
|
+
precision=5,
|
|
382
|
+
millify=True if not verbose else False,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
exchange_cell = format_cell(
|
|
386
|
+
tao_value_.tao,
|
|
387
|
+
prev.get("tao_value"),
|
|
388
|
+
unit="τ",
|
|
389
|
+
unit_first_=True,
|
|
390
|
+
precision=4,
|
|
391
|
+
millify=True if not verbose else False,
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
if netuid != 0:
|
|
395
|
+
swap_cell = format_cell(
|
|
396
|
+
swapped_tao_value_.tao,
|
|
397
|
+
prev.get("swapped_value"),
|
|
398
|
+
unit="τ",
|
|
399
|
+
unit_first_=True,
|
|
400
|
+
precision=4,
|
|
401
|
+
millify=True if not verbose else False,
|
|
402
|
+
)
|
|
403
|
+
else:
|
|
404
|
+
swap_cell = f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]N/A[/{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]"
|
|
405
|
+
|
|
406
|
+
emission_value = substake_.emission.tao / (pool.tempo or 1)
|
|
407
|
+
emission_cell = format_cell(
|
|
408
|
+
emission_value,
|
|
409
|
+
prev.get("emission"),
|
|
410
|
+
unit=symbol,
|
|
411
|
+
unit_first_=unit_first,
|
|
412
|
+
precision=4,
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
tao_emission_value = substake_.tao_emission.tao / (pool.tempo or 1)
|
|
416
|
+
tao_emission_cell = format_cell(
|
|
417
|
+
tao_emission_value,
|
|
418
|
+
prev.get("tao_emission"),
|
|
419
|
+
unit="τ",
|
|
420
|
+
unit_first_=unit_first,
|
|
421
|
+
precision=4,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
subnet_name_cell = (
|
|
425
|
+
f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}]"
|
|
426
|
+
f" {get_subnet_name(dynamic_info_for_lt[netuid])}"
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
# Claimable amount cell
|
|
430
|
+
hotkey_ss58 = substake_.hotkey_ss58
|
|
431
|
+
claimable_amount = Balance.from_meshlet(0)
|
|
432
|
+
if (
|
|
433
|
+
hotkey_ss58 in claimable_amounts_
|
|
434
|
+
and netuid in claimable_amounts_[hotkey_ss58]
|
|
435
|
+
):
|
|
436
|
+
claimable_amount = claimable_amounts_[hotkey_ss58][netuid]
|
|
437
|
+
|
|
438
|
+
current_data_[netuid]["claimable"] = claimable_amount.tao
|
|
439
|
+
|
|
440
|
+
claimable_cell = format_cell(
|
|
441
|
+
claimable_amount.tao,
|
|
442
|
+
prev.get("claimable"),
|
|
443
|
+
unit=symbol,
|
|
444
|
+
unit_first_=unit_first,
|
|
445
|
+
precision=5,
|
|
446
|
+
millify=True if not verbose else False,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
rows.append(
|
|
450
|
+
[
|
|
451
|
+
str(netuid), # Netuid
|
|
452
|
+
subnet_name_cell,
|
|
453
|
+
exchange_cell, # Exchange value
|
|
454
|
+
stake_cell, # Stake amount
|
|
455
|
+
rate_cell, # Rate
|
|
456
|
+
# swap_cell, # Swap value
|
|
457
|
+
"YES"
|
|
458
|
+
if substake_.is_registered
|
|
459
|
+
else f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]NO", # Registration status
|
|
460
|
+
emission_cell, # Emission rate
|
|
461
|
+
tao_emission_cell, # MESH emission rate
|
|
462
|
+
claimable_cell, # Claimable amount
|
|
463
|
+
]
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
live_table = define_table(
|
|
467
|
+
hotkey_name_, rows, total_tao_value_, total_swapped_tao_value_
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
for row in rows:
|
|
471
|
+
live_table.add_row(*row)
|
|
472
|
+
|
|
473
|
+
return live_table, current_data_
|
|
474
|
+
|
|
475
|
+
# Main execution
|
|
476
|
+
block_hash = await meshtensor.substrate.get_chain_head()
|
|
477
|
+
(
|
|
478
|
+
(
|
|
479
|
+
sub_stakes,
|
|
480
|
+
registered_delegate_info,
|
|
481
|
+
dynamic_info,
|
|
482
|
+
claimable_amounts,
|
|
483
|
+
),
|
|
484
|
+
balance,
|
|
485
|
+
) = await asyncio.gather(
|
|
486
|
+
get_stake_data(block_hash),
|
|
487
|
+
meshtensor.get_balance(coldkey_address, block_hash=block_hash),
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
# Iterate over substakes and aggregate them by hotkey.
|
|
491
|
+
hotkeys_to_substakes: dict[str, list[StakeInfo]] = defaultdict(list)
|
|
492
|
+
|
|
493
|
+
for substake in sub_stakes:
|
|
494
|
+
if substake.stake.meshlet != 0:
|
|
495
|
+
hotkeys_to_substakes[substake.hotkey_ss58].append(substake)
|
|
496
|
+
|
|
497
|
+
if not hotkeys_to_substakes:
|
|
498
|
+
print_error(f"No stakes found for coldkey ss58: ({coldkey_address})")
|
|
499
|
+
return
|
|
500
|
+
|
|
501
|
+
if live:
|
|
502
|
+
# Select one hotkey for live monitoring
|
|
503
|
+
if len(hotkeys_to_substakes) > 1:
|
|
504
|
+
console.print(
|
|
505
|
+
"\n[bold]Multiple hotkeys found. Please select one for live monitoring:[/bold]"
|
|
506
|
+
)
|
|
507
|
+
for idx, hotkey in enumerate(hotkeys_to_substakes.keys()):
|
|
508
|
+
name = (
|
|
509
|
+
f"{registered_delegate_info[hotkey].display} ({hotkey})"
|
|
510
|
+
if hotkey in registered_delegate_info
|
|
511
|
+
else hotkey
|
|
512
|
+
)
|
|
513
|
+
console.print(f"[{idx}] [{COLOR_PALETTE['GENERAL']['HEADER']}]{name}")
|
|
514
|
+
|
|
515
|
+
selected_idx = Prompt.ask(
|
|
516
|
+
"Enter hotkey index",
|
|
517
|
+
choices=[str(i) for i in range(len(hotkeys_to_substakes))],
|
|
518
|
+
)
|
|
519
|
+
selected_hotkey = list(hotkeys_to_substakes.keys())[int(selected_idx)]
|
|
520
|
+
else:
|
|
521
|
+
selected_hotkey = list(hotkeys_to_substakes.keys())[0]
|
|
522
|
+
|
|
523
|
+
hotkey_name = (
|
|
524
|
+
f"{registered_delegate_info[selected_hotkey].display} ({selected_hotkey})"
|
|
525
|
+
if selected_hotkey in registered_delegate_info
|
|
526
|
+
else selected_hotkey
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
refresh_interval = 10 # seconds
|
|
530
|
+
progress = Progress(
|
|
531
|
+
TextColumn("[progress.description]{task.description}"),
|
|
532
|
+
BarColumn(bar_width=20),
|
|
533
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
534
|
+
console=console,
|
|
535
|
+
)
|
|
536
|
+
progress_task = progress.add_task("Updating: ", total=refresh_interval)
|
|
537
|
+
|
|
538
|
+
previous_block = None
|
|
539
|
+
current_block = None
|
|
540
|
+
previous_data = None
|
|
541
|
+
|
|
542
|
+
with Live(console=console, auto_refresh=True) as live:
|
|
543
|
+
try:
|
|
544
|
+
while True:
|
|
545
|
+
block_hash = await meshtensor.substrate.get_chain_head()
|
|
546
|
+
(
|
|
547
|
+
sub_stakes,
|
|
548
|
+
registered_delegate_info,
|
|
549
|
+
dynamic_info_,
|
|
550
|
+
claimable_amounts_live,
|
|
551
|
+
) = await get_stake_data(block_hash)
|
|
552
|
+
selected_stakes = [
|
|
553
|
+
stake
|
|
554
|
+
for stake in sub_stakes
|
|
555
|
+
if stake.hotkey_ss58 == selected_hotkey
|
|
556
|
+
]
|
|
557
|
+
|
|
558
|
+
block_number = await meshtensor.substrate.get_block_number(None)
|
|
559
|
+
|
|
560
|
+
previous_block = current_block
|
|
561
|
+
current_block = block_number
|
|
562
|
+
new_blocks = (
|
|
563
|
+
"N/A"
|
|
564
|
+
if previous_block is None
|
|
565
|
+
else str(current_block - previous_block)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
table, current_data = create_live_table(
|
|
569
|
+
selected_stakes,
|
|
570
|
+
dynamic_info_,
|
|
571
|
+
hotkey_name,
|
|
572
|
+
claimable_amounts_live,
|
|
573
|
+
previous_data,
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
previous_data = current_data
|
|
577
|
+
progress.reset(progress_task)
|
|
578
|
+
start_time = asyncio.get_event_loop().time()
|
|
579
|
+
|
|
580
|
+
block_info = (
|
|
581
|
+
f"Previous: [dark_sea_green]{previous_block}[/dark_sea_green] "
|
|
582
|
+
f"Current: [dark_sea_green]{current_block}[/dark_sea_green] "
|
|
583
|
+
f"Diff: [dark_sea_green]{new_blocks}[/dark_sea_green]"
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
message = f"\nLive stake view - Press [bold red]Ctrl+C[/bold red] to exit\n{block_info}"
|
|
587
|
+
live_render = Group(message, progress, table)
|
|
588
|
+
live.update(live_render)
|
|
589
|
+
|
|
590
|
+
while not progress.finished:
|
|
591
|
+
await asyncio.sleep(0.1)
|
|
592
|
+
elapsed = asyncio.get_event_loop().time() - start_time
|
|
593
|
+
progress.update(
|
|
594
|
+
progress_task, completed=min(elapsed, refresh_interval)
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
except KeyboardInterrupt:
|
|
598
|
+
console.print("\n[bold]Stopped live updates[/bold]")
|
|
599
|
+
return
|
|
600
|
+
|
|
601
|
+
else:
|
|
602
|
+
# Iterate over each hotkey and make a table
|
|
603
|
+
counter = 0
|
|
604
|
+
num_hotkeys = len(hotkeys_to_substakes)
|
|
605
|
+
all_hks_swapped_tao_value = Balance(0)
|
|
606
|
+
all_hks_tao_value = Balance(0)
|
|
607
|
+
dict_output = {
|
|
608
|
+
"stake_info": {},
|
|
609
|
+
"coldkey_address": coldkey_address,
|
|
610
|
+
"network": meshtensor.network,
|
|
611
|
+
"free_balance": 0.0,
|
|
612
|
+
"total_tao_value": 0.0,
|
|
613
|
+
"total_swapped_tao_value": 0.0,
|
|
614
|
+
}
|
|
615
|
+
for hotkey, substakes in hotkeys_to_substakes.items():
|
|
616
|
+
counter += 1
|
|
617
|
+
tao_value, swapped_tao_value, substake_values_ = create_table(
|
|
618
|
+
hotkey, substakes, claimable_amounts
|
|
619
|
+
)
|
|
620
|
+
dict_output["stake_info"][hotkey] = substake_values_
|
|
621
|
+
all_hks_tao_value += tao_value
|
|
622
|
+
all_hks_swapped_tao_value += swapped_tao_value
|
|
623
|
+
|
|
624
|
+
if num_hotkeys > 1 and counter < num_hotkeys and prompt and not json_output:
|
|
625
|
+
console.print("\nPress Enter to continue to the next hotkey...")
|
|
626
|
+
input()
|
|
627
|
+
|
|
628
|
+
total_tao_value = (
|
|
629
|
+
f"τ {millify_tao(all_hks_tao_value.tao + balance.tao)}"
|
|
630
|
+
if not verbose
|
|
631
|
+
else all_hks_tao_value + balance
|
|
632
|
+
)
|
|
633
|
+
total_swapped_tao_value = (
|
|
634
|
+
f"τ {millify_tao(all_hks_swapped_tao_value.tao)}"
|
|
635
|
+
if not verbose
|
|
636
|
+
else all_hks_swapped_tao_value
|
|
637
|
+
)
|
|
638
|
+
console.print("\n\n")
|
|
639
|
+
console.print(
|
|
640
|
+
f"Wallet:\n"
|
|
641
|
+
f" Coldkey SS58: "
|
|
642
|
+
f"[{COLOR_PALETTE.G.CK}]{coldkey_address}[/{COLOR_PALETTE.G.CK}]\n"
|
|
643
|
+
f" Free Balance: "
|
|
644
|
+
f"[{COLOR_PALETTE.G.BALANCE}]{balance}[/{COLOR_PALETTE.G.BALANCE}]\n"
|
|
645
|
+
f" Total MESH Swapped Value ({Balance.unit}): "
|
|
646
|
+
f"[{COLOR_PALETTE.G.BALANCE}]{total_swapped_tao_value}[/{COLOR_PALETTE.G.BALANCE}]\n"
|
|
647
|
+
f" Total MESH Value (including free balance) ({Balance.unit}): "
|
|
648
|
+
f"[{COLOR_PALETTE.G.BALANCE}]{total_tao_value}[/{COLOR_PALETTE.G.BALANCE}]\n"
|
|
649
|
+
)
|
|
650
|
+
dict_output["free_balance"] = balance.tao
|
|
651
|
+
dict_output["total_tao_value"] = all_hks_tao_value.tao + balance.tao
|
|
652
|
+
dict_output["total_swapped_tao_value"] = all_hks_swapped_tao_value.tao
|
|
653
|
+
if json_output:
|
|
654
|
+
json_console.print(json.dumps(dict_output))
|
|
655
|
+
if not sub_stakes:
|
|
656
|
+
console.print(
|
|
657
|
+
f"\n[blue]No stakes found for coldkey ss58: ({coldkey_address})"
|
|
658
|
+
)
|
|
659
|
+
else:
|
|
660
|
+
# TODO: Temporarily returning till we update docs
|
|
661
|
+
return
|
|
662
|
+
display_table = Prompt.ask(
|
|
663
|
+
"\nPress Enter to view column descriptions or type 'q' to skip:",
|
|
664
|
+
choices=["", "q"],
|
|
665
|
+
default="",
|
|
666
|
+
show_choices=True,
|
|
667
|
+
).lower()
|
|
668
|
+
|
|
669
|
+
if display_table == "q":
|
|
670
|
+
console.print(
|
|
671
|
+
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING_EXTRA_1']}]Column descriptions skipped."
|
|
672
|
+
)
|
|
673
|
+
else:
|
|
674
|
+
header = """
|
|
675
|
+
[bold white]Description[/bold white]: Each table displays information about stake associated with a hotkey. The columns are as follows:
|
|
676
|
+
"""
|
|
677
|
+
console.print(header)
|
|
678
|
+
description_table = Table(
|
|
679
|
+
show_header=False, box=box.SIMPLE, show_edge=False, show_lines=True
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
fields = [
|
|
683
|
+
("[bold tan]Netuid[/bold tan]", "The netuid of the subnet."),
|
|
684
|
+
(
|
|
685
|
+
"[bold tan]Symbol[/bold tan]",
|
|
686
|
+
"The symbol for the subnet's dynamic MESH token.",
|
|
687
|
+
),
|
|
688
|
+
(
|
|
689
|
+
"[bold tan]Stake (α)[/bold tan]",
|
|
690
|
+
"The stake amount this hotkey holds in the subnet, expressed in subnet's alpha token currency. This can change whenever staking or unstaking occurs on this hotkey in this subnet. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#staking[/blue].",
|
|
691
|
+
),
|
|
692
|
+
(
|
|
693
|
+
"[bold tan]MESH Reserves (τ_in)[/bold tan]",
|
|
694
|
+
'Number of MESH in the MESH reserves of the pool for this subnet. Attached to every subnet is a subnet pool, containing a MESH reserve and the alpha reserve. See also "Alpha Pool (α_in)" description. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#subnet-pool[/blue].',
|
|
695
|
+
),
|
|
696
|
+
(
|
|
697
|
+
"[bold tan]Alpha Reserves (α_in)[/bold tan]",
|
|
698
|
+
"Number of subnet alpha tokens in the alpha reserves of the pool for this subnet. This reserve, together with 'MESH Pool (τ_in)', form the subnet pool for every subnet. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#subnet-pool[/blue].",
|
|
699
|
+
),
|
|
700
|
+
(
|
|
701
|
+
"[bold tan]RATE (τ_in/α_in)[/bold tan]",
|
|
702
|
+
"Exchange rate between MESH and subnet dMESH token. Calculated as the reserve ratio: (MESH Pool (τ_in) / Alpha Pool (α_in)). Note that the terms relative price, alpha token price, alpha price are the same as exchange rate. This rate can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#rate-%CF%84_in%CE%B1_in[/blue].",
|
|
703
|
+
),
|
|
704
|
+
(
|
|
705
|
+
"[bold tan]Alpha out (α_out)[/bold tan]",
|
|
706
|
+
"Total stake in the subnet, expressed in subnet's alpha token currency. This is the sum of all the stakes present in all the hotkeys in this subnet. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#stake-%CE%B1_out-or-alpha-out-%CE%B1_out",
|
|
707
|
+
),
|
|
708
|
+
(
|
|
709
|
+
"[bold tan]MESH Equiv (τ_in x α/α_out)[/bold tan]",
|
|
710
|
+
'MESH-equivalent value of the hotkeys stake α (i.e., Stake(α)). Calculated as (MESH Reserves(τ_in) x (Stake(α) / ALPHA Out(α_out)). This value is weighted with (1-γ), where γ is the local weight coefficient, and used in determining the overall stake weight of the hotkey in this subnet. Also see the "Local weight coeff (γ)" column of "meshcli subnet list" command output. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#local-weight-or-tao-equiv-%CF%84_in-x-%CE%B1%CE%B1_out[/blue].',
|
|
711
|
+
),
|
|
712
|
+
(
|
|
713
|
+
"[bold tan]Exchange Value (α x τ/α)[/bold tan]",
|
|
714
|
+
"This is the potential τ you will receive if you unstake from this hotkey now on this subnet. Note: The MESH Equiv(τ_in x α/α_out) indicates validator stake weight while this Exchange Value shows τ you will receive if you unstake now. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#exchange-value-%CE%B1-x-%CF%84%CE%B1[/blue].",
|
|
715
|
+
),
|
|
716
|
+
# (
|
|
717
|
+
# "[bold tan]Swap (α → τ)[/bold tan]",
|
|
718
|
+
# "This is the τ you will receive if you unstake from this hotkey now on this subnet. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#swap-%CE%B1--%CF%84[/blue].",
|
|
719
|
+
# ),
|
|
720
|
+
(
|
|
721
|
+
"[bold tan]Registered[/bold tan]",
|
|
722
|
+
"Indicates if the hotkey is registered in this subnet or not. \nFor more, see [blue]https://docs.meshtensor.com/learn/anatomy-of-incentive-mechanism#tempo[/blue].",
|
|
723
|
+
),
|
|
724
|
+
(
|
|
725
|
+
"[bold tan]Emission (α/block)[/bold tan]",
|
|
726
|
+
"Shows the portion of the one α/block emission into this subnet that is received by this hotkey, according to YC2 in this subnet. This can change every block. \nFor more, see [blue]https://docs.meshtensor.com/dynamic-tao/dtao-guide#emissions[/blue].",
|
|
727
|
+
),
|
|
728
|
+
]
|
|
729
|
+
|
|
730
|
+
description_table.add_column(
|
|
731
|
+
"Field",
|
|
732
|
+
no_wrap=True,
|
|
733
|
+
style="bold tan",
|
|
734
|
+
)
|
|
735
|
+
description_table.add_column("Description", overflow="fold")
|
|
736
|
+
for field_name, description in fields:
|
|
737
|
+
description_table.add_row(field_name, description)
|
|
738
|
+
console.print(description_table)
|