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.
Files changed (74) hide show
  1. meshtensor_cli/__init__.py +22 -0
  2. meshtensor_cli/cli.py +10742 -0
  3. meshtensor_cli/doc_generation_helper.py +4 -0
  4. meshtensor_cli/src/__init__.py +1085 -0
  5. meshtensor_cli/src/commands/__init__.py +0 -0
  6. meshtensor_cli/src/commands/axon/__init__.py +0 -0
  7. meshtensor_cli/src/commands/axon/axon.py +132 -0
  8. meshtensor_cli/src/commands/crowd/__init__.py +0 -0
  9. meshtensor_cli/src/commands/crowd/contribute.py +621 -0
  10. meshtensor_cli/src/commands/crowd/contributors.py +200 -0
  11. meshtensor_cli/src/commands/crowd/create.py +783 -0
  12. meshtensor_cli/src/commands/crowd/dissolve.py +219 -0
  13. meshtensor_cli/src/commands/crowd/refund.py +233 -0
  14. meshtensor_cli/src/commands/crowd/update.py +418 -0
  15. meshtensor_cli/src/commands/crowd/utils.py +124 -0
  16. meshtensor_cli/src/commands/crowd/view.py +991 -0
  17. meshtensor_cli/src/commands/governance/__init__.py +0 -0
  18. meshtensor_cli/src/commands/governance/governance.py +794 -0
  19. meshtensor_cli/src/commands/liquidity/__init__.py +0 -0
  20. meshtensor_cli/src/commands/liquidity/liquidity.py +699 -0
  21. meshtensor_cli/src/commands/liquidity/utils.py +202 -0
  22. meshtensor_cli/src/commands/proxy.py +700 -0
  23. meshtensor_cli/src/commands/stake/__init__.py +0 -0
  24. meshtensor_cli/src/commands/stake/add.py +799 -0
  25. meshtensor_cli/src/commands/stake/auto_staking.py +306 -0
  26. meshtensor_cli/src/commands/stake/children_hotkeys.py +865 -0
  27. meshtensor_cli/src/commands/stake/claim.py +770 -0
  28. meshtensor_cli/src/commands/stake/list.py +738 -0
  29. meshtensor_cli/src/commands/stake/move.py +1211 -0
  30. meshtensor_cli/src/commands/stake/remove.py +1466 -0
  31. meshtensor_cli/src/commands/stake/wizard.py +323 -0
  32. meshtensor_cli/src/commands/subnets/__init__.py +0 -0
  33. meshtensor_cli/src/commands/subnets/mechanisms.py +515 -0
  34. meshtensor_cli/src/commands/subnets/price.py +733 -0
  35. meshtensor_cli/src/commands/subnets/subnets.py +2908 -0
  36. meshtensor_cli/src/commands/sudo.py +1294 -0
  37. meshtensor_cli/src/commands/tc/__init__.py +0 -0
  38. meshtensor_cli/src/commands/tc/tc.py +190 -0
  39. meshtensor_cli/src/commands/treasury/__init__.py +0 -0
  40. meshtensor_cli/src/commands/treasury/treasury.py +194 -0
  41. meshtensor_cli/src/commands/view.py +354 -0
  42. meshtensor_cli/src/commands/wallets.py +2311 -0
  43. meshtensor_cli/src/commands/weights.py +467 -0
  44. meshtensor_cli/src/meshtensor/__init__.py +0 -0
  45. meshtensor_cli/src/meshtensor/balances.py +313 -0
  46. meshtensor_cli/src/meshtensor/chain_data.py +1263 -0
  47. meshtensor_cli/src/meshtensor/extrinsics/__init__.py +0 -0
  48. meshtensor_cli/src/meshtensor/extrinsics/mev_shield.py +174 -0
  49. meshtensor_cli/src/meshtensor/extrinsics/registration.py +1861 -0
  50. meshtensor_cli/src/meshtensor/extrinsics/root.py +550 -0
  51. meshtensor_cli/src/meshtensor/extrinsics/serving.py +255 -0
  52. meshtensor_cli/src/meshtensor/extrinsics/transfer.py +239 -0
  53. meshtensor_cli/src/meshtensor/meshtensor_interface.py +2598 -0
  54. meshtensor_cli/src/meshtensor/minigraph.py +254 -0
  55. meshtensor_cli/src/meshtensor/networking.py +12 -0
  56. meshtensor_cli/src/meshtensor/templates/main-filters.j2 +24 -0
  57. meshtensor_cli/src/meshtensor/templates/main-header.j2 +36 -0
  58. meshtensor_cli/src/meshtensor/templates/neuron-details.j2 +111 -0
  59. meshtensor_cli/src/meshtensor/templates/price-multi.j2 +113 -0
  60. meshtensor_cli/src/meshtensor/templates/price-single.j2 +99 -0
  61. meshtensor_cli/src/meshtensor/templates/subnet-details-header.j2 +49 -0
  62. meshtensor_cli/src/meshtensor/templates/subnet-details.j2 +32 -0
  63. meshtensor_cli/src/meshtensor/templates/subnet-metrics.j2 +57 -0
  64. meshtensor_cli/src/meshtensor/templates/subnets-table.j2 +28 -0
  65. meshtensor_cli/src/meshtensor/templates/table.j2 +267 -0
  66. meshtensor_cli/src/meshtensor/templates/view.css +1058 -0
  67. meshtensor_cli/src/meshtensor/templates/view.j2 +43 -0
  68. meshtensor_cli/src/meshtensor/templates/view.js +1053 -0
  69. meshtensor_cli/src/meshtensor/utils.py +2007 -0
  70. meshtensor_cli/version.py +23 -0
  71. meshtensor_cli-9.18.1.dist-info/METADATA +261 -0
  72. meshtensor_cli-9.18.1.dist-info/RECORD +74 -0
  73. meshtensor_cli-9.18.1.dist-info/WHEEL +4 -0
  74. meshtensor_cli-9.18.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,1263 @@
1
+ from abc import abstractmethod
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+ from typing import Optional, Any, Union
5
+
6
+ import netaddr
7
+ from scalecodec.utils.ss58 import ss58_encode
8
+
9
+ from meshtensor_cli.src.meshtensor.balances import Balance, fixed_to_float
10
+ from meshtensor_cli.src.meshtensor.networking import int_to_ip
11
+ from meshtensor_cli.src.meshtensor.utils import (
12
+ SS58_FORMAT,
13
+ u16_normalized_float as u16tf,
14
+ u64_normalized_float as u64tf,
15
+ decode_account_id,
16
+ get_netuid_and_subuid_by_storage_index,
17
+ )
18
+
19
+
20
+ class ChainDataType(Enum):
21
+ NeuronInfo = 1
22
+ DelegateInfo = 2
23
+ NeuronInfoLite = 3
24
+ StakeInfo = 4
25
+ SubnetHyperparameters = 5
26
+ DelegateInfoLite = 6
27
+ DynamicInfo = 7
28
+ ScheduledColdkeySwapInfo = 8
29
+ SubnetInfo = 9
30
+ SubnetState = 10
31
+ SubnetIdentity = 11
32
+
33
+
34
+ def decode_hex_identity(info_dictionary):
35
+ decoded_info = {}
36
+ for k, v in info_dictionary.items():
37
+ if isinstance(v, dict):
38
+ item = next(iter(v.values()))
39
+ else:
40
+ item = v
41
+
42
+ if isinstance(item, tuple):
43
+ try:
44
+ decoded_info[k] = bytes(item).decode()
45
+ except UnicodeDecodeError:
46
+ print(f"Could not decode: {k}: {item}")
47
+ else:
48
+ decoded_info[k] = item
49
+ return decoded_info
50
+
51
+
52
+ def process_stake_data(stake_data, netuid):
53
+ decoded_stake_data = {}
54
+ for account_id_bytes, stake_ in stake_data:
55
+ account_id = decode_account_id(account_id_bytes)
56
+ decoded_stake_data.update(
57
+ {account_id: Balance.from_meshlet(stake_).set_unit(netuid)}
58
+ )
59
+ return decoded_stake_data
60
+
61
+
62
+ def _tbwu(val: int, netuid: Optional[int] = 0) -> Balance:
63
+ """Returns a Balance object from a value and unit."""
64
+ return Balance.from_meshlet(val).set_unit(netuid)
65
+
66
+
67
+ def _chr_str(codes: tuple[int]) -> str:
68
+ """Converts a tuple of integer Unicode code points into a string."""
69
+ return "".join(map(chr, codes))
70
+
71
+
72
+ def process_nested(data: Union[tuple, dict], chr_transform):
73
+ """Processes nested data structures by applying a transformation function to their elements."""
74
+ if isinstance(data, (list, tuple)):
75
+ if len(data) > 0 and isinstance(data[0], dict):
76
+ return [
77
+ {k: chr_transform(v) for k, v in item.items()}
78
+ if item is not None
79
+ else None
80
+ for item in data
81
+ ]
82
+ return {}
83
+ elif isinstance(data, dict):
84
+ return {k: chr_transform(v) for k, v in data.items()}
85
+
86
+
87
+ @dataclass
88
+ class AxonInfo:
89
+ version: int
90
+ ip: str
91
+ port: int
92
+ ip_type: int
93
+ hotkey: str
94
+ coldkey: str
95
+ protocol: int = 4
96
+ placeholder1: int = 0
97
+ placeholder2: int = 0
98
+
99
+ @property
100
+ def is_serving(self) -> bool:
101
+ """True if the endpoint is serving."""
102
+ return self.ip != "0.0.0.0"
103
+
104
+ @classmethod
105
+ def from_neuron_info(cls, neuron_info: dict) -> "AxonInfo":
106
+ """
107
+ Converts a dictionary to an AxonInfo object.
108
+
109
+ Args:
110
+ neuron_info (dict): A dictionary containing the neuron information.
111
+
112
+ Returns:
113
+ instance (AxonInfo): An instance of AxonInfo created from the dictionary.
114
+ """
115
+ return cls(
116
+ version=neuron_info["axon_info"]["version"],
117
+ ip=int_to_ip(int(neuron_info["axon_info"]["ip"])),
118
+ port=neuron_info["axon_info"]["port"],
119
+ ip_type=neuron_info["axon_info"]["ip_type"],
120
+ hotkey=neuron_info["hotkey"],
121
+ coldkey=neuron_info["coldkey"],
122
+ )
123
+
124
+
125
+ @dataclass
126
+ class InfoBase:
127
+ """Base dataclass for info objects."""
128
+
129
+ @abstractmethod
130
+ def _fix_decoded(self, decoded: Any) -> "InfoBase":
131
+ raise NotImplementedError(
132
+ "This is an abstract method and must be implemented in a subclass."
133
+ )
134
+
135
+ @classmethod
136
+ def from_any(cls, data: Any) -> "InfoBase":
137
+ return cls._fix_decoded(data)
138
+
139
+ @classmethod
140
+ def list_from_any(cls, data_list: list[Any]) -> list["InfoBase"]:
141
+ return [cls.from_any(data) for data in data_list]
142
+
143
+ def __getitem__(self, item):
144
+ return getattr(self, item)
145
+
146
+ def get(self, item, default=None):
147
+ return getattr(self, item, default)
148
+
149
+
150
+ @dataclass
151
+ class SubnetHyperparameters(InfoBase):
152
+ """
153
+ This class represents the hyperparameters for a subnet.
154
+ Attributes:
155
+ rho (int): The rate of decay of some value.
156
+ kappa (int): A constant multiplier used in calculations.
157
+ immunity_period (int): The period during which immunity is active.
158
+ min_allowed_weights (int): Minimum allowed weights.
159
+ max_weight_limit (float): Maximum weight limit.
160
+ tempo (int): The tempo or rate of operation.
161
+ min_difficulty (int): Minimum difficulty for some operations.
162
+ max_difficulty (int): Maximum difficulty for some operations.
163
+ weights_version (int): The version number of the weights used.
164
+ weights_rate_limit (int): Rate limit for processing weights.
165
+ adjustment_interval (int): Interval at which adjustments are made.
166
+ activity_cutoff (int): Activity cutoff threshold.
167
+ registration_allowed (bool): Indicates if registration is allowed.
168
+ target_regs_per_interval (int): Target number of registrations per interval.
169
+ min_burn (int): Minimum burn value.
170
+ max_burn (int): Maximum burn value.
171
+ bonds_moving_avg (int): Moving average of bonds.
172
+ max_regs_per_block (int): Maximum number of registrations per block.
173
+ serving_rate_limit (int): Limit on the rate of service.
174
+ max_validators (int): Maximum number of validators.
175
+ adjustment_alpha (int): Alpha value for adjustments.
176
+ difficulty (int): Difficulty level.
177
+ commit_reveal_period (int): Interval for commit-reveal weights.
178
+ commit_reveal_weights_enabled (bool): Flag indicating if commit-reveal weights are enabled.
179
+ alpha_high (int): High value of alpha.
180
+ alpha_low (int): Low value of alpha.
181
+ liquid_alpha_enabled (bool): Flag indicating if liquid alpha is enabled.
182
+ alpha_sigmoid_steepness (float):
183
+ yuma_version (int): Version of yuma.
184
+ subnet_is_active (bool): Indicates if subnet is active after START CALL.
185
+ transfers_enabled (bool): Flag indicating if transfers are enabled.
186
+ bonds_reset_enabled (bool): Flag indicating if bonds are reset enabled.
187
+ user_liquidity_enabled (bool): Flag indicating if user liquidity is enabled.
188
+ """
189
+
190
+ rho: int
191
+ kappa: int
192
+ immunity_period: int
193
+ min_allowed_weights: int
194
+ max_weight_limit: float
195
+ tempo: int
196
+ min_difficulty: int
197
+ max_difficulty: int
198
+ weights_version: int
199
+ weights_rate_limit: int
200
+ adjustment_interval: int
201
+ activity_cutoff: int
202
+ registration_allowed: bool
203
+ target_regs_per_interval: int
204
+ min_burn: int
205
+ max_burn: int
206
+ bonds_moving_avg: int
207
+ max_regs_per_block: int
208
+ serving_rate_limit: int
209
+ max_validators: int
210
+ adjustment_alpha: int
211
+ difficulty: int
212
+ commit_reveal_period: int
213
+ commit_reveal_weights_enabled: bool
214
+ alpha_high: int
215
+ alpha_low: int
216
+ liquid_alpha_enabled: bool
217
+ alpha_sigmoid_steepness: float
218
+ yuma_version: int
219
+ subnet_is_active: bool
220
+ transfers_enabled: bool
221
+ bonds_reset_enabled: bool
222
+ user_liquidity_enabled: bool
223
+
224
+ @classmethod
225
+ def _fix_decoded(
226
+ cls, decoded: Union[dict, "SubnetHyperparameters"]
227
+ ) -> "SubnetHyperparameters":
228
+ return cls(
229
+ activity_cutoff=decoded["activity_cutoff"],
230
+ adjustment_alpha=decoded["adjustment_alpha"],
231
+ adjustment_interval=decoded["adjustment_interval"],
232
+ alpha_high=decoded["alpha_high"],
233
+ alpha_low=decoded["alpha_low"],
234
+ alpha_sigmoid_steepness=fixed_to_float(
235
+ decoded["alpha_sigmoid_steepness"], frac_bits=32
236
+ ),
237
+ bonds_moving_avg=decoded["bonds_moving_avg"],
238
+ bonds_reset_enabled=decoded["bonds_reset_enabled"],
239
+ commit_reveal_weights_enabled=decoded["commit_reveal_weights_enabled"],
240
+ commit_reveal_period=decoded["commit_reveal_period"],
241
+ difficulty=decoded["difficulty"],
242
+ immunity_period=decoded["immunity_period"],
243
+ kappa=decoded["kappa"],
244
+ liquid_alpha_enabled=decoded["liquid_alpha_enabled"],
245
+ max_burn=decoded["max_burn"],
246
+ max_difficulty=decoded["max_difficulty"],
247
+ max_regs_per_block=decoded["max_regs_per_block"],
248
+ max_validators=decoded["max_validators"],
249
+ max_weight_limit=decoded["max_weights_limit"],
250
+ min_allowed_weights=decoded["min_allowed_weights"],
251
+ min_burn=decoded["min_burn"],
252
+ min_difficulty=decoded["min_difficulty"],
253
+ registration_allowed=decoded["registration_allowed"],
254
+ rho=decoded["rho"],
255
+ serving_rate_limit=decoded["serving_rate_limit"],
256
+ subnet_is_active=decoded["subnet_is_active"],
257
+ target_regs_per_interval=decoded["target_regs_per_interval"],
258
+ tempo=decoded["tempo"],
259
+ transfers_enabled=decoded["transfers_enabled"],
260
+ user_liquidity_enabled=decoded["user_liquidity_enabled"],
261
+ weights_rate_limit=decoded["weights_rate_limit"],
262
+ weights_version=decoded["weights_version"],
263
+ yuma_version=decoded["yuma_version"],
264
+ )
265
+
266
+
267
+ @dataclass
268
+ class StakeInfo(InfoBase):
269
+ """Dataclass for stake info."""
270
+
271
+ hotkey_ss58: str # Hotkey address
272
+ coldkey_ss58: str # Coldkey address
273
+ netuid: int
274
+ stake: Balance # Stake for the hotkey-coldkey pair
275
+ locked: Balance # Stake which is locked.
276
+ emission: Balance # Emission for the hotkey-coldkey pair
277
+ tao_emission: Balance # MESH emission for the hotkey-coldkey pair
278
+ drain: int
279
+ is_registered: bool
280
+
281
+ @classmethod
282
+ def _fix_decoded(cls, decoded: Any) -> "StakeInfo":
283
+ hotkey = decode_account_id(decoded.get("hotkey"))
284
+ coldkey = decode_account_id(decoded.get("coldkey"))
285
+ netuid = int(decoded.get("netuid"))
286
+ stake = Balance.from_meshlet(decoded.get("stake")).set_unit(netuid)
287
+ locked = Balance.from_meshlet(decoded.get("locked")).set_unit(netuid)
288
+ emission = Balance.from_meshlet(decoded.get("emission")).set_unit(netuid)
289
+ tao_emission = Balance.from_meshlet(decoded.get("tao_emission"))
290
+ drain = int(decoded.get("drain"))
291
+ is_registered = bool(decoded.get("is_registered"))
292
+
293
+ return cls(
294
+ hotkey,
295
+ coldkey,
296
+ netuid,
297
+ stake,
298
+ locked,
299
+ emission,
300
+ tao_emission,
301
+ drain,
302
+ is_registered,
303
+ )
304
+
305
+
306
+ @dataclass
307
+ class NeuronInfo(InfoBase):
308
+ """Dataclass for neuron metadata."""
309
+
310
+ hotkey: str
311
+ coldkey: str
312
+ uid: int
313
+ netuid: int
314
+ active: int
315
+ stake: Balance
316
+ # mapping of coldkey to amount staked to this Neuron
317
+ stake_dict: dict[str, Balance]
318
+ total_stake: Balance
319
+ rank: float
320
+ emission: float
321
+ incentive: float
322
+ consensus: float
323
+ trust: float
324
+ validator_trust: float
325
+ dividends: float
326
+ last_update: int
327
+ validator_permit: bool
328
+ weights: list[list[int]]
329
+ bonds: list[list[int]]
330
+ pruning_score: int
331
+ axon_info: Optional[AxonInfo] = None
332
+ is_null: bool = False
333
+
334
+ @classmethod
335
+ def from_weights_bonds_and_neuron_lite(
336
+ cls,
337
+ neuron_lite: "NeuronInfoLite",
338
+ weights_as_dict: dict[int, list[tuple[int, int]]],
339
+ bonds_as_dict: dict[int, list[tuple[int, int]]],
340
+ ) -> "NeuronInfo":
341
+ n_dict = neuron_lite.__dict__
342
+ n_dict["weights"] = weights_as_dict.get(neuron_lite.uid, [])
343
+ n_dict["bonds"] = bonds_as_dict.get(neuron_lite.uid, [])
344
+
345
+ return cls(**n_dict)
346
+
347
+ @staticmethod
348
+ def get_null_neuron() -> "NeuronInfo":
349
+ neuron = NeuronInfo(
350
+ uid=0,
351
+ netuid=0,
352
+ active=0,
353
+ stake=Balance.from_meshlet(0),
354
+ stake_dict={},
355
+ total_stake=Balance.from_meshlet(0),
356
+ rank=0,
357
+ emission=0,
358
+ incentive=0,
359
+ consensus=0,
360
+ trust=0,
361
+ validator_trust=0,
362
+ dividends=0,
363
+ last_update=0,
364
+ validator_permit=False,
365
+ weights=[],
366
+ bonds=[],
367
+ axon_info=None,
368
+ is_null=True,
369
+ coldkey="000000000000000000000000000000000000000000000000",
370
+ hotkey="000000000000000000000000000000000000000000000000",
371
+ pruning_score=0,
372
+ )
373
+ return neuron
374
+
375
+ @classmethod
376
+ def _fix_decoded(cls, decoded: Any) -> "NeuronInfo":
377
+ netuid = decoded.get("netuid")
378
+ stake_dict = process_stake_data(decoded.get("stake"), netuid=netuid)
379
+ total_stake = sum(stake_dict.values()) if stake_dict else Balance(0)
380
+ axon_info = decoded.get("axon_info", {})
381
+ coldkey = decode_account_id(decoded.get("coldkey"))
382
+ hotkey = decode_account_id(decoded.get("hotkey"))
383
+ return cls(
384
+ hotkey=hotkey,
385
+ coldkey=coldkey,
386
+ uid=decoded.get("uid"),
387
+ netuid=netuid,
388
+ active=decoded.get("active"),
389
+ stake=total_stake,
390
+ stake_dict=stake_dict,
391
+ total_stake=total_stake,
392
+ rank=u16tf(decoded.get("rank")),
393
+ emission=decoded.get("emission") / 1e9,
394
+ incentive=u16tf(decoded.get("incentive")),
395
+ consensus=u16tf(decoded.get("consensus")),
396
+ trust=u16tf(decoded.get("trust")),
397
+ validator_trust=u16tf(decoded.get("validator_trust")),
398
+ dividends=u16tf(decoded.get("dividends")),
399
+ last_update=decoded.get("last_update"),
400
+ validator_permit=decoded.get("validator_permit"),
401
+ weights=[[e[0], e[1]] for e in decoded.get("weights")],
402
+ bonds=[[e[0], e[1]] for e in decoded.get("bonds")],
403
+ pruning_score=decoded.get("pruning_score"),
404
+ axon_info=AxonInfo(
405
+ version=axon_info.get("version"),
406
+ ip=str(netaddr.IPAddress(axon_info.get("ip"))),
407
+ port=axon_info.get("port"),
408
+ ip_type=axon_info.get("ip_type"),
409
+ placeholder1=axon_info.get("placeholder1"),
410
+ placeholder2=axon_info.get("placeholder2"),
411
+ protocol=axon_info.get("protocol"),
412
+ hotkey=hotkey,
413
+ coldkey=coldkey,
414
+ ),
415
+ is_null=False,
416
+ )
417
+
418
+
419
+ @dataclass
420
+ class NeuronInfoLite(InfoBase):
421
+ """Dataclass for neuron metadata, but without the weights and bonds."""
422
+
423
+ hotkey: str
424
+ coldkey: str
425
+ uid: int
426
+ netuid: int
427
+ active: int
428
+ stake: Balance
429
+ # mapping of coldkey to amount staked to this Neuron
430
+ stake_dict: dict[str, Balance]
431
+ total_stake: Balance
432
+ rank: float
433
+ emission: float
434
+ incentive: float
435
+ consensus: float
436
+ trust: float
437
+ validator_trust: float
438
+ dividends: float
439
+ last_update: int
440
+ validator_permit: bool
441
+ axon_info: AxonInfo
442
+ pruning_score: int
443
+ is_null: bool = False
444
+
445
+ @staticmethod
446
+ def get_null_neuron() -> "NeuronInfoLite":
447
+ neuron = NeuronInfoLite(
448
+ uid=0,
449
+ netuid=0,
450
+ active=0,
451
+ stake=Balance.from_meshlet(0),
452
+ stake_dict={},
453
+ total_stake=Balance.from_meshlet(0),
454
+ rank=0,
455
+ emission=0,
456
+ incentive=0,
457
+ consensus=0,
458
+ trust=0,
459
+ validator_trust=0,
460
+ dividends=0,
461
+ last_update=0,
462
+ validator_permit=False,
463
+ axon_info=None,
464
+ is_null=True,
465
+ coldkey="000000000000000000000000000000000000000000000000",
466
+ hotkey="000000000000000000000000000000000000000000000000",
467
+ pruning_score=0,
468
+ )
469
+ return neuron
470
+
471
+ @classmethod
472
+ def _fix_decoded(cls, decoded: Union[dict, "NeuronInfoLite"]) -> "NeuronInfoLite":
473
+ active = decoded.get("active")
474
+ axon_info = decoded.get("axon_info", {})
475
+ coldkey = decode_account_id(decoded.get("coldkey"))
476
+ consensus = decoded.get("consensus")
477
+ dividends = decoded.get("dividends")
478
+ emission = decoded.get("emission")
479
+ hotkey = decode_account_id(decoded.get("hotkey"))
480
+ incentive = decoded.get("incentive")
481
+ last_update = decoded.get("last_update")
482
+ netuid = decoded.get("netuid")
483
+ pruning_score = decoded.get("pruning_score")
484
+ rank = decoded.get("rank")
485
+ stake_dict = process_stake_data(decoded.get("stake"), netuid)
486
+ stake = sum(stake_dict.values()) if stake_dict else Balance(0)
487
+ trust = decoded.get("trust")
488
+ uid = decoded.get("uid")
489
+ validator_permit = decoded.get("validator_permit")
490
+ validator_trust = decoded.get("validator_trust")
491
+
492
+ neuron = cls(
493
+ active=active,
494
+ axon_info=AxonInfo(
495
+ version=axon_info.get("version"),
496
+ ip=str(netaddr.IPAddress(axon_info.get("ip"))),
497
+ port=axon_info.get("port"),
498
+ ip_type=axon_info.get("ip_type"),
499
+ placeholder1=axon_info.get("placeholder1"),
500
+ placeholder2=axon_info.get("placeholder2"),
501
+ protocol=axon_info.get("protocol"),
502
+ hotkey=hotkey,
503
+ coldkey=coldkey,
504
+ ),
505
+ coldkey=coldkey,
506
+ consensus=u16tf(consensus),
507
+ dividends=u16tf(dividends),
508
+ emission=emission / 1e9,
509
+ hotkey=hotkey,
510
+ incentive=u16tf(incentive),
511
+ last_update=last_update,
512
+ netuid=netuid,
513
+ pruning_score=pruning_score,
514
+ rank=u16tf(rank),
515
+ stake_dict=stake_dict,
516
+ stake=stake,
517
+ total_stake=stake,
518
+ trust=u16tf(trust),
519
+ uid=uid,
520
+ validator_permit=validator_permit,
521
+ validator_trust=u16tf(validator_trust),
522
+ )
523
+
524
+ return neuron
525
+
526
+
527
+ @dataclass
528
+ class DelegateInfo(InfoBase):
529
+ """
530
+ Dataclass for delegate information. For a lighter version of this class, see :func:`DelegateInfoLite`.
531
+
532
+ :param hotkey_ss58: Hotkey of the delegate for which the information is being fetched.
533
+ :param total_stake: Total stake of the delegate.
534
+ :param nominators: list of nominators of the delegate and their stake.
535
+ :param take: Take of the delegate as a percentage.
536
+ :param owner_ss58: Coldkey of the owner.
537
+ :param registrations: list of subnets that the delegate is registered on.
538
+ :param validator_permits: list of subnets that the delegate is allowed to validate on.
539
+ :param return_per_1000: Return per 1000 MESH, for the delegate over a day.
540
+ :param total_daily_return: Total daily return of the delegate.
541
+
542
+ """
543
+
544
+ hotkey_ss58: str # Hotkey of delegate
545
+ total_stake: Balance # Total stake of the delegate
546
+ nominators: list[
547
+ tuple[str, Balance]
548
+ ] # list of nominators of the delegate and their stake
549
+ owner_ss58: str # Coldkey of owner
550
+ take: float # Take of the delegate as a percentage
551
+ validator_permits: list[
552
+ int
553
+ ] # list of subnets that the delegate is allowed to validate on
554
+ registrations: list[int] # list of subnets that the delegate is registered on
555
+ return_per_1000: Balance # Return per 1000 mesh of the delegate over a day
556
+ total_daily_return: Balance # Total daily return of the delegate
557
+
558
+ @classmethod
559
+ def _fix_decoded(cls, decoded: "DelegateInfo") -> "DelegateInfo":
560
+ hotkey = decode_account_id(decoded.get("hotkey_ss58"))
561
+ owner = decode_account_id(decoded.get("owner_ss58"))
562
+ nominators = [
563
+ (decode_account_id(x), Balance.from_meshlet(y))
564
+ for x, y in decoded.get("nominators")
565
+ ]
566
+ total_stake = sum((x[1] for x in nominators)) if nominators else Balance(0)
567
+ return cls(
568
+ hotkey_ss58=hotkey,
569
+ total_stake=total_stake,
570
+ nominators=nominators,
571
+ owner_ss58=owner,
572
+ take=u16tf(decoded.get("take")),
573
+ validator_permits=decoded.get("validator_permits"),
574
+ registrations=decoded.get("registrations"),
575
+ return_per_1000=Balance.from_meshlet(decoded.get("return_per_1000")),
576
+ total_daily_return=Balance.from_meshlet(decoded.get("total_daily_return")),
577
+ )
578
+
579
+
580
+ @dataclass
581
+ class DelegateInfoLite(InfoBase):
582
+ """
583
+ Dataclass for light delegate information.
584
+
585
+ Args:
586
+ hotkey_ss58 (str): Hotkey of the delegate for which the information is being fetched.
587
+ owner_ss58 (str): Coldkey of the owner.
588
+ total_stake (int): Total stake of the delegate.
589
+ owner_stake (int): Own stake of the delegate.
590
+ take (float): Take of the delegate as a percentage. None if custom
591
+ """
592
+
593
+ hotkey_ss58: str # Hotkey of delegate
594
+ owner_ss58: str # Coldkey of owner
595
+ take: Optional[float]
596
+ total_stake: Balance # Total stake of the delegate
597
+ previous_total_stake: Optional[Balance] # Total stake of the delegate
598
+ owner_stake: Balance # Own stake of the delegate
599
+
600
+ @classmethod
601
+ def _fix_decoded(cls, decoded: Any) -> "DelegateInfoLite":
602
+ """Fixes the decoded values."""
603
+ decoded_take = decoded.get("take")
604
+
605
+ if decoded_take == 65535:
606
+ fixed_take = None
607
+ else:
608
+ fixed_take = u16tf(decoded_take)
609
+
610
+ return cls(
611
+ hotkey_ss58=ss58_encode(decoded.get("delegate_ss58"), SS58_FORMAT),
612
+ owner_ss58=ss58_encode(decoded.get("owner_ss58"), SS58_FORMAT),
613
+ take=fixed_take,
614
+ total_stake=Balance.from_meshlet(decoded.get("total_stake")),
615
+ owner_stake=Balance.from_meshlet(decoded.get("owner_stake")),
616
+ previous_total_stake=None,
617
+ )
618
+
619
+
620
+ @dataclass
621
+ class SubnetInfo(InfoBase):
622
+ """Dataclass for subnet info."""
623
+
624
+ netuid: int
625
+ rho: int
626
+ kappa: int
627
+ difficulty: int
628
+ immunity_period: int
629
+ max_allowed_validators: int
630
+ min_allowed_weights: int
631
+ max_weights_limit: float
632
+ scaling_law_power: float
633
+ subnetwork_n: int
634
+ max_n: int
635
+ blocks_since_epoch: int
636
+ tempo: int
637
+ modality: int
638
+ connection_requirements: dict[str, float]
639
+ emission_value: float
640
+ burn: Balance
641
+ owner_ss58: str
642
+
643
+ @classmethod
644
+ def _fix_decoded(cls, decoded: "SubnetInfo") -> "SubnetInfo":
645
+ return cls(
646
+ netuid=decoded.get("netuid"),
647
+ rho=decoded.get("rho"),
648
+ kappa=decoded.get("kappa"),
649
+ difficulty=decoded.get("difficulty"),
650
+ immunity_period=decoded.get("immunity_period"),
651
+ max_allowed_validators=decoded.get("max_allowed_validators"),
652
+ min_allowed_weights=decoded.get("min_allowed_weights"),
653
+ max_weights_limit=decoded.get("max_weights_limit"),
654
+ scaling_law_power=decoded.get("scaling_law_power"),
655
+ subnetwork_n=decoded.get("subnetwork_n"),
656
+ max_n=decoded.get("max_allowed_uids"),
657
+ blocks_since_epoch=decoded.get("blocks_since_last_step"),
658
+ tempo=decoded.get("tempo"),
659
+ modality=decoded.get("network_modality"),
660
+ connection_requirements={
661
+ str(int(netuid)): u16tf(int(req))
662
+ for (netuid, req) in decoded.get("network_connect")
663
+ },
664
+ emission_value=decoded.get("emission_value"),
665
+ burn=Balance.from_meshlet(decoded.get("burn")),
666
+ owner_ss58=decode_account_id(decoded.get("owner")),
667
+ )
668
+
669
+
670
+ @dataclass
671
+ class SubnetIdentity(InfoBase):
672
+ """Dataclass for subnet identity information."""
673
+
674
+ subnet_name: str
675
+ github_repo: str
676
+ subnet_contact: str
677
+ subnet_url: str
678
+ discord: str
679
+ description: str
680
+ logo_url: str
681
+ additional: str
682
+
683
+ @classmethod
684
+ def _fix_decoded(cls, decoded: dict) -> "SubnetIdentity":
685
+ return cls(
686
+ subnet_name=bytes(decoded["subnet_name"]).decode(),
687
+ github_repo=bytes(decoded["github_repo"]).decode(),
688
+ subnet_contact=bytes(decoded["subnet_contact"]).decode(),
689
+ subnet_url=bytes(decoded["subnet_url"]).decode(),
690
+ discord=bytes(decoded["discord"]).decode(),
691
+ description=bytes(decoded["description"]).decode(),
692
+ logo_url=bytes(decoded["logo_url"]).decode(),
693
+ additional=bytes(decoded["additional"]).decode(),
694
+ )
695
+
696
+
697
+ @dataclass
698
+ class DynamicInfo(InfoBase):
699
+ netuid: int
700
+ owner_hotkey: str
701
+ owner_coldkey: str
702
+ subnet_name: str
703
+ symbol: str
704
+ tempo: int
705
+ last_step: int
706
+ blocks_since_last_step: int
707
+ emission: Balance
708
+ alpha_in: Balance
709
+ alpha_out: Balance
710
+ tao_in: Balance
711
+ price: Balance
712
+ k: float
713
+ is_dynamic: bool
714
+ alpha_out_emission: Balance
715
+ alpha_in_emission: Balance
716
+ tao_in_emission: Balance
717
+ pending_alpha_emission: Balance
718
+ pending_root_emission: Balance
719
+ network_registered_at: int
720
+ subnet_identity: Optional[SubnetIdentity]
721
+ subnet_volume: Balance
722
+ moving_price: float
723
+
724
+ @classmethod
725
+ def _fix_decoded(cls, decoded: Any) -> "DynamicInfo":
726
+ """Returns a DynamicInfo object from a decoded DynamicInfo dictionary."""
727
+
728
+ netuid = int(decoded.get("netuid"))
729
+ symbol = bytes([int(b) for b in decoded.get("token_symbol")]).decode()
730
+ subnet_name = bytes([int(b) for b in decoded.get("subnet_name")]).decode()
731
+ is_dynamic = True if netuid > 0 else False # Patching for netuid 0
732
+
733
+ owner_hotkey = decode_account_id(decoded.get("owner_hotkey"))
734
+ owner_coldkey = decode_account_id(decoded.get("owner_coldkey"))
735
+
736
+ emission = Balance.from_meshlet(decoded.get("emission")).set_unit(0)
737
+ alpha_in = Balance.from_meshlet(decoded.get("alpha_in")).set_unit(netuid)
738
+ alpha_out = Balance.from_meshlet(decoded.get("alpha_out")).set_unit(netuid)
739
+ tao_in = Balance.from_meshlet(decoded.get("tao_in")).set_unit(0)
740
+ alpha_out_emission = Balance.from_meshlet(
741
+ decoded.get("alpha_out_emission")
742
+ ).set_unit(netuid)
743
+ alpha_in_emission = Balance.from_meshlet(decoded.get("alpha_in_emission")).set_unit(
744
+ netuid
745
+ )
746
+ subnet_volume = Balance.from_meshlet(decoded.get("subnet_volume")).set_unit(netuid)
747
+ tao_in_emission = Balance.from_meshlet(decoded.get("tao_in_emission")).set_unit(0)
748
+ pending_alpha_emission = Balance.from_meshlet(
749
+ decoded.get("pending_alpha_emission")
750
+ ).set_unit(netuid)
751
+ pending_root_emission = Balance.from_meshlet(
752
+ decoded.get("pending_root_emission")
753
+ ).set_unit(0)
754
+ price = (
755
+ Balance.from_tao(1.0)
756
+ if netuid == 0
757
+ else Balance.from_tao(tao_in.tao / alpha_in.tao)
758
+ if alpha_in.tao > 0
759
+ else Balance.from_tao(1)
760
+ ) # TODO: Patching this temporarily for netuid 0
761
+
762
+ if decoded.get("subnet_identity"):
763
+ subnet_identity = SubnetIdentity.from_any(decoded.get("subnet_identity"))
764
+ else:
765
+ subnet_identity = None
766
+
767
+ return cls(
768
+ netuid=netuid,
769
+ owner_hotkey=owner_hotkey,
770
+ owner_coldkey=owner_coldkey,
771
+ subnet_name=subnet_name,
772
+ symbol=symbol,
773
+ tempo=int(decoded.get("tempo")),
774
+ last_step=int(decoded.get("last_step")),
775
+ blocks_since_last_step=int(decoded.get("blocks_since_last_step")),
776
+ emission=emission,
777
+ alpha_in=alpha_in,
778
+ alpha_out=alpha_out,
779
+ tao_in=tao_in,
780
+ k=tao_in.meshlet * alpha_in.meshlet,
781
+ is_dynamic=is_dynamic,
782
+ price=price,
783
+ alpha_out_emission=alpha_out_emission,
784
+ alpha_in_emission=alpha_in_emission,
785
+ tao_in_emission=tao_in_emission,
786
+ pending_alpha_emission=pending_alpha_emission,
787
+ pending_root_emission=pending_root_emission,
788
+ network_registered_at=int(decoded.get("network_registered_at")),
789
+ subnet_identity=subnet_identity,
790
+ subnet_volume=subnet_volume,
791
+ moving_price=fixed_to_float(decoded["moving_price"], 32),
792
+ )
793
+
794
+ def tao_to_alpha(self, tao: Balance) -> Balance:
795
+ if self.price.tao != 0:
796
+ return Balance.from_tao(tao.tao / self.price.tao).set_unit(self.netuid)
797
+ else:
798
+ return Balance.from_tao(0)
799
+
800
+ def alpha_to_tao(self, alpha: Balance) -> Balance:
801
+ return Balance.from_tao(alpha.tao * self.price.tao)
802
+
803
+ def tao_to_alpha_with_slippage(
804
+ self, tao: Balance
805
+ ) -> tuple[Balance, Balance, float]:
806
+ """
807
+ Returns an estimate of how much Alpha a staker would receive if they stake their mesh using the current pool
808
+ state.
809
+
810
+ Args:
811
+ tao: Amount of MESH to stake.
812
+ Returns:
813
+ Tuple of balances where the first part is the amount of Alpha received, and the
814
+ second part (slippage) is the difference between the estimated amount and ideal
815
+ amount as if there was no slippage
816
+ """
817
+ if self.is_dynamic:
818
+ new_tao_in = self.tao_in + tao
819
+ if new_tao_in == 0:
820
+ return tao, Balance.from_meshlet(0)
821
+ new_alpha_in = self.k / new_tao_in
822
+
823
+ # Amount of alpha given to the staker
824
+ alpha_returned = Balance.from_meshlet(
825
+ self.alpha_in.meshlet - new_alpha_in.meshlet
826
+ ).set_unit(self.netuid)
827
+
828
+ # Ideal conversion as if there is no slippage, just price
829
+ alpha_ideal = self.tao_to_alpha(tao)
830
+
831
+ if alpha_ideal.tao > alpha_returned.tao:
832
+ slippage = Balance.from_tao(
833
+ alpha_ideal.tao - alpha_returned.tao
834
+ ).set_unit(self.netuid)
835
+ else:
836
+ slippage = Balance.from_tao(0)
837
+ else:
838
+ alpha_returned = tao.set_unit(self.netuid)
839
+ slippage = Balance.from_tao(0)
840
+
841
+ slippage_pct_float = (
842
+ 100 * float(slippage) / float(slippage + alpha_returned)
843
+ if slippage + alpha_returned != 0
844
+ else 0
845
+ )
846
+ return alpha_returned, slippage, slippage_pct_float
847
+
848
+ def alpha_to_tao_with_slippage(
849
+ self, alpha: Balance
850
+ ) -> tuple[Balance, Balance, float]:
851
+ """
852
+ Returns an estimate of how much MESH a staker would receive if they unstake their alpha using the current pool
853
+ state.
854
+
855
+ Args:
856
+ alpha: Amount of Alpha to stake.
857
+ Returns:
858
+ Tuple of balances where the first part is the amount of MESH received, and the
859
+ second part (slippage) is the difference between the estimated amount and ideal
860
+ amount as if there was no slippage
861
+ """
862
+ if self.is_dynamic:
863
+ new_alpha_in = self.alpha_in + alpha
864
+ new_tao_reserve = self.k / new_alpha_in
865
+ # Amount of MESH given to the unstaker
866
+ tao_returned = Balance.from_meshlet(self.tao_in - new_tao_reserve)
867
+
868
+ # Ideal conversion as if there is no slippage, just price
869
+ tao_ideal = self.alpha_to_tao(alpha)
870
+
871
+ if tao_ideal > tao_returned:
872
+ slippage = Balance.from_tao(tao_ideal.tao - tao_returned.tao)
873
+ else:
874
+ slippage = Balance.from_tao(0)
875
+ else:
876
+ tao_returned = alpha.set_unit(0)
877
+ slippage = Balance.from_tao(0)
878
+ slippage_pct_float = (
879
+ 100 * float(slippage) / float(slippage + tao_returned)
880
+ if slippage + tao_returned != 0
881
+ else 0
882
+ )
883
+ return tao_returned, slippage, slippage_pct_float
884
+
885
+
886
+ @dataclass
887
+ class ScheduledColdkeySwapInfo(InfoBase):
888
+ """Dataclass for scheduled coldkey swap information."""
889
+
890
+ old_coldkey: str
891
+ new_coldkey: str
892
+ arbitration_block: int
893
+
894
+ @classmethod
895
+ def _fix_decoded(cls, decoded: Any) -> "ScheduledColdkeySwapInfo":
896
+ """Fixes the decoded values."""
897
+ return cls(
898
+ old_coldkey=decode_account_id(decoded.get("old_coldkey")),
899
+ new_coldkey=decode_account_id(decoded.get("new_coldkey")),
900
+ arbitration_block=decoded.get("arbitration_block"),
901
+ )
902
+
903
+
904
+ @dataclass
905
+ class SubnetState(InfoBase):
906
+ netuid: int
907
+ hotkeys: list[str]
908
+ coldkeys: list[str]
909
+ active: list[bool]
910
+ validator_permit: list[bool]
911
+ pruning_score: list[float]
912
+ last_update: list[int]
913
+ emission: list[Balance]
914
+ dividends: list[float]
915
+ incentives: list[float]
916
+ consensus: list[float]
917
+ trust: list[float]
918
+ rank: list[float]
919
+ block_at_registration: list[int]
920
+ alpha_stake: list[Balance]
921
+ tao_stake: list[Balance]
922
+ total_stake: list[Balance]
923
+ emission_history: list[list[int]]
924
+
925
+ @classmethod
926
+ def _fix_decoded(cls, decoded: Any) -> "SubnetState":
927
+ netuid = decoded.get("netuid")
928
+ return cls(
929
+ netuid=netuid,
930
+ hotkeys=[decode_account_id(val) for val in decoded.get("hotkeys")],
931
+ coldkeys=[decode_account_id(val) for val in decoded.get("coldkeys")],
932
+ active=decoded.get("active"),
933
+ validator_permit=decoded.get("validator_permit"),
934
+ pruning_score=[u16tf(val) for val in decoded.get("pruning_score")],
935
+ last_update=decoded.get("last_update"),
936
+ emission=[
937
+ Balance.from_meshlet(val).set_unit(netuid)
938
+ for val in decoded.get("emission")
939
+ ],
940
+ dividends=[u16tf(val) for val in decoded.get("dividends")],
941
+ incentives=[u16tf(val) for val in decoded.get("incentives")],
942
+ consensus=[u16tf(val) for val in decoded.get("consensus")],
943
+ trust=[u16tf(val) for val in decoded.get("trust")],
944
+ rank=[u16tf(val) for val in decoded.get("rank")],
945
+ block_at_registration=decoded.get("block_at_registration"),
946
+ alpha_stake=[
947
+ Balance.from_meshlet(val).set_unit(netuid)
948
+ for val in decoded.get("alpha_stake")
949
+ ],
950
+ tao_stake=[
951
+ Balance.from_meshlet(val).set_unit(0) for val in decoded.get("tao_stake")
952
+ ],
953
+ total_stake=[
954
+ Balance.from_meshlet(val).set_unit(netuid)
955
+ for val in decoded.get("total_stake")
956
+ ],
957
+ emission_history=decoded.get("emission_history"),
958
+ )
959
+
960
+
961
+ @dataclass
962
+ class ChainIdentity(InfoBase):
963
+ """Dataclass for chain identity information."""
964
+
965
+ name: str
966
+ url: str
967
+ github: str
968
+ image: str
969
+ discord: str
970
+ description: str
971
+ additional: str
972
+
973
+ @classmethod
974
+ def _from_dict(cls, decoded: dict) -> "ChainIdentity":
975
+ """Returns a ChainIdentity object from decoded chain data."""
976
+ return cls(
977
+ name=decoded["name"],
978
+ url=decoded["url"],
979
+ github=decoded["github_repo"],
980
+ image=decoded["image"],
981
+ discord=decoded["discord"],
982
+ description=decoded["description"],
983
+ additional=decoded["additional"],
984
+ )
985
+
986
+
987
+ @dataclass
988
+ class MetagraphInfo(InfoBase):
989
+ # Subnet index
990
+ netuid: int
991
+
992
+ # Name and symbol
993
+ name: str
994
+ symbol: str
995
+ identity: Optional[SubnetIdentity]
996
+ network_registered_at: int
997
+
998
+ # Keys for owner.
999
+ owner_hotkey: str # hotkey
1000
+ owner_coldkey: str # coldkey
1001
+
1002
+ # Tempo terms.
1003
+ block: int # block at call.
1004
+ tempo: int # epoch tempo
1005
+ last_step: int
1006
+ blocks_since_last_step: int
1007
+
1008
+ # Subnet emission terms
1009
+ subnet_emission: Balance # subnet emission via tao
1010
+ alpha_in: Balance # amount of alpha in reserve
1011
+ alpha_out: Balance # amount of alpha outstanding
1012
+ tao_in: Balance # amount of mesh injected per block
1013
+ alpha_out_emission: Balance # amount injected in alpha reserves per block
1014
+ alpha_in_emission: Balance # amount injected outstanding per block
1015
+ tao_in_emission: Balance # amount of mesh injected per block
1016
+ pending_alpha_emission: Balance # pending alpha to be distributed
1017
+ pending_root_emission: Balance # pending mesh for root divs to be distributed
1018
+ subnet_volume: Balance # volume of the subnet in MESH
1019
+ moving_price: Balance # subnet moving price.
1020
+
1021
+ # Hparams for epoch
1022
+ rho: int # subnet rho param
1023
+ kappa: float # subnet kappa param
1024
+
1025
+ # Validator params
1026
+ min_allowed_weights: float # min allowed weights per val
1027
+ max_weights_limit: float # max allowed weights per val
1028
+ weights_version: int # allowed weights version
1029
+ weights_rate_limit: int # rate limit on weights.
1030
+ activity_cutoff: int # validator weights cut off period in blocks
1031
+ max_validators: int # max allowed validators.
1032
+
1033
+ # Registration
1034
+ num_uids: int
1035
+ max_uids: int
1036
+ burn: Balance # current burn cost.
1037
+ difficulty: float # current difficulty.
1038
+ registration_allowed: bool # allows registrations.
1039
+ pow_registration_allowed: bool # pow registration enabled.
1040
+ immunity_period: int # subnet miner immunity period
1041
+ min_difficulty: float # min pow difficulty
1042
+ max_difficulty: float # max pow difficulty
1043
+ min_burn: Balance # min mesh burn
1044
+ max_burn: Balance # max mesh burn
1045
+ adjustment_alpha: float # adjustment speed for registration params.
1046
+ adjustment_interval: int # pow and burn adjustment interval
1047
+ target_regs_per_interval: int # target registrations per interval
1048
+ max_regs_per_block: int # max registrations per block.
1049
+ serving_rate_limit: int # axon serving rate limit
1050
+
1051
+ # CR
1052
+ commit_reveal_weights_enabled: bool # Is CR enabled.
1053
+ commit_reveal_period: int # Commit reveal interval
1054
+
1055
+ # Bonds
1056
+ liquid_alpha_enabled: bool # Bonds liquid enabled.
1057
+ alpha_high: float # Alpha param high
1058
+ alpha_low: float # Alpha param low
1059
+ bonds_moving_avg: float # Bonds moving avg
1060
+
1061
+ # Metagraph info.
1062
+ hotkeys: list[str] # hotkey per UID
1063
+ coldkeys: list[str] # coldkey per UID
1064
+ identities: list[Optional[ChainIdentity]] # coldkeys identities
1065
+ axons: list[AxonInfo] # UID axons.
1066
+ active: list[bool] # Active per UID
1067
+ validator_permit: list[bool] # Val permit per UID
1068
+ pruning_score: list[float] # Pruning per UID
1069
+ last_update: list[int] # Last update per UID
1070
+ emission: list[Balance] # Emission per UID
1071
+ dividends: list[float] # Dividends per UID
1072
+ incentives: list[float] # Mining incentives per UID
1073
+ consensus: list[float] # Consensus per UID
1074
+ trust: list[float] # Trust per UID
1075
+ rank: list[float] # Rank per UID
1076
+ block_at_registration: list[int] # Reg block per UID
1077
+ alpha_stake: list[Balance] # Alpha staked per UID
1078
+ tao_stake: list[Balance] # MESH staked per UID
1079
+ total_stake: list[Balance] # Total stake per UID
1080
+
1081
+ # Dividend break down.
1082
+ tao_dividends_per_hotkey: list[
1083
+ tuple[str, Balance]
1084
+ ] # List of dividend payouts in mesh via root.
1085
+ alpha_dividends_per_hotkey: list[
1086
+ tuple[str, Balance]
1087
+ ] # List of dividend payout in alpha via subnet.
1088
+ subuid: int = 0
1089
+
1090
+ @classmethod
1091
+ def _fix_decoded(cls, decoded: dict) -> "MetagraphInfo":
1092
+ """Returns a MetagraphInfo object from decoded chain data."""
1093
+ # Subnet index
1094
+ _netuid, _subuid = get_netuid_and_subuid_by_storage_index(decoded["netuid"])
1095
+
1096
+ # Name and symbol
1097
+ decoded.update({"name": bytes(decoded.get("name")).decode()})
1098
+ decoded.update({"symbol": bytes(decoded.get("symbol")).decode()})
1099
+ for key in ["identities", "identity"]:
1100
+ raw_data = decoded.get(key)
1101
+ processed = process_nested(raw_data, _chr_str)
1102
+ decoded.update({key: processed})
1103
+
1104
+ return cls(
1105
+ # Subnet index
1106
+ netuid=_netuid,
1107
+ subuid=_subuid,
1108
+ # Name and symbol
1109
+ name=decoded["name"],
1110
+ symbol=decoded["symbol"],
1111
+ identity=decoded["identity"],
1112
+ network_registered_at=decoded["network_registered_at"],
1113
+ # Keys for owner.
1114
+ owner_hotkey=decoded["owner_hotkey"],
1115
+ owner_coldkey=decoded["owner_coldkey"],
1116
+ # Tempo terms.
1117
+ block=decoded["block"],
1118
+ tempo=decoded["tempo"],
1119
+ last_step=decoded["last_step"],
1120
+ blocks_since_last_step=decoded["blocks_since_last_step"],
1121
+ # Subnet emission terms
1122
+ subnet_emission=_tbwu(decoded["subnet_emission"]),
1123
+ alpha_in=_tbwu(decoded["alpha_in"], _netuid),
1124
+ alpha_out=_tbwu(decoded["alpha_out"], _netuid),
1125
+ tao_in=_tbwu(decoded["tao_in"]),
1126
+ alpha_out_emission=_tbwu(decoded["alpha_out_emission"], _netuid),
1127
+ alpha_in_emission=_tbwu(decoded["alpha_in_emission"], _netuid),
1128
+ tao_in_emission=_tbwu(decoded["tao_in_emission"]),
1129
+ pending_alpha_emission=_tbwu(decoded["pending_alpha_emission"], _netuid),
1130
+ pending_root_emission=_tbwu(decoded["pending_root_emission"]),
1131
+ subnet_volume=_tbwu(decoded["subnet_volume"], _netuid),
1132
+ moving_price=Balance.from_tao(
1133
+ fixed_to_float(decoded.get("moving_price"), 32)
1134
+ ),
1135
+ # Hparams for epoch
1136
+ rho=decoded["rho"],
1137
+ kappa=decoded["kappa"],
1138
+ # Validator params
1139
+ min_allowed_weights=u16tf(decoded["min_allowed_weights"]),
1140
+ max_weights_limit=u16tf(decoded["max_weights_limit"]),
1141
+ weights_version=decoded["weights_version"],
1142
+ weights_rate_limit=decoded["weights_rate_limit"],
1143
+ activity_cutoff=decoded["activity_cutoff"],
1144
+ max_validators=decoded["max_validators"],
1145
+ # Registration
1146
+ num_uids=decoded["num_uids"],
1147
+ max_uids=decoded["max_uids"],
1148
+ burn=_tbwu(decoded["burn"]),
1149
+ difficulty=u64tf(decoded["difficulty"]),
1150
+ registration_allowed=decoded["registration_allowed"],
1151
+ pow_registration_allowed=decoded["pow_registration_allowed"],
1152
+ immunity_period=decoded["immunity_period"],
1153
+ min_difficulty=u64tf(decoded["min_difficulty"]),
1154
+ max_difficulty=u64tf(decoded["max_difficulty"]),
1155
+ min_burn=_tbwu(decoded["min_burn"]),
1156
+ max_burn=_tbwu(decoded["max_burn"]),
1157
+ adjustment_alpha=u64tf(decoded["adjustment_alpha"]),
1158
+ adjustment_interval=decoded["adjustment_interval"],
1159
+ target_regs_per_interval=decoded["target_regs_per_interval"],
1160
+ max_regs_per_block=decoded["max_regs_per_block"],
1161
+ serving_rate_limit=decoded["serving_rate_limit"],
1162
+ # CR
1163
+ commit_reveal_weights_enabled=decoded["commit_reveal_weights_enabled"],
1164
+ commit_reveal_period=decoded["commit_reveal_period"],
1165
+ # Bonds
1166
+ liquid_alpha_enabled=decoded["liquid_alpha_enabled"],
1167
+ alpha_high=u16tf(decoded["alpha_high"]),
1168
+ alpha_low=u16tf(decoded["alpha_low"]),
1169
+ bonds_moving_avg=u64tf(decoded["bonds_moving_avg"]),
1170
+ # Metagraph info.
1171
+ hotkeys=[decode_account_id(ck) for ck in decoded.get("hotkeys", [])],
1172
+ coldkeys=[decode_account_id(hk) for hk in decoded.get("coldkeys", [])],
1173
+ identities=decoded["identities"],
1174
+ axons=decoded.get("axons", []),
1175
+ active=decoded["active"],
1176
+ validator_permit=decoded["validator_permit"],
1177
+ pruning_score=[u16tf(ps) for ps in decoded.get("pruning_score", [])],
1178
+ last_update=decoded["last_update"],
1179
+ emission=[_tbwu(em, _netuid) for em in decoded.get("emission", [])],
1180
+ dividends=[u16tf(dv) for dv in decoded.get("dividends", [])],
1181
+ incentives=[u16tf(ic) for ic in decoded.get("incentives", [])],
1182
+ consensus=[u16tf(cs) for cs in decoded.get("consensus", [])],
1183
+ trust=[u16tf(tr) for tr in decoded.get("trust", [])],
1184
+ rank=[u16tf(rk) for rk in decoded.get("rank", [])],
1185
+ block_at_registration=decoded["block_at_registration"],
1186
+ alpha_stake=[_tbwu(ast, _netuid) for ast in decoded["alpha_stake"]],
1187
+ tao_stake=[_tbwu(ts) for ts in decoded["tao_stake"]],
1188
+ total_stake=[_tbwu(ts, _netuid) for ts in decoded["total_stake"]],
1189
+ # Dividend break down
1190
+ tao_dividends_per_hotkey=[
1191
+ (decode_account_id(alpha[0]), _tbwu(alpha[1]))
1192
+ for alpha in decoded["tao_dividends_per_hotkey"]
1193
+ ],
1194
+ alpha_dividends_per_hotkey=[
1195
+ (decode_account_id(adphk[0]), _tbwu(adphk[1], _netuid))
1196
+ for adphk in decoded["alpha_dividends_per_hotkey"]
1197
+ ],
1198
+ )
1199
+
1200
+
1201
+ @dataclass
1202
+ class SimSwapResult:
1203
+ tao_amount: Balance
1204
+ alpha_amount: Balance
1205
+ tao_fee: Balance
1206
+ alpha_fee: Balance
1207
+
1208
+ @classmethod
1209
+ def from_dict(cls, d: dict, netuid: int) -> "SimSwapResult":
1210
+ return cls(
1211
+ tao_amount=Balance.from_meshlet(d["tao_amount"]).set_unit(0),
1212
+ alpha_amount=Balance.from_meshlet(d["alpha_amount"]).set_unit(netuid),
1213
+ tao_fee=Balance.from_meshlet(d["tao_fee"]).set_unit(0),
1214
+ alpha_fee=Balance.from_meshlet(d["alpha_fee"]).set_unit(netuid),
1215
+ )
1216
+
1217
+
1218
+ @dataclass
1219
+ class CrowdloanData(InfoBase):
1220
+ creator: Optional[str]
1221
+ funds_account: Optional[str]
1222
+ deposit: Balance
1223
+ min_contribution: Balance
1224
+ cap: Balance
1225
+ raised: Balance
1226
+ end: int
1227
+ finalized: bool
1228
+ contributors_count: int
1229
+ target_address: Optional[str]
1230
+ has_call: bool
1231
+ call_details: Optional[dict] = None
1232
+
1233
+ @classmethod
1234
+ def _fix_decoded(cls, decoded: dict[str, Any]) -> "CrowdloanData":
1235
+ creator = (
1236
+ decode_account_id(creator_raw)
1237
+ if (creator_raw := decoded.get("creator"))
1238
+ else None
1239
+ )
1240
+ funds_account = (
1241
+ decode_account_id(funds_raw)
1242
+ if (funds_raw := decoded.get("funds_account"))
1243
+ else None
1244
+ )
1245
+ target_address = (
1246
+ decode_account_id(target_raw)
1247
+ if (target_raw := decoded.get("target_address"))
1248
+ else None
1249
+ )
1250
+ return cls(
1251
+ creator=creator,
1252
+ funds_account=funds_account,
1253
+ deposit=Balance.from_meshlet(int(decoded["deposit"])),
1254
+ min_contribution=Balance.from_meshlet(int(decoded["min_contribution"])),
1255
+ cap=Balance.from_meshlet(int(decoded["cap"])),
1256
+ raised=Balance.from_meshlet(int(decoded["raised"])),
1257
+ end=int(decoded["end"]),
1258
+ finalized=bool(decoded["finalized"]),
1259
+ contributors_count=int(decoded["contributors_count"]),
1260
+ target_address=target_address,
1261
+ has_call=bool(decoded["call"]),
1262
+ call_details=decoded["call_details"],
1263
+ )