meshtensor-cli 9.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. meshtensor_cli/__init__.py +22 -0
  2. meshtensor_cli/cli.py +10742 -0
  3. meshtensor_cli/doc_generation_helper.py +4 -0
  4. meshtensor_cli/src/__init__.py +1085 -0
  5. meshtensor_cli/src/commands/__init__.py +0 -0
  6. meshtensor_cli/src/commands/axon/__init__.py +0 -0
  7. meshtensor_cli/src/commands/axon/axon.py +132 -0
  8. meshtensor_cli/src/commands/crowd/__init__.py +0 -0
  9. meshtensor_cli/src/commands/crowd/contribute.py +621 -0
  10. meshtensor_cli/src/commands/crowd/contributors.py +200 -0
  11. meshtensor_cli/src/commands/crowd/create.py +783 -0
  12. meshtensor_cli/src/commands/crowd/dissolve.py +219 -0
  13. meshtensor_cli/src/commands/crowd/refund.py +233 -0
  14. meshtensor_cli/src/commands/crowd/update.py +418 -0
  15. meshtensor_cli/src/commands/crowd/utils.py +124 -0
  16. meshtensor_cli/src/commands/crowd/view.py +991 -0
  17. meshtensor_cli/src/commands/governance/__init__.py +0 -0
  18. meshtensor_cli/src/commands/governance/governance.py +794 -0
  19. meshtensor_cli/src/commands/liquidity/__init__.py +0 -0
  20. meshtensor_cli/src/commands/liquidity/liquidity.py +699 -0
  21. meshtensor_cli/src/commands/liquidity/utils.py +202 -0
  22. meshtensor_cli/src/commands/proxy.py +700 -0
  23. meshtensor_cli/src/commands/stake/__init__.py +0 -0
  24. meshtensor_cli/src/commands/stake/add.py +799 -0
  25. meshtensor_cli/src/commands/stake/auto_staking.py +306 -0
  26. meshtensor_cli/src/commands/stake/children_hotkeys.py +865 -0
  27. meshtensor_cli/src/commands/stake/claim.py +770 -0
  28. meshtensor_cli/src/commands/stake/list.py +738 -0
  29. meshtensor_cli/src/commands/stake/move.py +1211 -0
  30. meshtensor_cli/src/commands/stake/remove.py +1466 -0
  31. meshtensor_cli/src/commands/stake/wizard.py +323 -0
  32. meshtensor_cli/src/commands/subnets/__init__.py +0 -0
  33. meshtensor_cli/src/commands/subnets/mechanisms.py +515 -0
  34. meshtensor_cli/src/commands/subnets/price.py +733 -0
  35. meshtensor_cli/src/commands/subnets/subnets.py +2908 -0
  36. meshtensor_cli/src/commands/sudo.py +1294 -0
  37. meshtensor_cli/src/commands/tc/__init__.py +0 -0
  38. meshtensor_cli/src/commands/tc/tc.py +190 -0
  39. meshtensor_cli/src/commands/treasury/__init__.py +0 -0
  40. meshtensor_cli/src/commands/treasury/treasury.py +194 -0
  41. meshtensor_cli/src/commands/view.py +354 -0
  42. meshtensor_cli/src/commands/wallets.py +2311 -0
  43. meshtensor_cli/src/commands/weights.py +467 -0
  44. meshtensor_cli/src/meshtensor/__init__.py +0 -0
  45. meshtensor_cli/src/meshtensor/balances.py +313 -0
  46. meshtensor_cli/src/meshtensor/chain_data.py +1263 -0
  47. meshtensor_cli/src/meshtensor/extrinsics/__init__.py +0 -0
  48. meshtensor_cli/src/meshtensor/extrinsics/mev_shield.py +174 -0
  49. meshtensor_cli/src/meshtensor/extrinsics/registration.py +1861 -0
  50. meshtensor_cli/src/meshtensor/extrinsics/root.py +550 -0
  51. meshtensor_cli/src/meshtensor/extrinsics/serving.py +255 -0
  52. meshtensor_cli/src/meshtensor/extrinsics/transfer.py +239 -0
  53. meshtensor_cli/src/meshtensor/meshtensor_interface.py +2598 -0
  54. meshtensor_cli/src/meshtensor/minigraph.py +254 -0
  55. meshtensor_cli/src/meshtensor/networking.py +12 -0
  56. meshtensor_cli/src/meshtensor/templates/main-filters.j2 +24 -0
  57. meshtensor_cli/src/meshtensor/templates/main-header.j2 +36 -0
  58. meshtensor_cli/src/meshtensor/templates/neuron-details.j2 +111 -0
  59. meshtensor_cli/src/meshtensor/templates/price-multi.j2 +113 -0
  60. meshtensor_cli/src/meshtensor/templates/price-single.j2 +99 -0
  61. meshtensor_cli/src/meshtensor/templates/subnet-details-header.j2 +49 -0
  62. meshtensor_cli/src/meshtensor/templates/subnet-details.j2 +32 -0
  63. meshtensor_cli/src/meshtensor/templates/subnet-metrics.j2 +57 -0
  64. meshtensor_cli/src/meshtensor/templates/subnets-table.j2 +28 -0
  65. meshtensor_cli/src/meshtensor/templates/table.j2 +267 -0
  66. meshtensor_cli/src/meshtensor/templates/view.css +1058 -0
  67. meshtensor_cli/src/meshtensor/templates/view.j2 +43 -0
  68. meshtensor_cli/src/meshtensor/templates/view.js +1053 -0
  69. meshtensor_cli/src/meshtensor/utils.py +2007 -0
  70. meshtensor_cli/version.py +23 -0
  71. meshtensor_cli-9.18.1.dist-info/METADATA +261 -0
  72. meshtensor_cli-9.18.1.dist-info/RECORD +74 -0
  73. meshtensor_cli-9.18.1.dist-info/WHEEL +4 -0
  74. meshtensor_cli-9.18.1.dist-info/entry_points.txt +3 -0
File without changes
@@ -0,0 +1,699 @@
1
+ import asyncio
2
+ import json
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from async_substrate_interface import AsyncExtrinsicReceipt
6
+ from rich.table import Column, Table
7
+
8
+ from meshtensor_cli.src import COLORS
9
+ from meshtensor_cli.src.meshtensor.utils import (
10
+ confirm_action,
11
+ unlock_key,
12
+ console,
13
+ print_error,
14
+ json_console,
15
+ print_extrinsic_id,
16
+ )
17
+ from meshtensor_cli.src.meshtensor.balances import Balance, fixed_to_float
18
+ from meshtensor_cli.src.commands.liquidity.utils import (
19
+ LiquidityPosition,
20
+ calculate_fees,
21
+ get_fees,
22
+ price_to_tick,
23
+ tick_to_price,
24
+ )
25
+
26
+ if TYPE_CHECKING:
27
+ from meshtensor_wallet import Wallet
28
+ from meshtensor_cli.src.meshtensor.meshtensor_interface import MeshtensorInterface
29
+
30
+
31
+ async def add_liquidity_extrinsic(
32
+ meshtensor: "MeshtensorInterface",
33
+ wallet: "Wallet",
34
+ hotkey_ss58: str,
35
+ netuid: int,
36
+ proxy: Optional[str],
37
+ liquidity: Balance,
38
+ price_low: Balance,
39
+ price_high: Balance,
40
+ wait_for_inclusion: bool = True,
41
+ wait_for_finalization: bool = False,
42
+ ) -> tuple[bool, str, Optional[AsyncExtrinsicReceipt]]:
43
+ """
44
+ Adds liquidity to the specified price range.
45
+
46
+ Arguments:
47
+ meshtensor: The Meshtensor client instance used for blockchain interaction.
48
+ wallet: The wallet used to sign the extrinsic (must be unlocked).
49
+ hotkey_ss58: the SS58 of the hotkey to use for this transaction.
50
+ netuid: The UID of the target subnet for which the call is being initiated.
51
+ proxy: Optional proxy to use for this extrinsic submission.
52
+ liquidity: The amount of liquidity to be added.
53
+ price_low: The lower bound of the price tick range.
54
+ price_high: The upper bound of the price tick range.
55
+ wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
56
+ wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
57
+
58
+ Returns:
59
+ tuple:
60
+ bool: True if successful, False otherwise.
61
+ str: success message if successful, error message otherwise.
62
+ AsyncExtrinsicReceipt: extrinsic receipt if successful, None otherwise.
63
+
64
+ Note: Adding is allowed even when user liquidity is enabled in specified subnet. Call
65
+ `toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
66
+ """
67
+ if not (unlock := unlock_key(wallet)).success:
68
+ return False, unlock.message, None
69
+
70
+ tick_low = price_to_tick(price_low.tao)
71
+ tick_high = price_to_tick(price_high.tao)
72
+
73
+ call = await meshtensor.substrate.compose_call(
74
+ call_module="Swap",
75
+ call_function="add_liquidity",
76
+ call_params={
77
+ "hotkey": hotkey_ss58,
78
+ "netuid": netuid,
79
+ "tick_low": tick_low,
80
+ "tick_high": tick_high,
81
+ "liquidity": liquidity.meshlet,
82
+ },
83
+ )
84
+
85
+ return await meshtensor.sign_and_send_extrinsic(
86
+ call=call,
87
+ wallet=wallet,
88
+ proxy=proxy,
89
+ wait_for_inclusion=wait_for_inclusion,
90
+ wait_for_finalization=wait_for_finalization,
91
+ )
92
+
93
+
94
+ async def modify_liquidity_extrinsic(
95
+ meshtensor: "MeshtensorInterface",
96
+ wallet: "Wallet",
97
+ hotkey_ss58: str,
98
+ netuid: int,
99
+ proxy: Optional[str],
100
+ position_id: int,
101
+ liquidity_delta: Balance,
102
+ wait_for_inclusion: bool = True,
103
+ wait_for_finalization: bool = False,
104
+ ) -> tuple[bool, str, Optional[AsyncExtrinsicReceipt]]:
105
+ """Modifies liquidity in liquidity position by adding or removing liquidity from it.
106
+
107
+ Arguments:
108
+ meshtensor: The Meshtensor client instance used for blockchain interaction.
109
+ wallet: The wallet used to sign the extrinsic (must be unlocked).
110
+ hotkey_ss58: the SS58 of the hotkey to use for this transaction.
111
+ netuid: The UID of the target subnet for which the call is being initiated.
112
+ proxy: Optional proxy to use for this extrinsic submission.
113
+ position_id: The id of the position record in the pool.
114
+ liquidity_delta: The amount of liquidity to be added or removed (add if positive or remove if negative).
115
+ wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
116
+ wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
117
+
118
+ Returns:
119
+ tuple:
120
+ bool: True if successful, False otherwise.
121
+ str: success message if successful, error message otherwise.
122
+ AsyncExtrinsicReceipt: extrinsic receipt if successful, None otherwise.
123
+
124
+ Note: Modifying is allowed even when user liquidity is enabled in specified subnet.
125
+ Call `toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
126
+ """
127
+ if not (unlock := unlock_key(wallet)).success:
128
+ return False, unlock.message, None
129
+
130
+ call = await meshtensor.substrate.compose_call(
131
+ call_module="Swap",
132
+ call_function="modify_position",
133
+ call_params={
134
+ "hotkey": hotkey_ss58,
135
+ "netuid": netuid,
136
+ "position_id": position_id,
137
+ "liquidity_delta": liquidity_delta.meshlet,
138
+ },
139
+ )
140
+
141
+ return await meshtensor.sign_and_send_extrinsic(
142
+ call=call,
143
+ wallet=wallet,
144
+ proxy=proxy,
145
+ wait_for_inclusion=wait_for_inclusion,
146
+ wait_for_finalization=wait_for_finalization,
147
+ )
148
+
149
+
150
+ async def remove_liquidity_extrinsic(
151
+ meshtensor: "MeshtensorInterface",
152
+ wallet: "Wallet",
153
+ hotkey_ss58: str,
154
+ proxy: Optional[str],
155
+ netuid: int,
156
+ position_id: int,
157
+ wait_for_inclusion: bool = True,
158
+ wait_for_finalization: bool = False,
159
+ ) -> tuple[bool, str, Optional[AsyncExtrinsicReceipt]]:
160
+ """Remove liquidity and credit balances back to wallet's hotkey stake.
161
+
162
+ Arguments:
163
+ meshtensor: The Meshtensor client instance used for blockchain interaction.
164
+ wallet: The wallet used to sign the extrinsic (must be unlocked).
165
+ hotkey_ss58: the SS58 of the hotkey to use for this transaction.
166
+ proxy: Optional proxy to use for this extrinsic submission.
167
+ netuid: The UID of the target subnet for which the call is being initiated.
168
+ position_id: The id of the position record in the pool.
169
+ wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
170
+ wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
171
+
172
+ Returns:
173
+ tuple:
174
+ bool: True if successful, False otherwise.
175
+ str: success message if successful, error message otherwise.
176
+ AsyncExtrinsicReceipt: extrinsic receipt if successful, None otherwise.
177
+
178
+ Note: Adding is allowed even when user liquidity is enabled in specified subnet.
179
+ Call `toggle_user_liquidity_extrinsic` to enable/disable user liquidity.
180
+ """
181
+ if not (unlock := unlock_key(wallet)).success:
182
+ return False, unlock.message, None
183
+
184
+ call = await meshtensor.substrate.compose_call(
185
+ call_module="Swap",
186
+ call_function="remove_liquidity",
187
+ call_params={
188
+ "hotkey": hotkey_ss58,
189
+ "netuid": netuid,
190
+ "position_id": position_id,
191
+ },
192
+ )
193
+
194
+ return await meshtensor.sign_and_send_extrinsic(
195
+ call=call,
196
+ wallet=wallet,
197
+ proxy=proxy,
198
+ wait_for_inclusion=wait_for_inclusion,
199
+ wait_for_finalization=wait_for_finalization,
200
+ )
201
+
202
+
203
+ async def toggle_user_liquidity_extrinsic(
204
+ meshtensor: "MeshtensorInterface",
205
+ wallet: "Wallet",
206
+ netuid: int,
207
+ enable: bool,
208
+ wait_for_inclusion: bool = True,
209
+ wait_for_finalization: bool = False,
210
+ ) -> tuple[bool, str, Optional[AsyncExtrinsicReceipt]]:
211
+ """Allow to toggle user liquidity for specified subnet.
212
+
213
+ Arguments:
214
+ meshtensor: The Meshtensor client instance used for blockchain interaction.
215
+ wallet: The wallet used to sign the extrinsic (must be unlocked).
216
+ netuid: The UID of the target subnet for which the call is being initiated.
217
+ enable: Boolean indicating whether to enable user liquidity.
218
+ wait_for_inclusion: Whether to wait for the extrinsic to be included in a block. Defaults to True.
219
+ wait_for_finalization: Whether to wait for finalization of the extrinsic. Defaults to False.
220
+
221
+ Returns:
222
+ Tuple[bool, str]:
223
+ - True and a success message if the extrinsic is successfully submitted or processed.
224
+ - False and an error message if the submission fails or the wallet cannot be unlocked.
225
+ """
226
+ if not (unlock := unlock_key(wallet)).success:
227
+ return False, unlock.message, None
228
+
229
+ call = await meshtensor.substrate.compose_call(
230
+ call_module="Swap",
231
+ call_function="toggle_user_liquidity",
232
+ call_params={"netuid": netuid, "enable": enable},
233
+ )
234
+
235
+ return await meshtensor.sign_and_send_extrinsic(
236
+ call=call,
237
+ wallet=wallet,
238
+ wait_for_inclusion=wait_for_inclusion,
239
+ wait_for_finalization=wait_for_finalization,
240
+ )
241
+
242
+
243
+ # Command
244
+ async def add_liquidity(
245
+ meshtensor: "MeshtensorInterface",
246
+ wallet: "Wallet",
247
+ hotkey_ss58: str,
248
+ netuid: Optional[int],
249
+ proxy: Optional[str],
250
+ liquidity: Balance,
251
+ price_low: Balance,
252
+ price_high: Balance,
253
+ prompt: bool,
254
+ decline: bool,
255
+ quiet: bool,
256
+ json_output: bool,
257
+ ) -> tuple[bool, str]:
258
+ """Add liquidity position to provided subnet."""
259
+ # Check wallet access
260
+ if not (ulw := unlock_key(wallet)).success:
261
+ return False, ulw.message
262
+
263
+ # Check that the subnet exists.
264
+ if not await meshtensor.subnet_exists(netuid=netuid):
265
+ return False, f"Subnet with netuid: {netuid} does not exist in {meshtensor}."
266
+
267
+ if prompt:
268
+ console.print(
269
+ "You are about to add a LiquidityPosition with:\n"
270
+ f"\tliquidity: {liquidity}\n"
271
+ f"\tprice low: {price_low}\n"
272
+ f"\tprice high: {price_high}\n"
273
+ f"\tto SN: {netuid}\n"
274
+ f"\tusing wallet with name: {wallet.name}"
275
+ )
276
+
277
+ if not confirm_action(
278
+ "Would you like to continue?", decline=decline, quiet=quiet
279
+ ):
280
+ return False, "User cancelled operation."
281
+
282
+ success, message, ext_receipt = await add_liquidity_extrinsic(
283
+ meshtensor=meshtensor,
284
+ wallet=wallet,
285
+ hotkey_ss58=hotkey_ss58,
286
+ netuid=netuid,
287
+ proxy=proxy,
288
+ liquidity=liquidity,
289
+ price_low=price_low,
290
+ price_high=price_high,
291
+ )
292
+ if success:
293
+ await print_extrinsic_id(ext_receipt)
294
+ ext_id = await ext_receipt.get_extrinsic_identifier()
295
+ else:
296
+ ext_id = None
297
+ if json_output:
298
+ json_console.print_json(
299
+ data={
300
+ "success": success,
301
+ "message": message,
302
+ "extrinsic_identifier": ext_id,
303
+ }
304
+ )
305
+ else:
306
+ if success:
307
+ console.print(
308
+ "[green]LiquidityPosition has been successfully added.[/green]"
309
+ )
310
+ else:
311
+ print_error(f"Error: {message}")
312
+ return success, message
313
+
314
+
315
+ async def get_liquidity_list(
316
+ meshtensor: "MeshtensorInterface",
317
+ wallet: "Wallet",
318
+ netuid: Optional[int],
319
+ ) -> tuple[bool, str, list]:
320
+ """
321
+ Args:
322
+ wallet: wallet object
323
+ meshtensor: MeshtensorInterface object
324
+ netuid: the netuid to stake to (None indicates all subnets)
325
+
326
+ Returns:
327
+ Tuple of (success, error message, liquidity list)
328
+ """
329
+
330
+ if not await meshtensor.subnet_exists(netuid=netuid):
331
+ return False, f"Subnet with netuid: {netuid} does not exist in {meshtensor}.", []
332
+
333
+ if not await meshtensor.is_subnet_active(netuid=netuid):
334
+ return False, f"Subnet with netuid: {netuid} is not active in {meshtensor}.", []
335
+
336
+ block_hash = await meshtensor.substrate.get_chain_head()
337
+ (
338
+ positions_response,
339
+ fee_global_tao,
340
+ fee_global_alpha,
341
+ current_sqrt_price,
342
+ ) = await asyncio.gather(
343
+ meshtensor.substrate.query_map(
344
+ module="Swap",
345
+ storage_function="Positions",
346
+ params=[netuid, wallet.coldkeypub.ss58_address],
347
+ block_hash=block_hash,
348
+ ),
349
+ meshtensor.query(
350
+ module="Swap",
351
+ storage_function="FeeGlobalTao",
352
+ params=[netuid],
353
+ block_hash=block_hash,
354
+ ),
355
+ meshtensor.query(
356
+ module="Swap",
357
+ storage_function="FeeGlobalAlpha",
358
+ params=[netuid],
359
+ block_hash=block_hash,
360
+ ),
361
+ meshtensor.query(
362
+ module="Swap",
363
+ storage_function="AlphaSqrtPrice",
364
+ params=[netuid],
365
+ block_hash=block_hash,
366
+ ),
367
+ )
368
+ if len(positions_response.records) == 0:
369
+ return False, "No liquidity positions found.", []
370
+
371
+ current_sqrt_price = fixed_to_float(current_sqrt_price)
372
+ fee_global_tao = fixed_to_float(fee_global_tao)
373
+ fee_global_alpha = fixed_to_float(fee_global_alpha)
374
+
375
+ current_price = current_sqrt_price * current_sqrt_price
376
+ current_tick = price_to_tick(current_price)
377
+
378
+ preprocessed_positions = []
379
+ positions_futures = []
380
+
381
+ async for _, p in positions_response:
382
+ position = p.value
383
+ tick_index_low = position.get("tick_low")[0]
384
+ tick_index_high = position.get("tick_high")[0]
385
+ preprocessed_positions.append((position, tick_index_low, tick_index_high))
386
+
387
+ # Get ticks for the position (for below/above fees)
388
+ positions_futures.append(
389
+ asyncio.gather(
390
+ meshtensor.query(
391
+ module="Swap",
392
+ storage_function="Ticks",
393
+ params=[netuid, tick_index_low],
394
+ block_hash=block_hash,
395
+ ),
396
+ meshtensor.query(
397
+ module="Swap",
398
+ storage_function="Ticks",
399
+ params=[netuid, tick_index_high],
400
+ block_hash=block_hash,
401
+ ),
402
+ )
403
+ )
404
+
405
+ awaited_futures = await asyncio.gather(*positions_futures)
406
+
407
+ positions = []
408
+
409
+ for (position, tick_index_low, tick_index_high), (tick_low, tick_high) in zip(
410
+ preprocessed_positions, awaited_futures
411
+ ):
412
+ tao_fees_below_low = get_fees(
413
+ current_tick=current_tick,
414
+ tick=tick_low,
415
+ tick_index=tick_index_low,
416
+ quote=True,
417
+ global_fees_tao=fee_global_tao,
418
+ global_fees_alpha=fee_global_alpha,
419
+ above=False,
420
+ )
421
+ tao_fees_above_high = get_fees(
422
+ current_tick=current_tick,
423
+ tick=tick_high,
424
+ tick_index=tick_index_high,
425
+ quote=True,
426
+ global_fees_tao=fee_global_tao,
427
+ global_fees_alpha=fee_global_alpha,
428
+ above=True,
429
+ )
430
+ alpha_fees_below_low = get_fees(
431
+ current_tick=current_tick,
432
+ tick=tick_low,
433
+ tick_index=tick_index_low,
434
+ quote=False,
435
+ global_fees_tao=fee_global_tao,
436
+ global_fees_alpha=fee_global_alpha,
437
+ above=False,
438
+ )
439
+ alpha_fees_above_high = get_fees(
440
+ current_tick=current_tick,
441
+ tick=tick_high,
442
+ tick_index=tick_index_high,
443
+ quote=False,
444
+ global_fees_tao=fee_global_tao,
445
+ global_fees_alpha=fee_global_alpha,
446
+ above=True,
447
+ )
448
+
449
+ # Get position accrued fees
450
+ fees_tao, fees_alpha = calculate_fees(
451
+ position=position,
452
+ global_fees_tao=fee_global_tao,
453
+ global_fees_alpha=fee_global_alpha,
454
+ tao_fees_below_low=tao_fees_below_low,
455
+ tao_fees_above_high=tao_fees_above_high,
456
+ alpha_fees_below_low=alpha_fees_below_low,
457
+ alpha_fees_above_high=alpha_fees_above_high,
458
+ netuid=netuid,
459
+ )
460
+
461
+ lp = LiquidityPosition(
462
+ **{
463
+ "id": position.get("id")[0],
464
+ "price_low": Balance.from_tao(
465
+ tick_to_price(position.get("tick_low")[0])
466
+ ),
467
+ "price_high": Balance.from_tao(
468
+ tick_to_price(position.get("tick_high")[0])
469
+ ),
470
+ "liquidity": Balance.from_meshlet(position.get("liquidity")),
471
+ "fees_tao": fees_tao,
472
+ "fees_alpha": fees_alpha,
473
+ "netuid": position.get("netuid"),
474
+ }
475
+ )
476
+ positions.append(lp)
477
+
478
+ return True, "", positions
479
+
480
+
481
+ async def show_liquidity_list(
482
+ meshtensor: "MeshtensorInterface",
483
+ wallet: "Wallet",
484
+ netuid: int,
485
+ json_output: bool = False,
486
+ ) -> None:
487
+ current_price_, liquidity_list_ = await asyncio.gather(
488
+ meshtensor.subnet(netuid=netuid),
489
+ get_liquidity_list(meshtensor, wallet, netuid),
490
+ return_exceptions=True,
491
+ )
492
+ if isinstance(current_price_, Exception):
493
+ success = False
494
+ err_msg = str(current_price_)
495
+ positions = []
496
+ elif isinstance(liquidity_list_, Exception):
497
+ success = False
498
+ err_msg = str(liquidity_list_)
499
+ positions = []
500
+ else:
501
+ (success, err_msg, positions) = liquidity_list_
502
+ if not success:
503
+ if json_output:
504
+ json_console.print(
505
+ json.dumps({"success": success, "err_msg": err_msg, "positions": []})
506
+ )
507
+ return
508
+ else:
509
+ print_error(f"Error: {err_msg}")
510
+ return
511
+ liquidity_table = Table(
512
+ Column("ID", justify="center"),
513
+ Column("Liquidity", justify="center"),
514
+ Column("Alpha", justify="center"),
515
+ Column("Tao", justify="center"),
516
+ Column("Price low", justify="center"),
517
+ Column("Price high", justify="center"),
518
+ Column("Fee MESH", justify="center"),
519
+ Column("Fee Alpha", justify="center"),
520
+ title=f"\n[{COLORS.G.HEADER}]{'Liquidity Positions of '}{wallet.name} wallet in SN #{netuid}\n"
521
+ "Alpha and Tao columns are respective portions of liquidity.",
522
+ show_footer=False,
523
+ show_edge=True,
524
+ header_style="bold white",
525
+ border_style="bright_black",
526
+ style="bold",
527
+ title_justify="center",
528
+ show_lines=False,
529
+ pad_edge=True,
530
+ )
531
+ json_table = []
532
+ current_price = current_price_.price
533
+ lp: LiquidityPosition
534
+ for lp in positions:
535
+ alpha, mesh = lp.to_token_amounts(current_price)
536
+ liquidity_table.add_row(
537
+ str(lp.id),
538
+ str(lp.liquidity.tao),
539
+ str(alpha),
540
+ str(tao),
541
+ str(lp.price_low),
542
+ str(lp.price_high),
543
+ str(lp.fees_tao),
544
+ str(lp.fees_alpha),
545
+ )
546
+ json_table.append(
547
+ {
548
+ "id": lp.id,
549
+ "liquidity": lp.liquidity.tao,
550
+ "token_amounts": {"alpha": alpha.tao, "mesh": tao.tao},
551
+ "price_low": lp.price_low.tao,
552
+ "price_high": lp.price_high.tao,
553
+ "fees_tao": lp.fees_tao.tao,
554
+ "fees_alpha": lp.fees_alpha.tao,
555
+ "netuid": lp.netuid,
556
+ }
557
+ )
558
+ if not json_output:
559
+ console.print(liquidity_table)
560
+ else:
561
+ json_console.print(
562
+ json.dumps({"success": True, "err_msg": "", "positions": json_table})
563
+ )
564
+
565
+
566
+ async def remove_liquidity(
567
+ meshtensor: "MeshtensorInterface",
568
+ wallet: "Wallet",
569
+ hotkey_ss58: str,
570
+ netuid: int,
571
+ proxy: Optional[str],
572
+ position_id: Optional[int] = None,
573
+ prompt: Optional[bool] = None,
574
+ decline: bool = False,
575
+ quiet: bool = False,
576
+ all_liquidity_ids: Optional[bool] = None,
577
+ json_output: bool = False,
578
+ ) -> None:
579
+ """Remove liquidity position from provided subnet."""
580
+ if not await meshtensor.subnet_exists(netuid=netuid):
581
+ return None
582
+
583
+ if all_liquidity_ids:
584
+ success, msg, positions = await get_liquidity_list(meshtensor, wallet, netuid)
585
+ if not success:
586
+ if json_output:
587
+ json_console.print_json(
588
+ data={"success": False, "err_msg": msg, "positions": positions}
589
+ )
590
+ else:
591
+ return print_error(f"Error: {msg}")
592
+ return None
593
+ else:
594
+ position_ids = [p.id for p in positions]
595
+ else:
596
+ position_ids = [position_id]
597
+
598
+ if prompt:
599
+ console.print("You are about to remove LiquidityPositions with:")
600
+ console.print(f"\tSubnet: {netuid}")
601
+ console.print(f"\tWallet name: {wallet.name}")
602
+ for pos in position_ids:
603
+ console.print(f"\tPosition id: {pos}")
604
+
605
+ if not confirm_action(
606
+ "Would you like to continue?", decline=decline, quiet=quiet
607
+ ):
608
+ return None
609
+
610
+ # TODO does this never break because of the nonce?
611
+ results = await asyncio.gather(
612
+ *[
613
+ remove_liquidity_extrinsic(
614
+ meshtensor=meshtensor,
615
+ wallet=wallet,
616
+ hotkey_ss58=hotkey_ss58,
617
+ proxy=proxy,
618
+ netuid=netuid,
619
+ position_id=pos_id,
620
+ )
621
+ for pos_id in position_ids
622
+ ]
623
+ )
624
+ if not json_output:
625
+ for (success, msg, ext_receipt), posid in zip(results, position_ids):
626
+ if success:
627
+ await print_extrinsic_id(ext_receipt)
628
+ console.print(f"[green] Position {posid} has been removed.")
629
+ else:
630
+ print_error(f"Error removing {posid}: {msg}")
631
+ else:
632
+ json_table = {}
633
+ for (success, msg, ext_receipt), posid in zip(results, position_ids):
634
+ json_table[posid] = {
635
+ "success": success,
636
+ "err_msg": msg,
637
+ "extrinsic_identifier": await ext_receipt.get_extrinsic_identifier(),
638
+ }
639
+ json_console.print_json(data=json_table)
640
+ return None
641
+
642
+
643
+ async def modify_liquidity(
644
+ meshtensor: "MeshtensorInterface",
645
+ wallet: "Wallet",
646
+ hotkey_ss58: str,
647
+ netuid: int,
648
+ proxy: Optional[str],
649
+ position_id: int,
650
+ liquidity_delta: Balance,
651
+ prompt: Optional[bool] = None,
652
+ decline: bool = False,
653
+ quiet: bool = False,
654
+ json_output: bool = False,
655
+ ) -> bool:
656
+ """Modify liquidity position in provided subnet."""
657
+ if not await meshtensor.subnet_exists(netuid=netuid):
658
+ err_msg = f"Subnet with netuid: {netuid} does not exist in {meshtensor}."
659
+ if json_output:
660
+ json_console.print(json.dumps({"success": False, "err_msg": err_msg}))
661
+ else:
662
+ print_error(err_msg)
663
+ return False
664
+
665
+ if prompt:
666
+ console.print(
667
+ "You are about to modify a LiquidityPosition with:"
668
+ f"\tSubnet: {netuid}\n"
669
+ f"\tPosition id: {position_id}\n"
670
+ f"\tWallet name: {wallet.name}\n"
671
+ f"\tLiquidity delta: {liquidity_delta}"
672
+ )
673
+
674
+ if not confirm_action(
675
+ "Would you like to continue?", decline=decline, quiet=quiet
676
+ ):
677
+ return False
678
+
679
+ success, msg, ext_receipt = await modify_liquidity_extrinsic(
680
+ meshtensor=meshtensor,
681
+ wallet=wallet,
682
+ hotkey_ss58=hotkey_ss58,
683
+ netuid=netuid,
684
+ proxy=proxy,
685
+ position_id=position_id,
686
+ liquidity_delta=liquidity_delta,
687
+ )
688
+ if json_output:
689
+ ext_id = await ext_receipt.get_extrinsic_identifier() if success else None
690
+ json_console.print_json(
691
+ data={"success": success, "err_msg": msg, "extrinsic_identifier": ext_id}
692
+ )
693
+ else:
694
+ if success:
695
+ await print_extrinsic_id(ext_receipt)
696
+ console.print(f"[green] Position {position_id} has been modified.")
697
+ else:
698
+ print_error(f"Error modifying {position_id}: {msg}")
699
+ return success