@@ -157,6 +157,9 @@ def swap_stake_extrinsic(
157
157
amount : Optional [Balance ] = None ,
158
158
wait_for_inclusion : bool = True ,
159
159
wait_for_finalization : bool = False ,
160
+ safe_staking : bool = False ,
161
+ allow_partial_stake : bool = False ,
162
+ rate_threshold : float = 0.005 ,
160
163
) -> bool :
161
164
"""
162
165
Moves stake between subnets while keeping the same coldkey-hotkey pair ownership.
@@ -170,6 +173,9 @@ def swap_stake_extrinsic(
170
173
amount (Union[Balance, float]): Amount to swap.
171
174
wait_for_inclusion (bool): If true, waits for inclusion before returning.
172
175
wait_for_finalization (bool): If true, waits for finalization before returning.
176
+ safe_staking (bool): If true, enables price safety checks to protect against price impact.
177
+ allow_partial_stake (bool): If true, allows partial stake swaps when the full amount would exceed the price threshold.
178
+ rate_threshold (float): Maximum allowed increase in price ratio (0.005 = 0.5%).
173
179
174
180
Returns:
175
181
success (bool): True if the swap was successful.
@@ -203,20 +209,45 @@ def swap_stake_extrinsic(
203
209
return False
204
210
205
211
try :
206
- logging .info (
207
- f"Swapping stake for hotkey [blue]{ hotkey_ss58 } [/blue]\n "
208
- f"Amount: [green]{ amount } [/green] from netuid [yellow]{ origin_netuid } [/yellow] to netuid "
209
- f"[yellow]{ destination_netuid } [/yellow]"
210
- )
212
+ call_params = {
213
+ "hotkey" : hotkey_ss58 ,
214
+ "origin_netuid" : origin_netuid ,
215
+ "destination_netuid" : destination_netuid ,
216
+ "alpha_amount" : amount .rao ,
217
+ }
218
+
219
+ if safe_staking :
220
+ origin_pool = subtensor .subnet (netuid = origin_netuid )
221
+ destination_pool = subtensor .subnet (netuid = destination_netuid )
222
+ swap_rate_ratio = origin_pool .price .rao / destination_pool .price .rao
223
+ swap_rate_ratio_with_tolerance = swap_rate_ratio * (1 + rate_threshold )
224
+
225
+ logging .info (
226
+ f"Swapping stake with safety for hotkey [blue]{ hotkey_ss58 } [/blue]\n "
227
+ f"Amount: [green]{ amount } [/green] from netuid [yellow]{ origin_netuid } [/yellow] to netuid "
228
+ f"[yellow]{ destination_netuid } [/yellow]\n "
229
+ f"Current price ratio: [green]{ swap_rate_ratio :.4f} [/green], "
230
+ f"Ratio with tolerance: [yellow]{ swap_rate_ratio_with_tolerance :.4f} [/yellow]"
231
+ )
232
+ call_params .update (
233
+ {
234
+ "limit_price" : swap_rate_ratio_with_tolerance ,
235
+ "allow_partial" : allow_partial_stake ,
236
+ }
237
+ )
238
+ call_function = "swap_stake_limit"
239
+ else :
240
+ logging .info (
241
+ f"Swapping stake for hotkey [blue]{ hotkey_ss58 } [/blue]\n "
242
+ f"Amount: [green]{ amount } [/green] from netuid [yellow]{ origin_netuid } [/yellow] to netuid "
243
+ f"[yellow]{ destination_netuid } [/yellow]"
244
+ )
245
+ call_function = "swap_stake"
246
+
211
247
call = subtensor .substrate .compose_call (
212
248
call_module = "SubtensorModule" ,
213
- call_function = "swap_stake" ,
214
- call_params = {
215
- "hotkey" : hotkey_ss58 ,
216
- "origin_netuid" : origin_netuid ,
217
- "destination_netuid" : destination_netuid ,
218
- "alpha_amount" : amount .rao ,
219
- },
249
+ call_function = call_function ,
250
+ call_params = call_params ,
220
251
)
221
252
222
253
success , err_msg = subtensor .sign_and_send_extrinsic (
@@ -251,7 +282,12 @@ def swap_stake_extrinsic(
251
282
252
283
return True
253
284
else :
254
- logging .error (f":cross_mark: [red]Failed[/red]: { err_msg } " )
285
+ if safe_staking and "Custom error: 8" in err_msg :
286
+ logging .error (
287
+ ":cross_mark: [red]Failed[/red]: Price ratio exceeded tolerance limit. Either increase price tolerance or enable partial staking."
288
+ )
289
+ else :
290
+ logging .error (f":cross_mark: [red]Failed[/red]: { err_msg } " )
255
291
return False
256
292
257
293
except Exception as e :
0 commit comments