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
@@ -0,0 +1,219 @@
1
+ import asyncio
2
+ import json
3
+ from typing import Optional
4
+
5
+ from meshtensor_wallet import Wallet
6
+ from rich.table import Column, Table, box
7
+
8
+ from meshtensor_cli.src import COLORS
9
+ from meshtensor_cli.src.meshtensor.meshtensor_interface import MeshtensorInterface
10
+ from meshtensor_cli.src.commands.crowd.view import show_crowdloan_details
11
+ from meshtensor_cli.src.meshtensor.utils import (
12
+ blocks_to_duration,
13
+ confirm_action,
14
+ console,
15
+ json_console,
16
+ print_extrinsic_id,
17
+ print_error,
18
+ unlock_key,
19
+ )
20
+
21
+
22
+ async def dissolve_crowdloan(
23
+ meshtensor: MeshtensorInterface,
24
+ wallet: Wallet,
25
+ proxy: Optional[str],
26
+ crowdloan_id: int,
27
+ wait_for_inclusion: bool = True,
28
+ wait_for_finalization: bool = False,
29
+ prompt: bool = True,
30
+ decline: bool = False,
31
+ quiet: bool = False,
32
+ json_output: bool = False,
33
+ ) -> tuple[bool, str]:
34
+ """Dissolve a non-finalized crowdloan after refunding contributors.
35
+
36
+ The creator can reclaim their deposit once every other contribution has been
37
+ refunded (i.e., the raised amount equals the creator's contribution).
38
+
39
+ Args:
40
+ meshtensor: MeshtensorInterface object for chain interaction.
41
+ wallet: Wallet object containing the creator's coldkey.
42
+ proxy: Optional proxy to use for this extrinsic submission
43
+ crowdloan_id: ID of the crowdloan to dissolve.
44
+ wait_for_inclusion: Wait for transaction inclusion.
45
+ wait_for_finalization: Wait for transaction finalization.
46
+ prompt: Whether to prompt for confirmation.
47
+ json_output: Whether to output the results as JSON or human-readable.
48
+
49
+ Returns:
50
+ tuple[bool, str]: Success status and message.
51
+ """
52
+
53
+ creator_ss58 = wallet.coldkeypub.ss58_address
54
+
55
+ crowdloan, current_block = await asyncio.gather(
56
+ meshtensor.get_single_crowdloan(crowdloan_id),
57
+ meshtensor.substrate.get_block_number(None),
58
+ )
59
+
60
+ if not crowdloan:
61
+ error_msg = f"Crowdloan #{crowdloan_id} not found."
62
+ if json_output:
63
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
64
+ else:
65
+ print_error(f"[red]{error_msg}[/red]")
66
+ return False, error_msg
67
+
68
+ if crowdloan.finalized:
69
+ error_msg = (
70
+ f"Crowdloan #{crowdloan_id} is already finalized and cannot be dissolved."
71
+ )
72
+ if json_output:
73
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
74
+ else:
75
+ print_error(f"[red]{error_msg}[/red]")
76
+ return False, f"Crowdloan #{crowdloan_id} is finalized."
77
+
78
+ if creator_ss58 != crowdloan.creator:
79
+ error_msg = f"Only the creator can dissolve this crowdloan. Creator: {crowdloan.creator}, Your address: {creator_ss58}"
80
+ if json_output:
81
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
82
+ else:
83
+ print_error(
84
+ f"[red]Only the creator can dissolve this crowdloan.[/red]\n"
85
+ f"Creator: [blue]{crowdloan.creator}[/blue]\n"
86
+ f"Your address: [blue]{creator_ss58}[/blue]"
87
+ )
88
+ return False, "Only the creator can dissolve this crowdloan."
89
+
90
+ creator_contribution = await meshtensor.get_crowdloan_contribution(
91
+ crowdloan_id, crowdloan.creator
92
+ )
93
+
94
+ if creator_contribution != crowdloan.raised:
95
+ error_msg = (
96
+ f"Crowdloan still holds funds from other contributors. "
97
+ f"Raised: {crowdloan.raised.tao}, Creator's contribution: {creator_contribution.tao}. "
98
+ "Run 'meshcli crowd refund' until only the creator's funds remain."
99
+ )
100
+ if json_output:
101
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
102
+ else:
103
+ print_error(
104
+ f"[red]Crowdloan still holds funds from other contributors.[/red]\n"
105
+ f"Raised amount: [yellow]{crowdloan.raised}[/yellow]\n"
106
+ f"Creator's contribution: [yellow]{creator_contribution}[/yellow]\n"
107
+ "Run [cyan]meshcli crowd refund[/cyan] until only the creator's funds remain."
108
+ )
109
+ return False, "Crowdloan not ready to dissolve."
110
+
111
+ await show_crowdloan_details(
112
+ meshtensor=meshtensor,
113
+ crowdloan_id=crowdloan_id,
114
+ wallet=wallet,
115
+ verbose=False,
116
+ crowdloan=crowdloan,
117
+ current_block=current_block,
118
+ )
119
+
120
+ summary = Table(
121
+ Column("Field", style=COLORS.G.SUBHEAD),
122
+ Column("Value", style=COLORS.G.TEMPO),
123
+ box=box.SIMPLE,
124
+ show_header=False,
125
+ )
126
+ summary.add_row("Crowdloan ID", f"#{crowdloan_id}")
127
+ summary.add_row("Raised", str(crowdloan.raised))
128
+ summary.add_row("Creator Contribution", str(creator_contribution))
129
+ summary.add_row(
130
+ "Remaining Contributors",
131
+ str(max(0, crowdloan.contributors_count - 1)),
132
+ )
133
+ time_remaining = crowdloan.end - current_block
134
+ summary.add_row(
135
+ "Time Remaining",
136
+ blocks_to_duration(time_remaining) if time_remaining > 0 else "Ended",
137
+ )
138
+
139
+ console.print("\n[bold cyan]Crowdloan Dissolution Summary[/bold cyan]")
140
+ console.print(summary)
141
+
142
+ if prompt and not confirm_action(
143
+ f"\n[bold]Proceed with dissolving crowdloan #{crowdloan_id}?[/bold]",
144
+ default=False,
145
+ decline=decline,
146
+ quiet=quiet,
147
+ ):
148
+ if json_output:
149
+ json_console.print(
150
+ json.dumps(
151
+ {"success": False, "error": "Dissolution cancelled by user."}
152
+ )
153
+ )
154
+ else:
155
+ console.print("[yellow]Dissolution cancelled.[/yellow]")
156
+ return False, "Dissolution cancelled by user."
157
+
158
+ unlock_status = unlock_key(wallet)
159
+ if not unlock_status.success:
160
+ if json_output:
161
+ json_console.print(
162
+ json.dumps({"success": False, "error": unlock_status.message})
163
+ )
164
+ else:
165
+ print_error(f"[red]{unlock_status.message}[/red]")
166
+ return False, unlock_status.message
167
+
168
+ with console.status(
169
+ ":satellite: Submitting dissolve transaction...", spinner="aesthetic"
170
+ ):
171
+ call = await meshtensor.substrate.compose_call(
172
+ call_module="Crowdloan",
173
+ call_function="dissolve",
174
+ call_params={"crowdloan_id": crowdloan_id},
175
+ )
176
+ (
177
+ success,
178
+ error_message,
179
+ extrinsic_receipt,
180
+ ) = await meshtensor.sign_and_send_extrinsic(
181
+ call=call,
182
+ wallet=wallet,
183
+ proxy=proxy,
184
+ wait_for_inclusion=wait_for_inclusion,
185
+ wait_for_finalization=wait_for_finalization,
186
+ )
187
+
188
+ if not success:
189
+ if json_output:
190
+ json_console.print(
191
+ json.dumps(
192
+ {
193
+ "success": False,
194
+ "error": error_message or "Failed to dissolve crowdloan.",
195
+ }
196
+ )
197
+ )
198
+ else:
199
+ print_error(f"[red]Failed to dissolve crowdloan.[/red]\n{error_message}")
200
+ return False, error_message
201
+
202
+ if json_output:
203
+ extrinsic_id = await extrinsic_receipt.get_extrinsic_identifier()
204
+ output_dict = {
205
+ "success": True,
206
+ "error": None,
207
+ "extrinsic_identifier": extrinsic_id,
208
+ "data": {
209
+ "crowdloan_id": crowdloan_id,
210
+ "creator": crowdloan.creator,
211
+ "total_dissolved": creator_contribution.tao,
212
+ },
213
+ }
214
+ json_console.print(json.dumps(output_dict))
215
+ else:
216
+ await print_extrinsic_id(extrinsic_receipt)
217
+ console.print("[green]Crowdloan dissolved successfully![/green]")
218
+
219
+ return True, "Crowdloan dissolved successfully."
@@ -0,0 +1,233 @@
1
+ import asyncio
2
+ import json
3
+ from typing import Optional
4
+
5
+ from meshtensor_wallet import Wallet
6
+ from rich.table import Table, Column, box
7
+
8
+ from meshtensor_cli.src import COLORS
9
+ from meshtensor_cli.src.meshtensor.meshtensor_interface import MeshtensorInterface
10
+ from meshtensor_cli.src.meshtensor.utils import (
11
+ confirm_action,
12
+ console,
13
+ json_console,
14
+ print_extrinsic_id,
15
+ print_error,
16
+ unlock_key,
17
+ )
18
+ from meshtensor_cli.src.commands.crowd.view import show_crowdloan_details
19
+ from meshtensor_cli.src.commands.crowd.utils import get_constant
20
+
21
+
22
+ async def refund_crowdloan(
23
+ meshtensor: MeshtensorInterface,
24
+ wallet: Wallet,
25
+ proxy: Optional[str],
26
+ crowdloan_id: int,
27
+ wait_for_inclusion: bool = True,
28
+ wait_for_finalization: bool = False,
29
+ prompt: bool = True,
30
+ decline: bool = False,
31
+ quiet: bool = False,
32
+ json_output: bool = False,
33
+ ) -> tuple[bool, str]:
34
+ """Refund contributors of a non-finalized crowdloan.
35
+
36
+ This extrinsic refunds all contributors (excluding the creator) up to the
37
+ RefundContributorsLimit. If there are more contributors than the limit,
38
+ this call may need to be executed multiple times until all contributors
39
+ are refunded.
40
+
41
+ Anyone can call this function - it does not need to be the creator.
42
+
43
+ Args:
44
+ meshtensor: MeshtensorInterface object for chain interaction
45
+ wallet: Wallet object containing coldkey (any wallet can call this)
46
+ proxy: Optional proxy to use for extrinsic submission
47
+ crowdloan_id: ID of the crowdloan to refund
48
+ wait_for_inclusion: Wait for transaction inclusion
49
+ wait_for_finalization: Wait for transaction finalization
50
+ prompt: Whether to prompt for confirmation
51
+ json_output: Whether to output as JSON or human-readable
52
+
53
+ Returns:
54
+ tuple[bool, str]: Success status and message
55
+ """
56
+ creator_ss58 = wallet.coldkeypub.ss58_address
57
+ crowdloan, current_block = await asyncio.gather(
58
+ meshtensor.get_single_crowdloan(crowdloan_id),
59
+ meshtensor.substrate.get_block_number(None),
60
+ )
61
+
62
+ if not crowdloan:
63
+ error_msg = f"Crowdloan #{crowdloan_id} not found."
64
+ if json_output:
65
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
66
+ else:
67
+ print_error(f"[red]{error_msg}[/red]")
68
+ return False, error_msg
69
+
70
+ if crowdloan.finalized:
71
+ error_msg = f"Crowdloan #{crowdloan_id} is already finalized. Finalized crowdloans cannot be refunded."
72
+ if json_output:
73
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
74
+ else:
75
+ print_error(f"[red]{error_msg}[/red]")
76
+ return False, f"Crowdloan #{crowdloan_id} is already finalized."
77
+
78
+ if creator_ss58 != crowdloan.creator:
79
+ error_msg = f"Only the creator can refund this crowdloan. Creator: {crowdloan.creator}, Your address: {creator_ss58}"
80
+ if json_output:
81
+ json_console.print(json.dumps({"success": False, "error": error_msg}))
82
+ else:
83
+ print_error(
84
+ f"[red]Only the creator can refund this crowdloan.[/red]\n"
85
+ f"Creator: [blue]{crowdloan.creator}[/blue]\n"
86
+ f"Your address: [blue]{creator_ss58}[/blue]"
87
+ )
88
+ return False, "Only the creator can refund this crowdloan."
89
+
90
+ await show_crowdloan_details(
91
+ meshtensor=meshtensor,
92
+ crowdloan_id=crowdloan_id,
93
+ wallet=wallet,
94
+ verbose=False,
95
+ crowdloan=crowdloan,
96
+ current_block=current_block,
97
+ )
98
+
99
+ refund_limit = await get_constant(meshtensor, "RefundContributorsLimit")
100
+
101
+ console.print("\n[bold cyan]Crowdloan Refund Information[/bold cyan]\n")
102
+
103
+ info_table = Table(
104
+ Column("[bold white]Property", style=COLORS.G.SUBHEAD),
105
+ Column("[bold white]Value", style=COLORS.G.TEMPO),
106
+ show_footer=False,
107
+ show_header=False,
108
+ width=None,
109
+ pad_edge=False,
110
+ box=box.SIMPLE,
111
+ show_edge=True,
112
+ border_style="bright_black",
113
+ )
114
+
115
+ info_table.add_row("Crowdloan ID", f"#{crowdloan_id}")
116
+ info_table.add_row("Total Contributors", f"{crowdloan.contributors_count:,}")
117
+ info_table.add_row("Refund Limit (per call)", f"{refund_limit:,} contributors")
118
+ info_table.add_row("Amount to Refund", crowdloan.raised - crowdloan.deposit)
119
+
120
+ if current_block >= crowdloan.end:
121
+ if crowdloan.raised < crowdloan.cap:
122
+ status = "[red]Failed[/red] (Cap not reached)"
123
+ else:
124
+ status = "[yellow]Ended but not finalized[/yellow]"
125
+ else:
126
+ status = "[green]Active[/green] (Still accepting contributions)"
127
+
128
+ info_table.add_row("Status", status)
129
+
130
+ refundable_contributors = max(0, crowdloan.contributors_count)
131
+ estimated_calls = (
132
+ (refundable_contributors + refund_limit) // refund_limit
133
+ if refund_limit > 0
134
+ else 0
135
+ )
136
+
137
+ if estimated_calls > 1:
138
+ info_table.add_row(
139
+ "Estimated Calls Needed",
140
+ f"[yellow]~{estimated_calls}[/yellow] (due to contributor limit)",
141
+ )
142
+
143
+ console.print(info_table)
144
+
145
+ if estimated_calls > 1:
146
+ console.print(
147
+ f"\n[yellow]Note:[/yellow] Due to the [cyan]Refund Contributors Limit[/cyan] of {refund_limit:,} contributors per call,\n"
148
+ f" you may need to execute this command [yellow]{estimated_calls} times[/yellow] to refund all contributors.\n"
149
+ f" Each call will refund up to {refund_limit:,} contributors until all are processed.\n"
150
+ )
151
+
152
+ if prompt and not confirm_action(
153
+ f"\n[bold]Proceed with refunding contributors of Crowdloan #{crowdloan_id}?[/bold]",
154
+ default=False,
155
+ decline=decline,
156
+ quiet=quiet,
157
+ ):
158
+ if json_output:
159
+ json_console.print(
160
+ json.dumps({"success": False, "error": "Refund cancelled by user."})
161
+ )
162
+ else:
163
+ console.print("[yellow]Refund cancelled.[/yellow]")
164
+ return False, "Refund cancelled by user."
165
+
166
+ unlock_status = unlock_key(wallet)
167
+ if not unlock_status.success:
168
+ if json_output:
169
+ json_console.print(
170
+ json.dumps({"success": False, "error": unlock_status.message})
171
+ )
172
+ else:
173
+ print_error(f"[red]{unlock_status.message}[/red]")
174
+ return False, unlock_status.message
175
+
176
+ with console.status(
177
+ ":satellite: Submitting refund transaction...", spinner="aesthetic"
178
+ ):
179
+ call = await meshtensor.substrate.compose_call(
180
+ call_module="Crowdloan",
181
+ call_function="refund",
182
+ call_params={
183
+ "crowdloan_id": crowdloan_id,
184
+ },
185
+ )
186
+ (
187
+ success,
188
+ error_message,
189
+ extrinsic_receipt,
190
+ ) = await meshtensor.sign_and_send_extrinsic(
191
+ call=call,
192
+ wallet=wallet,
193
+ proxy=proxy,
194
+ wait_for_inclusion=wait_for_inclusion,
195
+ wait_for_finalization=wait_for_finalization,
196
+ )
197
+
198
+ if not success:
199
+ if json_output:
200
+ json_console.print(
201
+ json.dumps(
202
+ {
203
+ "success": False,
204
+ "error": error_message or "Failed to refund contributors.",
205
+ }
206
+ )
207
+ )
208
+ else:
209
+ print_error(f"[red]Failed to refund contributors.[/red]\n{error_message}")
210
+ return False, error_message
211
+
212
+ if json_output:
213
+ extrinsic_id = await extrinsic_receipt.get_extrinsic_identifier()
214
+ output_dict = {
215
+ "success": True,
216
+ "error": None,
217
+ "extrinsic_identifier": extrinsic_id,
218
+ "data": {
219
+ "crowdloan_id": crowdloan_id,
220
+ "refund_limit_per_call": refund_limit,
221
+ "total_contributors": crowdloan.contributors_count,
222
+ "estimated_calls_remaining": max(0, estimated_calls - 1),
223
+ "amount_refunded": (crowdloan.raised - crowdloan.deposit).tao,
224
+ },
225
+ }
226
+ json_console.print(json.dumps(output_dict))
227
+ else:
228
+ console.print(
229
+ f"[green]Contributors have been refunded for Crowdloan #{crowdloan_id}.[/green]"
230
+ )
231
+ await print_extrinsic_id(extrinsic_receipt)
232
+
233
+ return True, f"Contributors have been refunded for Crowdloan #{crowdloan_id}."