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,1103 @@
1
+ """
2
+ Stake display functions for RPC-based operations and extrinsic operations.
3
+ """
4
+
5
+ from typing import Any, Optional
6
+
7
+ from ...ui.colors import amount, info
8
+ from ...ui.components import HTCLIPanel, HTCLITable
9
+ from ...ui.display import HTCLIConsole
10
+
11
+ console = HTCLIConsole()
12
+
13
+
14
+ def display_coldkey_stakes_rpc(stakes_data: list[Any], coldkey: str):
15
+ """Display coldkey stakes from RPC response."""
16
+ if not stakes_data:
17
+ console.print(info(f"No stakes found for coldkey {coldkey}"))
18
+ return
19
+
20
+ def _format_tensor(value: Optional[int], precision: int = 4) -> str:
21
+ """Format wei value to TENSOR."""
22
+ if value is None or value == 0:
23
+ return "0.0000 TENSOR"
24
+ try:
25
+ tensor_value = int(value) / 1e18
26
+ return f"{tensor_value:,.{precision}f} TENSOR"
27
+ except (TypeError, ValueError):
28
+ return str(value)
29
+
30
+ # Create table for coldkey stakes with footer for totals
31
+ table = HTCLITable(
32
+ title=f"Coldkey Stakes: {coldkey}",
33
+ show_footer=True,
34
+ )
35
+ table.add_column("Subnet ID", style="cyan", justify="center")
36
+ table.add_column("Node ID", style="yellow", justify="center")
37
+ table.add_column("Hotkey", style="green")
38
+ table.add_column("Balance", style="magenta", justify="right")
39
+
40
+ total_balance = 0
41
+ for stake in stakes_data:
42
+ balance = int(stake.balance) if stake.balance else 0
43
+ total_balance += balance
44
+ table.add_row(
45
+ str(stake.subnet_id or "N/A"),
46
+ str(stake.subnet_node_id or "N/A"),
47
+ stake.hotkey or "N/A",
48
+ _format_tensor(balance),
49
+ )
50
+
51
+ # Add totals footer
52
+ table.set_column_footers(
53
+ [
54
+ f"[bold]Total ({len(stakes_data)} stake{'s' if len(stakes_data) != 1 else ''})[/bold]",
55
+ "",
56
+ "",
57
+ f"[bold]{_format_tensor(total_balance)}[/bold]",
58
+ ]
59
+ )
60
+
61
+ table.render()
62
+ console.print() # Add spacing after table
63
+
64
+
65
+ def display_delegate_stakes_rpc(stakes_data: list[Any], account: str):
66
+ """Display delegate stakes from RPC response."""
67
+ if not stakes_data:
68
+ console.print(info(f"No delegate stakes found for account {account}"))
69
+ return
70
+
71
+ def _format_tensor(value: Optional[int], precision: int = 4) -> str:
72
+ """Format wei value to TENSOR."""
73
+ if value is None or value == 0:
74
+ return "0.0000 TENSOR"
75
+ try:
76
+ tensor_value = int(value) / 1e18
77
+ return f"{tensor_value:,.{precision}f} TENSOR"
78
+ except (TypeError, ValueError):
79
+ return str(value)
80
+
81
+ def _format_shares(value: Optional[int]) -> str:
82
+ """Format shares value."""
83
+ if value is None or value == 0:
84
+ return "0"
85
+ try:
86
+ shares_value = int(value) / 1e18
87
+ return f"{shares_value:,.4f}"
88
+ except (TypeError, ValueError):
89
+ return str(value)
90
+
91
+ # Create table for delegate stakes with footer for totals
92
+ table = HTCLITable(
93
+ title=f"Subnet Delegate Stakes: {account}",
94
+ show_footer=True,
95
+ )
96
+ table.add_column("Subnet ID", style="cyan", justify="center")
97
+ table.add_column("Shares", style="yellow", justify="right")
98
+ table.add_column("Balance", style="magenta", justify="right")
99
+
100
+ total_shares = 0
101
+ total_balance = 0
102
+ for stake in stakes_data:
103
+ shares = int(stake.shares) if stake.shares else 0
104
+ balance = int(stake.balance) if stake.balance else 0
105
+ total_shares += shares
106
+ total_balance += balance
107
+ table.add_row(
108
+ str(stake.subnet_id),
109
+ _format_shares(shares),
110
+ _format_tensor(balance),
111
+ )
112
+
113
+ # Add totals footer
114
+ table.set_column_footers(
115
+ [
116
+ f"[bold]Total ({len(stakes_data)} stake{'s' if len(stakes_data) != 1 else ''})[/bold]",
117
+ f"[bold]{_format_shares(total_shares)}[/bold]",
118
+ f"[bold]{_format_tensor(total_balance)}[/bold]",
119
+ ]
120
+ )
121
+
122
+ table.render()
123
+ console.print() # Add spacing after table
124
+
125
+
126
+ def display_node_delegate_stakes_rpc(stakes_data: list[Any], account: str):
127
+ """Display node delegate stakes from RPC response."""
128
+ if not stakes_data:
129
+ console.print(info(f"No node delegate stakes found for account {account}"))
130
+ return
131
+
132
+ def _format_tensor(value: Optional[int], precision: int = 4) -> str:
133
+ """Format wei value to TENSOR."""
134
+ if value is None or value == 0:
135
+ return "0.0000 TENSOR"
136
+ try:
137
+ tensor_value = int(value) / 1e18
138
+ return f"{tensor_value:,.{precision}f} TENSOR"
139
+ except (TypeError, ValueError):
140
+ return str(value)
141
+
142
+ def _format_shares(value: Optional[int]) -> str:
143
+ """Format shares value."""
144
+ if value is None or value == 0:
145
+ return "0"
146
+ try:
147
+ shares_value = int(value) / 1e18
148
+ return f"{shares_value:,.4f}"
149
+ except (TypeError, ValueError):
150
+ return str(value)
151
+
152
+ # Create table for node delegate stakes with footer for totals
153
+ table = HTCLITable(
154
+ title=f"Node Delegate Stakes: {account}",
155
+ show_footer=True,
156
+ )
157
+ table.add_column("Subnet ID", style="cyan", justify="center")
158
+ table.add_column("Node ID", style="yellow", justify="center")
159
+ table.add_column("Shares", style="green", justify="right")
160
+ table.add_column("Balance", style="magenta", justify="right")
161
+
162
+ total_shares = 0
163
+ total_balance = 0
164
+ for stake in stakes_data:
165
+ shares = int(stake.shares) if stake.shares else 0
166
+ balance = int(stake.balance) if stake.balance else 0
167
+ total_shares += shares
168
+ total_balance += balance
169
+ table.add_row(
170
+ str(stake.subnet_id),
171
+ str(stake.subnet_node_id),
172
+ _format_shares(shares),
173
+ _format_tensor(balance),
174
+ )
175
+
176
+ # Add totals footer
177
+ table.set_column_footers(
178
+ [
179
+ f"[bold]Total ({len(stakes_data)} stake{'s' if len(stakes_data) != 1 else ''})[/bold]",
180
+ "",
181
+ f"[bold]{_format_shares(total_shares)}[/bold]",
182
+ f"[bold]{_format_tensor(total_balance)}[/bold]",
183
+ ]
184
+ )
185
+
186
+ table.render()
187
+ console.print() # Add spacing after table
188
+
189
+
190
+ def display_proof_of_stake_rpc(
191
+ proof_result: bool, subnet_id: int, peer_id: str, min_class: int
192
+ ):
193
+ """Display proof of stake verification result."""
194
+ from ...ui.components import HTCLIPanel
195
+
196
+ status = "✅ PASSED" if proof_result else "❌ FAILED"
197
+ status_color = "htcli.success" if proof_result else "htcli.error"
198
+
199
+ result_info = f"""
200
+ [htcli.accent]Proof of Stake Verification[/htcli.accent]
201
+
202
+ [htcli.value]Subnet ID:[/htcli.value] {subnet_id}
203
+ [htcli.value]Peer ID:[/htcli.value] {peer_id}
204
+ [htcli.value]Minimum Class:[/htcli.value] {min_class}
205
+ [htcli.value]Result:[/htcli.value] [{status_color}]{status}[/{status_color}]
206
+
207
+ [htcli.info]This peer {"meets" if proof_result else "does not meet"} the proof of stake requirements for subnet {subnet_id}.[/htcli.info]
208
+ """
209
+
210
+ panel = HTCLIPanel(
211
+ result_info,
212
+ title="🔐 Proof of Stake Verification",
213
+ border_style="htcli.info" if proof_result else "htcli.error",
214
+ highlight=True,
215
+ )
216
+ panel.render(console.console)
217
+
218
+
219
+ # ============================================================================
220
+ # EXTRINSIC DISPLAY FUNCTIONS - Write Operations
221
+ # ============================================================================
222
+
223
+
224
+ def display_stake_add_result(response):
225
+ """Display stake addition result."""
226
+ if hasattr(response, "success") and response.success:
227
+ total_stake_tensor = (
228
+ response.total_stake / 1e18
229
+ if hasattr(response, "total_stake") and response.total_stake
230
+ else 0
231
+ )
232
+ stake_added_tensor = (
233
+ (response.stake_added / 1e18)
234
+ if hasattr(response, "stake_added") and response.stake_added
235
+ else 0
236
+ )
237
+
238
+ block_hash = getattr(response, "block_hash", None)
239
+ content = f"""[htcli.success]✅ Stake Added Successfully![/htcli.success]
240
+
241
+ [htcli.value]Amount Added:[/htcli.value] {amount(f"{stake_added_tensor:,.4f} TENSOR")}
242
+ [htcli.value]New Total Stake:[/htcli.value] {amount(f"{total_stake_tensor:,.4f} TENSOR")}
243
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
244
+ [htcli.value]Block Number:[/htcli.value] {response.block_number or "N/A"}
245
+ """
246
+ if block_hash:
247
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
248
+
249
+ panel = HTCLIPanel(
250
+ content,
251
+ title="💰 Stake Added",
252
+ border_style="htcli.success",
253
+ highlight=True,
254
+ )
255
+ panel.render(console.console)
256
+ else:
257
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
258
+
259
+ # Check if it's a NotKeyOwner error and provide helpful guidance
260
+ if "NotKeyOwner" in error_msg or "does not own the hotkey" in error_msg:
261
+ content = """[htcli.error]❌ Failed to Add Stake[/htcli.error]
262
+
263
+ [htcli.warning]Key Ownership Error[/htcli.warning]
264
+
265
+ The coldkey wallet you selected does not own the hotkey for this node.
266
+
267
+ [htcli.info]💡 What this means:[/htcli.info]
268
+ You can only add stake using the coldkey that owns the hotkey associated with the node.
269
+
270
+ [htcli.info]💡 How to fix:[/htcli.info]
271
+ â€ĸ Make sure you're using the correct coldkey wallet that owns the node's hotkey
272
+ â€ĸ Verify the node ID and subnet ID are correct
273
+ â€ĸ If you don't own this node, you cannot add direct stake to it
274
+ (you can delegate stake instead using [bold]htcli stake delegate-add[/bold])
275
+ """
276
+ panel = HTCLIPanel(
277
+ content,
278
+ title="âš ī¸ Stake Addition Failed",
279
+ border_style="htcli.error",
280
+ highlight=True,
281
+ )
282
+ panel.render(console.console)
283
+ else:
284
+ # For other errors, use the simple format
285
+ console.print(f"[htcli.error]❌ Failed to add stake: {error_msg}[/]")
286
+
287
+
288
+ def display_stake_remove_result(response):
289
+ """Display stake removal result with unbonding information."""
290
+ if hasattr(response, "success") and response.success:
291
+ unbonding_amount_tensor = (
292
+ (response.unbonding_amount / 1e18)
293
+ if hasattr(response, "unbonding_amount") and response.unbonding_amount
294
+ else 0
295
+ )
296
+
297
+ block_hash = getattr(response, "block_hash", None)
298
+ block_number = getattr(response, "block_number", None)
299
+ content = f"""[htcli.success]✅ Stake Removed Successfully![/htcli.success]
300
+
301
+ [htcli.value]Amount Removed:[/htcli.value] {amount(f"{unbonding_amount_tensor:,.4f} TENSOR")}
302
+ [htcli.value]Status:[/htcli.value] [yellow]Unbonding (locked)[/yellow]
303
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
304
+ [htcli.value]Block Number:[/htcli.value] {block_number or "N/A"}
305
+ """
306
+ if block_hash:
307
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
308
+ content += """
309
+ [htcli.warning]⏰ Unbonding Period:[/htcli.warning]
310
+ Tokens will be available to claim after the unbonding period completes.
311
+ Use [bold]htcli stake claim[/bold] to claim when ready.
312
+ """
313
+
314
+ panel = HTCLIPanel(
315
+ content,
316
+ title="📤 Stake Removed",
317
+ border_style="htcli.warning",
318
+ highlight=True,
319
+ )
320
+ panel.render(console.console)
321
+ else:
322
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
323
+ console.print(f"[htcli.error]❌ Failed to remove stake: {error_msg}[/]")
324
+
325
+
326
+ def display_claim_result(response):
327
+ """Display unbonding claim result."""
328
+ if hasattr(response, "success") and response.success:
329
+ total_claimed_tensor = (
330
+ (response.total_claimed / 1e18)
331
+ if hasattr(response, "total_claimed") and response.total_claimed
332
+ else 0
333
+ )
334
+ entries_claimed = (
335
+ response.entries_claimed if hasattr(response, "entries_claimed") else 0
336
+ )
337
+
338
+ if total_claimed_tensor > 0:
339
+ content = f"""[htcli.success]✅ Unbondings Claimed Successfully![/htcli.success]
340
+
341
+ [htcli.value]Total Claimed:[/htcli.value] {amount(f"{total_claimed_tensor:,.4f} TENSOR")}
342
+ [htcli.value]Entries Claimed:[/htcli.value] {entries_claimed}
343
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
344
+ [htcli.value]Block Number:[/htcli.value] {response.block_number or "N/A"}
345
+ """
346
+ block_hash = getattr(response, "block_hash", None)
347
+ if block_hash:
348
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
349
+ content += "\n"
350
+
351
+ panel = HTCLIPanel(
352
+ content,
353
+ title="💰 Unbonding Claimed",
354
+ border_style="htcli.success",
355
+ highlight=True,
356
+ )
357
+ panel.render()
358
+ else:
359
+ content = """[htcli.info]â„šī¸ No Unbondings Ready to Claim[/htcli.info]
360
+
361
+ No tokens have completed the unbonding period yet.
362
+ Check back later when unbonding is complete.
363
+ """
364
+
365
+ panel = HTCLIPanel(
366
+ content,
367
+ title="đŸ’ĩ Claim Unbondings",
368
+ border_style=(
369
+ "htcli.success" if total_claimed_tensor > 0 else "htcli.info"
370
+ ),
371
+ highlight=True,
372
+ )
373
+ panel.render(console.console)
374
+ else:
375
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
376
+ console.print(f"[htcli.error]❌ Failed to claim unbondings: {error_msg}[/]")
377
+
378
+
379
+ def display_delegate_stake_result(response, operation="add"):
380
+ """Display delegate stake operation result."""
381
+ if hasattr(response, "success") and response.success:
382
+ if operation == "add":
383
+ stake_added_tensor = (
384
+ (response.stake_added / 1e18)
385
+ if hasattr(response, "stake_added") and response.stake_added
386
+ else 0
387
+ )
388
+ shares_received = (
389
+ response.shares_received
390
+ if hasattr(response, "shares_received")
391
+ and response.shares_received is not None
392
+ else 0
393
+ )
394
+
395
+ block_hash = getattr(response, "block_hash", None)
396
+ block_number = getattr(response, "block_number", None)
397
+
398
+ content = f"""[htcli.success]✅ Delegate Stake Added![/htcli.success]
399
+
400
+ [htcli.value]Amount Added:[/htcli.value] {amount(f"{stake_added_tensor:,.4f} TENSOR")}
401
+ [htcli.value]Shares Received:[/htcli.value] {shares_received:,}
402
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") and response.subnet_id is not None else "N/A"}
403
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
404
+ [htcli.value]Block Number:[/htcli.value] {block_number or "N/A"}
405
+ """
406
+ if block_hash:
407
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
408
+ title = "📊 Delegate Stake Added"
409
+ else:
410
+ shares_removed = (
411
+ response.shares_removed
412
+ if hasattr(response, "shares_removed")
413
+ and response.shares_removed is not None
414
+ else 0
415
+ )
416
+
417
+ block_hash = getattr(response, "block_hash", None)
418
+ block_number = getattr(response, "block_number", None)
419
+
420
+ content = f"""[htcli.success]✅ Delegate Stake Removed![/htcli.success]
421
+
422
+ [htcli.value]Shares Removed:[/htcli.value] {shares_removed:,}
423
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") and response.subnet_id is not None else "N/A"}
424
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
425
+ [htcli.value]Block Number:[/htcli.value] {block_number or "N/A"}
426
+ """
427
+ if block_hash:
428
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
429
+ content += "\n[htcli.info]💡 Tokens will be available after unbonding period.[/htcli.info]\n"
430
+ title = "📉 Delegate Stake Removed"
431
+
432
+ panel = HTCLIPanel(
433
+ content,
434
+ title=title,
435
+ border_style="htcli.success",
436
+ highlight=True,
437
+ )
438
+ panel.render(console.console)
439
+ else:
440
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
441
+ console.print(
442
+ f"[htcli.error]❌ Failed to {operation} delegate stake: {error_msg}[/]"
443
+ )
444
+
445
+
446
+ def display_validator_delegate_stake_result(response, operation="add"):
447
+ """Display validator delegate stake operation result."""
448
+ if hasattr(response, "success") and response.success:
449
+ validator_id = getattr(response, "validator_id", "N/A")
450
+ block_hash = getattr(response, "block_hash", None)
451
+ block_number = getattr(response, "block_number", None)
452
+ if operation == "add":
453
+ stake_tensor = (
454
+ response.stake_added / 1e18
455
+ if hasattr(response, "stake_added") and response.stake_added
456
+ else 0
457
+ )
458
+ content = f"""[htcli.success]✅ Validator Delegate Stake Added![/htcli.success]
459
+
460
+ [htcli.value]Amount Added:[/htcli.value] {amount(f"{stake_tensor:,.4f} TENSOR")}
461
+ [htcli.value]Validator ID:[/htcli.value] {validator_id}
462
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
463
+ """
464
+ title = "📊 Validator Delegate Stake Added"
465
+ else:
466
+ shares_removed = (
467
+ response.shares_removed
468
+ if hasattr(response, "shares_removed")
469
+ and response.shares_removed is not None
470
+ else 0
471
+ )
472
+ content = f"""[htcli.success]✅ Validator Delegate Stake Removed![/htcli.success]
473
+
474
+ [htcli.value]Shares Removed:[/htcli.value] {shares_removed:,}
475
+ [htcli.value]Validator ID:[/htcli.value] {validator_id}
476
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
477
+ """
478
+ title = "📉 Validator Delegate Stake Removed"
479
+ if block_number:
480
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
481
+ if block_hash:
482
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
483
+ panel = HTCLIPanel(
484
+ content,
485
+ title=title,
486
+ border_style="htcli.success",
487
+ highlight=True,
488
+ )
489
+ panel.render(console.console)
490
+ else:
491
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
492
+ console.print(
493
+ f"[htcli.error]❌ Failed to {operation} validator delegate stake: {error_msg}[/]"
494
+ )
495
+
496
+
497
+ def display_node_delegate_stake_result(response, operation="add"):
498
+ """Display node delegate stake operation result."""
499
+ if hasattr(response, "success") and response.success:
500
+ if operation == "add":
501
+ stake_added_tensor = (
502
+ (response.stake_added / 1e18)
503
+ if hasattr(response, "stake_added") and response.stake_added
504
+ else 0
505
+ )
506
+ shares_received = (
507
+ response.shares_received
508
+ if hasattr(response, "shares_received")
509
+ and response.shares_received is not None
510
+ else 0
511
+ )
512
+
513
+ block_hash = getattr(response, "block_hash", None)
514
+ block_number = getattr(response, "block_number", None)
515
+
516
+ content = f"""[htcli.success]✅ Node Delegate Stake Added![/htcli.success]
517
+
518
+ [htcli.value]Amount Added:[/htcli.value] {amount(f"{stake_added_tensor:,.4f} TENSOR")}
519
+ [htcli.value]Shares Received:[/htcli.value] {shares_received:,}
520
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") and response.subnet_id is not None else "N/A"}
521
+ [htcli.value]Node ID:[/htcli.value] {response.subnet_node_id if hasattr(response, "subnet_node_id") and response.subnet_node_id is not None else "N/A"}
522
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
523
+ [htcli.value]Block Number:[/htcli.value] {block_number or "N/A"}
524
+ """
525
+ if block_hash:
526
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
527
+ title = "đŸŽ¯ Node Delegate Stake Added"
528
+ else:
529
+ shares_removed = (
530
+ response.shares_removed
531
+ if hasattr(response, "shares_removed")
532
+ and response.shares_removed is not None
533
+ else 0
534
+ )
535
+
536
+ block_hash = getattr(response, "block_hash", None)
537
+ block_number = getattr(response, "block_number", None)
538
+
539
+ content = f"""[htcli.success]✅ Node Delegate Stake Removed![/htcli.success]
540
+
541
+ [htcli.value]Shares Removed:[/htcli.value] {shares_removed:,}
542
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") and response.subnet_id is not None else "N/A"}
543
+ [htcli.value]Node ID:[/htcli.value] {response.subnet_node_id if hasattr(response, "subnet_node_id") and response.subnet_node_id is not None else "N/A"}
544
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash if response.transaction_hash else "N/A"}
545
+ [htcli.value]Block Number:[/htcli.value] {block_number or "N/A"}
546
+ """
547
+ if block_hash:
548
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
549
+ content += "\n[htcli.info]💡 Tokens will be available after unbonding period.[/htcli.info]\n"
550
+ title = "đŸŽ¯ Node Delegate Stake Removed"
551
+
552
+ panel = HTCLIPanel(
553
+ content,
554
+ title=title,
555
+ border_style="htcli.success",
556
+ highlight=True,
557
+ )
558
+ panel.render(console.console)
559
+ else:
560
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
561
+ console.print(
562
+ f"[htcli.error]❌ Failed to {operation} node delegate stake: {error_msg}[/]"
563
+ )
564
+
565
+
566
+ def display_node_delegate_swap_result(response):
567
+ """Display node delegate swap result."""
568
+ if hasattr(response, "success") and response.success:
569
+ shares = (
570
+ response.shares_swapped
571
+ if hasattr(response, "shares_swapped") and response.shares_swapped
572
+ else 0
573
+ )
574
+ block_hash = getattr(response, "block_hash", None)
575
+ block_number = getattr(response, "block_number", None)
576
+ content = f"""[htcli.success]✅ Node Delegate Swap Submitted![/htcli.success]
577
+
578
+ [htcli.value]From:[/htcli.value] Subnet {getattr(response, "from_subnet_id", "N/A")} / Node {getattr(response, "from_subnet_node_id", "N/A")}
579
+ [htcli.value]To:[/htcli.value] Subnet {getattr(response, "to_subnet_id", "N/A")} / Node {getattr(response, "to_subnet_node_id", "N/A")}
580
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
581
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
582
+ """
583
+ if block_number:
584
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
585
+ if block_hash:
586
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
587
+ content += "[htcli.info]âš ī¸ Swap operations execute from the queue when eligible.[/htcli.info]\n"
588
+ panel = HTCLIPanel(
589
+ content,
590
+ title="🔁 Node Delegate Swap",
591
+ border_style="htcli.success",
592
+ highlight=True,
593
+ )
594
+ panel.render(console.console)
595
+ else:
596
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
597
+ console.print(
598
+ f"[htcli.error]❌ Failed to swap node delegate stake: {error_msg}[/]"
599
+ )
600
+
601
+
602
+ def display_node_delegate_transfer_result(response):
603
+ """Display node delegate transfer result."""
604
+ if hasattr(response, "success") and response.success:
605
+ shares = (
606
+ response.shares_transferred
607
+ if hasattr(response, "shares_transferred") and response.shares_transferred
608
+ else 0
609
+ )
610
+ block_hash = getattr(response, "block_hash", None)
611
+ block_number = getattr(response, "block_number", None)
612
+ from ...utils.wallet.crypto import format_address_display
613
+
614
+ recipient = (
615
+ format_address_display(response.to_account, truncate=False)
616
+ if hasattr(response, "to_account") and response.to_account
617
+ else "N/A"
618
+ )
619
+ content = f"""[htcli.success]✅ Node Delegate Transfer Complete![/htcli.success]
620
+
621
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") else "N/A"}
622
+ [htcli.value]Node ID:[/htcli.value] {response.subnet_node_id if hasattr(response, "subnet_node_id") else "N/A"}
623
+ [htcli.value]Recipient:[/htcli.value] {recipient}
624
+ [htcli.value]Shares Transferred:[/htcli.value] {shares:,}
625
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
626
+ """
627
+ if block_number:
628
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
629
+ if block_hash:
630
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
631
+ panel = HTCLIPanel(
632
+ content,
633
+ title="📤 Node Delegate Transfer",
634
+ border_style="htcli.success",
635
+ highlight=True,
636
+ )
637
+ panel.render(console.console)
638
+ else:
639
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
640
+ console.print(
641
+ f"[htcli.error]❌ Failed to transfer node delegate stake: {error_msg}[/]"
642
+ )
643
+
644
+
645
+ def display_node_delegate_donate_result(response):
646
+ """Display node delegate donation result."""
647
+ if hasattr(response, "success") and response.success:
648
+ donated_tensor = (
649
+ response.balance_donated / 1e18
650
+ if hasattr(response, "balance_donated") and response.balance_donated
651
+ else 0
652
+ )
653
+ block_hash = getattr(response, "block_hash", None)
654
+ block_number = getattr(response, "block_number", None)
655
+ content = f"""[htcli.success]✅ Donation Submitted![/htcli.success]
656
+
657
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") else "N/A"}
658
+ [htcli.value]Node ID:[/htcli.value] {response.subnet_node_id if hasattr(response, "subnet_node_id") else "N/A"}
659
+ [htcli.value]Amount Donated:[/htcli.value] {amount(f"{donated_tensor:,.4f} TENSOR")}
660
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
661
+ """
662
+ if block_number:
663
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
664
+ if block_hash:
665
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
666
+ content += "[htcli.info]🙏 Donation increases the node's delegate pool but not your balance.[/htcli.info]\n"
667
+ panel = HTCLIPanel(
668
+ content,
669
+ title="🎁 Node Delegate Donation",
670
+ border_style="htcli.success",
671
+ highlight=True,
672
+ )
673
+ panel.render(console.console)
674
+ else:
675
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
676
+ console.print(
677
+ f"[htcli.error]❌ Failed to donate node delegate stake: {error_msg}[/]"
678
+ )
679
+
680
+
681
+ def display_validator_delegate_swap_result(response):
682
+ """Display validator delegate swap result."""
683
+ if hasattr(response, "success") and response.success:
684
+ shares = (
685
+ response.shares_swapped
686
+ if hasattr(response, "shares_swapped") and response.shares_swapped
687
+ else 0
688
+ )
689
+ block_hash = getattr(response, "block_hash", None)
690
+ block_number = getattr(response, "block_number", None)
691
+ content = f"""[htcli.success]✅ Validator Delegate Swap Submitted![/htcli.success]
692
+
693
+ [htcli.value]From Validator:[/htcli.value] {getattr(response, "from_validator_id", "N/A")}
694
+ [htcli.value]To Validator:[/htcli.value] {getattr(response, "to_validator_id", "N/A")}
695
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
696
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
697
+ """
698
+ if block_number:
699
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
700
+ if block_hash:
701
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
702
+ panel = HTCLIPanel(
703
+ content,
704
+ title="🔁 Validator Delegate Swap",
705
+ border_style="htcli.success",
706
+ highlight=True,
707
+ )
708
+ panel.render(console.console)
709
+ else:
710
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
711
+ console.print(
712
+ f"[htcli.error]❌ Failed to swap validator delegate stake: {error_msg}[/]"
713
+ )
714
+
715
+
716
+ def display_validator_delegate_transfer_result(response):
717
+ """Display validator delegate transfer result."""
718
+ if hasattr(response, "success") and response.success:
719
+ shares = (
720
+ response.shares_transferred
721
+ if hasattr(response, "shares_transferred") and response.shares_transferred
722
+ else 0
723
+ )
724
+ block_hash = getattr(response, "block_hash", None)
725
+ block_number = getattr(response, "block_number", None)
726
+ from ...utils.wallet.crypto import format_address_display
727
+
728
+ recipient = (
729
+ format_address_display(response.to_account, truncate=False)
730
+ if hasattr(response, "to_account") and response.to_account
731
+ else "N/A"
732
+ )
733
+ content = f"""[htcli.success]✅ Validator Delegate Transfer Complete![/htcli.success]
734
+
735
+ [htcli.value]Validator ID:[/htcli.value] {getattr(response, "validator_id", "N/A")}
736
+ [htcli.value]Recipient:[/htcli.value] {recipient}
737
+ [htcli.value]Shares Transferred:[/htcli.value] {shares:,}
738
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
739
+ """
740
+ if block_number:
741
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
742
+ if block_hash:
743
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
744
+ panel = HTCLIPanel(
745
+ content,
746
+ title="📤 Validator Delegate Transfer",
747
+ border_style="htcli.success",
748
+ highlight=True,
749
+ )
750
+ panel.render(console.console)
751
+ else:
752
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
753
+ console.print(
754
+ f"[htcli.error]❌ Failed to transfer validator delegate stake: {error_msg}[/]"
755
+ )
756
+
757
+
758
+ def display_validator_delegate_donate_result(response):
759
+ """Display validator delegate donation result."""
760
+ if hasattr(response, "success") and response.success:
761
+ donated_tensor = (
762
+ response.balance_donated / 1e18
763
+ if hasattr(response, "balance_donated") and response.balance_donated
764
+ else 0
765
+ )
766
+ block_hash = getattr(response, "block_hash", None)
767
+ block_number = getattr(response, "block_number", None)
768
+ content = f"""[htcli.success]✅ Validator Delegate Donation Submitted![/htcli.success]
769
+
770
+ [htcli.value]Validator ID:[/htcli.value] {getattr(response, "validator_id", "N/A")}
771
+ [htcli.value]Amount Donated:[/htcli.value] {amount(f"{donated_tensor:,.4f} TENSOR")}
772
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
773
+ """
774
+ if block_number:
775
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
776
+ if block_hash:
777
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
778
+ panel = HTCLIPanel(
779
+ content,
780
+ title="🎁 Validator Delegate Donation",
781
+ border_style="htcli.success",
782
+ highlight=True,
783
+ )
784
+ panel.render(console.console)
785
+ else:
786
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
787
+ console.print(
788
+ f"[htcli.error]❌ Failed to donate validator delegate stake: {error_msg}[/]"
789
+ )
790
+
791
+
792
+ def display_swap_validator_to_subnet_result(response):
793
+ """Display swap from validator delegate to subnet delegate result."""
794
+ if hasattr(response, "success") and response.success:
795
+ shares = (
796
+ response.stake_swapped
797
+ if hasattr(response, "stake_swapped") and response.stake_swapped
798
+ else 0
799
+ )
800
+ block_hash = getattr(response, "block_hash", None)
801
+ block_number = getattr(response, "block_number", None)
802
+ content = f"""[htcli.success]✅ Validator → Subnet Swap Submitted![/htcli.success]
803
+
804
+ [htcli.value]Source Validator:[/htcli.value] {getattr(response, "validator_id", "N/A")}
805
+ [htcli.value]Destination Subnet:[/htcli.value] {getattr(response, "subnet_id", "N/A")}
806
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
807
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
808
+ """
809
+ if block_number:
810
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
811
+ if block_hash:
812
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
813
+ panel = HTCLIPanel(
814
+ content,
815
+ title="📤 Swap Validator → Subnet",
816
+ border_style="htcli.success",
817
+ highlight=True,
818
+ )
819
+ panel.render(console.console)
820
+ else:
821
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
822
+ console.print(
823
+ f"[htcli.error]❌ Failed to swap validator delegate stake to subnet: {error_msg}[/]"
824
+ )
825
+
826
+
827
+ def display_swap_subnet_to_validator_result(response):
828
+ """Display swap from subnet delegate to validator delegate result."""
829
+ if hasattr(response, "success") and response.success:
830
+ shares = (
831
+ response.stake_swapped
832
+ if hasattr(response, "stake_swapped") and response.stake_swapped
833
+ else 0
834
+ )
835
+ block_hash = getattr(response, "block_hash", None)
836
+ block_number = getattr(response, "block_number", None)
837
+ content = f"""[htcli.success]✅ Subnet → Validator Swap Submitted![/htcli.success]
838
+
839
+ [htcli.value]Source Subnet:[/htcli.value] {getattr(response, "subnet_id", "N/A")}
840
+ [htcli.value]Destination Validator:[/htcli.value] {getattr(response, "validator_id", "N/A")}
841
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
842
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
843
+ """
844
+ if block_number:
845
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
846
+ if block_hash:
847
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
848
+ panel = HTCLIPanel(
849
+ content,
850
+ title="đŸ“Ĩ Swap Subnet → Validator",
851
+ border_style="htcli.success",
852
+ highlight=True,
853
+ )
854
+ panel.render(console.console)
855
+ else:
856
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
857
+ console.print(
858
+ f"[htcli.error]❌ Failed to swap subnet delegate stake to validator: {error_msg}[/]"
859
+ )
860
+
861
+
862
+ def display_swap_node_to_subnet_result(response):
863
+ """Display swap from node delegate to subnet delegate result."""
864
+ if hasattr(response, "success") and response.success:
865
+ shares = (
866
+ response.stake_swapped
867
+ if hasattr(response, "stake_swapped") and response.stake_swapped
868
+ else 0
869
+ )
870
+ block_hash = getattr(response, "block_hash", None)
871
+ block_number = getattr(response, "block_number", None)
872
+ content = f"""[htcli.success]✅ Node → Subnet Swap Submitted![/htcli.success]
873
+
874
+ [htcli.value]Source Subnet:[/htcli.value] {getattr(response, "subnet_id", "N/A")}
875
+ [htcli.value]Source Node:[/htcli.value] {getattr(response, "subnet_node_id", "N/A")}
876
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
877
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
878
+ """
879
+ if block_number:
880
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
881
+ if block_hash:
882
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
883
+ content += "[htcli.info]â„šī¸ Swap will execute once the queue reaches your entry.[/htcli.info]\n"
884
+ panel = HTCLIPanel(
885
+ content,
886
+ title="📤 Swap Node → Subnet",
887
+ border_style="htcli.success",
888
+ highlight=True,
889
+ )
890
+ panel.render(console.console)
891
+ else:
892
+ from ...client.extrinsics.base import get_user_friendly_error
893
+
894
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
895
+ friendly_error = get_user_friendly_error(error_msg)
896
+
897
+ # Check for specific error types and provide detailed guidance
898
+ if (
899
+ "NotEnoughStakeToWithdraw" in error_msg
900
+ or "Insufficient stake shares" in friendly_error
901
+ ):
902
+ content = """[htcli.error]❌ Failed to Swap Node → Subnet[/htcli.error]
903
+
904
+ [htcli.warning]Insufficient Stake Shares[/htcli.warning]
905
+
906
+ You don't have enough stake shares in the node delegate position to swap the requested amount.
907
+
908
+ [htcli.info]💡 What this means:[/htcli.info]
909
+ You tried to swap more shares than you currently have staked in the node delegate position.
910
+
911
+ [htcli.info]💡 How to fix:[/htcli.info]
912
+ â€ĸ Check your current node delegate stake balance using:
913
+ [bold]htcli stake list-node-delegate --subnet-id <id> --node-id <id>[/bold]
914
+ â€ĸ Reduce the number of shares you're trying to swap
915
+ â€ĸ Make sure you're swapping from the correct subnet and node ID
916
+ """
917
+ panel = HTCLIPanel(
918
+ content,
919
+ title="âš ī¸ Swap Failed",
920
+ border_style="htcli.error",
921
+ highlight=True,
922
+ )
923
+ panel.render(console.console)
924
+ else:
925
+ # Generic error display
926
+ content = f"""[htcli.error]❌ Failed to Swap Node → Subnet[/htcli.error]
927
+
928
+ [htcli.value]Error:[/htcli.value] {friendly_error}
929
+
930
+ [htcli.info]💡 Troubleshooting:[/htcli.info]
931
+ â€ĸ Verify you have sufficient stake shares in the node delegate position
932
+ â€ĸ Check that the subnet ID and node ID are correct
933
+ â€ĸ Ensure the node is active and not paused
934
+ """
935
+ panel = HTCLIPanel(
936
+ content,
937
+ title="âš ī¸ Swap Failed",
938
+ border_style="htcli.error",
939
+ highlight=True,
940
+ )
941
+ panel.render(console.console)
942
+
943
+
944
+ def display_swap_subnet_to_node_result(response):
945
+ """Display swap from subnet delegate to node delegate result."""
946
+ if hasattr(response, "success") and response.success:
947
+ shares = (
948
+ response.stake_swapped
949
+ if hasattr(response, "stake_swapped") and response.stake_swapped
950
+ else 0
951
+ )
952
+ block_hash = getattr(response, "block_hash", None)
953
+ block_number = getattr(response, "block_number", None)
954
+ content = f"""[htcli.success]✅ Subnet → Node Swap Submitted![/htcli.success]
955
+
956
+ [htcli.value]Destination Subnet:[/htcli.value] {getattr(response, "subnet_id", "N/A")}
957
+ [htcli.value]Destination Node:[/htcli.value] {getattr(response, "subnet_node_id", "N/A")}
958
+ [htcli.value]Shares Swapped:[/htcli.value] {shares:,}
959
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
960
+ """
961
+ if block_number:
962
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
963
+ if block_hash:
964
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
965
+ content += "[htcli.info]â„šī¸ Swap will execute once eligible in the queue.[/htcli.info]\n"
966
+ panel = HTCLIPanel(
967
+ content,
968
+ title="đŸ“Ĩ Swap Subnet → Node",
969
+ border_style="htcli.success",
970
+ highlight=True,
971
+ )
972
+ panel.render(console.console)
973
+ else:
974
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
975
+ console.print(
976
+ f"[htcli.error]❌ Failed to swap from subnet to node: {error_msg}[/]"
977
+ )
978
+
979
+
980
+ def display_swap_queue_update_result(response):
981
+ """Display swap queue update result."""
982
+ if hasattr(response, "success") and response.success:
983
+ block_hash = getattr(response, "block_hash", None)
984
+ block_number = getattr(response, "block_number", None)
985
+ content = f"""[htcli.success]✅ Swap Queue Updated![/htcli.success]
986
+
987
+ [htcli.value]Queue Entry:[/htcli.value] {response.queue_position if hasattr(response, "queue_position") else "N/A"}
988
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
989
+ """
990
+ if block_number:
991
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
992
+ if block_hash:
993
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
994
+ content += "[htcli.info]💡 The queue entry now points to the new target.[/htcli.info]\n"
995
+ panel = HTCLIPanel(
996
+ content,
997
+ title="đŸ› ī¸ Swap Queue Update",
998
+ border_style="htcli.success",
999
+ highlight=True,
1000
+ )
1001
+ panel.render(console.console)
1002
+ else:
1003
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
1004
+ console.print(f"[htcli.error]❌ Failed to update swap queue: {error_msg}[/]")
1005
+
1006
+
1007
+ def display_delegate_swap_result(response):
1008
+ """Display delegate stake swap result."""
1009
+ if hasattr(response, "success") and response.success:
1010
+ block_hash = getattr(response, "block_hash", None)
1011
+ block_number = getattr(response, "block_number", None)
1012
+ content = f"""[htcli.success]✅ Delegate Stake Swapped![/htcli.success]
1013
+
1014
+ [htcli.value]From Subnet:[/htcli.value] {response.from_subnet_id if hasattr(response, "from_subnet_id") else "N/A"}
1015
+ [htcli.value]To Subnet:[/htcli.value] {response.to_subnet_id if hasattr(response, "to_subnet_id") else "N/A"}
1016
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
1017
+ """
1018
+ if block_number:
1019
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
1020
+ if block_hash:
1021
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
1022
+ content += "\n[htcli.info]💡 Your delegate stake has been moved to the new subnet.[/htcli.info]\n"
1023
+ panel = HTCLIPanel(
1024
+ content,
1025
+ title="🔄 Delegate Stake Swapped",
1026
+ border_style="htcli.success",
1027
+ highlight=True,
1028
+ )
1029
+ panel.render(console.console)
1030
+ else:
1031
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
1032
+ console.print(f"[htcli.error]❌ Failed to swap delegate stake: {error_msg}[/]")
1033
+
1034
+
1035
+ def display_delegate_transfer_result(response):
1036
+ """Display delegate stake transfer result."""
1037
+ if hasattr(response, "success") and response.success:
1038
+ block_hash = getattr(response, "block_hash", None)
1039
+ block_number = getattr(response, "block_number", None)
1040
+ from ...utils.wallet.crypto import format_address_display
1041
+
1042
+ from_acct = (
1043
+ format_address_display(response.from_account, truncate=False)
1044
+ if hasattr(response, "from_account") and response.from_account
1045
+ else "N/A"
1046
+ )
1047
+ to_acct = (
1048
+ format_address_display(response.to_account, truncate=False)
1049
+ if hasattr(response, "to_account") and response.to_account
1050
+ else "N/A"
1051
+ )
1052
+ content = f"""[htcli.success]✅ Delegate Stake Transferred![/htcli.success]
1053
+
1054
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") else "N/A"}
1055
+ [htcli.value]From:[/htcli.value] {from_acct}
1056
+ [htcli.value]To:[/htcli.value] {to_acct}
1057
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
1058
+ """
1059
+ if block_number:
1060
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
1061
+ if block_hash:
1062
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
1063
+ panel = HTCLIPanel(
1064
+ content,
1065
+ title="📤 Delegate Stake Transferred",
1066
+ border_style="htcli.success",
1067
+ highlight=True,
1068
+ )
1069
+ panel.render(console.console)
1070
+ else:
1071
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
1072
+ console.print(
1073
+ f"[htcli.error]❌ Failed to transfer delegate stake: {error_msg}[/]"
1074
+ )
1075
+
1076
+
1077
+ def display_delegate_donate_result(response):
1078
+ """Display delegate stake donation result."""
1079
+ if hasattr(response, "success") and response.success:
1080
+ block_hash = getattr(response, "block_hash", None)
1081
+ block_number = getattr(response, "block_number", None)
1082
+ content = f"""[htcli.success]✅ Donation Complete![/htcli.success]
1083
+
1084
+ [htcli.value]Subnet ID:[/htcli.value] {response.subnet_id if hasattr(response, "subnet_id") else "N/A"}
1085
+ [htcli.value]Transaction Hash:[/htcli.value] {response.transaction_hash or "N/A"}
1086
+ """
1087
+ if block_number:
1088
+ content += f"[htcli.value]Block Number:[/htcli.value] {block_number}\n"
1089
+ if block_hash:
1090
+ content += f"[htcli.value]Block Hash:[/htcli.value] {block_hash}\n"
1091
+ content += "\n[htcli.info]🙏 Thank you for contributing to the subnet treasury![/htcli.info]\n"
1092
+ panel = HTCLIPanel(
1093
+ content,
1094
+ title="🎁 Delegate Donation Complete",
1095
+ border_style="htcli.success",
1096
+ highlight=True,
1097
+ )
1098
+ panel.render(console.console)
1099
+ else:
1100
+ error_msg = response.error if hasattr(response, "error") else "Unknown error"
1101
+ console.print(
1102
+ f"[htcli.error]❌ Failed to donate delegate stake: {error_msg}[/]"
1103
+ )