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,1902 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Stake command handlers for RPC-based operations and extrinsic operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from ...dependencies import get_client
|
|
8
|
+
from ...errors.handlers import handle_and_display_error
|
|
9
|
+
from ...ui.components import HTCLILoadingContext
|
|
10
|
+
from ...utils import retrieve_wallet_with_validation
|
|
11
|
+
from .display import (
|
|
12
|
+
display_claim_result,
|
|
13
|
+
display_coldkey_stakes_rpc,
|
|
14
|
+
display_delegate_donate_result,
|
|
15
|
+
display_delegate_stake_result,
|
|
16
|
+
display_delegate_stakes_rpc,
|
|
17
|
+
display_delegate_swap_result,
|
|
18
|
+
display_delegate_transfer_result,
|
|
19
|
+
display_node_delegate_donate_result,
|
|
20
|
+
display_node_delegate_stake_result,
|
|
21
|
+
display_node_delegate_stakes_rpc,
|
|
22
|
+
display_node_delegate_swap_result,
|
|
23
|
+
display_node_delegate_transfer_result,
|
|
24
|
+
display_proof_of_stake_rpc,
|
|
25
|
+
display_stake_add_result,
|
|
26
|
+
display_stake_remove_result,
|
|
27
|
+
display_swap_node_to_subnet_result,
|
|
28
|
+
display_swap_queue_update_result,
|
|
29
|
+
display_swap_subnet_to_node_result,
|
|
30
|
+
display_swap_subnet_to_validator_result,
|
|
31
|
+
display_swap_validator_to_subnet_result,
|
|
32
|
+
display_validator_delegate_donate_result,
|
|
33
|
+
display_validator_delegate_stake_result,
|
|
34
|
+
display_validator_delegate_swap_result,
|
|
35
|
+
display_validator_delegate_transfer_result,
|
|
36
|
+
)
|
|
37
|
+
from .error_handling import handle_stake_error
|
|
38
|
+
from .prompts import (
|
|
39
|
+
prompt_delegate_donate,
|
|
40
|
+
prompt_delegate_stake_add,
|
|
41
|
+
prompt_delegate_stake_remove,
|
|
42
|
+
prompt_delegate_swap,
|
|
43
|
+
prompt_delegate_transfer,
|
|
44
|
+
prompt_node_delegate_donate,
|
|
45
|
+
prompt_node_delegate_stake_add,
|
|
46
|
+
prompt_node_delegate_stake_remove,
|
|
47
|
+
prompt_node_delegate_swap,
|
|
48
|
+
prompt_node_delegate_transfer,
|
|
49
|
+
prompt_stake_add,
|
|
50
|
+
prompt_stake_claim,
|
|
51
|
+
prompt_stake_remove,
|
|
52
|
+
prompt_swap_node_to_subnet,
|
|
53
|
+
prompt_swap_queue_update,
|
|
54
|
+
prompt_swap_subnet_to_node,
|
|
55
|
+
prompt_swap_subnet_to_validator,
|
|
56
|
+
prompt_swap_validator_to_subnet,
|
|
57
|
+
prompt_validator_delegate_donate,
|
|
58
|
+
prompt_validator_delegate_stake_add,
|
|
59
|
+
prompt_validator_delegate_stake_remove,
|
|
60
|
+
prompt_validator_delegate_swap,
|
|
61
|
+
prompt_validator_delegate_transfer,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_coldkey_stakes_handler(coldkey: Optional[str]):
|
|
66
|
+
"""Handle getting coldkey stakes using RPC.
|
|
67
|
+
|
|
68
|
+
Fetches all stake types:
|
|
69
|
+
- Direct stakes (from nodes owned by the coldkey)
|
|
70
|
+
- Delegate stakes (subnet delegate stakes)
|
|
71
|
+
- Node delegate stakes (node delegate stakes)
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
if coldkey is None:
|
|
75
|
+
from ...utils.prompts import string_prompt
|
|
76
|
+
|
|
77
|
+
coldkey = string_prompt("Enter coldkey address")
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
from ...utils.wallet.core import resolve_coldkey_address
|
|
81
|
+
|
|
82
|
+
resolved_coldkey = resolve_coldkey_address(coldkey)
|
|
83
|
+
except ValueError as e:
|
|
84
|
+
from ...ui.display import print_error
|
|
85
|
+
|
|
86
|
+
print_error(str(e))
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
client = get_client()
|
|
90
|
+
|
|
91
|
+
with HTCLILoadingContext(
|
|
92
|
+
f"Fetching all stakes for coldkey {resolved_coldkey}..."
|
|
93
|
+
):
|
|
94
|
+
# Fetch all three types of stakes
|
|
95
|
+
direct_stakes_result = client.rpc.wallet.network_get_coldkey_stakes(
|
|
96
|
+
resolved_coldkey
|
|
97
|
+
)
|
|
98
|
+
delegate_stakes_result = client.rpc.wallet.network_get_delegate_stakes(
|
|
99
|
+
resolved_coldkey
|
|
100
|
+
)
|
|
101
|
+
node_delegate_stakes_result = (
|
|
102
|
+
client.rpc.wallet.network_get_node_delegate_stakes(resolved_coldkey)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Display all stake types
|
|
106
|
+
has_any_stakes = False
|
|
107
|
+
|
|
108
|
+
# Display direct stakes
|
|
109
|
+
if direct_stakes_result.success and direct_stakes_result.data:
|
|
110
|
+
display_coldkey_stakes_rpc(direct_stakes_result.data, resolved_coldkey)
|
|
111
|
+
has_any_stakes = True
|
|
112
|
+
|
|
113
|
+
# Display delegate stakes
|
|
114
|
+
if delegate_stakes_result.success and delegate_stakes_result.data:
|
|
115
|
+
display_delegate_stakes_rpc(delegate_stakes_result.data, resolved_coldkey)
|
|
116
|
+
has_any_stakes = True
|
|
117
|
+
|
|
118
|
+
# Display node delegate stakes
|
|
119
|
+
if node_delegate_stakes_result.success and node_delegate_stakes_result.data:
|
|
120
|
+
display_node_delegate_stakes_rpc(
|
|
121
|
+
node_delegate_stakes_result.data, resolved_coldkey
|
|
122
|
+
)
|
|
123
|
+
has_any_stakes = True
|
|
124
|
+
|
|
125
|
+
# If no stakes found in any category
|
|
126
|
+
if not has_any_stakes:
|
|
127
|
+
from ...ui.colors import info
|
|
128
|
+
from ...ui.display import HTCLIConsole
|
|
129
|
+
|
|
130
|
+
console = HTCLIConsole()
|
|
131
|
+
console.print(info(f"No stakes found for coldkey {resolved_coldkey}"))
|
|
132
|
+
console.print(
|
|
133
|
+
info(
|
|
134
|
+
"Checked: direct stakes, delegate stakes, and node delegate stakes"
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
error_msg = str(e)
|
|
140
|
+
if not handle_stake_error(
|
|
141
|
+
error_msg,
|
|
142
|
+
None,
|
|
143
|
+
None,
|
|
144
|
+
"swap queue update",
|
|
145
|
+
client if "client" in locals() else None,
|
|
146
|
+
):
|
|
147
|
+
handle_and_display_error(e)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_delegate_stakes_handler(account: Optional[str]):
|
|
151
|
+
"""Handle getting delegate stakes using RPC."""
|
|
152
|
+
try:
|
|
153
|
+
if account is None:
|
|
154
|
+
from ...utils.prompts import string_prompt
|
|
155
|
+
|
|
156
|
+
account = string_prompt("Enter account address")
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
from ...utils.wallet.core import resolve_coldkey_address
|
|
160
|
+
|
|
161
|
+
account = resolve_coldkey_address(account)
|
|
162
|
+
except ValueError as e:
|
|
163
|
+
from ...ui.display import print_error
|
|
164
|
+
|
|
165
|
+
print_error(str(e))
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
client = get_client()
|
|
169
|
+
|
|
170
|
+
with HTCLILoadingContext(f"Fetching delegate stakes for account {account}..."):
|
|
171
|
+
result = client.rpc.wallet.network_get_delegate_stakes(account)
|
|
172
|
+
|
|
173
|
+
if result.success:
|
|
174
|
+
display_delegate_stakes_rpc(result.data, account)
|
|
175
|
+
else:
|
|
176
|
+
from ...ui.display import print_error
|
|
177
|
+
|
|
178
|
+
print_error(f"Failed to get delegate stakes: {result.message}")
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
error_msg = str(e)
|
|
182
|
+
if not handle_stake_error(
|
|
183
|
+
error_msg,
|
|
184
|
+
None,
|
|
185
|
+
None,
|
|
186
|
+
"swap queue update",
|
|
187
|
+
client if "client" in locals() else None,
|
|
188
|
+
):
|
|
189
|
+
handle_and_display_error(e)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def get_node_delegate_stakes_handler(account: Optional[str]):
|
|
193
|
+
"""Handle getting node delegate stakes using RPC."""
|
|
194
|
+
try:
|
|
195
|
+
if account is None:
|
|
196
|
+
from ...utils.prompts import string_prompt
|
|
197
|
+
|
|
198
|
+
account = string_prompt("Enter account address")
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
from ...utils.wallet.core import resolve_coldkey_address
|
|
202
|
+
|
|
203
|
+
account = resolve_coldkey_address(account)
|
|
204
|
+
except ValueError as e:
|
|
205
|
+
from ...ui.display import print_error
|
|
206
|
+
|
|
207
|
+
print_error(str(e))
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
client = get_client()
|
|
211
|
+
|
|
212
|
+
with HTCLILoadingContext(
|
|
213
|
+
f"Fetching node delegate stakes for account {account}..."
|
|
214
|
+
):
|
|
215
|
+
result = client.rpc.wallet.network_get_node_delegate_stakes(account)
|
|
216
|
+
|
|
217
|
+
if result.success:
|
|
218
|
+
display_node_delegate_stakes_rpc(result.data, account)
|
|
219
|
+
else:
|
|
220
|
+
from ...ui.display import print_error
|
|
221
|
+
|
|
222
|
+
print_error(f"Failed to get node delegate stakes: {result.message}")
|
|
223
|
+
|
|
224
|
+
except Exception as e:
|
|
225
|
+
error_msg = str(e)
|
|
226
|
+
if not handle_stake_error(
|
|
227
|
+
error_msg,
|
|
228
|
+
None,
|
|
229
|
+
None,
|
|
230
|
+
"swap queue update",
|
|
231
|
+
client if "client" in locals() else None,
|
|
232
|
+
):
|
|
233
|
+
handle_and_display_error(e)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def verify_proof_of_stake_handler(
|
|
237
|
+
subnet_id: Optional[int], peer_id: Optional[str], min_class: Optional[int]
|
|
238
|
+
):
|
|
239
|
+
"""Handle checking proof of stake using RPC."""
|
|
240
|
+
try:
|
|
241
|
+
if subnet_id is None:
|
|
242
|
+
from ...utils.prompts import integer_prompt
|
|
243
|
+
|
|
244
|
+
subnet_id = integer_prompt("Enter subnet ID")
|
|
245
|
+
|
|
246
|
+
if peer_id is None:
|
|
247
|
+
from ...utils.prompts import string_prompt
|
|
248
|
+
|
|
249
|
+
peer_id = string_prompt("Enter peer ID")
|
|
250
|
+
|
|
251
|
+
if min_class is None:
|
|
252
|
+
from ...utils.prompts import integer_prompt
|
|
253
|
+
|
|
254
|
+
min_class = integer_prompt("Enter minimum class (0-3)")
|
|
255
|
+
|
|
256
|
+
client = get_client()
|
|
257
|
+
|
|
258
|
+
# Convert peer_id to bytes for RPC
|
|
259
|
+
if isinstance(peer_id, str):
|
|
260
|
+
# Convert string to bytes
|
|
261
|
+
peer_id_bytes = peer_id.encode("utf-8")
|
|
262
|
+
else:
|
|
263
|
+
# Already bytes
|
|
264
|
+
peer_id_bytes = peer_id
|
|
265
|
+
|
|
266
|
+
with HTCLILoadingContext(f"Verifying proof of stake for peer {peer_id}..."):
|
|
267
|
+
result = client.rpc.subnet.network_proof_of_stake(
|
|
268
|
+
subnet_id, peer_id_bytes, min_class
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if result.success:
|
|
272
|
+
display_proof_of_stake_rpc(result.data, subnet_id, peer_id, min_class)
|
|
273
|
+
else:
|
|
274
|
+
from ...ui.display import print_error
|
|
275
|
+
|
|
276
|
+
print_error(f"Failed to verify proof of stake: {result.message}")
|
|
277
|
+
|
|
278
|
+
except Exception as e:
|
|
279
|
+
error_msg = str(e)
|
|
280
|
+
if not handle_stake_error(
|
|
281
|
+
error_msg,
|
|
282
|
+
None,
|
|
283
|
+
None,
|
|
284
|
+
"swap queue update",
|
|
285
|
+
client if "client" in locals() else None,
|
|
286
|
+
):
|
|
287
|
+
handle_and_display_error(e)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
# ============================================================================
|
|
291
|
+
# EXTRINSIC HANDLERS - Write Operations
|
|
292
|
+
# ============================================================================
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def add_stake_handler(
|
|
296
|
+
subnet_id: Optional[int] = None,
|
|
297
|
+
subnet_node_id: Optional[int] = None,
|
|
298
|
+
hotkey_address: Optional[str] = None,
|
|
299
|
+
stake_amount: Optional[float] = None,
|
|
300
|
+
coldkey: Optional[str] = None,
|
|
301
|
+
):
|
|
302
|
+
"""Handle adding stake to a node."""
|
|
303
|
+
try:
|
|
304
|
+
# STEP 1: Collect parameters via prompts
|
|
305
|
+
request = prompt_stake_add(
|
|
306
|
+
subnet_id=subnet_id,
|
|
307
|
+
node_id=subnet_node_id,
|
|
308
|
+
hotkey=hotkey_address, # Pass hotkey_address as hotkey parameter
|
|
309
|
+
amount=stake_amount,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# STEP 2: Get signing wallet
|
|
313
|
+
if coldkey:
|
|
314
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
315
|
+
|
|
316
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
317
|
+
else:
|
|
318
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
319
|
+
wallet_type="coldkey", purpose="sign the stake transaction"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# STEP 3: Execute via client
|
|
323
|
+
client = get_client()
|
|
324
|
+
with HTCLILoadingContext("Adding stake to node..."):
|
|
325
|
+
response = client.extrinsics.staking.add_stake(request, keypair)
|
|
326
|
+
|
|
327
|
+
# Check for errors in result
|
|
328
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
329
|
+
error_msg = response.get("error", "Stake add failed")
|
|
330
|
+
if handle_stake_error(
|
|
331
|
+
error_msg,
|
|
332
|
+
request.subnet_id,
|
|
333
|
+
request.subnet_node_id,
|
|
334
|
+
"add stake",
|
|
335
|
+
client,
|
|
336
|
+
):
|
|
337
|
+
return
|
|
338
|
+
|
|
339
|
+
# STEP 4: Display result
|
|
340
|
+
display_stake_add_result(response)
|
|
341
|
+
|
|
342
|
+
except Exception as e:
|
|
343
|
+
error_msg = str(e)
|
|
344
|
+
subnet_id_for_error = None
|
|
345
|
+
node_id_for_error = None
|
|
346
|
+
client_for_error = None
|
|
347
|
+
try:
|
|
348
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
349
|
+
node_id_for_error = (
|
|
350
|
+
request.subnet_node_id if "request" in locals() else None
|
|
351
|
+
)
|
|
352
|
+
client_for_error = client if "client" in locals() else None
|
|
353
|
+
except (AttributeError, NameError):
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
if not handle_stake_error(
|
|
357
|
+
error_msg,
|
|
358
|
+
subnet_id_for_error,
|
|
359
|
+
node_id_for_error,
|
|
360
|
+
"add stake",
|
|
361
|
+
client_for_error,
|
|
362
|
+
):
|
|
363
|
+
handle_and_display_error(e)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def remove_stake_handler(
|
|
367
|
+
subnet_id: Optional[int] = None,
|
|
368
|
+
hotkey: Optional[str] = None,
|
|
369
|
+
stake_amount: Optional[float] = None,
|
|
370
|
+
coldkey: Optional[str] = None,
|
|
371
|
+
):
|
|
372
|
+
"""Handle removing stake from a node."""
|
|
373
|
+
try:
|
|
374
|
+
# STEP 1: Resolve coldkey FIRST so we can use it for hotkey disambiguation
|
|
375
|
+
if coldkey:
|
|
376
|
+
from ...ui.display import print_error
|
|
377
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
378
|
+
|
|
379
|
+
try:
|
|
380
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey.strip())
|
|
381
|
+
except ValueError as e:
|
|
382
|
+
print_error(f"Failed to resolve coldkey '{coldkey}': {str(e)}")
|
|
383
|
+
print_error("Please provide a valid coldkey wallet name or address")
|
|
384
|
+
raise
|
|
385
|
+
except Exception as e:
|
|
386
|
+
raise RuntimeError(
|
|
387
|
+
f"Unexpected error resolving coldkey '{coldkey}': {str(e)}"
|
|
388
|
+
) from e
|
|
389
|
+
else:
|
|
390
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
391
|
+
wallet_type="coldkey", purpose="sign the unstake transaction"
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# STEP 2: Collect parameters (with coldkey context for hotkey disambiguation)
|
|
395
|
+
request = prompt_stake_remove(
|
|
396
|
+
subnet_id=subnet_id,
|
|
397
|
+
hotkey=hotkey,
|
|
398
|
+
amount=stake_amount,
|
|
399
|
+
coldkey_name=wallet_name, # Pass coldkey name for hotkey disambiguation
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
# STEP 3: Execute
|
|
403
|
+
client = get_client()
|
|
404
|
+
with HTCLILoadingContext("Removing stake from node..."):
|
|
405
|
+
response = client.extrinsics.staking.remove_stake(request, keypair)
|
|
406
|
+
|
|
407
|
+
# Check for errors in result
|
|
408
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
409
|
+
error_msg = response.get("error", "Stake remove failed")
|
|
410
|
+
if handle_stake_error(
|
|
411
|
+
error_msg, request.subnet_id, None, "remove stake", client
|
|
412
|
+
):
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
# STEP 4: Display
|
|
416
|
+
display_stake_remove_result(response)
|
|
417
|
+
|
|
418
|
+
except Exception as e:
|
|
419
|
+
error_msg = str(e)
|
|
420
|
+
subnet_id_for_error = None
|
|
421
|
+
client_for_error = None
|
|
422
|
+
try:
|
|
423
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
424
|
+
client_for_error = client if "client" in locals() else None
|
|
425
|
+
except (AttributeError, NameError):
|
|
426
|
+
pass
|
|
427
|
+
|
|
428
|
+
if not handle_stake_error(
|
|
429
|
+
error_msg, subnet_id_for_error, None, "remove stake", client_for_error
|
|
430
|
+
):
|
|
431
|
+
handle_and_display_error(e)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def claim_handler(coldkey: Optional[str] = None, yes: bool = False):
|
|
435
|
+
"""Handle claiming unbonded tokens."""
|
|
436
|
+
try:
|
|
437
|
+
# STEP 1: Prompt for confirmation (unless --yes flag is set)
|
|
438
|
+
if not yes:
|
|
439
|
+
prompt_stake_claim()
|
|
440
|
+
|
|
441
|
+
# STEP 2: Get signing wallet
|
|
442
|
+
if coldkey:
|
|
443
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
444
|
+
|
|
445
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
446
|
+
else:
|
|
447
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
448
|
+
wallet_type="coldkey", purpose="sign the claim transaction"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
# STEP 3: Execute
|
|
452
|
+
client = get_client()
|
|
453
|
+
with HTCLILoadingContext("Claiming unbonded tokens..."):
|
|
454
|
+
response = client.extrinsics.staking.claim_unbondings(keypair)
|
|
455
|
+
|
|
456
|
+
# Check for errors in result
|
|
457
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
458
|
+
error_msg = response.get("error", "Claim failed")
|
|
459
|
+
if handle_stake_error(error_msg, None, None, "claim", client):
|
|
460
|
+
return
|
|
461
|
+
|
|
462
|
+
# STEP 4: Display
|
|
463
|
+
display_claim_result(response)
|
|
464
|
+
|
|
465
|
+
except Exception as e:
|
|
466
|
+
error_msg = str(e)
|
|
467
|
+
client_for_error = None
|
|
468
|
+
try:
|
|
469
|
+
client_for_error = client if "client" in locals() else None
|
|
470
|
+
except NameError:
|
|
471
|
+
pass
|
|
472
|
+
|
|
473
|
+
if not handle_stake_error(error_msg, None, None, "claim", client_for_error):
|
|
474
|
+
handle_and_display_error(e)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def delegate_add_handler(
|
|
478
|
+
subnet_id: Optional[int] = None,
|
|
479
|
+
node_id: Optional[int] = None,
|
|
480
|
+
stake_amount: Optional[float] = None,
|
|
481
|
+
coldkey: Optional[str] = None,
|
|
482
|
+
validator_id: Optional[int] = None,
|
|
483
|
+
):
|
|
484
|
+
"""Handle adding delegate stake to a subnet, validator, or specific node.
|
|
485
|
+
|
|
486
|
+
Routes to validator delegate if validator_id is provided, node delegate if
|
|
487
|
+
node_id is provided, otherwise subnet delegate.
|
|
488
|
+
"""
|
|
489
|
+
try:
|
|
490
|
+
from ...ui.prompts import confirm_prompt
|
|
491
|
+
|
|
492
|
+
if validator_id is not None:
|
|
493
|
+
request = prompt_validator_delegate_stake_add(
|
|
494
|
+
validator_id=validator_id,
|
|
495
|
+
stake_amount=stake_amount,
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
if coldkey:
|
|
499
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
500
|
+
|
|
501
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
502
|
+
else:
|
|
503
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
504
|
+
wallet_type="coldkey",
|
|
505
|
+
purpose="sign the validator delegate stake transaction",
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
client = get_client()
|
|
509
|
+
with HTCLILoadingContext("Adding delegate stake to validator..."):
|
|
510
|
+
response = client.extrinsics.staking.add_to_validator_delegate_stake(
|
|
511
|
+
request, keypair
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
515
|
+
error_msg = response.get("error", "Validator delegate stake add failed")
|
|
516
|
+
if handle_stake_error(
|
|
517
|
+
error_msg, None, None, "add validator delegate stake", client
|
|
518
|
+
):
|
|
519
|
+
return
|
|
520
|
+
|
|
521
|
+
display_validator_delegate_stake_result(response, operation="add")
|
|
522
|
+
return
|
|
523
|
+
|
|
524
|
+
# Determine if this is node-level or subnet-level delegation
|
|
525
|
+
is_node_delegation = node_id is not None
|
|
526
|
+
|
|
527
|
+
# If no node_id provided via CLI, ask if user wants node-level delegation
|
|
528
|
+
if not is_node_delegation and subnet_id is not None:
|
|
529
|
+
want_node = confirm_prompt(
|
|
530
|
+
"Do you want to delegate to a specific node?", default=False
|
|
531
|
+
)
|
|
532
|
+
if want_node:
|
|
533
|
+
is_node_delegation = True
|
|
534
|
+
|
|
535
|
+
if is_node_delegation:
|
|
536
|
+
# NODE DELEGATE PATH
|
|
537
|
+
request = prompt_node_delegate_stake_add(
|
|
538
|
+
subnet_id=subnet_id,
|
|
539
|
+
subnet_node_id=node_id,
|
|
540
|
+
stake_amount=stake_amount,
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
if coldkey:
|
|
544
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
545
|
+
|
|
546
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
547
|
+
else:
|
|
548
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
549
|
+
wallet_type="coldkey",
|
|
550
|
+
purpose="sign the node delegate stake transaction",
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
client = get_client()
|
|
554
|
+
with HTCLILoadingContext("Adding delegate stake to node..."):
|
|
555
|
+
response = client.extrinsics.staking.add_to_node_delegate_stake(
|
|
556
|
+
request, keypair
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
560
|
+
error_msg = response.get("error", "Node delegate stake add failed")
|
|
561
|
+
if handle_stake_error(
|
|
562
|
+
error_msg,
|
|
563
|
+
request.subnet_id,
|
|
564
|
+
request.subnet_node_id,
|
|
565
|
+
"add node delegate stake",
|
|
566
|
+
client,
|
|
567
|
+
):
|
|
568
|
+
return
|
|
569
|
+
|
|
570
|
+
display_node_delegate_stake_result(response, operation="add")
|
|
571
|
+
else:
|
|
572
|
+
# SUBNET DELEGATE PATH
|
|
573
|
+
request = prompt_delegate_stake_add(
|
|
574
|
+
subnet_id=subnet_id,
|
|
575
|
+
stake_amount=stake_amount,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
if coldkey:
|
|
579
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
580
|
+
|
|
581
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
582
|
+
else:
|
|
583
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
584
|
+
wallet_type="coldkey", purpose="sign the delegate stake transaction"
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
client = get_client()
|
|
588
|
+
with HTCLILoadingContext("Adding delegate stake to subnet..."):
|
|
589
|
+
response = client.extrinsics.staking.add_to_delegate_stake(
|
|
590
|
+
request, keypair
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
594
|
+
error_msg = response.get("error", "Delegate stake add failed")
|
|
595
|
+
if handle_stake_error(
|
|
596
|
+
error_msg, request.subnet_id, None, "add delegate stake", client
|
|
597
|
+
):
|
|
598
|
+
return
|
|
599
|
+
|
|
600
|
+
display_delegate_stake_result(response, operation="add")
|
|
601
|
+
|
|
602
|
+
except Exception as e:
|
|
603
|
+
error_msg = str(e)
|
|
604
|
+
subnet_id_for_error = None
|
|
605
|
+
node_id_for_error = None
|
|
606
|
+
client_for_error = None
|
|
607
|
+
try:
|
|
608
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
609
|
+
node_id_for_error = (
|
|
610
|
+
getattr(request, "subnet_node_id", None)
|
|
611
|
+
if "request" in locals()
|
|
612
|
+
else None
|
|
613
|
+
)
|
|
614
|
+
client_for_error = client if "client" in locals() else None
|
|
615
|
+
except (AttributeError, NameError):
|
|
616
|
+
pass
|
|
617
|
+
|
|
618
|
+
if not handle_stake_error(
|
|
619
|
+
error_msg,
|
|
620
|
+
subnet_id_for_error,
|
|
621
|
+
node_id_for_error,
|
|
622
|
+
"add delegate stake",
|
|
623
|
+
client_for_error,
|
|
624
|
+
):
|
|
625
|
+
handle_and_display_error(e)
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def delegate_remove_handler(
|
|
629
|
+
subnet_id: Optional[int] = None,
|
|
630
|
+
node_id: Optional[int] = None,
|
|
631
|
+
shares_to_remove: Optional[int] = None,
|
|
632
|
+
coldkey: Optional[str] = None,
|
|
633
|
+
validator_id: Optional[int] = None,
|
|
634
|
+
):
|
|
635
|
+
"""Handle removing delegate stake from a subnet, validator, or specific node.
|
|
636
|
+
|
|
637
|
+
Routes to validator delegate if validator_id is provided, node delegate if
|
|
638
|
+
node_id is provided, otherwise subnet delegate.
|
|
639
|
+
"""
|
|
640
|
+
try:
|
|
641
|
+
from ...ui.prompts import confirm_prompt
|
|
642
|
+
|
|
643
|
+
if validator_id is not None:
|
|
644
|
+
request = prompt_validator_delegate_stake_remove(
|
|
645
|
+
validator_id=validator_id,
|
|
646
|
+
shares_to_remove=shares_to_remove,
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
if coldkey:
|
|
650
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
651
|
+
|
|
652
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
653
|
+
else:
|
|
654
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
655
|
+
wallet_type="coldkey",
|
|
656
|
+
purpose="sign the validator delegate unstake transaction",
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
client = get_client()
|
|
660
|
+
with HTCLILoadingContext("Removing delegate stake from validator..."):
|
|
661
|
+
response = client.extrinsics.staking.remove_validator_delegate_stake(
|
|
662
|
+
request, keypair
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
666
|
+
error_msg = response.get(
|
|
667
|
+
"error", "Validator delegate stake remove failed"
|
|
668
|
+
)
|
|
669
|
+
if handle_stake_error(
|
|
670
|
+
error_msg, None, None, "remove validator delegate stake", client
|
|
671
|
+
):
|
|
672
|
+
return
|
|
673
|
+
|
|
674
|
+
display_validator_delegate_stake_result(response, operation="remove")
|
|
675
|
+
return
|
|
676
|
+
|
|
677
|
+
# Determine if this is node-level or subnet-level removal
|
|
678
|
+
is_node_delegation = node_id is not None
|
|
679
|
+
|
|
680
|
+
# If no node_id provided via CLI, ask if user wants node-level removal
|
|
681
|
+
if not is_node_delegation and subnet_id is not None:
|
|
682
|
+
want_node = confirm_prompt(
|
|
683
|
+
"Do you want to remove from a specific node?", default=False
|
|
684
|
+
)
|
|
685
|
+
if want_node:
|
|
686
|
+
is_node_delegation = True
|
|
687
|
+
|
|
688
|
+
if is_node_delegation:
|
|
689
|
+
# NODE DELEGATE PATH
|
|
690
|
+
request = prompt_node_delegate_stake_remove(
|
|
691
|
+
subnet_id=subnet_id,
|
|
692
|
+
subnet_node_id=node_id,
|
|
693
|
+
shares_to_remove=shares_to_remove,
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
if coldkey:
|
|
697
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
698
|
+
|
|
699
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
700
|
+
else:
|
|
701
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
702
|
+
wallet_type="coldkey",
|
|
703
|
+
purpose="sign the node delegate unstake transaction",
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
client = get_client()
|
|
707
|
+
with HTCLILoadingContext("Removing delegate stake from node..."):
|
|
708
|
+
response = client.extrinsics.staking.remove_node_delegate_stake(
|
|
709
|
+
request, keypair
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
713
|
+
error_msg = response.get("error", "Node delegate stake remove failed")
|
|
714
|
+
if handle_stake_error(
|
|
715
|
+
error_msg,
|
|
716
|
+
request.subnet_id,
|
|
717
|
+
request.subnet_node_id,
|
|
718
|
+
"remove node delegate stake",
|
|
719
|
+
client,
|
|
720
|
+
):
|
|
721
|
+
return
|
|
722
|
+
|
|
723
|
+
display_node_delegate_stake_result(response, operation="remove")
|
|
724
|
+
else:
|
|
725
|
+
# SUBNET DELEGATE PATH
|
|
726
|
+
request = prompt_delegate_stake_remove(
|
|
727
|
+
subnet_id=subnet_id,
|
|
728
|
+
shares_to_remove=shares_to_remove,
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
if coldkey:
|
|
732
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
733
|
+
|
|
734
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
735
|
+
else:
|
|
736
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
737
|
+
wallet_type="coldkey",
|
|
738
|
+
purpose="sign the delegate unstake transaction",
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
client = get_client()
|
|
742
|
+
with HTCLILoadingContext("Removing delegate stake from subnet..."):
|
|
743
|
+
response = client.extrinsics.staking.remove_delegate_stake(
|
|
744
|
+
request, keypair
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
748
|
+
error_msg = response.get("error", "Delegate stake remove failed")
|
|
749
|
+
if handle_stake_error(
|
|
750
|
+
error_msg, request.subnet_id, None, "remove delegate stake", client
|
|
751
|
+
):
|
|
752
|
+
return
|
|
753
|
+
|
|
754
|
+
display_delegate_stake_result(response, operation="remove")
|
|
755
|
+
|
|
756
|
+
except Exception as e:
|
|
757
|
+
error_msg = str(e)
|
|
758
|
+
subnet_id_for_error = None
|
|
759
|
+
node_id_for_error = None
|
|
760
|
+
client_for_error = None
|
|
761
|
+
try:
|
|
762
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
763
|
+
node_id_for_error = (
|
|
764
|
+
getattr(request, "subnet_node_id", None)
|
|
765
|
+
if "request" in locals()
|
|
766
|
+
else None
|
|
767
|
+
)
|
|
768
|
+
client_for_error = client if "client" in locals() else None
|
|
769
|
+
except (AttributeError, NameError):
|
|
770
|
+
pass
|
|
771
|
+
|
|
772
|
+
if not handle_stake_error(
|
|
773
|
+
error_msg,
|
|
774
|
+
subnet_id_for_error,
|
|
775
|
+
node_id_for_error,
|
|
776
|
+
"remove delegate stake",
|
|
777
|
+
client_for_error,
|
|
778
|
+
):
|
|
779
|
+
handle_and_display_error(e)
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
def node_delegate_add_handler(
|
|
783
|
+
subnet_id: Optional[int] = None,
|
|
784
|
+
subnet_node_id: Optional[int] = None,
|
|
785
|
+
stake_amount: Optional[float] = None,
|
|
786
|
+
coldkey: Optional[str] = None,
|
|
787
|
+
):
|
|
788
|
+
"""Handle adding delegate stake to a specific node."""
|
|
789
|
+
try:
|
|
790
|
+
# STEP 1: Collect parameters
|
|
791
|
+
request = prompt_node_delegate_stake_add(
|
|
792
|
+
subnet_id=subnet_id,
|
|
793
|
+
subnet_node_id=subnet_node_id,
|
|
794
|
+
stake_amount=stake_amount,
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
# STEP 2: Get signing wallet (use coldkey if provided)
|
|
798
|
+
if coldkey:
|
|
799
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
800
|
+
|
|
801
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
802
|
+
else:
|
|
803
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
804
|
+
wallet_type="coldkey",
|
|
805
|
+
purpose="sign the node delegate stake transaction",
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
# STEP 3: Execute
|
|
809
|
+
client = get_client()
|
|
810
|
+
with HTCLILoadingContext("Adding delegate stake to node..."):
|
|
811
|
+
response = client.extrinsics.staking.add_to_node_delegate_stake(
|
|
812
|
+
request, keypair
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
# Check for errors in result
|
|
816
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
817
|
+
error_msg = response.get("error", "Node delegate stake add failed")
|
|
818
|
+
if handle_stake_error(
|
|
819
|
+
error_msg,
|
|
820
|
+
request.subnet_id,
|
|
821
|
+
request.subnet_node_id,
|
|
822
|
+
"add node delegate stake",
|
|
823
|
+
client,
|
|
824
|
+
):
|
|
825
|
+
return
|
|
826
|
+
|
|
827
|
+
# STEP 4: Display
|
|
828
|
+
display_node_delegate_stake_result(response, operation="add")
|
|
829
|
+
|
|
830
|
+
except Exception as e:
|
|
831
|
+
error_msg = str(e)
|
|
832
|
+
subnet_id_for_error = None
|
|
833
|
+
node_id_for_error = None
|
|
834
|
+
client_for_error = None
|
|
835
|
+
try:
|
|
836
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
837
|
+
node_id_for_error = (
|
|
838
|
+
request.subnet_node_id if "request" in locals() else None
|
|
839
|
+
)
|
|
840
|
+
client_for_error = client if "client" in locals() else None
|
|
841
|
+
except (AttributeError, NameError):
|
|
842
|
+
pass
|
|
843
|
+
|
|
844
|
+
if not handle_stake_error(
|
|
845
|
+
error_msg,
|
|
846
|
+
subnet_id_for_error,
|
|
847
|
+
node_id_for_error,
|
|
848
|
+
"add node delegate stake",
|
|
849
|
+
client_for_error,
|
|
850
|
+
):
|
|
851
|
+
handle_and_display_error(e)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def node_delegate_remove_handler(
|
|
855
|
+
subnet_id: Optional[int] = None,
|
|
856
|
+
subnet_node_id: Optional[int] = None,
|
|
857
|
+
shares_to_remove: Optional[int] = None,
|
|
858
|
+
):
|
|
859
|
+
"""Handle removing delegate stake from a specific node."""
|
|
860
|
+
try:
|
|
861
|
+
# STEP 1: Collect parameters
|
|
862
|
+
request = prompt_node_delegate_stake_remove(
|
|
863
|
+
subnet_id=subnet_id,
|
|
864
|
+
subnet_node_id=subnet_node_id,
|
|
865
|
+
shares_to_remove=shares_to_remove,
|
|
866
|
+
)
|
|
867
|
+
|
|
868
|
+
# STEP 2: Get signing wallet
|
|
869
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
870
|
+
wallet_type="coldkey", purpose="sign the node delegate unstake transaction"
|
|
871
|
+
)
|
|
872
|
+
|
|
873
|
+
# STEP 3: Execute
|
|
874
|
+
client = get_client()
|
|
875
|
+
with HTCLILoadingContext("Removing delegate stake from node..."):
|
|
876
|
+
response = client.extrinsics.staking.remove_node_delegate_stake(
|
|
877
|
+
request, keypair
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
# Check for errors in result
|
|
881
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
882
|
+
error_msg = response.get("error", "Node delegate stake remove failed")
|
|
883
|
+
if handle_stake_error(
|
|
884
|
+
error_msg,
|
|
885
|
+
request.subnet_id,
|
|
886
|
+
request.subnet_node_id,
|
|
887
|
+
"remove node delegate stake",
|
|
888
|
+
client,
|
|
889
|
+
):
|
|
890
|
+
return
|
|
891
|
+
|
|
892
|
+
# STEP 4: Display
|
|
893
|
+
display_node_delegate_stake_result(response, operation="remove")
|
|
894
|
+
|
|
895
|
+
except Exception as e:
|
|
896
|
+
error_msg = str(e)
|
|
897
|
+
subnet_id_for_error = None
|
|
898
|
+
node_id_for_error = None
|
|
899
|
+
client_for_error = None
|
|
900
|
+
try:
|
|
901
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
902
|
+
node_id_for_error = (
|
|
903
|
+
request.subnet_node_id if "request" in locals() else None
|
|
904
|
+
)
|
|
905
|
+
client_for_error = client if "client" in locals() else None
|
|
906
|
+
except (AttributeError, NameError):
|
|
907
|
+
pass
|
|
908
|
+
|
|
909
|
+
if not handle_stake_error(
|
|
910
|
+
error_msg,
|
|
911
|
+
subnet_id_for_error,
|
|
912
|
+
node_id_for_error,
|
|
913
|
+
"remove node delegate stake",
|
|
914
|
+
client_for_error,
|
|
915
|
+
):
|
|
916
|
+
handle_and_display_error(e)
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def node_delegate_swap_handler(
|
|
920
|
+
from_subnet_id: Optional[int] = None,
|
|
921
|
+
from_subnet_node_id: Optional[int] = None,
|
|
922
|
+
to_subnet_id: Optional[int] = None,
|
|
923
|
+
to_subnet_node_id: Optional[int] = None,
|
|
924
|
+
shares_to_swap: Optional[int] = None,
|
|
925
|
+
coldkey: Optional[str] = None,
|
|
926
|
+
):
|
|
927
|
+
"""Handle swapping node delegate shares between nodes."""
|
|
928
|
+
try:
|
|
929
|
+
request = prompt_node_delegate_swap(
|
|
930
|
+
from_subnet_id=from_subnet_id,
|
|
931
|
+
from_subnet_node_id=from_subnet_node_id,
|
|
932
|
+
to_subnet_id=to_subnet_id,
|
|
933
|
+
to_subnet_node_id=to_subnet_node_id,
|
|
934
|
+
shares_to_swap=shares_to_swap,
|
|
935
|
+
)
|
|
936
|
+
|
|
937
|
+
if coldkey:
|
|
938
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
939
|
+
|
|
940
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
941
|
+
else:
|
|
942
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
943
|
+
wallet_type="coldkey", purpose="sign the node delegate swap transaction"
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
client = get_client()
|
|
947
|
+
with HTCLILoadingContext("Submitting node delegate swap..."):
|
|
948
|
+
response = client.extrinsics.staking.swap_node_delegate_stake(
|
|
949
|
+
request, keypair
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
# Check for errors in result
|
|
953
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
954
|
+
error_msg = response.get("error", "Node delegate swap failed")
|
|
955
|
+
if handle_stake_error(
|
|
956
|
+
error_msg,
|
|
957
|
+
request.to_subnet_id,
|
|
958
|
+
request.to_subnet_node_id,
|
|
959
|
+
"swap node delegate stake",
|
|
960
|
+
client,
|
|
961
|
+
):
|
|
962
|
+
return
|
|
963
|
+
|
|
964
|
+
display_node_delegate_swap_result(response)
|
|
965
|
+
|
|
966
|
+
except Exception as e:
|
|
967
|
+
error_msg = str(e)
|
|
968
|
+
subnet_id_for_error = None
|
|
969
|
+
node_id_for_error = None
|
|
970
|
+
client_for_error = None
|
|
971
|
+
try:
|
|
972
|
+
subnet_id_for_error = (
|
|
973
|
+
request.to_subnet_id if "request" in locals() else None
|
|
974
|
+
)
|
|
975
|
+
node_id_for_error = (
|
|
976
|
+
request.to_subnet_node_id if "request" in locals() else None
|
|
977
|
+
)
|
|
978
|
+
client_for_error = client if "client" in locals() else None
|
|
979
|
+
except (AttributeError, NameError):
|
|
980
|
+
pass
|
|
981
|
+
|
|
982
|
+
if not handle_stake_error(
|
|
983
|
+
error_msg,
|
|
984
|
+
subnet_id_for_error,
|
|
985
|
+
node_id_for_error,
|
|
986
|
+
"swap node delegate stake",
|
|
987
|
+
client_for_error,
|
|
988
|
+
):
|
|
989
|
+
handle_and_display_error(e)
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
def node_delegate_transfer_handler(
|
|
993
|
+
subnet_id: Optional[int] = None,
|
|
994
|
+
subnet_node_id: Optional[int] = None,
|
|
995
|
+
to_account: Optional[str] = None,
|
|
996
|
+
shares_to_transfer: Optional[int] = None,
|
|
997
|
+
coldkey: Optional[str] = None,
|
|
998
|
+
):
|
|
999
|
+
"""Handle transferring node delegate shares."""
|
|
1000
|
+
try:
|
|
1001
|
+
request = prompt_node_delegate_transfer(
|
|
1002
|
+
subnet_id=subnet_id,
|
|
1003
|
+
subnet_node_id=subnet_node_id,
|
|
1004
|
+
to_account=to_account,
|
|
1005
|
+
shares_to_transfer=shares_to_transfer,
|
|
1006
|
+
)
|
|
1007
|
+
|
|
1008
|
+
if coldkey:
|
|
1009
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1010
|
+
|
|
1011
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1012
|
+
else:
|
|
1013
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1014
|
+
wallet_type="coldkey",
|
|
1015
|
+
purpose="sign the node delegate transfer transaction",
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
client = get_client()
|
|
1019
|
+
with HTCLILoadingContext("Transferring node delegate shares..."):
|
|
1020
|
+
response = client.extrinsics.staking.transfer_node_delegate_stake(
|
|
1021
|
+
request, keypair
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
# Check for errors in result
|
|
1025
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1026
|
+
error_msg = response.get("error", "Node delegate transfer failed")
|
|
1027
|
+
if handle_stake_error(
|
|
1028
|
+
error_msg,
|
|
1029
|
+
request.subnet_id,
|
|
1030
|
+
request.subnet_node_id,
|
|
1031
|
+
"transfer node delegate stake",
|
|
1032
|
+
client,
|
|
1033
|
+
):
|
|
1034
|
+
return
|
|
1035
|
+
|
|
1036
|
+
display_node_delegate_transfer_result(response)
|
|
1037
|
+
|
|
1038
|
+
except Exception as e:
|
|
1039
|
+
error_msg = str(e)
|
|
1040
|
+
subnet_id_for_error = None
|
|
1041
|
+
node_id_for_error = None
|
|
1042
|
+
client_for_error = None
|
|
1043
|
+
try:
|
|
1044
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
1045
|
+
node_id_for_error = (
|
|
1046
|
+
request.subnet_node_id if "request" in locals() else None
|
|
1047
|
+
)
|
|
1048
|
+
client_for_error = client if "client" in locals() else None
|
|
1049
|
+
except (AttributeError, NameError):
|
|
1050
|
+
pass
|
|
1051
|
+
|
|
1052
|
+
if not handle_stake_error(
|
|
1053
|
+
error_msg,
|
|
1054
|
+
subnet_id_for_error,
|
|
1055
|
+
node_id_for_error,
|
|
1056
|
+
"transfer node delegate stake",
|
|
1057
|
+
client_for_error,
|
|
1058
|
+
):
|
|
1059
|
+
handle_and_display_error(e)
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
def node_delegate_donate_handler(
|
|
1063
|
+
subnet_id: Optional[int] = None,
|
|
1064
|
+
subnet_node_id: Optional[int] = None,
|
|
1065
|
+
amount: Optional[float] = None,
|
|
1066
|
+
coldkey: Optional[str] = None,
|
|
1067
|
+
):
|
|
1068
|
+
"""Handle donating to node delegate stake pool."""
|
|
1069
|
+
try:
|
|
1070
|
+
request = prompt_node_delegate_donate(
|
|
1071
|
+
subnet_id=subnet_id,
|
|
1072
|
+
subnet_node_id=subnet_node_id,
|
|
1073
|
+
amount=amount,
|
|
1074
|
+
)
|
|
1075
|
+
|
|
1076
|
+
if coldkey:
|
|
1077
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1078
|
+
|
|
1079
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1080
|
+
else:
|
|
1081
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1082
|
+
wallet_type="coldkey",
|
|
1083
|
+
purpose="sign the node delegate donation transaction",
|
|
1084
|
+
)
|
|
1085
|
+
|
|
1086
|
+
client = get_client()
|
|
1087
|
+
with HTCLILoadingContext("Submitting node delegate donation..."):
|
|
1088
|
+
response = client.extrinsics.staking.donate_node_delegate_stake(
|
|
1089
|
+
request, keypair
|
|
1090
|
+
)
|
|
1091
|
+
|
|
1092
|
+
# Check for errors in result
|
|
1093
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1094
|
+
error_msg = response.get("error", "Node delegate donation failed")
|
|
1095
|
+
if handle_stake_error(
|
|
1096
|
+
error_msg,
|
|
1097
|
+
request.subnet_id,
|
|
1098
|
+
request.subnet_node_id,
|
|
1099
|
+
"donate node delegate stake",
|
|
1100
|
+
client,
|
|
1101
|
+
):
|
|
1102
|
+
return
|
|
1103
|
+
|
|
1104
|
+
display_node_delegate_donate_result(response)
|
|
1105
|
+
|
|
1106
|
+
except Exception as e:
|
|
1107
|
+
error_msg = str(e)
|
|
1108
|
+
subnet_id_for_error = None
|
|
1109
|
+
node_id_for_error = None
|
|
1110
|
+
client_for_error = None
|
|
1111
|
+
try:
|
|
1112
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
1113
|
+
node_id_for_error = (
|
|
1114
|
+
request.subnet_node_id if "request" in locals() else None
|
|
1115
|
+
)
|
|
1116
|
+
client_for_error = client if "client" in locals() else None
|
|
1117
|
+
except (AttributeError, NameError):
|
|
1118
|
+
pass
|
|
1119
|
+
|
|
1120
|
+
if not handle_stake_error(
|
|
1121
|
+
error_msg,
|
|
1122
|
+
subnet_id_for_error,
|
|
1123
|
+
node_id_for_error,
|
|
1124
|
+
"donate node delegate stake",
|
|
1125
|
+
client_for_error,
|
|
1126
|
+
):
|
|
1127
|
+
handle_and_display_error(e)
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
def swap_node_to_subnet_handler(
|
|
1131
|
+
from_subnet_id: Optional[int] = None,
|
|
1132
|
+
from_subnet_node_id: Optional[int] = None,
|
|
1133
|
+
to_subnet_id: Optional[int] = None,
|
|
1134
|
+
shares_to_swap: Optional[int] = None,
|
|
1135
|
+
coldkey: Optional[str] = None,
|
|
1136
|
+
):
|
|
1137
|
+
"""Handle swap from node delegate stake to subnet delegate stake."""
|
|
1138
|
+
try:
|
|
1139
|
+
request = prompt_swap_node_to_subnet(
|
|
1140
|
+
from_subnet_id=from_subnet_id,
|
|
1141
|
+
from_subnet_node_id=from_subnet_node_id,
|
|
1142
|
+
to_subnet_id=to_subnet_id,
|
|
1143
|
+
shares_to_swap=shares_to_swap,
|
|
1144
|
+
)
|
|
1145
|
+
|
|
1146
|
+
if coldkey:
|
|
1147
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1148
|
+
|
|
1149
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1150
|
+
else:
|
|
1151
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1152
|
+
wallet_type="coldkey", purpose="sign the swap transaction"
|
|
1153
|
+
)
|
|
1154
|
+
|
|
1155
|
+
client = get_client()
|
|
1156
|
+
with HTCLILoadingContext("Submitting node → subnet swap..."):
|
|
1157
|
+
response = client.extrinsics.staking.swap_from_node_to_subnet(
|
|
1158
|
+
request, keypair
|
|
1159
|
+
)
|
|
1160
|
+
|
|
1161
|
+
# Check for errors in result
|
|
1162
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1163
|
+
error_msg = response.get("error", "Node to subnet swap failed")
|
|
1164
|
+
if handle_stake_error(
|
|
1165
|
+
error_msg, request.to_subnet_id, None, "swap node to subnet", client
|
|
1166
|
+
):
|
|
1167
|
+
return
|
|
1168
|
+
|
|
1169
|
+
display_swap_node_to_subnet_result(response)
|
|
1170
|
+
|
|
1171
|
+
except Exception as e:
|
|
1172
|
+
error_msg = str(e)
|
|
1173
|
+
subnet_id_for_error = None
|
|
1174
|
+
client_for_error = None
|
|
1175
|
+
try:
|
|
1176
|
+
subnet_id_for_error = (
|
|
1177
|
+
request.to_subnet_id if "request" in locals() else None
|
|
1178
|
+
)
|
|
1179
|
+
client_for_error = client if "client" in locals() else None
|
|
1180
|
+
except (AttributeError, NameError):
|
|
1181
|
+
pass
|
|
1182
|
+
|
|
1183
|
+
if not handle_stake_error(
|
|
1184
|
+
error_msg,
|
|
1185
|
+
subnet_id_for_error,
|
|
1186
|
+
None,
|
|
1187
|
+
"swap node to subnet",
|
|
1188
|
+
client_for_error,
|
|
1189
|
+
):
|
|
1190
|
+
handle_and_display_error(e)
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
def swap_subnet_to_node_handler(
|
|
1194
|
+
from_subnet_id: Optional[int] = None,
|
|
1195
|
+
to_subnet_id: Optional[int] = None,
|
|
1196
|
+
to_subnet_node_id: Optional[int] = None,
|
|
1197
|
+
shares_to_swap: Optional[int] = None,
|
|
1198
|
+
coldkey: Optional[str] = None,
|
|
1199
|
+
):
|
|
1200
|
+
"""Handle swap from subnet delegate stake to node delegate stake."""
|
|
1201
|
+
try:
|
|
1202
|
+
request = prompt_swap_subnet_to_node(
|
|
1203
|
+
from_subnet_id=from_subnet_id,
|
|
1204
|
+
to_subnet_id=to_subnet_id,
|
|
1205
|
+
to_subnet_node_id=to_subnet_node_id,
|
|
1206
|
+
shares_to_swap=shares_to_swap,
|
|
1207
|
+
)
|
|
1208
|
+
|
|
1209
|
+
if coldkey:
|
|
1210
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1211
|
+
|
|
1212
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1213
|
+
else:
|
|
1214
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1215
|
+
wallet_type="coldkey", purpose="sign the swap transaction"
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
client = get_client()
|
|
1219
|
+
with HTCLILoadingContext("Submitting subnet → node swap..."):
|
|
1220
|
+
response = client.extrinsics.staking.swap_from_subnet_to_node(
|
|
1221
|
+
request, keypair
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
# Check for errors in result
|
|
1225
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1226
|
+
error_msg = response.get("error", "Subnet to node swap failed")
|
|
1227
|
+
if handle_stake_error(
|
|
1228
|
+
error_msg,
|
|
1229
|
+
request.to_subnet_id,
|
|
1230
|
+
request.to_subnet_node_id,
|
|
1231
|
+
"swap subnet to node",
|
|
1232
|
+
client,
|
|
1233
|
+
):
|
|
1234
|
+
return
|
|
1235
|
+
|
|
1236
|
+
display_swap_subnet_to_node_result(response)
|
|
1237
|
+
|
|
1238
|
+
except Exception as e:
|
|
1239
|
+
error_msg = str(e)
|
|
1240
|
+
subnet_id_for_error = None
|
|
1241
|
+
node_id_for_error = None
|
|
1242
|
+
client_for_error = None
|
|
1243
|
+
try:
|
|
1244
|
+
subnet_id_for_error = (
|
|
1245
|
+
request.to_subnet_id if "request" in locals() else None
|
|
1246
|
+
)
|
|
1247
|
+
node_id_for_error = (
|
|
1248
|
+
request.to_subnet_node_id if "request" in locals() else None
|
|
1249
|
+
)
|
|
1250
|
+
client_for_error = client if "client" in locals() else None
|
|
1251
|
+
except (AttributeError, NameError):
|
|
1252
|
+
pass
|
|
1253
|
+
|
|
1254
|
+
if not handle_stake_error(
|
|
1255
|
+
error_msg,
|
|
1256
|
+
subnet_id_for_error,
|
|
1257
|
+
node_id_for_error,
|
|
1258
|
+
"swap subnet to node",
|
|
1259
|
+
client_for_error,
|
|
1260
|
+
):
|
|
1261
|
+
handle_and_display_error(e)
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
def swap_validator_to_subnet_handler(
|
|
1265
|
+
from_validator_id: Optional[int] = None,
|
|
1266
|
+
to_subnet_id: Optional[int] = None,
|
|
1267
|
+
shares_to_swap: Optional[int] = None,
|
|
1268
|
+
coldkey: Optional[str] = None,
|
|
1269
|
+
):
|
|
1270
|
+
"""Handle swap from validator delegate stake to subnet delegate stake."""
|
|
1271
|
+
try:
|
|
1272
|
+
request = prompt_swap_validator_to_subnet(
|
|
1273
|
+
from_validator_id=from_validator_id,
|
|
1274
|
+
to_subnet_id=to_subnet_id,
|
|
1275
|
+
shares_to_swap=shares_to_swap,
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
if coldkey:
|
|
1279
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1280
|
+
|
|
1281
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1282
|
+
else:
|
|
1283
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1284
|
+
wallet_type="coldkey",
|
|
1285
|
+
purpose="sign the validator to subnet swap transaction",
|
|
1286
|
+
)
|
|
1287
|
+
|
|
1288
|
+
client = get_client()
|
|
1289
|
+
with HTCLILoadingContext("Submitting validator → subnet swap..."):
|
|
1290
|
+
response = client.extrinsics.staking.swap_from_validator_to_subnet(
|
|
1291
|
+
request, keypair
|
|
1292
|
+
)
|
|
1293
|
+
|
|
1294
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1295
|
+
error_msg = response.get("error", "Validator to subnet swap failed")
|
|
1296
|
+
if handle_stake_error(
|
|
1297
|
+
error_msg,
|
|
1298
|
+
request.to_subnet_id,
|
|
1299
|
+
None,
|
|
1300
|
+
"swap validator to subnet",
|
|
1301
|
+
client,
|
|
1302
|
+
):
|
|
1303
|
+
return
|
|
1304
|
+
|
|
1305
|
+
display_swap_validator_to_subnet_result(response)
|
|
1306
|
+
|
|
1307
|
+
except Exception as e:
|
|
1308
|
+
error_msg = str(e)
|
|
1309
|
+
subnet_id_for_error = None
|
|
1310
|
+
client_for_error = None
|
|
1311
|
+
try:
|
|
1312
|
+
subnet_id_for_error = (
|
|
1313
|
+
request.to_subnet_id if "request" in locals() else None
|
|
1314
|
+
)
|
|
1315
|
+
client_for_error = client if "client" in locals() else None
|
|
1316
|
+
except (AttributeError, NameError):
|
|
1317
|
+
pass
|
|
1318
|
+
|
|
1319
|
+
if not handle_stake_error(
|
|
1320
|
+
error_msg,
|
|
1321
|
+
subnet_id_for_error,
|
|
1322
|
+
None,
|
|
1323
|
+
"swap validator to subnet",
|
|
1324
|
+
client_for_error,
|
|
1325
|
+
):
|
|
1326
|
+
handle_and_display_error(e)
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
def swap_subnet_to_validator_handler(
|
|
1330
|
+
from_subnet_id: Optional[int] = None,
|
|
1331
|
+
to_validator_id: Optional[int] = None,
|
|
1332
|
+
shares_to_swap: Optional[int] = None,
|
|
1333
|
+
coldkey: Optional[str] = None,
|
|
1334
|
+
):
|
|
1335
|
+
"""Handle swap from subnet delegate stake to validator delegate stake."""
|
|
1336
|
+
try:
|
|
1337
|
+
request = prompt_swap_subnet_to_validator(
|
|
1338
|
+
from_subnet_id=from_subnet_id,
|
|
1339
|
+
to_validator_id=to_validator_id,
|
|
1340
|
+
shares_to_swap=shares_to_swap,
|
|
1341
|
+
)
|
|
1342
|
+
|
|
1343
|
+
if coldkey:
|
|
1344
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1345
|
+
|
|
1346
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1347
|
+
else:
|
|
1348
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1349
|
+
wallet_type="coldkey",
|
|
1350
|
+
purpose="sign the subnet to validator swap transaction",
|
|
1351
|
+
)
|
|
1352
|
+
|
|
1353
|
+
client = get_client()
|
|
1354
|
+
with HTCLILoadingContext("Submitting subnet → validator swap..."):
|
|
1355
|
+
response = client.extrinsics.staking.swap_from_subnet_to_validator(
|
|
1356
|
+
request, keypair
|
|
1357
|
+
)
|
|
1358
|
+
|
|
1359
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1360
|
+
error_msg = response.get("error", "Subnet to validator swap failed")
|
|
1361
|
+
if handle_stake_error(
|
|
1362
|
+
error_msg,
|
|
1363
|
+
request.from_subnet_id,
|
|
1364
|
+
None,
|
|
1365
|
+
"swap subnet to validator",
|
|
1366
|
+
client,
|
|
1367
|
+
):
|
|
1368
|
+
return
|
|
1369
|
+
|
|
1370
|
+
display_swap_subnet_to_validator_result(response)
|
|
1371
|
+
|
|
1372
|
+
except Exception as e:
|
|
1373
|
+
error_msg = str(e)
|
|
1374
|
+
subnet_id_for_error = None
|
|
1375
|
+
client_for_error = None
|
|
1376
|
+
try:
|
|
1377
|
+
subnet_id_for_error = (
|
|
1378
|
+
request.from_subnet_id if "request" in locals() else None
|
|
1379
|
+
)
|
|
1380
|
+
client_for_error = client if "client" in locals() else None
|
|
1381
|
+
except (AttributeError, NameError):
|
|
1382
|
+
pass
|
|
1383
|
+
|
|
1384
|
+
if not handle_stake_error(
|
|
1385
|
+
error_msg,
|
|
1386
|
+
subnet_id_for_error,
|
|
1387
|
+
None,
|
|
1388
|
+
"swap subnet to validator",
|
|
1389
|
+
client_for_error,
|
|
1390
|
+
):
|
|
1391
|
+
handle_and_display_error(e)
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
def swap_queue_update_handler(
|
|
1395
|
+
queue_id: Optional[int] = None,
|
|
1396
|
+
new_call_json: Optional[str] = None,
|
|
1397
|
+
coldkey: Optional[str] = None,
|
|
1398
|
+
):
|
|
1399
|
+
"""Handle updating a queued swap entry."""
|
|
1400
|
+
try:
|
|
1401
|
+
request = prompt_swap_queue_update(
|
|
1402
|
+
queue_id=queue_id,
|
|
1403
|
+
new_call_json=new_call_json,
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
if coldkey:
|
|
1407
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1408
|
+
|
|
1409
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1410
|
+
else:
|
|
1411
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1412
|
+
wallet_type="coldkey", purpose="sign the swap queue update"
|
|
1413
|
+
)
|
|
1414
|
+
|
|
1415
|
+
client = get_client()
|
|
1416
|
+
with HTCLILoadingContext("Updating swap queue entry..."):
|
|
1417
|
+
response = client.extrinsics.staking.update_swap_queue(request, keypair)
|
|
1418
|
+
|
|
1419
|
+
display_swap_queue_update_result(response)
|
|
1420
|
+
|
|
1421
|
+
except Exception as e:
|
|
1422
|
+
error_msg = str(e)
|
|
1423
|
+
if not handle_stake_error(
|
|
1424
|
+
error_msg,
|
|
1425
|
+
None,
|
|
1426
|
+
None,
|
|
1427
|
+
"swap queue update",
|
|
1428
|
+
client if "client" in locals() else None,
|
|
1429
|
+
):
|
|
1430
|
+
handle_and_display_error(e)
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
def delegate_swap_handler(
|
|
1434
|
+
from_subnet_id: Optional[int] = None,
|
|
1435
|
+
from_node_id: Optional[int] = None,
|
|
1436
|
+
to_subnet_id: Optional[int] = None,
|
|
1437
|
+
to_node_id: Optional[int] = None,
|
|
1438
|
+
shares: Optional[int] = None,
|
|
1439
|
+
coldkey: Optional[str] = None,
|
|
1440
|
+
from_validator_id: Optional[int] = None,
|
|
1441
|
+
to_validator_id: Optional[int] = None,
|
|
1442
|
+
):
|
|
1443
|
+
"""Handle swapping delegate stake between subnets, validators, or nodes.
|
|
1444
|
+
|
|
1445
|
+
Routes to validator delegate swap if validator IDs are provided, node delegate
|
|
1446
|
+
swap if node IDs are provided, otherwise subnet delegate swap.
|
|
1447
|
+
"""
|
|
1448
|
+
try:
|
|
1449
|
+
from ...ui.prompts import confirm_prompt
|
|
1450
|
+
|
|
1451
|
+
if from_validator_id is not None or to_validator_id is not None:
|
|
1452
|
+
request = prompt_validator_delegate_swap(
|
|
1453
|
+
from_validator_id=from_validator_id,
|
|
1454
|
+
to_validator_id=to_validator_id,
|
|
1455
|
+
shares_to_swap=shares,
|
|
1456
|
+
)
|
|
1457
|
+
|
|
1458
|
+
if coldkey:
|
|
1459
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1460
|
+
|
|
1461
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1462
|
+
else:
|
|
1463
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1464
|
+
wallet_type="coldkey",
|
|
1465
|
+
purpose="sign the validator delegate swap transaction",
|
|
1466
|
+
)
|
|
1467
|
+
|
|
1468
|
+
client = get_client()
|
|
1469
|
+
with HTCLILoadingContext("Swapping validator delegate stake..."):
|
|
1470
|
+
response = client.extrinsics.staking.swap_validator_delegate_stake(
|
|
1471
|
+
request, keypair
|
|
1472
|
+
)
|
|
1473
|
+
|
|
1474
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1475
|
+
error_msg = response.get("error", "Validator delegate swap failed")
|
|
1476
|
+
if handle_stake_error(
|
|
1477
|
+
error_msg, None, None, "swap validator delegate stake", client
|
|
1478
|
+
):
|
|
1479
|
+
return
|
|
1480
|
+
|
|
1481
|
+
display_validator_delegate_swap_result(response)
|
|
1482
|
+
return
|
|
1483
|
+
|
|
1484
|
+
# Determine if this is node-level or subnet-level swap
|
|
1485
|
+
is_node_swap = from_node_id is not None or to_node_id is not None
|
|
1486
|
+
|
|
1487
|
+
# If no node IDs provided via CLI, ask if user wants node-level swap
|
|
1488
|
+
if not is_node_swap and from_subnet_id is not None:
|
|
1489
|
+
want_node = confirm_prompt(
|
|
1490
|
+
"Do you want to swap between specific nodes?", default=False
|
|
1491
|
+
)
|
|
1492
|
+
if want_node:
|
|
1493
|
+
is_node_swap = True
|
|
1494
|
+
|
|
1495
|
+
if is_node_swap:
|
|
1496
|
+
# NODE DELEGATE SWAP PATH
|
|
1497
|
+
request = prompt_node_delegate_swap(
|
|
1498
|
+
from_subnet_id=from_subnet_id,
|
|
1499
|
+
from_subnet_node_id=from_node_id,
|
|
1500
|
+
to_subnet_id=to_subnet_id,
|
|
1501
|
+
to_subnet_node_id=to_node_id,
|
|
1502
|
+
shares_to_swap=shares,
|
|
1503
|
+
)
|
|
1504
|
+
|
|
1505
|
+
if coldkey:
|
|
1506
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1507
|
+
|
|
1508
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1509
|
+
else:
|
|
1510
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1511
|
+
wallet_type="coldkey",
|
|
1512
|
+
purpose="sign the node delegate swap transaction",
|
|
1513
|
+
)
|
|
1514
|
+
|
|
1515
|
+
client = get_client()
|
|
1516
|
+
with HTCLILoadingContext("Swapping node delegate stake..."):
|
|
1517
|
+
response = client.extrinsics.staking.swap_node_delegate_stake(
|
|
1518
|
+
request, keypair
|
|
1519
|
+
)
|
|
1520
|
+
|
|
1521
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1522
|
+
error_msg = response.get("error", "Node delegate swap failed")
|
|
1523
|
+
if handle_stake_error(
|
|
1524
|
+
error_msg,
|
|
1525
|
+
request.to_subnet_id,
|
|
1526
|
+
request.to_subnet_node_id,
|
|
1527
|
+
"swap node delegate stake",
|
|
1528
|
+
client,
|
|
1529
|
+
):
|
|
1530
|
+
return
|
|
1531
|
+
|
|
1532
|
+
display_node_delegate_swap_result(response)
|
|
1533
|
+
else:
|
|
1534
|
+
# SUBNET DELEGATE SWAP PATH
|
|
1535
|
+
request = prompt_delegate_swap(
|
|
1536
|
+
from_subnet_id=from_subnet_id,
|
|
1537
|
+
to_subnet_id=to_subnet_id,
|
|
1538
|
+
shares=shares,
|
|
1539
|
+
)
|
|
1540
|
+
|
|
1541
|
+
if coldkey:
|
|
1542
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1543
|
+
|
|
1544
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1545
|
+
else:
|
|
1546
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1547
|
+
wallet_type="coldkey", purpose="sign the delegate swap transaction"
|
|
1548
|
+
)
|
|
1549
|
+
|
|
1550
|
+
client = get_client()
|
|
1551
|
+
with HTCLILoadingContext("Swapping delegate stake between subnets..."):
|
|
1552
|
+
response = client.extrinsics.staking.swap_delegate_stake(
|
|
1553
|
+
request, keypair
|
|
1554
|
+
)
|
|
1555
|
+
|
|
1556
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1557
|
+
error_msg = response.get("error", "Delegate swap failed")
|
|
1558
|
+
if handle_stake_error(
|
|
1559
|
+
error_msg, request.to_subnet_id, None, "swap delegate stake", client
|
|
1560
|
+
):
|
|
1561
|
+
return
|
|
1562
|
+
|
|
1563
|
+
display_delegate_swap_result(response)
|
|
1564
|
+
|
|
1565
|
+
except Exception as e:
|
|
1566
|
+
error_msg = str(e)
|
|
1567
|
+
subnet_id_for_error = None
|
|
1568
|
+
node_id_for_error = None
|
|
1569
|
+
client_for_error = None
|
|
1570
|
+
try:
|
|
1571
|
+
subnet_id_for_error = (
|
|
1572
|
+
request.to_subnet_id if "request" in locals() else None
|
|
1573
|
+
)
|
|
1574
|
+
node_id_for_error = (
|
|
1575
|
+
getattr(request, "to_subnet_node_id", None)
|
|
1576
|
+
if "request" in locals()
|
|
1577
|
+
else None
|
|
1578
|
+
)
|
|
1579
|
+
client_for_error = client if "client" in locals() else None
|
|
1580
|
+
except (AttributeError, NameError):
|
|
1581
|
+
pass
|
|
1582
|
+
|
|
1583
|
+
if not handle_stake_error(
|
|
1584
|
+
error_msg,
|
|
1585
|
+
subnet_id_for_error,
|
|
1586
|
+
node_id_for_error,
|
|
1587
|
+
"swap delegate stake",
|
|
1588
|
+
client_for_error,
|
|
1589
|
+
):
|
|
1590
|
+
handle_and_display_error(e)
|
|
1591
|
+
|
|
1592
|
+
|
|
1593
|
+
def delegate_transfer_handler(
|
|
1594
|
+
subnet_id: Optional[int] = None,
|
|
1595
|
+
node_id: Optional[int] = None,
|
|
1596
|
+
to_account: Optional[str] = None,
|
|
1597
|
+
shares: Optional[int] = None,
|
|
1598
|
+
coldkey: Optional[str] = None,
|
|
1599
|
+
validator_id: Optional[int] = None,
|
|
1600
|
+
):
|
|
1601
|
+
"""Handle transferring delegate stake to another account.
|
|
1602
|
+
|
|
1603
|
+
Routes to validator delegate if validator_id is provided, node delegate if
|
|
1604
|
+
node_id is provided, otherwise subnet delegate.
|
|
1605
|
+
"""
|
|
1606
|
+
try:
|
|
1607
|
+
from ...ui.prompts import confirm_prompt
|
|
1608
|
+
|
|
1609
|
+
if validator_id is not None:
|
|
1610
|
+
request = prompt_validator_delegate_transfer(
|
|
1611
|
+
validator_id=validator_id,
|
|
1612
|
+
to_account=to_account,
|
|
1613
|
+
shares_to_transfer=shares,
|
|
1614
|
+
)
|
|
1615
|
+
|
|
1616
|
+
if coldkey:
|
|
1617
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1618
|
+
|
|
1619
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1620
|
+
else:
|
|
1621
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1622
|
+
wallet_type="coldkey",
|
|
1623
|
+
purpose="sign the validator delegate transfer transaction",
|
|
1624
|
+
)
|
|
1625
|
+
|
|
1626
|
+
client = get_client()
|
|
1627
|
+
with HTCLILoadingContext("Transferring validator delegate stake..."):
|
|
1628
|
+
response = client.extrinsics.staking.transfer_validator_delegate_stake(
|
|
1629
|
+
request, keypair
|
|
1630
|
+
)
|
|
1631
|
+
|
|
1632
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1633
|
+
error_msg = response.get("error", "Validator delegate transfer failed")
|
|
1634
|
+
if handle_stake_error(
|
|
1635
|
+
error_msg, None, None, "transfer validator delegate stake", client
|
|
1636
|
+
):
|
|
1637
|
+
return
|
|
1638
|
+
|
|
1639
|
+
display_validator_delegate_transfer_result(response)
|
|
1640
|
+
return
|
|
1641
|
+
|
|
1642
|
+
# Determine if this is node-level or subnet-level transfer
|
|
1643
|
+
is_node_transfer = node_id is not None
|
|
1644
|
+
|
|
1645
|
+
# If no node_id provided via CLI, ask if user wants node-level transfer
|
|
1646
|
+
if not is_node_transfer and subnet_id is not None:
|
|
1647
|
+
want_node = confirm_prompt(
|
|
1648
|
+
"Do you want to transfer from a specific node?", default=False
|
|
1649
|
+
)
|
|
1650
|
+
if want_node:
|
|
1651
|
+
is_node_transfer = True
|
|
1652
|
+
|
|
1653
|
+
if is_node_transfer:
|
|
1654
|
+
# NODE DELEGATE TRANSFER PATH
|
|
1655
|
+
request = prompt_node_delegate_transfer(
|
|
1656
|
+
subnet_id=subnet_id,
|
|
1657
|
+
subnet_node_id=node_id,
|
|
1658
|
+
to_account=to_account,
|
|
1659
|
+
shares_to_transfer=shares,
|
|
1660
|
+
)
|
|
1661
|
+
|
|
1662
|
+
if coldkey:
|
|
1663
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1664
|
+
|
|
1665
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1666
|
+
else:
|
|
1667
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1668
|
+
wallet_type="coldkey",
|
|
1669
|
+
purpose="sign the node delegate transfer transaction",
|
|
1670
|
+
)
|
|
1671
|
+
|
|
1672
|
+
client = get_client()
|
|
1673
|
+
with HTCLILoadingContext("Transferring node delegate stake..."):
|
|
1674
|
+
response = client.extrinsics.staking.transfer_node_delegate_stake(
|
|
1675
|
+
request, keypair
|
|
1676
|
+
)
|
|
1677
|
+
|
|
1678
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1679
|
+
error_msg = response.get("error", "Node delegate transfer failed")
|
|
1680
|
+
if handle_stake_error(
|
|
1681
|
+
error_msg,
|
|
1682
|
+
request.subnet_id,
|
|
1683
|
+
request.subnet_node_id,
|
|
1684
|
+
"transfer node delegate stake",
|
|
1685
|
+
client,
|
|
1686
|
+
):
|
|
1687
|
+
return
|
|
1688
|
+
|
|
1689
|
+
display_node_delegate_transfer_result(response)
|
|
1690
|
+
else:
|
|
1691
|
+
# SUBNET DELEGATE TRANSFER PATH
|
|
1692
|
+
request = prompt_delegate_transfer(
|
|
1693
|
+
subnet_id=subnet_id,
|
|
1694
|
+
to_account=to_account,
|
|
1695
|
+
shares=shares, # For subnet transfer
|
|
1696
|
+
)
|
|
1697
|
+
|
|
1698
|
+
if coldkey:
|
|
1699
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1700
|
+
|
|
1701
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1702
|
+
else:
|
|
1703
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1704
|
+
wallet_type="coldkey",
|
|
1705
|
+
purpose="sign the delegate transfer transaction",
|
|
1706
|
+
)
|
|
1707
|
+
|
|
1708
|
+
client = get_client()
|
|
1709
|
+
with HTCLILoadingContext("Transferring delegate stake..."):
|
|
1710
|
+
response = client.extrinsics.staking.transfer_delegate_stake(
|
|
1711
|
+
request, keypair
|
|
1712
|
+
)
|
|
1713
|
+
|
|
1714
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1715
|
+
error_msg = response.get("error", "Delegate transfer failed")
|
|
1716
|
+
if handle_stake_error(
|
|
1717
|
+
error_msg,
|
|
1718
|
+
request.subnet_id,
|
|
1719
|
+
None,
|
|
1720
|
+
"transfer delegate stake",
|
|
1721
|
+
client,
|
|
1722
|
+
):
|
|
1723
|
+
return
|
|
1724
|
+
|
|
1725
|
+
display_delegate_transfer_result(response)
|
|
1726
|
+
|
|
1727
|
+
except Exception as e:
|
|
1728
|
+
error_msg = str(e)
|
|
1729
|
+
subnet_id_for_error = None
|
|
1730
|
+
node_id_for_error = None
|
|
1731
|
+
client_for_error = None
|
|
1732
|
+
try:
|
|
1733
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
1734
|
+
node_id_for_error = (
|
|
1735
|
+
getattr(request, "subnet_node_id", None)
|
|
1736
|
+
if "request" in locals()
|
|
1737
|
+
else None
|
|
1738
|
+
)
|
|
1739
|
+
client_for_error = client if "client" in locals() else None
|
|
1740
|
+
except (AttributeError, NameError):
|
|
1741
|
+
pass
|
|
1742
|
+
|
|
1743
|
+
if not handle_stake_error(
|
|
1744
|
+
error_msg,
|
|
1745
|
+
subnet_id_for_error,
|
|
1746
|
+
node_id_for_error,
|
|
1747
|
+
"transfer delegate stake",
|
|
1748
|
+
client_for_error,
|
|
1749
|
+
):
|
|
1750
|
+
handle_and_display_error(e)
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
def delegate_donate_handler(
|
|
1754
|
+
subnet_id: Optional[int] = None,
|
|
1755
|
+
node_id: Optional[int] = None,
|
|
1756
|
+
amount: Optional[float] = None,
|
|
1757
|
+
coldkey: Optional[str] = None,
|
|
1758
|
+
validator_id: Optional[int] = None,
|
|
1759
|
+
):
|
|
1760
|
+
"""Handle donating delegate stake to subnet treasury, validator, or node pool.
|
|
1761
|
+
|
|
1762
|
+
Routes to validator delegate if validator_id is provided, node delegate if
|
|
1763
|
+
node_id is provided, otherwise subnet delegate.
|
|
1764
|
+
"""
|
|
1765
|
+
try:
|
|
1766
|
+
from ...ui.prompts import confirm_prompt
|
|
1767
|
+
|
|
1768
|
+
if validator_id is not None:
|
|
1769
|
+
request = prompt_validator_delegate_donate(
|
|
1770
|
+
validator_id=validator_id,
|
|
1771
|
+
amount=amount,
|
|
1772
|
+
)
|
|
1773
|
+
|
|
1774
|
+
if coldkey:
|
|
1775
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1776
|
+
|
|
1777
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1778
|
+
else:
|
|
1779
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1780
|
+
wallet_type="coldkey",
|
|
1781
|
+
purpose="sign the validator delegate donation transaction",
|
|
1782
|
+
)
|
|
1783
|
+
|
|
1784
|
+
client = get_client()
|
|
1785
|
+
with HTCLILoadingContext("Donating to validator delegate pool..."):
|
|
1786
|
+
response = client.extrinsics.staking.donate_validator_delegate_stake(
|
|
1787
|
+
request, keypair
|
|
1788
|
+
)
|
|
1789
|
+
|
|
1790
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1791
|
+
error_msg = response.get("error", "Validator delegate donation failed")
|
|
1792
|
+
if handle_stake_error(
|
|
1793
|
+
error_msg, None, None, "donate validator delegate stake", client
|
|
1794
|
+
):
|
|
1795
|
+
return
|
|
1796
|
+
|
|
1797
|
+
display_validator_delegate_donate_result(response)
|
|
1798
|
+
return
|
|
1799
|
+
|
|
1800
|
+
# Determine if this is node-level or subnet-level donation
|
|
1801
|
+
is_node_donation = node_id is not None
|
|
1802
|
+
|
|
1803
|
+
# If no node_id provided via CLI, ask if user wants node-level donation
|
|
1804
|
+
if not is_node_donation and subnet_id is not None:
|
|
1805
|
+
want_node = confirm_prompt(
|
|
1806
|
+
"Do you want to donate to a specific node?", default=False
|
|
1807
|
+
)
|
|
1808
|
+
if want_node:
|
|
1809
|
+
is_node_donation = True
|
|
1810
|
+
|
|
1811
|
+
if is_node_donation:
|
|
1812
|
+
# NODE DELEGATE DONATE PATH
|
|
1813
|
+
request = prompt_node_delegate_donate(
|
|
1814
|
+
subnet_id=subnet_id,
|
|
1815
|
+
subnet_node_id=node_id,
|
|
1816
|
+
amount=amount,
|
|
1817
|
+
)
|
|
1818
|
+
|
|
1819
|
+
if coldkey:
|
|
1820
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1821
|
+
|
|
1822
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1823
|
+
else:
|
|
1824
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1825
|
+
wallet_type="coldkey",
|
|
1826
|
+
purpose="sign the node delegate donation transaction",
|
|
1827
|
+
)
|
|
1828
|
+
|
|
1829
|
+
client = get_client()
|
|
1830
|
+
with HTCLILoadingContext("Donating to node delegate pool..."):
|
|
1831
|
+
response = client.extrinsics.staking.donate_node_delegate_stake(
|
|
1832
|
+
request, keypair
|
|
1833
|
+
)
|
|
1834
|
+
|
|
1835
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1836
|
+
error_msg = response.get("error", "Node delegate donation failed")
|
|
1837
|
+
if handle_stake_error(
|
|
1838
|
+
error_msg,
|
|
1839
|
+
request.subnet_id,
|
|
1840
|
+
request.subnet_node_id,
|
|
1841
|
+
"donate node delegate stake",
|
|
1842
|
+
client,
|
|
1843
|
+
):
|
|
1844
|
+
return
|
|
1845
|
+
|
|
1846
|
+
display_node_delegate_donate_result(response)
|
|
1847
|
+
else:
|
|
1848
|
+
# SUBNET DELEGATE DONATE PATH
|
|
1849
|
+
request = prompt_delegate_donate(
|
|
1850
|
+
subnet_id=subnet_id,
|
|
1851
|
+
amount=amount,
|
|
1852
|
+
)
|
|
1853
|
+
|
|
1854
|
+
if coldkey:
|
|
1855
|
+
from ...utils.wallet.core import resolve_coldkey_and_get_keypair
|
|
1856
|
+
|
|
1857
|
+
wallet_name, keypair = resolve_coldkey_and_get_keypair(coldkey)
|
|
1858
|
+
else:
|
|
1859
|
+
wallet_name, keypair = retrieve_wallet_with_validation(
|
|
1860
|
+
wallet_type="coldkey",
|
|
1861
|
+
purpose="sign the delegate donation transaction",
|
|
1862
|
+
)
|
|
1863
|
+
|
|
1864
|
+
client = get_client()
|
|
1865
|
+
with HTCLILoadingContext("Donating delegate stake to subnet treasury..."):
|
|
1866
|
+
response = client.extrinsics.staking.donate_delegate_stake(
|
|
1867
|
+
request, keypair
|
|
1868
|
+
)
|
|
1869
|
+
|
|
1870
|
+
if isinstance(response, dict) and not response.get("success", False):
|
|
1871
|
+
error_msg = response.get("error", "Delegate donation failed")
|
|
1872
|
+
if handle_stake_error(
|
|
1873
|
+
error_msg, request.subnet_id, None, "donate delegate stake", client
|
|
1874
|
+
):
|
|
1875
|
+
return
|
|
1876
|
+
|
|
1877
|
+
display_delegate_donate_result(response)
|
|
1878
|
+
|
|
1879
|
+
except Exception as e:
|
|
1880
|
+
error_msg = str(e)
|
|
1881
|
+
subnet_id_for_error = None
|
|
1882
|
+
node_id_for_error = None
|
|
1883
|
+
client_for_error = None
|
|
1884
|
+
try:
|
|
1885
|
+
subnet_id_for_error = request.subnet_id if "request" in locals() else None
|
|
1886
|
+
node_id_for_error = (
|
|
1887
|
+
getattr(request, "subnet_node_id", None)
|
|
1888
|
+
if "request" in locals()
|
|
1889
|
+
else None
|
|
1890
|
+
)
|
|
1891
|
+
client_for_error = client if "client" in locals() else None
|
|
1892
|
+
except (AttributeError, NameError):
|
|
1893
|
+
pass
|
|
1894
|
+
|
|
1895
|
+
if not handle_stake_error(
|
|
1896
|
+
error_msg,
|
|
1897
|
+
subnet_id_for_error,
|
|
1898
|
+
node_id_for_error,
|
|
1899
|
+
"donate delegate stake",
|
|
1900
|
+
client_for_error,
|
|
1901
|
+
):
|
|
1902
|
+
handle_and_display_error(e)
|