htcli 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. htcli-1.1.0.dist-info/METADATA +509 -0
  2. htcli-1.1.0.dist-info/RECORD +140 -0
  3. htcli-1.1.0.dist-info/WHEEL +4 -0
  4. htcli-1.1.0.dist-info/entry_points.txt +2 -0
  5. htcli-1.1.0.dist-info/licenses/LICENSE +21 -0
  6. src/__init__.py +0 -0
  7. src/htcli/__init__.py +5 -0
  8. src/htcli/client/__init__.py +338 -0
  9. src/htcli/client/extrinsics/__init__.py +26 -0
  10. src/htcli/client/extrinsics/base.py +487 -0
  11. src/htcli/client/extrinsics/consensus.py +79 -0
  12. src/htcli/client/extrinsics/governance.py +714 -0
  13. src/htcli/client/extrinsics/identity.py +490 -0
  14. src/htcli/client/extrinsics/node.py +1054 -0
  15. src/htcli/client/extrinsics/overwatch.py +401 -0
  16. src/htcli/client/extrinsics/staking.py +1504 -0
  17. src/htcli/client/extrinsics/subnet.py +2218 -0
  18. src/htcli/client/extrinsics/validator.py +203 -0
  19. src/htcli/client/extrinsics/wallet.py +323 -0
  20. src/htcli/client/offchain/__init__.py +10 -0
  21. src/htcli/client/offchain/backup.py +385 -0
  22. src/htcli/client/offchain/config.py +541 -0
  23. src/htcli/client/offchain/wallet.py +839 -0
  24. src/htcli/client/rpc/__init__.py +20 -0
  25. src/htcli/client/rpc/chain.py +568 -0
  26. src/htcli/client/rpc/node.py +783 -0
  27. src/htcli/client/rpc/overwatch.py +680 -0
  28. src/htcli/client/rpc/staking.py +216 -0
  29. src/htcli/client/rpc/subnet.py +2104 -0
  30. src/htcli/client/rpc/wallet.py +912 -0
  31. src/htcli/commands/__init__.py +31 -0
  32. src/htcli/commands/chain/__init__.py +66 -0
  33. src/htcli/commands/chain/display.py +204 -0
  34. src/htcli/commands/chain/handlers.py +260 -0
  35. src/htcli/commands/config/__init__.py +158 -0
  36. src/htcli/commands/config/display.py +353 -0
  37. src/htcli/commands/config/handlers.py +347 -0
  38. src/htcli/commands/config/prompts.py +357 -0
  39. src/htcli/commands/consensus/__init__.py +61 -0
  40. src/htcli/commands/consensus/handlers.py +100 -0
  41. src/htcli/commands/governance/__init__.py +49 -0
  42. src/htcli/commands/governance/handlers.py +81 -0
  43. src/htcli/commands/node/__init__.py +304 -0
  44. src/htcli/commands/node/display.py +749 -0
  45. src/htcli/commands/node/error_handling.py +470 -0
  46. src/htcli/commands/node/handlers.py +844 -0
  47. src/htcli/commands/node/prompts.py +346 -0
  48. src/htcli/commands/overwatch/__init__.py +219 -0
  49. src/htcli/commands/overwatch/display.py +396 -0
  50. src/htcli/commands/overwatch/error_handling.py +276 -0
  51. src/htcli/commands/overwatch/handlers.py +443 -0
  52. src/htcli/commands/overwatch/prompts.py +359 -0
  53. src/htcli/commands/stake/__init__.py +736 -0
  54. src/htcli/commands/stake/display.py +1103 -0
  55. src/htcli/commands/stake/error_handling.py +425 -0
  56. src/htcli/commands/stake/handlers.py +1902 -0
  57. src/htcli/commands/stake/prompts.py +1080 -0
  58. src/htcli/commands/subnet/__init__.py +639 -0
  59. src/htcli/commands/subnet/display.py +801 -0
  60. src/htcli/commands/subnet/error_handling.py +524 -0
  61. src/htcli/commands/subnet/handlers.py +2855 -0
  62. src/htcli/commands/subnet/prompts.py +1225 -0
  63. src/htcli/commands/validator/__init__.py +192 -0
  64. src/htcli/commands/validator/display.py +54 -0
  65. src/htcli/commands/validator/handlers.py +340 -0
  66. src/htcli/commands/wallet/__init__.py +546 -0
  67. src/htcli/commands/wallet/display.py +806 -0
  68. src/htcli/commands/wallet/error_handling.py +210 -0
  69. src/htcli/commands/wallet/handlers.py +3040 -0
  70. src/htcli/commands/wallet/prompts.py +1518 -0
  71. src/htcli/config.py +184 -0
  72. src/htcli/dependencies.py +186 -0
  73. src/htcli/errors/__init__.py +63 -0
  74. src/htcli/errors/base.py +141 -0
  75. src/htcli/errors/display.py +20 -0
  76. src/htcli/errors/handlers.py +710 -0
  77. src/htcli/main.py +343 -0
  78. src/htcli/models/__init__.py +21 -0
  79. src/htcli/models/enums/enum_types.py +35 -0
  80. src/htcli/models/errors.py +103 -0
  81. src/htcli/models/requests/__init__.py +197 -0
  82. src/htcli/models/requests/config.py +70 -0
  83. src/htcli/models/requests/consensus.py +19 -0
  84. src/htcli/models/requests/governance.py +38 -0
  85. src/htcli/models/requests/identity.py +51 -0
  86. src/htcli/models/requests/key.py +22 -0
  87. src/htcli/models/requests/node.py +91 -0
  88. src/htcli/models/requests/overwatch.py +64 -0
  89. src/htcli/models/requests/staking.py +580 -0
  90. src/htcli/models/requests/subnet.py +195 -0
  91. src/htcli/models/requests/validator.py +139 -0
  92. src/htcli/models/requests/wallet.py +118 -0
  93. src/htcli/models/responses/__init__.py +147 -0
  94. src/htcli/models/responses/base.py +18 -0
  95. src/htcli/models/responses/chain.py +39 -0
  96. src/htcli/models/responses/config.py +58 -0
  97. src/htcli/models/responses/identity.py +102 -0
  98. src/htcli/models/responses/overwatch.py +51 -0
  99. src/htcli/models/responses/staking.py +502 -0
  100. src/htcli/models/responses/subnet.py +856 -0
  101. src/htcli/models/responses/wallet.py +185 -0
  102. src/htcli/ui/__init__.py +87 -0
  103. src/htcli/ui/colors.py +309 -0
  104. src/htcli/ui/components/__init__.py +60 -0
  105. src/htcli/ui/components/panels.py +174 -0
  106. src/htcli/ui/components/progress.py +166 -0
  107. src/htcli/ui/components/spinners.py +92 -0
  108. src/htcli/ui/components/tables.py +809 -0
  109. src/htcli/ui/components/trees.py +721 -0
  110. src/htcli/ui/display.py +336 -0
  111. src/htcli/ui/prompts.py +870 -0
  112. src/htcli/utils/__init__.py +76 -0
  113. src/htcli/utils/blockchain/__init__.py +75 -0
  114. src/htcli/utils/blockchain/formatting.py +368 -0
  115. src/htcli/utils/blockchain/patches.py +286 -0
  116. src/htcli/utils/blockchain/peer_id.py +186 -0
  117. src/htcli/utils/blockchain/staking.py +448 -0
  118. src/htcli/utils/blockchain/type_registry.py +1373 -0
  119. src/htcli/utils/blockchain/validation.py +179 -0
  120. src/htcli/utils/cache.py +613 -0
  121. src/htcli/utils/constants.py +38 -0
  122. src/htcli/utils/legacy/__init__.py +12 -0
  123. src/htcli/utils/legacy/colors.py +311 -0
  124. src/htcli/utils/legacy/crypto.py +1176 -0
  125. src/htcli/utils/legacy/formatting.py +452 -0
  126. src/htcli/utils/legacy/interactive.py +306 -0
  127. src/htcli/utils/legacy/subnet_manifest.py +265 -0
  128. src/htcli/utils/legacy/validation.py +488 -0
  129. src/htcli/utils/logging.py +183 -0
  130. src/htcli/utils/network/__init__.py +20 -0
  131. src/htcli/utils/network/subnet.py +344 -0
  132. src/htcli/utils/prompts.py +27 -0
  133. src/htcli/utils/scale_codec.py +155 -0
  134. src/htcli/utils/validation/__init__.py +57 -0
  135. src/htcli/utils/validation/prompt_validators.py +267 -0
  136. src/htcli/utils/wallet/__init__.py +65 -0
  137. src/htcli/utils/wallet/auth.py +151 -0
  138. src/htcli/utils/wallet/core.py +1069 -0
  139. src/htcli/utils/wallet/crypto.py +1615 -0
  140. src/htcli/utils/wallet/migration.py +159 -0
@@ -0,0 +1,714 @@
1
+ """
2
+ Governance extrinsics for HTCLI.
3
+ """
4
+
5
+ from typing import Any, Optional
6
+
7
+ from substrateinterface import Keypair, SubstrateInterface
8
+
9
+ from ...models.requests import (
10
+ GovernanceCollectiveRemoveOverwatchNodeRequest,
11
+ GovernanceCollectiveRemoveSubnetNodeRequest,
12
+ GovernanceCollectiveRemoveSubnetRequest,
13
+ GovernanceParameterUpdateRequest,
14
+ GovernancePauseRequest,
15
+ GovernanceUnpauseRequest,
16
+ )
17
+ from ...utils.logging import get_logger
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ class GovernanceExtrinsics:
23
+ """Client for governance-related extrinsics."""
24
+
25
+ def __init__(self, substrate: Optional[SubstrateInterface] = None):
26
+ """Initialize the governance client."""
27
+ self.substrate = substrate
28
+
29
+ # ============================================================================
30
+ # NETWORK PAUSE/UNPAUSE
31
+ # ============================================================================
32
+
33
+ def pause_network(
34
+ self, request: GovernancePauseRequest, keypair: Keypair
35
+ ) -> dict[str, Any]:
36
+ """
37
+ Pause the network (governance only).
38
+
39
+ Args:
40
+ request: Network pause request
41
+ keypair: Keypair for signing the transaction (must be governance)
42
+
43
+ Returns:
44
+ dictionary with operation result
45
+ """
46
+ try:
47
+ logger.info("Pausing network")
48
+
49
+ call = self.substrate.compose_call(
50
+ call_module="Network", call_function="pause_network", call_params={}
51
+ )
52
+
53
+ response = self._submit_extrinsic(call, keypair)
54
+
55
+ if response["success"]:
56
+ response["message"] = "Network paused successfully"
57
+
58
+ return response
59
+
60
+ except Exception as e:
61
+ logger.error(f"Error pausing network: {e}")
62
+ return {"success": False, "error": str(e)}
63
+
64
+ def unpause_network(
65
+ self, request: GovernanceUnpauseRequest, keypair: Keypair
66
+ ) -> dict[str, Any]:
67
+ """
68
+ Unpause the network (governance only).
69
+
70
+ Args:
71
+ request: Network unpause request
72
+ keypair: Keypair for signing the transaction (must be governance)
73
+
74
+ Returns:
75
+ dictionary with operation result
76
+ """
77
+ try:
78
+ logger.info("Unpausing network")
79
+
80
+ call = self.substrate.compose_call(
81
+ call_module="Network", call_function="unpause_network", call_params={}
82
+ )
83
+
84
+ response = self._submit_extrinsic(call, keypair)
85
+
86
+ if response["success"]:
87
+ response["message"] = "Network unpaused successfully"
88
+
89
+ return response
90
+
91
+ except Exception as e:
92
+ logger.error(f"Error unpausing network: {e}")
93
+ return {"success": False, "error": str(e)}
94
+
95
+ # ============================================================================
96
+ # COLLECTIVE REMOVAL OPERATIONS
97
+ # ============================================================================
98
+
99
+ def collective_remove_subnet(
100
+ self, request: GovernanceCollectiveRemoveSubnetRequest, keypair: Keypair
101
+ ) -> dict[str, Any]:
102
+ """
103
+ Remove a subnet collectively (governance only).
104
+
105
+ Args:
106
+ request: Collective subnet removal request
107
+ keypair: Keypair for signing the transaction (must be governance)
108
+
109
+ Returns:
110
+ dictionary with operation result
111
+ """
112
+ try:
113
+ logger.info(f"Collectively removing subnet {request.subnet_id}")
114
+
115
+ call = self.substrate.compose_call(
116
+ call_module="Network",
117
+ call_function="collective_remove_subnet",
118
+ call_params={"subnet_id": request.subnet_id},
119
+ )
120
+
121
+ response = self._submit_extrinsic(call, keypair)
122
+
123
+ if response["success"]:
124
+ response["message"] = f"Subnet {request.subnet_id} removed collectively"
125
+
126
+ return response
127
+
128
+ except Exception as e:
129
+ logger.error(f"Error collectively removing subnet: {e}")
130
+ return {"success": False, "error": str(e)}
131
+
132
+ def collective_remove_subnet_node(
133
+ self, request: GovernanceCollectiveRemoveSubnetNodeRequest, keypair: Keypair
134
+ ) -> dict[str, Any]:
135
+ """
136
+ Remove a subnet node collectively (governance only).
137
+
138
+ Args:
139
+ request: Collective subnet node removal request
140
+ keypair: Keypair for signing the transaction (must be governance)
141
+
142
+ Returns:
143
+ dictionary with operation result
144
+ """
145
+ try:
146
+ logger.info(
147
+ f"Collectively removing subnet {request.subnet_id} node {request.subnet_node_id}"
148
+ )
149
+
150
+ call = self.substrate.compose_call(
151
+ call_module="Network",
152
+ call_function="collective_remove_subnet_node",
153
+ call_params={
154
+ "subnet_id": request.subnet_id,
155
+ "subnet_node_id": request.subnet_node_id,
156
+ },
157
+ )
158
+
159
+ response = self._submit_extrinsic(call, keypair)
160
+
161
+ if response["success"]:
162
+ response["message"] = (
163
+ f"Subnet {request.subnet_id} node {request.subnet_node_id} removed collectively"
164
+ )
165
+
166
+ return response
167
+
168
+ except Exception as e:
169
+ logger.error(f"Error collectively removing subnet node: {e}")
170
+ return {"success": False, "error": str(e)}
171
+
172
+ def collective_remove_overwatch_node(
173
+ self, request: GovernanceCollectiveRemoveOverwatchNodeRequest, keypair: Keypair
174
+ ) -> dict[str, Any]:
175
+ """
176
+ Remove an overwatch node collectively (governance only).
177
+
178
+ Args:
179
+ request: Collective overwatch node removal request
180
+ keypair: Keypair for signing the transaction (must be governance)
181
+
182
+ Returns:
183
+ dictionary with operation result
184
+ """
185
+ try:
186
+ logger.info(
187
+ f"Collectively removing overwatch node {request.overwatch_node_id}"
188
+ )
189
+
190
+ call = self.substrate.compose_call(
191
+ call_module="Network",
192
+ call_function="collective_remove_overwatch_node",
193
+ call_params={"overwatch_node_id": request.overwatch_node_id},
194
+ )
195
+
196
+ response = self._submit_extrinsic(call, keypair)
197
+
198
+ if response["success"]:
199
+ response["message"] = (
200
+ f"Overwatch node {request.overwatch_node_id} removed collectively"
201
+ )
202
+
203
+ return response
204
+
205
+ except Exception as e:
206
+ logger.error(f"Error collectively removing overwatch node: {e}")
207
+ return {"success": False, "error": str(e)}
208
+
209
+ # ============================================================================
210
+ # PARAMETER UPDATES
211
+ # ============================================================================
212
+
213
+ def set_min_delegate_stake_percentage(
214
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
215
+ ) -> dict[str, Any]:
216
+ """
217
+ Set minimum delegate stake percentage (governance only).
218
+
219
+ Args:
220
+ request: Parameter update request
221
+ keypair: Keypair for signing the transaction (must be governance)
222
+
223
+ Returns:
224
+ dictionary with operation result
225
+ """
226
+ try:
227
+ logger.info(f"Setting min delegate stake percentage to {request.value}")
228
+
229
+ call = self.substrate.compose_call(
230
+ call_module="Network",
231
+ call_function="set_min_delegate_stake_percentage",
232
+ call_params={"value": request.value},
233
+ )
234
+
235
+ response = self._submit_extrinsic(call, keypair)
236
+
237
+ if response["success"]:
238
+ response["message"] = (
239
+ f"Min delegate stake percentage set to {request.value}"
240
+ )
241
+
242
+ return response
243
+
244
+ except Exception as e:
245
+ logger.error(f"Error setting min delegate stake percentage: {e}")
246
+ return {"success": False, "error": str(e)}
247
+
248
+ def set_max_delegate_stake_percentage(
249
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
250
+ ) -> dict[str, Any]:
251
+ """
252
+ Set maximum delegate stake percentage (governance only).
253
+
254
+ Args:
255
+ request: Parameter update request
256
+ keypair: Keypair for signing the transaction (must be governance)
257
+
258
+ Returns:
259
+ dictionary with operation result
260
+ """
261
+ try:
262
+ logger.info(f"Setting max delegate stake percentage to {request.value}")
263
+
264
+ call = self.substrate.compose_call(
265
+ call_module="Network",
266
+ call_function="set_max_delegate_stake_percentage",
267
+ call_params={"value": request.value},
268
+ )
269
+
270
+ response = self._submit_extrinsic(call, keypair)
271
+
272
+ if response["success"]:
273
+ response["message"] = (
274
+ f"Max delegate stake percentage set to {request.value}"
275
+ )
276
+
277
+ return response
278
+
279
+ except Exception as e:
280
+ logger.error(f"Error setting max delegate stake percentage: {e}")
281
+ return {"success": False, "error": str(e)}
282
+
283
+ def set_min_max_registered_nodes(
284
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
285
+ ) -> dict[str, Any]:
286
+ """
287
+ Set minimum max registered nodes (governance only).
288
+
289
+ Args:
290
+ request: Parameter update request
291
+ keypair: Keypair for signing the transaction (must be governance)
292
+
293
+ Returns:
294
+ dictionary with operation result
295
+ """
296
+ try:
297
+ logger.info(f"Setting min max registered nodes to {request.value}")
298
+
299
+ call = self.substrate.compose_call(
300
+ call_module="Network",
301
+ call_function="set_min_max_registered_nodes",
302
+ call_params={"value": request.value},
303
+ )
304
+
305
+ response = self._submit_extrinsic(call, keypair)
306
+
307
+ if response["success"]:
308
+ response["message"] = f"Min max registered nodes set to {request.value}"
309
+
310
+ return response
311
+
312
+ except Exception as e:
313
+ logger.error(f"Error setting min max registered nodes: {e}")
314
+ return {"success": False, "error": str(e)}
315
+
316
+ def set_max_max_registered_nodes(
317
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
318
+ ) -> dict[str, Any]:
319
+ """
320
+ Set maximum max registered nodes (governance only).
321
+
322
+ Args:
323
+ request: Parameter update request
324
+ keypair: Keypair for signing the transaction (must be governance)
325
+
326
+ Returns:
327
+ dictionary with operation result
328
+ """
329
+ try:
330
+ logger.info(f"Setting max max registered nodes to {request.value}")
331
+
332
+ call = self.substrate.compose_call(
333
+ call_module="Network",
334
+ call_function="set_max_max_registered_nodes",
335
+ call_params={"value": request.value},
336
+ )
337
+
338
+ response = self._submit_extrinsic(call, keypair)
339
+
340
+ if response["success"]:
341
+ response["message"] = f"Max max registered nodes set to {request.value}"
342
+
343
+ return response
344
+
345
+ except Exception as e:
346
+ logger.error(f"Error setting max max registered nodes: {e}")
347
+ return {"success": False, "error": str(e)}
348
+
349
+ def set_network_min_stake_balance(
350
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
351
+ ) -> dict[str, Any]:
352
+ """
353
+ Set network minimum stake balance (governance only).
354
+
355
+ Args:
356
+ request: Parameter update request
357
+ keypair: Keypair for signing the transaction (must be governance)
358
+
359
+ Returns:
360
+ dictionary with operation result
361
+ """
362
+ try:
363
+ logger.info(f"Setting network min stake balance to {request.value}")
364
+
365
+ call = self.substrate.compose_call(
366
+ call_module="Network",
367
+ call_function="set_network_min_stake_balance",
368
+ call_params={"value": request.value},
369
+ )
370
+
371
+ response = self._submit_extrinsic(call, keypair)
372
+
373
+ if response["success"]:
374
+ response["message"] = (
375
+ f"Network min stake balance set to {request.value}"
376
+ )
377
+
378
+ return response
379
+
380
+ except Exception as e:
381
+ logger.error(f"Error setting network min stake balance: {e}")
382
+ return {"success": False, "error": str(e)}
383
+
384
+ def set_network_max_stake_balance(
385
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
386
+ ) -> dict[str, Any]:
387
+ """
388
+ Set network maximum stake balance (governance only).
389
+
390
+ Args:
391
+ request: Parameter update request
392
+ keypair: Keypair for signing the transaction (must be governance)
393
+
394
+ Returns:
395
+ dictionary with operation result
396
+ """
397
+ try:
398
+ logger.info(f"Setting network max stake balance to {request.value}")
399
+
400
+ call = self.substrate.compose_call(
401
+ call_module="Network",
402
+ call_function="set_network_max_stake_balance",
403
+ call_params={"value": request.value},
404
+ )
405
+
406
+ response = self._submit_extrinsic(call, keypair)
407
+
408
+ if response["success"]:
409
+ response["message"] = (
410
+ f"Network max stake balance set to {request.value}"
411
+ )
412
+
413
+ return response
414
+
415
+ except Exception as e:
416
+ logger.error(f"Error setting network max stake balance: {e}")
417
+ return {"success": False, "error": str(e)}
418
+
419
+ def set_tx_rate_limit(
420
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
421
+ ) -> dict[str, Any]:
422
+ """
423
+ Set transaction rate limit (governance only).
424
+
425
+ Args:
426
+ request: Parameter update request
427
+ keypair: Keypair for signing the transaction (must be governance)
428
+
429
+ Returns:
430
+ dictionary with operation result
431
+ """
432
+ try:
433
+ logger.info(f"Setting transaction rate limit to {request.value}")
434
+
435
+ call = self.substrate.compose_call(
436
+ call_module="Network",
437
+ call_function="set_tx_rate_limit",
438
+ call_params={"value": request.value},
439
+ )
440
+
441
+ response = self._submit_extrinsic(call, keypair)
442
+
443
+ if response["success"]:
444
+ response["message"] = f"Transaction rate limit set to {request.value}"
445
+
446
+ return response
447
+
448
+ except Exception as e:
449
+ logger.error(f"Error setting transaction rate limit: {e}")
450
+ return {"success": False, "error": str(e)}
451
+
452
+ def set_min_registration_cost(
453
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
454
+ ) -> dict[str, Any]:
455
+ """Set min registration cost."""
456
+ try:
457
+ logger.info(f"Setting min registration cost to {request.value}")
458
+ call = self.substrate.compose_call(
459
+ call_module="Network",
460
+ call_function="set_min_registration_cost",
461
+ call_params={"value": request.value},
462
+ )
463
+ return self._submit_extrinsic(call, keypair)
464
+ except Exception as e:
465
+ logger.error(f"Error setting min registration cost: {e}")
466
+ return {"success": False, "error": str(e)}
467
+
468
+ def set_target_registrations_per_interval(
469
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
470
+ ) -> dict[str, Any]:
471
+ """Set target registrations per interval."""
472
+ try:
473
+ logger.info(f"Setting target regs per interval to {request.value}")
474
+ call = self.substrate.compose_call(
475
+ call_module="Network",
476
+ call_function="set_target_registrations_per_interval",
477
+ call_params={"value": request.value},
478
+ )
479
+ return self._submit_extrinsic(call, keypair)
480
+ except Exception as e:
481
+ logger.error(f"Error setting target regs per interval: {e}")
482
+ return {"success": False, "error": str(e)}
483
+
484
+ def set_max_registrations_per_interval(
485
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
486
+ ) -> dict[str, Any]:
487
+ """Set max registrations per interval."""
488
+ try:
489
+ logger.info(f"Setting max regs per interval to {request.value}")
490
+ call = self.substrate.compose_call(
491
+ call_module="Network",
492
+ call_function="set_max_registrations_per_interval",
493
+ call_params={"value": request.value},
494
+ )
495
+ return self._submit_extrinsic(call, keypair)
496
+ except Exception as e:
497
+ logger.error(f"Error setting max regs per interval: {e}")
498
+ return {"success": False, "error": str(e)}
499
+
500
+ def set_adjustment_alpha(
501
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
502
+ ) -> dict[str, Any]:
503
+ """Set adjustment alpha."""
504
+ try:
505
+ logger.info(f"Setting adjustment alpha to {request.value}")
506
+ call = self.substrate.compose_call(
507
+ call_module="Network",
508
+ call_function="set_adjustment_alpha",
509
+ call_params={"value": request.value},
510
+ )
511
+ return self._submit_extrinsic(call, keypair)
512
+ except Exception as e:
513
+ logger.error(f"Error setting adjustment alpha: {e}")
514
+ return {"success": False, "error": str(e)}
515
+
516
+ def set_target_max_subnet_nodes(
517
+ self, request: GovernanceParameterUpdateRequest, keypair: Keypair
518
+ ) -> dict[str, Any]:
519
+ """Set target max subnet nodes."""
520
+ try:
521
+ logger.info(f"Setting target max subnet nodes to {request.value}")
522
+ call = self.substrate.compose_call(
523
+ call_module="Network",
524
+ call_function="set_target_max_subnet_nodes",
525
+ call_params={"value": request.value},
526
+ )
527
+ return self._submit_extrinsic(call, keypair)
528
+ except Exception as e:
529
+ logger.error(f"Error setting target max subnet nodes: {e}")
530
+ return {"success": False, "error": str(e)}
531
+
532
+ # ============================================================================
533
+ # QUERY METHODS
534
+ # ============================================================================
535
+
536
+ def get_network_state(self) -> str:
537
+ """
538
+ Get the current network state.
539
+
540
+ Returns:
541
+ Network state (Active/Paused)
542
+ """
543
+ try:
544
+ is_paused = self.substrate.query(
545
+ module="Network", storage_function="IsPaused"
546
+ ).value
547
+
548
+ return "Paused" if is_paused else "Active"
549
+
550
+ except Exception as e:
551
+ logger.error(f"Error getting network state: {e}")
552
+ return "Unknown"
553
+
554
+ def get_governance_parameters(self) -> dict[str, Any]:
555
+ """
556
+ Get current governance parameters.
557
+
558
+ Returns:
559
+ dictionary with governance parameters
560
+ """
561
+ try:
562
+ parameters = {}
563
+
564
+ # Query various governance parameters
565
+ parameter_queries = [
566
+ ("min_delegate_stake_percentage", "MinDelegateStakePercentage"),
567
+ ("max_delegate_stake_percentage", "MaxDelegateStakePercentage"),
568
+ ("min_max_registered_nodes", "MinMaxRegisteredNodes"),
569
+ ("max_max_registered_nodes", "MaxMaxRegisteredNodes"),
570
+ ("network_min_stake_balance", "NetworkMinStakeBalance"),
571
+ ("network_max_stake_balance", "NetworkMaxStakeBalance"),
572
+ ("tx_rate_limit", "TxRateLimit"),
573
+ ("epoch_length", "EpochLength"),
574
+ ("min_stake_balance", "MinStakeBalance"),
575
+ ("max_stake_balance", "MaxStakeBalance"),
576
+ ]
577
+
578
+ for param_name, storage_key in parameter_queries:
579
+ try:
580
+ value = self.substrate.query(
581
+ module="Network", storage_function=storage_key
582
+ ).value
583
+ parameters[param_name] = value
584
+ except Exception as e:
585
+ logger.warning(f"Could not query {param_name}: {e}")
586
+ parameters[param_name] = None
587
+
588
+ return parameters
589
+
590
+ except Exception as e:
591
+ logger.error(f"Error getting governance parameters: {e}")
592
+ return {}
593
+
594
+ def get_network_info(self) -> dict[str, Any]:
595
+ """
596
+ Get general network information.
597
+
598
+ Returns:
599
+ dictionary with network information
600
+ """
601
+ try:
602
+ info = {}
603
+
604
+ # Get basic network stats
605
+ total_subnets = (
606
+ self.substrate.query(
607
+ module="Network", storage_function="TotalSubnetUids"
608
+ ).value
609
+ or 0
610
+ )
611
+
612
+ total_nodes = (
613
+ self.substrate.query(
614
+ module="Network", storage_function="TotalSubnetNodes"
615
+ ).value
616
+ or 0
617
+ )
618
+
619
+ total_overwatch_nodes = (
620
+ self.substrate.query(
621
+ module="Network", storage_function="TotalOverwatchNodes"
622
+ ).value
623
+ or 0
624
+ )
625
+
626
+ current_epoch = self.get_current_epoch()
627
+ network_state = self.get_network_state()
628
+
629
+ info.update(
630
+ {
631
+ "total_subnets": total_subnets,
632
+ "total_nodes": total_nodes,
633
+ "total_overwatch_nodes": total_overwatch_nodes,
634
+ "current_epoch": current_epoch,
635
+ "network_state": network_state,
636
+ }
637
+ )
638
+
639
+ return info
640
+
641
+ except Exception as e:
642
+ logger.error(f"Error getting network info: {e}")
643
+ return {}
644
+
645
+ def get_current_epoch(self) -> int:
646
+ """
647
+ Get the current epoch number.
648
+
649
+ Returns:
650
+ Current epoch number
651
+ """
652
+ try:
653
+ current_block = self.substrate.get_block_number()
654
+ epoch_length = (
655
+ self.substrate.query(
656
+ module="Network", storage_function="EpochLength"
657
+ ).value
658
+ or 300
659
+ )
660
+
661
+ return current_block // epoch_length
662
+
663
+ except Exception as e:
664
+ logger.error(f"Error getting current epoch: {e}")
665
+ return 0
666
+
667
+ # ============================================================================
668
+ # PRIVATE HELPER METHODS
669
+ # ============================================================================
670
+
671
+ def _submit_extrinsic(self, call, keypair: Keypair) -> dict[str, Any]:
672
+ """Submit an extrinsic and return the result."""
673
+ try:
674
+ extrinsic = self.substrate.create_signed_extrinsic(
675
+ call=call,
676
+ keypair=keypair,
677
+ era={"period": 64}, # 64 block era
678
+ )
679
+
680
+ response = self.substrate.submit_extrinsic(
681
+ extrinsic, wait_for_inclusion=True, wait_for_finalization=True
682
+ )
683
+
684
+ if response.is_success:
685
+ return {
686
+ "success": True,
687
+ "extrinsic_hash": response.extrinsic_hash,
688
+ "block_hash": response.block_hash,
689
+ "block_number": response.block_number,
690
+ }
691
+ else:
692
+ error_msg = self._extract_error_message(response)
693
+ return {"success": False, "error": error_msg}
694
+
695
+ except Exception as e:
696
+ logger.error(f"Error submitting extrinsic: {e}")
697
+ return {"success": False, "error": str(e)}
698
+
699
+ def _extract_error_message(self, response) -> str:
700
+ """Extract error message from failed response."""
701
+ try:
702
+ for event in response.triggered_events:
703
+ if (
704
+ event.value["module_id"] == "System"
705
+ and event.value["event_id"] == "ExtrinsicFailed"
706
+ ):
707
+ error = event.value["attributes"][0]
708
+ if hasattr(error, "name"):
709
+ return f"Extrinsic failed: {error.name}"
710
+ return f"Extrinsic failed: {str(error)}"
711
+ except Exception as e:
712
+ logger.warning(f"Could not extract error message: {e}")
713
+
714
+ return "Unknown error occurred"