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.
- htcli-1.1.0.dist-info/METADATA +509 -0
- htcli-1.1.0.dist-info/RECORD +140 -0
- htcli-1.1.0.dist-info/WHEEL +4 -0
- htcli-1.1.0.dist-info/entry_points.txt +2 -0
- htcli-1.1.0.dist-info/licenses/LICENSE +21 -0
- src/__init__.py +0 -0
- src/htcli/__init__.py +5 -0
- src/htcli/client/__init__.py +338 -0
- src/htcli/client/extrinsics/__init__.py +26 -0
- src/htcli/client/extrinsics/base.py +487 -0
- src/htcli/client/extrinsics/consensus.py +79 -0
- src/htcli/client/extrinsics/governance.py +714 -0
- src/htcli/client/extrinsics/identity.py +490 -0
- src/htcli/client/extrinsics/node.py +1054 -0
- src/htcli/client/extrinsics/overwatch.py +401 -0
- src/htcli/client/extrinsics/staking.py +1504 -0
- src/htcli/client/extrinsics/subnet.py +2218 -0
- src/htcli/client/extrinsics/validator.py +203 -0
- src/htcli/client/extrinsics/wallet.py +323 -0
- src/htcli/client/offchain/__init__.py +10 -0
- src/htcli/client/offchain/backup.py +385 -0
- src/htcli/client/offchain/config.py +541 -0
- src/htcli/client/offchain/wallet.py +839 -0
- src/htcli/client/rpc/__init__.py +20 -0
- src/htcli/client/rpc/chain.py +568 -0
- src/htcli/client/rpc/node.py +783 -0
- src/htcli/client/rpc/overwatch.py +680 -0
- src/htcli/client/rpc/staking.py +216 -0
- src/htcli/client/rpc/subnet.py +2104 -0
- src/htcli/client/rpc/wallet.py +912 -0
- src/htcli/commands/__init__.py +31 -0
- src/htcli/commands/chain/__init__.py +66 -0
- src/htcli/commands/chain/display.py +204 -0
- src/htcli/commands/chain/handlers.py +260 -0
- src/htcli/commands/config/__init__.py +158 -0
- src/htcli/commands/config/display.py +353 -0
- src/htcli/commands/config/handlers.py +347 -0
- src/htcli/commands/config/prompts.py +357 -0
- src/htcli/commands/consensus/__init__.py +61 -0
- src/htcli/commands/consensus/handlers.py +100 -0
- src/htcli/commands/governance/__init__.py +49 -0
- src/htcli/commands/governance/handlers.py +81 -0
- src/htcli/commands/node/__init__.py +304 -0
- src/htcli/commands/node/display.py +749 -0
- src/htcli/commands/node/error_handling.py +470 -0
- src/htcli/commands/node/handlers.py +844 -0
- src/htcli/commands/node/prompts.py +346 -0
- src/htcli/commands/overwatch/__init__.py +219 -0
- src/htcli/commands/overwatch/display.py +396 -0
- src/htcli/commands/overwatch/error_handling.py +276 -0
- src/htcli/commands/overwatch/handlers.py +443 -0
- src/htcli/commands/overwatch/prompts.py +359 -0
- src/htcli/commands/stake/__init__.py +736 -0
- src/htcli/commands/stake/display.py +1103 -0
- src/htcli/commands/stake/error_handling.py +425 -0
- src/htcli/commands/stake/handlers.py +1902 -0
- src/htcli/commands/stake/prompts.py +1080 -0
- src/htcli/commands/subnet/__init__.py +639 -0
- src/htcli/commands/subnet/display.py +801 -0
- src/htcli/commands/subnet/error_handling.py +524 -0
- src/htcli/commands/subnet/handlers.py +2855 -0
- src/htcli/commands/subnet/prompts.py +1225 -0
- src/htcli/commands/validator/__init__.py +192 -0
- src/htcli/commands/validator/display.py +54 -0
- src/htcli/commands/validator/handlers.py +340 -0
- src/htcli/commands/wallet/__init__.py +546 -0
- src/htcli/commands/wallet/display.py +806 -0
- src/htcli/commands/wallet/error_handling.py +210 -0
- src/htcli/commands/wallet/handlers.py +3040 -0
- src/htcli/commands/wallet/prompts.py +1518 -0
- src/htcli/config.py +184 -0
- src/htcli/dependencies.py +186 -0
- src/htcli/errors/__init__.py +63 -0
- src/htcli/errors/base.py +141 -0
- src/htcli/errors/display.py +20 -0
- src/htcli/errors/handlers.py +710 -0
- src/htcli/main.py +343 -0
- src/htcli/models/__init__.py +21 -0
- src/htcli/models/enums/enum_types.py +35 -0
- src/htcli/models/errors.py +103 -0
- src/htcli/models/requests/__init__.py +197 -0
- src/htcli/models/requests/config.py +70 -0
- src/htcli/models/requests/consensus.py +19 -0
- src/htcli/models/requests/governance.py +38 -0
- src/htcli/models/requests/identity.py +51 -0
- src/htcli/models/requests/key.py +22 -0
- src/htcli/models/requests/node.py +91 -0
- src/htcli/models/requests/overwatch.py +64 -0
- src/htcli/models/requests/staking.py +580 -0
- src/htcli/models/requests/subnet.py +195 -0
- src/htcli/models/requests/validator.py +139 -0
- src/htcli/models/requests/wallet.py +118 -0
- src/htcli/models/responses/__init__.py +147 -0
- src/htcli/models/responses/base.py +18 -0
- src/htcli/models/responses/chain.py +39 -0
- src/htcli/models/responses/config.py +58 -0
- src/htcli/models/responses/identity.py +102 -0
- src/htcli/models/responses/overwatch.py +51 -0
- src/htcli/models/responses/staking.py +502 -0
- src/htcli/models/responses/subnet.py +856 -0
- src/htcli/models/responses/wallet.py +185 -0
- src/htcli/ui/__init__.py +87 -0
- src/htcli/ui/colors.py +309 -0
- src/htcli/ui/components/__init__.py +60 -0
- src/htcli/ui/components/panels.py +174 -0
- src/htcli/ui/components/progress.py +166 -0
- src/htcli/ui/components/spinners.py +92 -0
- src/htcli/ui/components/tables.py +809 -0
- src/htcli/ui/components/trees.py +721 -0
- src/htcli/ui/display.py +336 -0
- src/htcli/ui/prompts.py +870 -0
- src/htcli/utils/__init__.py +76 -0
- src/htcli/utils/blockchain/__init__.py +75 -0
- src/htcli/utils/blockchain/formatting.py +368 -0
- src/htcli/utils/blockchain/patches.py +286 -0
- src/htcli/utils/blockchain/peer_id.py +186 -0
- src/htcli/utils/blockchain/staking.py +448 -0
- src/htcli/utils/blockchain/type_registry.py +1373 -0
- src/htcli/utils/blockchain/validation.py +179 -0
- src/htcli/utils/cache.py +613 -0
- src/htcli/utils/constants.py +38 -0
- src/htcli/utils/legacy/__init__.py +12 -0
- src/htcli/utils/legacy/colors.py +311 -0
- src/htcli/utils/legacy/crypto.py +1176 -0
- src/htcli/utils/legacy/formatting.py +452 -0
- src/htcli/utils/legacy/interactive.py +306 -0
- src/htcli/utils/legacy/subnet_manifest.py +265 -0
- src/htcli/utils/legacy/validation.py +488 -0
- src/htcli/utils/logging.py +183 -0
- src/htcli/utils/network/__init__.py +20 -0
- src/htcli/utils/network/subnet.py +344 -0
- src/htcli/utils/prompts.py +27 -0
- src/htcli/utils/scale_codec.py +155 -0
- src/htcli/utils/validation/__init__.py +57 -0
- src/htcli/utils/validation/prompt_validators.py +267 -0
- src/htcli/utils/wallet/__init__.py +65 -0
- src/htcli/utils/wallet/auth.py +151 -0
- src/htcli/utils/wallet/core.py +1069 -0
- src/htcli/utils/wallet/crypto.py +1615 -0
- src/htcli/utils/wallet/migration.py +159 -0
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Wallet command display logic.
|
|
3
|
+
|
|
4
|
+
Handles formatting and displaying results for wallet operations using HTCLI UI components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from rich.padding import Padding
|
|
10
|
+
|
|
11
|
+
from ...models.responses import (
|
|
12
|
+
WalletCreateResponse,
|
|
13
|
+
WalletDeleteResponse,
|
|
14
|
+
WalletListResponse,
|
|
15
|
+
WalletStatusResponse,
|
|
16
|
+
WalletTransferResponse,
|
|
17
|
+
WalletUpdateResponse,
|
|
18
|
+
)
|
|
19
|
+
from ...ui.colors import address, address_full, error, info, primary, success, warning
|
|
20
|
+
from ...ui.components import (
|
|
21
|
+
HTCLIPanel,
|
|
22
|
+
HTCLITable,
|
|
23
|
+
create_htcli_balance_table,
|
|
24
|
+
create_wallet_hierarchy_tree,
|
|
25
|
+
create_wallet_minimal_table,
|
|
26
|
+
)
|
|
27
|
+
from ...ui.display import (
|
|
28
|
+
HTCLIConsole,
|
|
29
|
+
print_error,
|
|
30
|
+
print_info,
|
|
31
|
+
print_success,
|
|
32
|
+
print_warning,
|
|
33
|
+
)
|
|
34
|
+
from ...ui.prompts import confirm_prompt
|
|
35
|
+
|
|
36
|
+
console = HTCLIConsole()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _copy_to_clipboard(text: str):
|
|
40
|
+
"""Copy text to clipboard if pyperclip is installed."""
|
|
41
|
+
try:
|
|
42
|
+
import pyperclip
|
|
43
|
+
|
|
44
|
+
pyperclip.copy(text)
|
|
45
|
+
print_success("📋 Copied to clipboard!", emoji=False)
|
|
46
|
+
except ImportError:
|
|
47
|
+
print_warning("📋 Could not copy to clipboard.", emoji=False)
|
|
48
|
+
print_info(
|
|
49
|
+
"Install pyperclip for automatic copying: pip install pyperclip",
|
|
50
|
+
emoji=False,
|
|
51
|
+
)
|
|
52
|
+
console.print("Please copy the phrase manually.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def display_wallet_creation_result(
|
|
56
|
+
response: WalletCreateResponse,
|
|
57
|
+
copy_mnemonic: bool = False,
|
|
58
|
+
owner_name: Optional[str] = None,
|
|
59
|
+
owner_address: Optional[str] = None,
|
|
60
|
+
preseeded_name: Optional[str] = None,
|
|
61
|
+
):
|
|
62
|
+
"""Display wallet creation results."""
|
|
63
|
+
print_success("Wallet created successfully!")
|
|
64
|
+
|
|
65
|
+
# Display key details in a table
|
|
66
|
+
table = HTCLITable(title="Wallet Details")
|
|
67
|
+
table.add_column("Property", style="white")
|
|
68
|
+
table.add_column("Value", style="dim")
|
|
69
|
+
table.add_row("Name", response.name)
|
|
70
|
+
table.add_row("Type", response.wallet_type.title())
|
|
71
|
+
table.add_row("Key Type", response.key_type.upper())
|
|
72
|
+
table.add_row("Address", address(response.address))
|
|
73
|
+
table.add_row("Public Key", response.public_key)
|
|
74
|
+
if owner_name and owner_address:
|
|
75
|
+
table.add_row("Owner", f"{owner_name} ({address(owner_address)})")
|
|
76
|
+
if preseeded_name:
|
|
77
|
+
table.add_row("Preseeded From", preseeded_name.title())
|
|
78
|
+
table.add_row("Encryption", "🔒 Enabled" if response.encrypted else "Disabled")
|
|
79
|
+
console.print(table.table)
|
|
80
|
+
|
|
81
|
+
# Mnemonic display in a panel
|
|
82
|
+
if response.mnemonic:
|
|
83
|
+
# Display mnemonic with separate subtitle
|
|
84
|
+
display_mnemonic_with_copy_option(
|
|
85
|
+
response.mnemonic,
|
|
86
|
+
response.name,
|
|
87
|
+
response.wallet_type.title(),
|
|
88
|
+
copy_mnemonic=copy_mnemonic,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def display_mnemonic_panel(
|
|
93
|
+
mnemonic: str, wallet_name: str, wallet_type: str = "Coldkey"
|
|
94
|
+
):
|
|
95
|
+
"""Display mnemonic in a beautiful panel."""
|
|
96
|
+
words = mnemonic.split()
|
|
97
|
+
|
|
98
|
+
# Create a table for evenly spaced words
|
|
99
|
+
mnemonic_table = HTCLITable(
|
|
100
|
+
show_header=False,
|
|
101
|
+
show_lines=False,
|
|
102
|
+
show_edge=False,
|
|
103
|
+
border_style="red",
|
|
104
|
+
padding=(0, 1),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Add columns for 4 words per row
|
|
108
|
+
for _ in range(4):
|
|
109
|
+
mnemonic_table.add_column("", justify="center", width=20)
|
|
110
|
+
|
|
111
|
+
# Add rows of 4 words each
|
|
112
|
+
for i in range(0, 12, 4):
|
|
113
|
+
row_words = []
|
|
114
|
+
for j in range(4):
|
|
115
|
+
if i + j < len(words):
|
|
116
|
+
word_num = i + j + 1
|
|
117
|
+
row_words.append(f"{word_num:2d}. {words[i + j]}")
|
|
118
|
+
else:
|
|
119
|
+
row_words.append("")
|
|
120
|
+
mnemonic_table.add_row(*row_words)
|
|
121
|
+
|
|
122
|
+
panel = HTCLIPanel(
|
|
123
|
+
mnemonic_table.table,
|
|
124
|
+
title=f"[bold red]🔐 {wallet_type} Recovery Phrase[/bold red]",
|
|
125
|
+
border_style="red",
|
|
126
|
+
padding=(1, 2),
|
|
127
|
+
highlight=True,
|
|
128
|
+
)
|
|
129
|
+
console.print(panel.panel)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def display_mnemonic_with_copy_option(
|
|
133
|
+
mnemonic: str,
|
|
134
|
+
wallet_name: str,
|
|
135
|
+
wallet_type: str = "Coldkey",
|
|
136
|
+
copy_mnemonic: bool = False,
|
|
137
|
+
):
|
|
138
|
+
"""Display mnemonic and offer clipboard copy option.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
mnemonic: The recovery phrase to display
|
|
142
|
+
wallet_name: Name of the wallet
|
|
143
|
+
wallet_type: Type of wallet (Coldkey/Hotkey)
|
|
144
|
+
copy_mnemonic: If True, automatically copy to clipboard without prompting
|
|
145
|
+
"""
|
|
146
|
+
# Display the mnemonic in a beautiful panel only
|
|
147
|
+
display_mnemonic_panel(mnemonic, wallet_name, wallet_type)
|
|
148
|
+
|
|
149
|
+
# Display subtitle separately
|
|
150
|
+
console.print(
|
|
151
|
+
"[bold yellow]Store this securely. It is the only way to recover your wallet.[/bold yellow]"
|
|
152
|
+
)
|
|
153
|
+
console.print()
|
|
154
|
+
|
|
155
|
+
# Handle clipboard copy
|
|
156
|
+
if copy_mnemonic:
|
|
157
|
+
# Automatically copy if flag is set
|
|
158
|
+
_copy_to_clipboard(mnemonic)
|
|
159
|
+
else:
|
|
160
|
+
# Offer clipboard copy only if flag is not set
|
|
161
|
+
if confirm_prompt("Copy recovery phrase to clipboard?", default=False):
|
|
162
|
+
_copy_to_clipboard(mnemonic)
|
|
163
|
+
|
|
164
|
+
# Final security reminder
|
|
165
|
+
console.print("\n[bold red]🔒 Security Reminder:[/bold red]")
|
|
166
|
+
console.print("• Store this recovery phrase in a secure, offline location")
|
|
167
|
+
console.print("• Never share it with anyone")
|
|
168
|
+
console.print("• Consider using a hardware wallet for additional security")
|
|
169
|
+
console.print("• Test your recovery process in a safe environment")
|
|
170
|
+
console.print()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def display_wallet_generation_result(
|
|
174
|
+
coldkey_response: WalletCreateResponse,
|
|
175
|
+
hotkey_response: WalletCreateResponse,
|
|
176
|
+
copy_mnemonic: bool = False,
|
|
177
|
+
):
|
|
178
|
+
"""Display unified results for wallet generation (both coldkey and hotkey)."""
|
|
179
|
+
console.print()
|
|
180
|
+
print_success("Wallet created successfully!")
|
|
181
|
+
console.print(primary("Both coldkey and hotkey have been generated.\n"))
|
|
182
|
+
|
|
183
|
+
# Create a unified summary table
|
|
184
|
+
summary_table = HTCLITable(title="Wallet Summary")
|
|
185
|
+
summary_table.add_column("Property", style="bold white")
|
|
186
|
+
summary_table.add_column("Coldkey", style="cyan")
|
|
187
|
+
summary_table.add_column("Hotkey", style="yellow")
|
|
188
|
+
|
|
189
|
+
summary_table.add_row("Name", coldkey_response.name, hotkey_response.name)
|
|
190
|
+
summary_table.add_row(
|
|
191
|
+
"Address", address(coldkey_response.address), address(hotkey_response.address)
|
|
192
|
+
)
|
|
193
|
+
summary_table.add_row(
|
|
194
|
+
"Key Type", coldkey_response.key_type.upper(), hotkey_response.key_type.upper()
|
|
195
|
+
)
|
|
196
|
+
summary_table.add_row(
|
|
197
|
+
"Encryption",
|
|
198
|
+
"🔒 Enabled" if coldkey_response.encrypted else "Disabled",
|
|
199
|
+
"🔒 Enabled" if hotkey_response.encrypted else "Disabled",
|
|
200
|
+
)
|
|
201
|
+
summary_table.add_row(
|
|
202
|
+
"Owner", "—", f"{coldkey_response.name} ({address(coldkey_response.address)})"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
console.print(summary_table.table)
|
|
206
|
+
console.print()
|
|
207
|
+
|
|
208
|
+
# Display both mnemonics in a unified format
|
|
209
|
+
console.print("[bold red]🔐 Recovery Phrases[/bold red]\n")
|
|
210
|
+
console.print(
|
|
211
|
+
"[bold yellow]⚠️ CRITICAL: Store these phrases securely. They are the only way to recover your wallets.[/bold yellow]\n"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Coldkey mnemonic
|
|
215
|
+
console.print("[bold cyan]📘 Coldkey Recovery Phrase:[/bold cyan]")
|
|
216
|
+
display_mnemonic_panel(coldkey_response.mnemonic, coldkey_response.name, "Coldkey")
|
|
217
|
+
console.print()
|
|
218
|
+
|
|
219
|
+
# Hotkey mnemonic
|
|
220
|
+
console.print("[bold yellow]📗 Hotkey Recovery Phrase:[/bold yellow]")
|
|
221
|
+
display_mnemonic_panel(hotkey_response.mnemonic, hotkey_response.name, "Hotkey")
|
|
222
|
+
console.print()
|
|
223
|
+
|
|
224
|
+
# Handle clipboard copy
|
|
225
|
+
if copy_mnemonic:
|
|
226
|
+
# Copy both mnemonics (coldkey first, then hotkey)
|
|
227
|
+
combined = (
|
|
228
|
+
f"Coldkey: {coldkey_response.mnemonic}\nHotkey: {hotkey_response.mnemonic}"
|
|
229
|
+
)
|
|
230
|
+
_copy_to_clipboard(combined)
|
|
231
|
+
else:
|
|
232
|
+
# Offer to copy each mnemonic separately
|
|
233
|
+
if confirm_prompt("Copy coldkey recovery phrase to clipboard?", default=False):
|
|
234
|
+
_copy_to_clipboard(coldkey_response.mnemonic)
|
|
235
|
+
if confirm_prompt("Copy hotkey recovery phrase to clipboard?", default=False):
|
|
236
|
+
_copy_to_clipboard(hotkey_response.mnemonic)
|
|
237
|
+
|
|
238
|
+
# Final security reminder
|
|
239
|
+
console.print("\n[bold red]🔒 Security Reminder:[/bold red]")
|
|
240
|
+
console.print("• Store both recovery phrases in a secure, offline location")
|
|
241
|
+
console.print("• Never share them with anyone")
|
|
242
|
+
console.print("• Consider using a hardware wallet for additional security")
|
|
243
|
+
console.print("• Test your recovery process in a safe environment")
|
|
244
|
+
console.print("• Keep coldkey and hotkey phrases separate and clearly labeled")
|
|
245
|
+
console.print()
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def display_wallet_restoration_result(
|
|
249
|
+
response: WalletCreateResponse,
|
|
250
|
+
import_method: str,
|
|
251
|
+
owner_name: Optional[str] = None,
|
|
252
|
+
owner_address: Optional[str] = None,
|
|
253
|
+
):
|
|
254
|
+
"""Display wallet restoration results."""
|
|
255
|
+
print_success(f"Wallet restored successfully from {import_method}!")
|
|
256
|
+
console.print()
|
|
257
|
+
|
|
258
|
+
# Display key details in a table
|
|
259
|
+
table = HTCLITable(title="Restored Wallet Details")
|
|
260
|
+
table.add_column("Property", style="bold #5EE7FF")
|
|
261
|
+
table.add_column("Value", style="#CBD5E0")
|
|
262
|
+
table.add_row("Name", response.name)
|
|
263
|
+
table.add_row("Type", response.wallet_type.title())
|
|
264
|
+
table.add_row("Key Type", response.key_type.upper())
|
|
265
|
+
table.add_row("Address", address(response.address))
|
|
266
|
+
table.add_row("Public Key", response.public_key)
|
|
267
|
+
if owner_name and owner_address:
|
|
268
|
+
table.add_row("Owner", f"{owner_name} ({address(owner_address)})")
|
|
269
|
+
table.add_row("Encryption", "🔒 Enabled" if response.encrypted else "Disabled")
|
|
270
|
+
table.render()
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def display_wallet_list(response: WalletListResponse, format_type: str = "tree"):
|
|
274
|
+
"""Display wallet list using existing patterns."""
|
|
275
|
+
if not response.wallets:
|
|
276
|
+
# Show friendly panel when no wallets exist
|
|
277
|
+
content = """[htcli.info]📭 No wallets found in your wallet directory.[/htcli.info]
|
|
278
|
+
|
|
279
|
+
[htcli.subtitle]💡 To create your first wallet, use one of these commands:[/htcli.subtitle]
|
|
280
|
+
|
|
281
|
+
[htcli.value]• Generate a new coldkey:[/htcli.value]
|
|
282
|
+
[bold cyan]htcli wallet generate-coldkey --name <wallet-name>[/bold cyan]
|
|
283
|
+
|
|
284
|
+
[htcli.value]• Generate a new hotkey:[/htcli.value]
|
|
285
|
+
[bold cyan]htcli wallet generate-hotkey --name <hotkey-name> --owner <coldkey-name>[/bold cyan]
|
|
286
|
+
|
|
287
|
+
[htcli.value]• Restore from mnemonic:[/htcli.value]
|
|
288
|
+
[bold cyan]htcli wallet restore-coldkey --name <wallet-name>[/bold cyan]
|
|
289
|
+
|
|
290
|
+
[htcli.info]For more information, run: [bold]htcli wallet --help[/bold][/htcli.info]"""
|
|
291
|
+
|
|
292
|
+
panel = HTCLIPanel(
|
|
293
|
+
content,
|
|
294
|
+
title="💼 No Wallets Found",
|
|
295
|
+
border_style="htcli.info",
|
|
296
|
+
highlight=True,
|
|
297
|
+
)
|
|
298
|
+
panel.render(console.console)
|
|
299
|
+
console.print()
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
if format_type == "json":
|
|
303
|
+
console.print_json(data=response.wallets)
|
|
304
|
+
elif format_type == "table":
|
|
305
|
+
table = create_wallet_minimal_table(response.wallets)
|
|
306
|
+
console.print(table.table)
|
|
307
|
+
# Show summary
|
|
308
|
+
console.print(
|
|
309
|
+
f"\n[bold]Summary:[/bold] {response.coldkeys} coldkeys, {response.hotkeys} hotkeys"
|
|
310
|
+
)
|
|
311
|
+
else: # tree format
|
|
312
|
+
_ = create_wallet_hierarchy_tree(response.wallets)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def display_wallet_status(response: WalletStatusResponse, format_type: str = "table"):
|
|
316
|
+
"""Display wallet status using existing patterns."""
|
|
317
|
+
if not response.wallets:
|
|
318
|
+
print_warning("No wallets found.")
|
|
319
|
+
print_info("Create a wallet with: htcli wallet generate-coldkey")
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
console.print(primary("🔐 Your Blockchain Identity"))
|
|
323
|
+
console.print(f" Total Keys: {response.total_keys}")
|
|
324
|
+
console.print(f" Total Addresses: {response.total_addresses}")
|
|
325
|
+
console.print()
|
|
326
|
+
|
|
327
|
+
if format_type == "json":
|
|
328
|
+
console.print_json(data=response.wallets)
|
|
329
|
+
else:
|
|
330
|
+
table = create_wallet_minimal_table(response.wallets)
|
|
331
|
+
table.render()
|
|
332
|
+
# Show summary
|
|
333
|
+
console.print(
|
|
334
|
+
f"\n[bold]Summary:[/bold] {response.total_keys} keys, {response.total_addresses} addresses"
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def display_balance_info(address: str, balance: float = 0):
|
|
339
|
+
"""Display helpful information when balance is 0."""
|
|
340
|
+
if balance == 0:
|
|
341
|
+
console.print(
|
|
342
|
+
"\n[bold yellow]💡 Note:[/bold yellow] This wallet has no balance."
|
|
343
|
+
)
|
|
344
|
+
console.print(f"• To receive funds, share this address: [bold]{address}[/bold]")
|
|
345
|
+
console.print(
|
|
346
|
+
"• You can transfer funds from another wallet using: [bold]htcli wallet transfer[/bold]"
|
|
347
|
+
)
|
|
348
|
+
console.print("• Transaction fees are typically around 0.001-0.01 TENSOR")
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def display_all_wallet_balances(
|
|
352
|
+
wallet_balances: list[dict],
|
|
353
|
+
totals: dict,
|
|
354
|
+
format_type: str,
|
|
355
|
+
network_name: Optional[str] = None,
|
|
356
|
+
):
|
|
357
|
+
"""Display balance for all wallets using the new standardized table."""
|
|
358
|
+
if not wallet_balances:
|
|
359
|
+
print_warning("No wallets found or balances retrieved.")
|
|
360
|
+
return
|
|
361
|
+
|
|
362
|
+
if format_type == "json":
|
|
363
|
+
json_data = {
|
|
364
|
+
"wallets": [
|
|
365
|
+
{
|
|
366
|
+
"name": wb.get("name"),
|
|
367
|
+
"address": wb.get("address"),
|
|
368
|
+
"free_balance": wb.get("free_balance", 0),
|
|
369
|
+
"direct_stake": wb.get("direct_stake", 0),
|
|
370
|
+
"delegate_stake": wb.get("delegate_stake", 0),
|
|
371
|
+
"node_delegate_stake": wb.get("node_delegate_stake", 0),
|
|
372
|
+
"overwatch_stake": wb.get("overwatch_stake", 0),
|
|
373
|
+
"unbonding": wb.get("unbonding", 0),
|
|
374
|
+
"staked_balance": wb.get("staked_balance", 0),
|
|
375
|
+
"total_balance": wb.get("total_balance", 0),
|
|
376
|
+
}
|
|
377
|
+
for wb in wallet_balances
|
|
378
|
+
],
|
|
379
|
+
"totals": totals,
|
|
380
|
+
"network": network_name,
|
|
381
|
+
}
|
|
382
|
+
console.print_json(data=json_data)
|
|
383
|
+
else:
|
|
384
|
+
table = create_htcli_balance_table(
|
|
385
|
+
wallet_balances, totals, network_name=network_name, show_totals=True
|
|
386
|
+
)
|
|
387
|
+
console.print(Padding(table, (0, 0, 1, 0)))
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def display_single_wallet_balance(
|
|
391
|
+
response,
|
|
392
|
+
wallet_name: Optional[str],
|
|
393
|
+
wallet_type: str,
|
|
394
|
+
format_type: str,
|
|
395
|
+
show_guidance: bool,
|
|
396
|
+
staking_balance: int = 0,
|
|
397
|
+
staking_breakdown: Optional[dict] = None,
|
|
398
|
+
network_name: Optional[str] = None,
|
|
399
|
+
):
|
|
400
|
+
"""Display the balance for a single wallet or address using the new standardized table."""
|
|
401
|
+
breakdown = _normalize_staking_breakdown(staking_breakdown, staking_balance)
|
|
402
|
+
staking_balance = breakdown["total"]
|
|
403
|
+
balance_wei = _response_balance(response)
|
|
404
|
+
|
|
405
|
+
if format_type == "json":
|
|
406
|
+
data = response.dict() if hasattr(response, "dict") else response
|
|
407
|
+
if isinstance(data, dict):
|
|
408
|
+
data["staking_balance"] = staking_balance
|
|
409
|
+
data["staking_breakdown"] = {
|
|
410
|
+
"direct_stake": breakdown["direct_stake"],
|
|
411
|
+
"delegate_stake": breakdown["delegate_stake"],
|
|
412
|
+
"node_delegate_stake": breakdown["node_delegate_stake"],
|
|
413
|
+
"overwatch_stake": breakdown["overwatch_stake"],
|
|
414
|
+
"unbonding": breakdown["unbonding"],
|
|
415
|
+
}
|
|
416
|
+
data["total_balance"] = balance_wei + staking_balance
|
|
417
|
+
console.print_json(data=data)
|
|
418
|
+
return
|
|
419
|
+
|
|
420
|
+
# BalanceResponse has fields directly - convert from wei to TENSOR for display
|
|
421
|
+
total_balance = balance_wei + staking_balance
|
|
422
|
+
|
|
423
|
+
table = create_htcli_balance_table(
|
|
424
|
+
[
|
|
425
|
+
{
|
|
426
|
+
"name": wallet_name or wallet_type,
|
|
427
|
+
"address": response.address or "Unknown",
|
|
428
|
+
"free_balance": balance_wei,
|
|
429
|
+
"direct_stake": breakdown["direct_stake"],
|
|
430
|
+
"delegate_stake": breakdown["delegate_stake"],
|
|
431
|
+
"node_delegate_stake": breakdown["node_delegate_stake"],
|
|
432
|
+
"overwatch_stake": breakdown["overwatch_stake"],
|
|
433
|
+
"unbonding": breakdown["unbonding"],
|
|
434
|
+
"staked_balance": staking_balance,
|
|
435
|
+
"total_balance": total_balance,
|
|
436
|
+
}
|
|
437
|
+
],
|
|
438
|
+
totals={
|
|
439
|
+
"free": balance_wei,
|
|
440
|
+
"direct_stake": breakdown["direct_stake"],
|
|
441
|
+
"delegate_stake": breakdown["delegate_stake"],
|
|
442
|
+
"node_delegate_stake": breakdown["node_delegate_stake"],
|
|
443
|
+
"overwatch_stake": breakdown["overwatch_stake"],
|
|
444
|
+
"unbonding": breakdown["unbonding"],
|
|
445
|
+
"staked": staking_balance,
|
|
446
|
+
"total": total_balance,
|
|
447
|
+
},
|
|
448
|
+
network_name=network_name,
|
|
449
|
+
show_totals=False,
|
|
450
|
+
)
|
|
451
|
+
console.print(Padding(table, (0, 0, 1, 0)))
|
|
452
|
+
|
|
453
|
+
# Display additional details in a panel below the table
|
|
454
|
+
# TODO: Re-enable panel after fixing display issues
|
|
455
|
+
# from ...ui.components import HTCLIPanel
|
|
456
|
+
|
|
457
|
+
# balance_wei = response.balance or 0
|
|
458
|
+
# details_content = f"""[htcli.accent]Account Information[/htcli.accent]
|
|
459
|
+
|
|
460
|
+
# [htcli.value]Wallet Name:[/htcli.value] {wallet_name or "N/A"}
|
|
461
|
+
# [htcli.value]Wallet Type:[/htcli.value] {wallet_type}
|
|
462
|
+
# [htcli.value]Address:[/htcli.value] {response.address or "Unknown"}
|
|
463
|
+
# [htcli.value]Status:[/htcli.value] Active
|
|
464
|
+
|
|
465
|
+
# [htcli.accent]Balance Details[/htcli.accent]
|
|
466
|
+
|
|
467
|
+
# [htcli.value]Balance (TENSOR):[/htcli.value] {balance_tensor:,.2f} TENSOR
|
|
468
|
+
# [htcli.value]Balance (Wei):[/htcli.value] {balance_wei:,} wei
|
|
469
|
+
# [htcli.value]Available:[/htcli.value] {balance_tensor:,.2f} TENSOR
|
|
470
|
+
# """
|
|
471
|
+
|
|
472
|
+
# details_panel = HTCLIPanel(
|
|
473
|
+
# details_content,
|
|
474
|
+
# title="📊 Account Details",
|
|
475
|
+
# border_style="htcli.info",
|
|
476
|
+
# padding=(1, 2),
|
|
477
|
+
# )
|
|
478
|
+
# details_panel.render()
|
|
479
|
+
|
|
480
|
+
if show_guidance:
|
|
481
|
+
display_balance_info(response.address or "Unknown", response.balance or 0)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def _response_balance(response) -> int:
|
|
485
|
+
if isinstance(response, dict):
|
|
486
|
+
return int(response.get("balance", 0) or 0)
|
|
487
|
+
return int(getattr(response, "balance", 0) or 0)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def _normalize_staking_breakdown(
|
|
491
|
+
staking_breakdown: Optional[dict], staking_balance: int
|
|
492
|
+
) -> dict:
|
|
493
|
+
component_keys = (
|
|
494
|
+
"direct_stake",
|
|
495
|
+
"delegate_stake",
|
|
496
|
+
"node_delegate_stake",
|
|
497
|
+
"overwatch_stake",
|
|
498
|
+
"unbonding",
|
|
499
|
+
)
|
|
500
|
+
breakdown = dict.fromkeys(component_keys, 0)
|
|
501
|
+
|
|
502
|
+
if staking_breakdown:
|
|
503
|
+
for key in component_keys:
|
|
504
|
+
breakdown[key] = int(staking_breakdown.get(key, 0) or 0)
|
|
505
|
+
|
|
506
|
+
component_total = sum(breakdown.values())
|
|
507
|
+
breakdown["total"] = int(
|
|
508
|
+
(staking_breakdown or {}).get("total", 0)
|
|
509
|
+
or component_total
|
|
510
|
+
or staking_balance
|
|
511
|
+
or 0
|
|
512
|
+
)
|
|
513
|
+
return breakdown
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def display_wallet_transfer_result(
|
|
517
|
+
response: WalletTransferResponse, dry_run: bool = False
|
|
518
|
+
):
|
|
519
|
+
"""Display wallet transfer results with beautiful formatting."""
|
|
520
|
+
from ...ui.components import HTCLIPanel
|
|
521
|
+
|
|
522
|
+
# Format the amount nicely - handle string type
|
|
523
|
+
if isinstance(response.amount, str):
|
|
524
|
+
try:
|
|
525
|
+
amount_float = float(response.amount)
|
|
526
|
+
amount_str = f"{amount_float:,.4f} TENSOR"
|
|
527
|
+
except (ValueError, TypeError):
|
|
528
|
+
amount_str = f"{response.amount} TENSOR"
|
|
529
|
+
elif isinstance(response.amount, (int, float)):
|
|
530
|
+
amount_str = f"{response.amount:,.4f} TENSOR"
|
|
531
|
+
else:
|
|
532
|
+
amount_str = str(response.amount)
|
|
533
|
+
|
|
534
|
+
# Safely format addresses with checksum
|
|
535
|
+
from ...utils.wallet.crypto import format_address_display
|
|
536
|
+
|
|
537
|
+
from_addr = (
|
|
538
|
+
format_address_display(str(response.from_address), truncate=False)
|
|
539
|
+
if response.from_address
|
|
540
|
+
else "Unknown"
|
|
541
|
+
)
|
|
542
|
+
to_addr = (
|
|
543
|
+
format_address_display(str(response.to_address), truncate=False)
|
|
544
|
+
if response.to_address
|
|
545
|
+
else "Unknown"
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
# Build content string
|
|
549
|
+
content = f"""[htcli.success]✅ Transfer completed successfully![/htcli.success]
|
|
550
|
+
|
|
551
|
+
[htcli.value]From:[/htcli.value] [htcli.address]{from_addr}[/htcli.address]
|
|
552
|
+
[htcli.value]To:[/htcli.value] [htcli.address]{to_addr}[/htcli.address]
|
|
553
|
+
[htcli.value]Amount:[/htcli.value] [htcli.amount]{amount_str}[/htcli.amount]
|
|
554
|
+
"""
|
|
555
|
+
|
|
556
|
+
# Add transaction details for real transfers
|
|
557
|
+
if not dry_run and response.transaction_hash:
|
|
558
|
+
content += f"\n[htcli.value]Transaction Hash:[/htcli.value] [htcli.subtitle]{response.transaction_hash}[/htcli.subtitle]\n"
|
|
559
|
+
# Add block hash if available
|
|
560
|
+
if response.block_hash:
|
|
561
|
+
content += f"[htcli.value]Block Hash:[/htcli.value] [htcli.subtitle]{response.block_hash}[/htcli.subtitle]\n"
|
|
562
|
+
|
|
563
|
+
# Display with HTCLIPanel
|
|
564
|
+
panel = HTCLIPanel(
|
|
565
|
+
content,
|
|
566
|
+
title="💸 Transfer Complete" if not dry_run else "🔍 Transfer Preview",
|
|
567
|
+
border_style="htcli.success" if not dry_run else "htcli.info",
|
|
568
|
+
highlight=True,
|
|
569
|
+
)
|
|
570
|
+
panel.render()
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def display_wallet_update_result(response: WalletUpdateResponse):
|
|
574
|
+
"""Display wallet update results."""
|
|
575
|
+
print_success("Wallet updated successfully!")
|
|
576
|
+
console.print()
|
|
577
|
+
|
|
578
|
+
console.print(f"[bold]Wallet:[/bold] {response.old_name} → {response.new_name}")
|
|
579
|
+
console.print(f"[bold]Address:[/bold] {address(response.address)}")
|
|
580
|
+
console.print(f"[bold]Key Type:[/bold] {response.key_type.upper()}")
|
|
581
|
+
|
|
582
|
+
console.print()
|
|
583
|
+
console.print("[bold]Updates:[/bold]")
|
|
584
|
+
console.print(
|
|
585
|
+
f" Name: {'✅ Updated' if response.name_updated else '❌ No change'}"
|
|
586
|
+
)
|
|
587
|
+
console.print(
|
|
588
|
+
f" Password: {'✅ Updated' if response.password_updated else '❌ No change'}"
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
if response.owner_updated is not None:
|
|
592
|
+
console.print(
|
|
593
|
+
f" Owner: {'✅ Updated' if response.owner_updated else '❌ No change'}"
|
|
594
|
+
)
|
|
595
|
+
if (
|
|
596
|
+
response.owner_updated
|
|
597
|
+
and response.old_owner_address
|
|
598
|
+
and response.new_owner_address
|
|
599
|
+
):
|
|
600
|
+
console.print(
|
|
601
|
+
f" {address(response.old_owner_address)} → {address(response.new_owner_address)}"
|
|
602
|
+
)
|
|
603
|
+
# Show on-chain transaction details if available
|
|
604
|
+
if response.transaction_hash:
|
|
605
|
+
console.print()
|
|
606
|
+
console.print("[bold]On-Chain Update:[/bold]")
|
|
607
|
+
console.print(f" Transaction: {response.transaction_hash}")
|
|
608
|
+
if response.block_hash:
|
|
609
|
+
console.print(f" Block Hash: {response.block_hash}")
|
|
610
|
+
if response.block_number:
|
|
611
|
+
console.print(f" Block Number: {response.block_number}")
|
|
612
|
+
console.print()
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def display_wallet_deletion_result(response: WalletDeleteResponse):
|
|
616
|
+
"""Display wallet deletion results in a beautiful panel."""
|
|
617
|
+
import sys
|
|
618
|
+
|
|
619
|
+
from ...ui.components import HTCLIPanel
|
|
620
|
+
|
|
621
|
+
# Build content string
|
|
622
|
+
content = f"""[htcli.success]🎉 Successfully deleted {response.total_deleted} wallet(s)[/htcli.success]
|
|
623
|
+
|
|
624
|
+
[htcli.title]📊 Deletion Statistics:[/htcli.title]
|
|
625
|
+
• Coldkeys: [htcli.value]{response.coldkeys_deleted}[/htcli.value]
|
|
626
|
+
• Standalone Hotkeys: [htcli.value]{response.hotkeys_deleted}[/htcli.value] (directly deleted)
|
|
627
|
+
• Associated Hotkeys: [htcli.value]{response.associated_hotkeys_deleted}[/htcli.value] (deleted with owner coldkey)"""
|
|
628
|
+
|
|
629
|
+
content += "\n\n[htcli.error]🗑️ Deleted Wallets:[/htcli.error]"
|
|
630
|
+
for wallet_name in response.deleted_wallets:
|
|
631
|
+
content += f"\n • [htcli.value]{wallet_name}[/htcli.value]"
|
|
632
|
+
|
|
633
|
+
# Show associated hotkey details if any
|
|
634
|
+
if response.associated_hotkey_details:
|
|
635
|
+
content += "\n\n[htcli.title]🔑 Associated Hotkeys Deleted:[/htcli.title]"
|
|
636
|
+
for hotkey_info in response.associated_hotkey_details:
|
|
637
|
+
hotkey_name = hotkey_info.get("name", "Unknown")
|
|
638
|
+
owner_name = hotkey_info.get("owner", "Unknown")
|
|
639
|
+
content += f"\n • [htcli.value]{hotkey_name}[/htcli.value] (owned by [htcli.accent]{owner_name}[/htcli.accent])"
|
|
640
|
+
|
|
641
|
+
content += (
|
|
642
|
+
"\n\n[htcli.warning]💡 Note: This action cannot be undone.[/htcli.warning]"
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
# Create and display panel
|
|
646
|
+
panel = HTCLIPanel(
|
|
647
|
+
content,
|
|
648
|
+
title="✅ Wallet Deletion Complete",
|
|
649
|
+
border_style="htcli.success",
|
|
650
|
+
highlight=True,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
console.print()
|
|
654
|
+
panel.render()
|
|
655
|
+
console.print()
|
|
656
|
+
|
|
657
|
+
# Ensure output is flushed
|
|
658
|
+
sys.stdout.flush()
|
|
659
|
+
sys.stderr.flush()
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def display_wallet_describe_result(wallet_info: dict, balance_info: dict = None):
|
|
663
|
+
"""Display comprehensive wallet information."""
|
|
664
|
+
from ...utils.blockchain.formatting import TensorAmount
|
|
665
|
+
|
|
666
|
+
print_success("Wallet Information")
|
|
667
|
+
console.print()
|
|
668
|
+
|
|
669
|
+
# Main wallet details table
|
|
670
|
+
table = HTCLITable(
|
|
671
|
+
title=f"[bold blue]📋 {wallet_info['name']} Details[/bold blue]",
|
|
672
|
+
border_style="blue",
|
|
673
|
+
header_style="bold cyan",
|
|
674
|
+
)
|
|
675
|
+
table.add_column("Property", style="bold white", width=20)
|
|
676
|
+
table.add_column("Value", style="bright_white", width=60)
|
|
677
|
+
|
|
678
|
+
# Basic wallet information
|
|
679
|
+
table.add_row("Name", wallet_info["name"])
|
|
680
|
+
table.add_row(
|
|
681
|
+
"Type", "Hotkey" if wallet_info.get("is_hotkey", False) else "Coldkey"
|
|
682
|
+
)
|
|
683
|
+
table.add_row("Key Type", wallet_info.get("key_type", "ECDSA").upper())
|
|
684
|
+
table.add_row("Address (Full)", address_full(wallet_info["address"]))
|
|
685
|
+
table.add_row("Public Key", wallet_info.get("public_key", "N/A"))
|
|
686
|
+
table.add_row(
|
|
687
|
+
"Encryption",
|
|
688
|
+
"🔒 Enabled" if wallet_info.get("encrypted", False) else "Disabled",
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
# Owner information for hotkeys
|
|
692
|
+
if wallet_info.get("is_hotkey", False) and wallet_info.get("owner_name"):
|
|
693
|
+
table.add_row(
|
|
694
|
+
"Owner",
|
|
695
|
+
f"{wallet_info['owner_name']} ({address(wallet_info.get('owner_address', 'N/A'))})",
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
console.print(table.table)
|
|
699
|
+
console.print()
|
|
700
|
+
|
|
701
|
+
# Balance information for coldkeys
|
|
702
|
+
if not wallet_info.get("is_hotkey", False) and balance_info:
|
|
703
|
+
if "error" in balance_info:
|
|
704
|
+
print_warning(f"Unable to fetch balance: {balance_info['error']}")
|
|
705
|
+
else:
|
|
706
|
+
balance_table = HTCLITable(
|
|
707
|
+
title="[bold green]💰 Balance Information[/bold green]",
|
|
708
|
+
border_style="green",
|
|
709
|
+
header_style="bold bright_green",
|
|
710
|
+
)
|
|
711
|
+
balance_table.add_column("Property", style="bold white", width=20)
|
|
712
|
+
balance_table.add_column("Value", style="bright_white", width=40)
|
|
713
|
+
|
|
714
|
+
try:
|
|
715
|
+
balance = balance_info.get("balance", 0)
|
|
716
|
+
if isinstance(balance, (int, float)) and balance > 0:
|
|
717
|
+
amount = TensorAmount.from_wei(balance)
|
|
718
|
+
balance_table.add_row(
|
|
719
|
+
"Free Balance", f"{amount.tensor:,.3f} TENSOR"
|
|
720
|
+
)
|
|
721
|
+
balance_table.add_row("Raw Balance", f"{balance:,}")
|
|
722
|
+
else:
|
|
723
|
+
balance_table.add_row("Free Balance", "0.000 TENSOR")
|
|
724
|
+
balance_table.add_row("Raw Balance", "0")
|
|
725
|
+
except Exception:
|
|
726
|
+
balance_table.add_row("Free Balance", "[red]Error calculating[/red]")
|
|
727
|
+
balance_table.add_row("Raw Balance", "[red]Error calculating[/red]")
|
|
728
|
+
|
|
729
|
+
console.print(balance_table.table)
|
|
730
|
+
console.print()
|
|
731
|
+
|
|
732
|
+
# Additional information for hotkeys
|
|
733
|
+
if wallet_info.get("is_hotkey", False):
|
|
734
|
+
hotkey_table = HTCLITable(
|
|
735
|
+
title="[bold yellow]Hotkey Information[/bold yellow]",
|
|
736
|
+
border_style="yellow",
|
|
737
|
+
header_style="bold bright_yellow",
|
|
738
|
+
)
|
|
739
|
+
hotkey_table.add_column("Property", style="bold white", width=20)
|
|
740
|
+
hotkey_table.add_column("Value", style="bright_white", width=40)
|
|
741
|
+
|
|
742
|
+
hotkey_table.add_row("Purpose", "Used for node operations and staking")
|
|
743
|
+
hotkey_table.add_row(
|
|
744
|
+
"Security", "Keep this key secure but accessible for node operations"
|
|
745
|
+
)
|
|
746
|
+
hotkey_table.add_row("Owner", wallet_info.get("owner_name", "Unknown"))
|
|
747
|
+
|
|
748
|
+
console.print(hotkey_table.table)
|
|
749
|
+
console.print()
|
|
750
|
+
|
|
751
|
+
# Security reminders
|
|
752
|
+
security_table = HTCLITable(
|
|
753
|
+
title="[bold red]🔒 Security Information[/bold red]",
|
|
754
|
+
border_style="red",
|
|
755
|
+
header_style="bold bright_red",
|
|
756
|
+
)
|
|
757
|
+
security_table.add_column("Property", style="bold white", width=20)
|
|
758
|
+
security_table.add_column("Value", style="bright_white", width=60)
|
|
759
|
+
|
|
760
|
+
if wallet_info.get("is_hotkey", False):
|
|
761
|
+
security_table.add_row("Backup", "Store hotkey securely for node operations")
|
|
762
|
+
security_table.add_row("Access", "Keep accessible for automated node functions")
|
|
763
|
+
security_table.add_row("Rotation", "Consider rotating hotkeys periodically")
|
|
764
|
+
else:
|
|
765
|
+
security_table.add_row("Backup", "Store coldkey in secure, offline location")
|
|
766
|
+
security_table.add_row("Access", "Limit access to essential operations only")
|
|
767
|
+
security_table.add_row(
|
|
768
|
+
"Recovery", "Keep recovery phrase in multiple secure locations"
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
console.print(security_table.table)
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
def display_identity_update_result(response: dict, hotkey_address: str):
|
|
775
|
+
"""Display identity update results."""
|
|
776
|
+
print_success("Identity updated successfully!")
|
|
777
|
+
console.print()
|
|
778
|
+
|
|
779
|
+
# Display identity details in a table
|
|
780
|
+
table = HTCLITable(
|
|
781
|
+
title="[bold blue]🆔 Identity Information[/bold blue]",
|
|
782
|
+
border_style="blue",
|
|
783
|
+
header_style="bold cyan",
|
|
784
|
+
)
|
|
785
|
+
table.add_column("Property", style="bold white", width=20)
|
|
786
|
+
table.add_column("Value", style="bright_white", width=60)
|
|
787
|
+
|
|
788
|
+
# Hotkey Address
|
|
789
|
+
table.add_row("Hotkey", address(hotkey_address))
|
|
790
|
+
|
|
791
|
+
# Parse fields from the extrinsic call if possible, or display generic success
|
|
792
|
+
# Since we don't have the full parsed identity object here, we'll show what we can
|
|
793
|
+
# Ideally, we should fetch the updated identity to show here, but for now:
|
|
794
|
+
|
|
795
|
+
console.print(table.table)
|
|
796
|
+
console.print()
|
|
797
|
+
|
|
798
|
+
# Transaction details
|
|
799
|
+
if response.get("transaction_hash"):
|
|
800
|
+
console.print("[bold]Transaction Details:[/bold]")
|
|
801
|
+
console.print(f" Transaction Hash: {response.get('transaction_hash')}")
|
|
802
|
+
if response.get("block_hash"):
|
|
803
|
+
console.print(f" Block Hash: {response.get('block_hash')}")
|
|
804
|
+
if response.get("block_number"):
|
|
805
|
+
console.print(f" Block Number: {response.get('block_number')}")
|
|
806
|
+
console.print()
|