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,470 @@
1
+ """
2
+ Error handling utilities for subnet node commands.
3
+ Provides user-friendly error messages for all subnet node-related errors.
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ from ...ui.components import HTCLIPanel
9
+ from ...ui.display import HTCLIConsole
10
+
11
+
12
+ def handle_node_error(
13
+ error_msg: str,
14
+ subnet_id: Optional[int] = None,
15
+ subnet_node_id: Optional[int] = None,
16
+ operation: str = "operation",
17
+ client=None,
18
+ ) -> bool:
19
+ """
20
+ Handle subnet node-related errors with user-friendly messages.
21
+
22
+ Args:
23
+ error_msg: The error message from the blockchain
24
+ subnet_id: The subnet ID (if applicable)
25
+ subnet_node_id: The subnet node ID (if applicable)
26
+ operation: Description of the operation being performed
27
+ client: Optional client instance for fetching additional info
28
+
29
+ Returns:
30
+ bool: True if error was handled, False otherwise
31
+ """
32
+ console = HTCLIConsole()
33
+ subnet_id_str = f" {subnet_id}" if subnet_id is not None else ""
34
+ node_id_str = f" {subnet_node_id}" if subnet_node_id is not None else ""
35
+
36
+ # System-level errors (checked first)
37
+ if "Paused" in error_msg and "Subnet" not in error_msg:
38
+ error_panel = HTCLIPanel(
39
+ "The network is currently paused.\n\n"
40
+ "⏸️ All transactions are temporarily disabled on the network.\n\n"
41
+ "💡 Please wait for the network to resume operations.\n"
42
+ " Check network status or try again later.",
43
+ title="⏸️ Network Paused",
44
+ border_style="htcli.warning",
45
+ highlight=True,
46
+ )
47
+ error_panel.render(console.console)
48
+ return True
49
+
50
+ elif "BadOrigin" in error_msg or ("invalid" in error_msg.lower() and "signature" in error_msg.lower()):
51
+ error_panel = HTCLIPanel(
52
+ "Invalid transaction signature.\n\n"
53
+ "💡 This usually means:\n"
54
+ " - Your wallet is not properly unlocked\n"
55
+ " - The signing key doesn't match the account\n"
56
+ " - There's an issue with your wallet configuration\n\n"
57
+ " Try: htcli wallet unlock to unlock your wallet\n"
58
+ " Or check your wallet configuration: htcli wallet list",
59
+ title="❌ Invalid Signature",
60
+ border_style="htcli.error",
61
+ highlight=True,
62
+ )
63
+ error_panel.render(console.console)
64
+ return True
65
+
66
+ elif "TxRateLimitExceeded" in error_msg:
67
+ error_panel = HTCLIPanel(
68
+ "Transaction rate limit exceeded.\n\n"
69
+ "⏱️ You've exceeded the maximum number of transactions allowed for your account.\n\n"
70
+ "💡 Wait a moment before submitting another transaction.\n"
71
+ " Rate limits help prevent spam and ensure network stability.",
72
+ title="⏳ Rate Limit Exceeded",
73
+ border_style="htcli.warning",
74
+ highlight=True,
75
+ )
76
+ error_panel.render(console.console)
77
+ return True
78
+
79
+ # Common errors that apply to most operations
80
+ elif "InvalidSubnetId" in error_msg:
81
+ error_panel = HTCLIPanel(
82
+ f"Subnet{subnet_id_str} does not exist.\n\n"
83
+ f"💡 Check the subnet ID and try again.\n"
84
+ f" Use: htcli subnet list to see available subnets",
85
+ title="❌ Invalid Subnet ID",
86
+ border_style="htcli.error",
87
+ highlight=True,
88
+ )
89
+ error_panel.render(console.console)
90
+ return True
91
+
92
+ elif "InvalidSubnetNodeId" in error_msg:
93
+ error_panel = HTCLIPanel(
94
+ f"Subnet node{node_id_str} does not exist in subnet{subnet_id_str}.\n\n"
95
+ f"💡 Check the subnet node ID and try again.\n"
96
+ f" Use: htcli node list --subnet-id{subnet_id_str} to see available nodes",
97
+ title="❌ Invalid Subnet Node ID",
98
+ border_style="htcli.error",
99
+ highlight=True,
100
+ )
101
+ error_panel.render(console.console)
102
+ return True
103
+
104
+ elif "NotKeyOwner" in error_msg:
105
+ error_panel = HTCLIPanel(
106
+ f"You are not the owner of this subnet node{node_id_str}.\n\n"
107
+ f"💡 Make sure you're using the correct coldkey or hotkey wallet.\n"
108
+ f" Only the node owner (coldkey or hotkey) can perform this operation.\n"
109
+ f" Check node ownership: htcli node info --subnet-id{subnet_id_str} --node-id{node_id_str}",
110
+ title="❌ Permission Denied",
111
+ border_style="htcli.error",
112
+ highlight=True,
113
+ )
114
+ error_panel.render(console.console)
115
+ return True
116
+
117
+ elif "SubnetIsPaused" in error_msg:
118
+ error_panel = HTCLIPanel(
119
+ f"Subnet{subnet_id_str} is paused and cannot perform this action.\n\n"
120
+ f"💡 The subnet must be unpaused first.\n"
121
+ f" Use: htcli subnet unpause --subnet-id{subnet_id_str}",
122
+ title="⏸️ Subnet Paused",
123
+ border_style="htcli.warning",
124
+ highlight=True,
125
+ )
126
+ error_panel.render(console.console)
127
+ return True
128
+
129
+ elif "SubnetMustBeRegisteringOrActivated" in error_msg:
130
+ error_panel = HTCLIPanel(
131
+ f"Cannot register node to subnet{subnet_id_str} during enactment period.\n\n"
132
+ f"💡 Node registration is blocked during the enactment period.\n"
133
+ f" Nodes can only be registered during:\n"
134
+ f" - Registration period (before activation)\n"
135
+ f" - Active state (after activation)\n\n"
136
+ f" Wait for the enactment period to end and try again.",
137
+ title="⚠️ Registration Blocked",
138
+ border_style="htcli.warning",
139
+ highlight=True,
140
+ )
141
+ error_panel.render(console.console)
142
+ return True
143
+
144
+ # Registration-specific errors
145
+ elif "ColdkeyMatchesHotkey" in error_msg:
146
+ error_panel = HTCLIPanel(
147
+ "Coldkey and hotkey must be different.\n\n"
148
+ "💡 For security reasons, the coldkey and hotkey cannot be the same account.\n"
149
+ " Use different accounts for coldkey (owner) and hotkey (node operator).",
150
+ title="❌ Invalid Key Configuration",
151
+ border_style="htcli.error",
152
+ highlight=True,
153
+ )
154
+ error_panel.render(console.console)
155
+ return True
156
+
157
+ elif "HotkeyHasOwner" in error_msg:
158
+ error_panel = HTCLIPanel(
159
+ "This hotkey is already in use by another node.\n\n"
160
+ "💡 Each hotkey can only operate one node across the entire network.\n"
161
+ " Use a different hotkey that is not already registered.",
162
+ title="❌ Hotkey Already In Use",
163
+ border_style="htcli.error",
164
+ highlight=True,
165
+ )
166
+ error_panel.render(console.console)
167
+ return True
168
+
169
+ elif "HotkeyAlreadyRegisteredToColdkey" in error_msg:
170
+ error_panel = HTCLIPanel(
171
+ "This hotkey is already registered to your coldkey.\n\n"
172
+ "💡 You cannot register the same hotkey twice.\n"
173
+ " Use a different hotkey for this node.",
174
+ title="❌ Hotkey Already Registered",
175
+ border_style="htcli.error",
176
+ highlight=True,
177
+ )
178
+ error_panel.render(console.console)
179
+ return True
180
+
181
+ elif "PeerIdsMustBeUnique" in error_msg:
182
+ error_panel = HTCLIPanel(
183
+ "Peer IDs must be unique from each other.\n\n"
184
+ "💡 The peer_id, bootnode_peer_id, and client_peer_id must all be different.\n"
185
+ " Each peer ID serves a different network function and must be distinct.",
186
+ title="❌ Duplicate Peer IDs",
187
+ border_style="htcli.error",
188
+ highlight=True,
189
+ )
190
+ error_panel.render(console.console)
191
+ return True
192
+
193
+ elif "InvalidPeerId" in error_msg:
194
+ error_panel = HTCLIPanel(
195
+ "Invalid peer ID format.\n\n"
196
+ "💡 Peer IDs must be valid libp2p format (base58-encoded).\n"
197
+ " Check your peer ID format and try again.",
198
+ title="❌ Invalid Peer ID",
199
+ border_style="htcli.error",
200
+ highlight=True,
201
+ )
202
+ error_panel.render(console.console)
203
+ return True
204
+
205
+ elif "InvalidBootnodePeerId" in error_msg:
206
+ error_panel = HTCLIPanel(
207
+ "Invalid bootnode peer ID format.\n\n"
208
+ "💡 Bootnode peer IDs must be valid libp2p format (base58-encoded).\n"
209
+ " Check your bootnode peer ID format and try again.",
210
+ title="❌ Invalid Bootnode Peer ID",
211
+ border_style="htcli.error",
212
+ highlight=True,
213
+ )
214
+ error_panel.render(console.console)
215
+ return True
216
+
217
+ elif "InvalidClientPeerId" in error_msg:
218
+ error_panel = HTCLIPanel(
219
+ "Invalid client peer ID format.\n\n"
220
+ "💡 Client peer IDs must be valid libp2p format (base58-encoded).\n"
221
+ " Check your client peer ID format and try again.",
222
+ title="❌ Invalid Client Peer ID",
223
+ border_style="htcli.error",
224
+ highlight=True,
225
+ )
226
+ error_panel.render(console.console)
227
+ return True
228
+
229
+ elif "PeerIdExist" in error_msg:
230
+ error_panel = HTCLIPanel(
231
+ f"This peer ID is already in use in subnet{subnet_id_str}.\n\n"
232
+ f"💡 Peer IDs must be unique within each subnet.\n"
233
+ f" Use a different peer ID that is not already registered.",
234
+ title="❌ Peer ID Already Exists",
235
+ border_style="htcli.error",
236
+ highlight=True,
237
+ )
238
+ error_panel.render(console.console)
239
+ return True
240
+
241
+ elif "BootnodePeerIdExist" in error_msg:
242
+ error_panel = HTCLIPanel(
243
+ f"This bootnode peer ID is already in use in subnet{subnet_id_str}.\n\n"
244
+ f"💡 Bootnode peer IDs must be unique within each subnet.\n"
245
+ f" Use a different bootnode peer ID that is not already registered.",
246
+ title="❌ Bootnode Peer ID Already Exists",
247
+ border_style="htcli.error",
248
+ highlight=True,
249
+ )
250
+ error_panel.render(console.console)
251
+ return True
252
+
253
+ elif "ClientPeerIdExist" in error_msg:
254
+ error_panel = HTCLIPanel(
255
+ f"This client peer ID is already in use in subnet{subnet_id_str}.\n\n"
256
+ f"💡 Client peer IDs must be unique within each subnet.\n"
257
+ f" Use a different client peer ID that is not already registered.",
258
+ title="❌ Client Peer ID Already Exists",
259
+ border_style="htcli.error",
260
+ highlight=True,
261
+ )
262
+ error_panel.render(console.console)
263
+ return True
264
+
265
+ elif "BootnodeExist" in error_msg:
266
+ error_panel = HTCLIPanel(
267
+ f"This bootnode multiaddr is already in use in subnet{subnet_id_str}.\n\n"
268
+ f"💡 Bootnode multiaddrs must be unique within each subnet.\n"
269
+ f" Use a different bootnode multiaddr that is not already registered.",
270
+ title="❌ Bootnode Already Exists",
271
+ border_style="htcli.error",
272
+ highlight=True,
273
+ )
274
+ error_panel.render(console.console)
275
+ return True
276
+
277
+ elif "ColdkeyRegistrationWhitelist" in error_msg:
278
+ error_panel = HTCLIPanel(
279
+ "Your coldkey is not whitelisted for node registration.\n\n"
280
+ "💡 During the subnet registration period, only whitelisted coldkeys can register nodes.\n"
281
+ " Contact the subnet owner to get your coldkey added to the whitelist.",
282
+ title="❌ Not Whitelisted",
283
+ border_style="htcli.error",
284
+ highlight=True,
285
+ )
286
+ error_panel.render(console.console)
287
+ return True
288
+
289
+ elif "MaxRegisteredNodes" in error_msg:
290
+ error_panel = HTCLIPanel(
291
+ f"Subnet{subnet_id_str} has reached maximum node capacity.\n\n"
292
+ f"💡 The subnet has reached its maximum number of registered nodes.\n"
293
+ f" Wait for a node slot to become available or check if any nodes can be removed.",
294
+ title="❌ Subnet at Capacity",
295
+ border_style="htcli.error",
296
+ highlight=True,
297
+ )
298
+ error_panel.render(console.console)
299
+ return True
300
+
301
+ elif "MaxSubnetNodes" in error_msg:
302
+ error_panel = HTCLIPanel(
303
+ "Maximum subnet nodes reached.\n\n"
304
+ "💡 The subnet has reached its maximum node limit.\n"
305
+ " Wait for nodes to be removed or check subnet capacity.",
306
+ title="❌ Maximum Nodes Reached",
307
+ border_style="htcli.error",
308
+ highlight=True,
309
+ )
310
+ error_panel.render(console.console)
311
+ return True
312
+
313
+ elif "SubnetNodeUniqueParamTaken" in error_msg or "UniqueParameterTaken" in error_msg:
314
+ error_panel = HTCLIPanel(
315
+ f"This unique parameter is already in use in subnet{subnet_id_str}.\n\n"
316
+ f"💡 Unique parameters must be unique within each subnet.\n"
317
+ f" Use a different unique parameter value.",
318
+ title="❌ Unique Parameter Already Taken",
319
+ border_style="htcli.error",
320
+ highlight=True,
321
+ )
322
+ error_panel.render(console.console)
323
+ return True
324
+
325
+ elif "MaxBurnAmountExceeded" in error_msg:
326
+ error_panel = HTCLIPanel(
327
+ "Registration burn cost exceeds your maximum amount limit.\n\n"
328
+ "💡 The current registration burn cost is higher than your max_burn_amount.\n"
329
+ " This protects you from unexpected cost increases.\n"
330
+ " Increase your max_burn_amount parameter or wait for costs to decrease.",
331
+ title="❌ Burn Cost Exceeds Maximum",
332
+ border_style="htcli.error",
333
+ highlight=True,
334
+ )
335
+ error_panel.render(console.console)
336
+ return True
337
+
338
+ elif "BalanceBurnError" in error_msg:
339
+ error_panel = HTCLIPanel(
340
+ "Insufficient balance to pay registration burn fee.\n\n"
341
+ "💡 You don't have enough balance to cover the registration burn cost.\n"
342
+ " Ensure your wallet has sufficient funds and try again.\n"
343
+ " Check your balance: htcli wallet balance",
344
+ title="❌ Insufficient Balance for Burn",
345
+ border_style="htcli.error",
346
+ highlight=True,
347
+ )
348
+ error_panel.render(console.console)
349
+ return True
350
+
351
+ elif "MustUnstakeToRegister" in error_msg:
352
+ error_panel = HTCLIPanel(
353
+ "You must unstake before registering a node.\n\n"
354
+ "💡 This hotkey has existing stake that must be unstaked first.\n"
355
+ " Unstake your existing stake, then try registering again.\n"
356
+ " Use: htcli stake unstake to remove your stake",
357
+ title="❌ Must Unstake First",
358
+ border_style="htcli.error",
359
+ highlight=True,
360
+ )
361
+ error_panel.render(console.console)
362
+ return True
363
+
364
+ # Removal-specific errors
365
+ elif "ElectedValidatorCannotRemove" in error_msg:
366
+ error_panel = HTCLIPanel(
367
+ f"Cannot remove node{node_id_str} - it is an elected validator.\n\n"
368
+ f"💡 Elected validators cannot be removed during the current epoch.\n"
369
+ f" This ensures validators can be properly rewarded or penalized.\n"
370
+ f" Wait until the next epoch and try again.",
371
+ title="⚠️ Cannot Remove Validator",
372
+ border_style="htcli.warning",
373
+ highlight=True,
374
+ )
375
+ error_panel.render(console.console)
376
+ return True
377
+
378
+ # Delegate reward rate errors
379
+ elif "InvalidDelegateRewardRate" in error_msg:
380
+ error_panel = HTCLIPanel(
381
+ "Invalid delegate reward rate.\n\n"
382
+ "💡 Delegate reward rate must be:\n"
383
+ " - Between 0% and 100% (0 to percentage_factor_as_u128)\n"
384
+ " - Not exceed MaxDelegateStakePercentage\n\n"
385
+ " Use a valid reward rate and try again.",
386
+ title="❌ Invalid Reward Rate",
387
+ border_style="htcli.error",
388
+ highlight=True,
389
+ )
390
+ error_panel.render(console.console)
391
+ return True
392
+
393
+ # Staking errors (from do_add_stake)
394
+ elif "InvalidAmount" in error_msg or "AmountZero" in error_msg:
395
+ error_panel = HTCLIPanel(
396
+ "Invalid stake amount.\n\n"
397
+ "💡 Stake amount must be greater than zero.\n"
398
+ " Provide a valid stake amount and try again.",
399
+ title="❌ Invalid Amount",
400
+ border_style="htcli.error",
401
+ highlight=True,
402
+ )
403
+ error_panel.render(console.console)
404
+ return True
405
+
406
+ elif "MinStakeNotReached" in error_msg:
407
+ error_panel = HTCLIPanel(
408
+ "Stake amount below minimum requirement.\n\n"
409
+ "💡 The stake amount must meet the subnet's minimum stake requirement.\n"
410
+ " Check the subnet's min_stake parameter and increase your stake.",
411
+ title="❌ Below Minimum Stake",
412
+ border_style="htcli.error",
413
+ highlight=True,
414
+ )
415
+ error_panel.render(console.console)
416
+ return True
417
+
418
+ elif "MaxStakeReached" in error_msg:
419
+ error_panel = HTCLIPanel(
420
+ "Stake amount exceeds maximum limit.\n\n"
421
+ "💡 The stake amount exceeds the subnet's maximum stake limit.\n"
422
+ " Check the subnet's max_stake parameter and reduce your stake.",
423
+ title="❌ Exceeds Maximum Stake",
424
+ border_style="htcli.error",
425
+ highlight=True,
426
+ )
427
+ error_panel.render(console.console)
428
+ return True
429
+
430
+ elif "NotEnoughBalanceToStake" in error_msg:
431
+ error_panel = HTCLIPanel(
432
+ "Insufficient balance to stake.\n\n"
433
+ "💡 You don't have enough balance to stake and keep your account alive.\n"
434
+ " Ensure your wallet has sufficient funds.\n"
435
+ " Check your balance: htcli wallet balance",
436
+ title="❌ Insufficient Balance",
437
+ border_style="htcli.error",
438
+ highlight=True,
439
+ )
440
+ error_panel.render(console.console)
441
+ return True
442
+
443
+ elif "CouldNotConvertToBalance" in error_msg:
444
+ error_panel = HTCLIPanel(
445
+ "Balance conversion failed.\n\n"
446
+ "💡 Failed to convert u128 value to BalanceOf type.\n"
447
+ " This usually indicates an overflow or invalid value.\n"
448
+ " Check your input values and try again.",
449
+ title="❌ Conversion Error",
450
+ border_style="htcli.error",
451
+ highlight=True,
452
+ )
453
+ error_panel.render(console.console)
454
+ return True
455
+
456
+ elif "BalanceWithdrawalError" in error_msg:
457
+ error_panel = HTCLIPanel(
458
+ "Cannot withdraw balance - would kill account.\n\n"
459
+ "💡 Withdrawing this amount would leave your account with insufficient balance.\n"
460
+ " Accounts must maintain a minimum balance to stay alive.\n"
461
+ " Reduce the withdrawal amount and try again.",
462
+ title="❌ Balance Withdrawal Error",
463
+ border_style="htcli.error",
464
+ highlight=True,
465
+ )
466
+ error_panel.render(console.console)
467
+ return True
468
+
469
+ return False # Error not handled by this function
470
+