cartha-cli 1.0.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.
@@ -0,0 +1,274 @@
1
+ """Register command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import bittensor as bt
6
+ import typer
7
+ from rich.prompt import Confirm
8
+ from rich.table import Table
9
+
10
+ from ..bt import (
11
+ RegistrationResult,
12
+ get_burn_cost,
13
+ get_subtensor,
14
+ get_wallet,
15
+ register_hotkey,
16
+ )
17
+ from ..config import settings
18
+ from ..display import display_clock_and_countdown
19
+ from ..verifier import VerifierError
20
+ from .common import (
21
+ console,
22
+ handle_unexpected_exception,
23
+ handle_wallet_exception,
24
+ )
25
+ from .shared_options import (
26
+ wallet_name_option,
27
+ wallet_hotkey_option,
28
+ network_option,
29
+ netuid_option,
30
+ )
31
+
32
+
33
+ def register(
34
+ wallet_name: str | None = wallet_name_option(required=False),
35
+ wallet_hotkey: str | None = wallet_hotkey_option(required=False),
36
+ network: str = network_option(),
37
+ netuid: int = netuid_option(),
38
+ burned: bool = typer.Option(
39
+ True,
40
+ "--burned/--pow",
41
+ help="Burned registration by default; pass --pow to run PoW registration.",
42
+ ),
43
+ cuda: bool = typer.Option(
44
+ False, "--cuda", help="Enable CUDA for PoW registration."
45
+ ),
46
+ ) -> None:
47
+ """Register your hotkey on the Cartha subnet (subnet 35 on finney, subnet 78 on testnet).
48
+
49
+ USAGE:
50
+ ------
51
+ Interactive mode (recommended): 'cartha miner register' (will prompt for wallet)
52
+ With arguments: 'cartha miner register -w cold -wh hot'
53
+
54
+ ALIASES:
55
+ --------
56
+ Wallet: --wallet-name, --coldkey, -w | --wallet-hotkey, --hotkey, -wh
57
+ Network: --network, -n
58
+
59
+ REGISTRATION OPTIONS:
60
+ ---------------------
61
+ --burned (default): Register using burned TAO
62
+ --pow: Register using Proof of Work
63
+ --cuda: Enable CUDA for PoW registration
64
+
65
+ After registration, use 'cartha vault lock' to create lock positions.
66
+
67
+ ⚠️ Note: Password generation is no longer supported. The new lock flow uses
68
+ session tokens instead of passwords.
69
+ """
70
+
71
+ assert wallet_name is not None # nosec - enforced by Typer prompt
72
+ assert wallet_hotkey is not None # nosec - enforced by Typer prompt
73
+
74
+ # Auto-map netuid and verifier URL based on network
75
+ if network == "test":
76
+ netuid = 78
77
+ elif network == "finney":
78
+ netuid = 35
79
+ # Warn that mainnet is not live yet
80
+ console.print()
81
+ console.print("[bold yellow]⚠️ MAINNET NOT AVAILABLE YET[/]")
82
+ console.print()
83
+ console.print("[yellow]Cartha subnet is currently in testnet phase (subnet 78 on test network).[/]")
84
+ console.print("[yellow]Mainnet (subnet 35 on finney network) has not been announced yet.[/]")
85
+ console.print()
86
+ console.print("[bold cyan]To use testnet:[/]")
87
+ console.print(" cartha miner register --network test")
88
+ console.print()
89
+ console.print("[dim]If you continue with finney network, registration will attempt[/]")
90
+ console.print("[dim]subnet 35 but the subnet may not be operational yet.[/]")
91
+ console.print()
92
+ if not Confirm.ask("[yellow]Continue with finney network anyway?[/]", default=False):
93
+ console.print("[yellow]Cancelled. Use --network test for testnet.[/]")
94
+ raise typer.Exit(code=0)
95
+ # Note: netuid parameter is kept for backwards compatibility / explicit override
96
+
97
+ from ..config import get_verifier_url_for_network
98
+ expected_verifier_url = get_verifier_url_for_network(network)
99
+ if settings.verifier_url != expected_verifier_url:
100
+ settings.verifier_url = expected_verifier_url
101
+
102
+ subtensor = None
103
+ try:
104
+ # Initialize subtensor and wallet to get info before registration
105
+ try:
106
+ subtensor = get_subtensor(network)
107
+ wallet = get_wallet(wallet_name, wallet_hotkey)
108
+ except bt.KeyFileError as exc:
109
+ handle_wallet_exception(
110
+ wallet_name=wallet_name, wallet_hotkey=wallet_hotkey, exc=exc
111
+ )
112
+ except typer.Exit:
113
+ raise
114
+ except Exception as exc:
115
+ handle_unexpected_exception("Failed to initialize wallet/subtensor", exc)
116
+
117
+ hotkey_ss58 = wallet.hotkey.ss58_address
118
+ coldkey_ss58 = wallet.coldkeypub.ss58_address
119
+
120
+ # Check if already registered
121
+ if subtensor.is_hotkey_registered(hotkey_ss58, netuid=netuid):
122
+ neuron = subtensor.get_neuron_for_pubkey_and_subnet(hotkey_ss58, netuid)
123
+ uid = (
124
+ None if getattr(neuron, "is_null", False) else getattr(neuron, "uid", None)
125
+ )
126
+ if uid is not None:
127
+ console.print(f"[bold yellow]Hotkey already registered[/]. UID: {uid}")
128
+ raise typer.Exit(code=0)
129
+
130
+ # Get registration cost and balance
131
+ registration_cost = None
132
+ balance = None
133
+
134
+ if burned:
135
+ try:
136
+ registration_cost = get_burn_cost(network, netuid)
137
+ except Exception as exc:
138
+ # Log warning but continue - cost may not be available on all networks
139
+ console.print(
140
+ f"[bold yellow]Warning: Could not fetch registration cost[/]: {exc}"
141
+ )
142
+
143
+ try:
144
+ balance_obj = subtensor.get_balance(coldkey_ss58)
145
+ # Convert Balance object to float using .tao property
146
+ balance = balance_obj.tao if hasattr(balance_obj, "tao") else float(balance_obj)
147
+ except Exception:
148
+ pass
149
+
150
+ # Display registration summary table (like btcli)
151
+ console.print(f"[bold]Using the wallet path from config:[/] {wallet.path}")
152
+
153
+ summary_table = Table(title="Registration Summary")
154
+ summary_table.add_column("Field", style="cyan")
155
+ summary_table.add_column("Value", style="yellow")
156
+
157
+ summary_table.add_row("Netuid", str(netuid))
158
+ if burned:
159
+ if registration_cost is not None:
160
+ summary_table.add_row("Cost", f"τ {registration_cost:.4f}")
161
+ else:
162
+ summary_table.add_row("Cost", "Unable to fetch")
163
+ summary_table.add_row("Hotkey", hotkey_ss58)
164
+ summary_table.add_row("Coldkey", coldkey_ss58)
165
+ summary_table.add_row("Network", network)
166
+
167
+ console.print(summary_table)
168
+
169
+ # Display balance and cost (already converted to float above)
170
+ if balance is not None:
171
+ console.print(f"\n[bold]Your balance is:[/] {balance:.4f} τ")
172
+
173
+ if registration_cost is not None:
174
+ console.print(
175
+ f"[bold]The cost to register by recycle is[/] {registration_cost:.4f} τ"
176
+ )
177
+
178
+ # Display clock and countdown
179
+ console.print()
180
+ display_clock_and_countdown()
181
+
182
+ # Confirmation prompt
183
+ if not typer.confirm("\nDo you want to continue?", default=False):
184
+ console.print("[bold yellow]Registration cancelled.[/]")
185
+ raise typer.Exit(code=0)
186
+
187
+ console.print("\n[bold cyan]Registering...[/]")
188
+
189
+ try:
190
+ result: RegistrationResult = register_hotkey(
191
+ network=network,
192
+ wallet_name=wallet_name,
193
+ hotkey_name=wallet_hotkey,
194
+ netuid=netuid,
195
+ burned=burned,
196
+ cuda=cuda,
197
+ )
198
+ except bt.KeyFileError as exc:
199
+ handle_wallet_exception(
200
+ wallet_name=wallet_name, wallet_hotkey=wallet_hotkey, exc=exc
201
+ )
202
+ except typer.Exit:
203
+ raise
204
+ except Exception as exc:
205
+ handle_unexpected_exception("Registration failed unexpectedly", exc)
206
+
207
+ if result.status == "already":
208
+ console.print(f"[bold yellow]Hotkey already registered[/]. UID: {result.uid}")
209
+ raise typer.Exit(code=0)
210
+
211
+ if not result.success:
212
+ console.print("[bold red]Registration failed.[/]")
213
+ raise typer.Exit(code=1)
214
+
215
+ # Display extrinsic if available
216
+ if result.extrinsic:
217
+ console.print(
218
+ f"[bold green]✔ Your extrinsic has been included as[/] [cyan]{result.extrinsic}[/]"
219
+ )
220
+
221
+ # Display balance update if available (already converted to float in register_hotkey)
222
+ if result.balance_before is not None and result.balance_after is not None:
223
+ console.print(
224
+ f"[bold]Balance:[/] {result.balance_before:.4f} τ -> {result.balance_after:.4f} τ"
225
+ )
226
+
227
+ # Display success message with UID
228
+ if result.status == "burned":
229
+ console.print(
230
+ "[bold green]✔ Registered on netuid[/] "
231
+ f"[cyan]{netuid}[/] [bold green]with UID[/] [cyan]{result.uid}[/]"
232
+ )
233
+ else:
234
+ console.print(
235
+ "[bold green]✔ Registered on netuid[/] "
236
+ f"[cyan]{netuid}[/] [bold green]with UID[/] [cyan]{result.uid}[/]"
237
+ )
238
+
239
+ if result.uid is not None:
240
+ slot_uid = str(result.uid)
241
+ console.print()
242
+ console.print(
243
+ "[bold green]✓ Registration complete![/] "
244
+ f"Hotkey: {result.hotkey}, Slot UID: {slot_uid}"
245
+ )
246
+ console.print()
247
+ console.print(
248
+ "[bold cyan]Next steps:[/]"
249
+ )
250
+ console.print(
251
+ " • Use [green]cartha vault lock[/] to create a lock position"
252
+ )
253
+ console.print(
254
+ " • Use [green]cartha miner status[/] to check your miner status"
255
+ )
256
+ console.print()
257
+ console.print(
258
+ "[dim]Note: The new lock flow uses session tokens instead of passwords. "
259
+ "Password generation is no longer supported.[/]"
260
+ )
261
+ else:
262
+ console.print(
263
+ "[bold yellow]UID not yet available[/] (node may still be syncing)."
264
+ )
265
+
266
+ raise typer.Exit(code=0)
267
+ finally:
268
+ # Clean up subtensor connection
269
+ if subtensor is not None:
270
+ try:
271
+ if hasattr(subtensor, "close"):
272
+ subtensor.close()
273
+ except Exception:
274
+ pass
@@ -0,0 +1,235 @@
1
+ """Shared option definitions for consistent CLI interface.
2
+
3
+ This module provides reusable typer.Option definitions with comprehensive aliases
4
+ to ensure consistency across all CLI commands.
5
+ """
6
+
7
+ import typer
8
+ from ..config import settings
9
+
10
+
11
+ def wallet_name_option(required: bool = True):
12
+ """Coldkey wallet name option with consistent aliases.
13
+
14
+ Aliases: --wallet-name, --wallet.name, --coldkey, -w
15
+ """
16
+ if required:
17
+ return typer.Option(
18
+ ...,
19
+ "--wallet-name",
20
+ "--wallet.name",
21
+ "--coldkey",
22
+ "-w",
23
+ prompt="Coldkey wallet name",
24
+ help="Coldkey wallet name (aliases: --wallet-name, --wallet.name, --coldkey, -w)",
25
+ show_default=False,
26
+ )
27
+ else:
28
+ return typer.Option(
29
+ None,
30
+ "--wallet-name",
31
+ "--wallet.name",
32
+ "--coldkey",
33
+ "-w",
34
+ help="Coldkey wallet name (aliases: --wallet-name, --wallet.name, --coldkey, -w)",
35
+ show_default=False,
36
+ )
37
+
38
+
39
+ def wallet_hotkey_option(required: bool = True):
40
+ """Hotkey name option with consistent aliases.
41
+
42
+ Aliases: --wallet-hotkey, --wallet.hotkey, --hotkey, -wh
43
+ """
44
+ if required:
45
+ return typer.Option(
46
+ ...,
47
+ "--wallet-hotkey",
48
+ "--wallet.hotkey",
49
+ "--hotkey",
50
+ "-wh",
51
+ prompt="Hotkey name",
52
+ help="Hotkey name (aliases: --wallet-hotkey, --wallet.hotkey, --hotkey, -wh)",
53
+ show_default=False,
54
+ )
55
+ else:
56
+ return typer.Option(
57
+ None,
58
+ "--wallet-hotkey",
59
+ "--wallet.hotkey",
60
+ "--hotkey",
61
+ "-wh",
62
+ help="Hotkey name (aliases: --wallet-hotkey, --wallet.hotkey, --hotkey, -wh)",
63
+ show_default=False,
64
+ )
65
+
66
+
67
+ def pool_id_option():
68
+ """Pool ID option with aliases.
69
+
70
+ Aliases: --pool-id, --pool, --poolid, -p
71
+ """
72
+ return typer.Option(
73
+ None,
74
+ "--pool-id",
75
+ "--pool",
76
+ "--poolid",
77
+ "-p",
78
+ help="Pool name (e.g., BTCUSD, ETHUSD) or hex ID (0x...) (aliases: --pool-id, --pool, --poolid, -p)",
79
+ show_default=False,
80
+ )
81
+
82
+
83
+ def chain_id_option():
84
+ """Chain ID option with aliases.
85
+
86
+ Aliases: --chain-id, --chain, --chainid
87
+ """
88
+ return typer.Option(
89
+ None,
90
+ "--chain-id",
91
+ "--chain",
92
+ "--chainid",
93
+ help="EVM chain ID (auto-detected from pool if not provided) (aliases: --chain-id, --chain, --chainid)",
94
+ show_default=False,
95
+ )
96
+
97
+
98
+ def vault_address_option():
99
+ """Vault contract address option with aliases.
100
+
101
+ Aliases: --vault-address, --vault
102
+ """
103
+ return typer.Option(
104
+ None,
105
+ "--vault-address",
106
+ "--vault",
107
+ help="Vault contract address (auto-detected from pool if not provided) (aliases: --vault-address, --vault)",
108
+ show_default=False,
109
+ )
110
+
111
+
112
+ def owner_evm_option():
113
+ """Owner EVM address option with aliases.
114
+
115
+ Aliases: --owner-evm, --owner, --evm-address, --evm, -e
116
+ """
117
+ return typer.Option(
118
+ None,
119
+ "--owner-evm",
120
+ "--owner",
121
+ "--evm-address",
122
+ "--evm",
123
+ "-e",
124
+ help="EVM address that will own the lock position (aliases: --owner-evm, --owner, --evm-address, --evm, -e)",
125
+ show_default=False,
126
+ )
127
+
128
+
129
+ def amount_option():
130
+ """Amount option.
131
+
132
+ Aliases: --amount, -a
133
+ """
134
+ return typer.Option(
135
+ None,
136
+ "--amount",
137
+ "-a",
138
+ help="Lock amount in USDC (e.g., 250.5). Auto-detects if normalized USDC or base units (>1e9) (alias: -a)",
139
+ show_default=False,
140
+ )
141
+
142
+
143
+ def lock_days_option():
144
+ """Lock days option with aliases.
145
+
146
+ Aliases: --lock-days, --days, -d
147
+ """
148
+ return typer.Option(
149
+ None,
150
+ "--lock-days",
151
+ "--days",
152
+ "-d",
153
+ help="Lock duration in days (e.g., 365) (aliases: --lock-days, --days, -d)",
154
+ show_default=False,
155
+ )
156
+
157
+
158
+ def network_option():
159
+ """Network option with netuid auto-mapping.
160
+
161
+ Aliases: --network, -n
162
+ Maps: test → netuid 78, finney → netuid 35
163
+ """
164
+ return typer.Option(
165
+ settings.network,
166
+ "--network",
167
+ "-n",
168
+ help="Bittensor network (test or finney). Auto-maps to correct netuid (test=78, finney=35)"
169
+ )
170
+
171
+
172
+ def netuid_option():
173
+ """Netuid option."""
174
+ return typer.Option(
175
+ settings.netuid,
176
+ "--netuid",
177
+ help="Subnet netuid"
178
+ )
179
+
180
+
181
+ def slot_option():
182
+ """Slot UID option with aliases.
183
+
184
+ Aliases: --slot, --uid, -u
185
+ """
186
+ return typer.Option(
187
+ None,
188
+ "--slot",
189
+ "--uid",
190
+ "-u",
191
+ help="Subnet UID assigned to the miner (aliases: --slot, --uid, -u). If not provided, will auto-fetch or prompt.",
192
+ show_default=False,
193
+ )
194
+
195
+
196
+ def auto_fetch_uid_option():
197
+ """Auto-fetch UID option."""
198
+ return typer.Option(
199
+ True,
200
+ "--auto-fetch-uid/--no-auto-fetch-uid",
201
+ help="Automatically fetch UID from Bittensor network (default: enabled).",
202
+ show_default=False,
203
+ )
204
+
205
+
206
+ def tx_hash_option():
207
+ """Transaction hash option with aliases.
208
+
209
+ Aliases: --tx-hash, --tx, --transaction
210
+ """
211
+ return typer.Option(
212
+ None,
213
+ "--tx-hash",
214
+ "--tx",
215
+ "--transaction",
216
+ help="Transaction hash (aliases: --tx-hash, --tx, --transaction)",
217
+ )
218
+
219
+
220
+ def json_output_option():
221
+ """JSON output option."""
222
+ return typer.Option(
223
+ False,
224
+ "--json",
225
+ help="Emit responses as JSON."
226
+ )
227
+
228
+
229
+ def refresh_option():
230
+ """Refresh option for triggering manual processing."""
231
+ return typer.Option(
232
+ False,
233
+ "--refresh",
234
+ help="If position not found, manually trigger verifier to process a lock transaction.",
235
+ )
@@ -0,0 +1,15 @@
1
+ """Version command."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ from .common import console
6
+
7
+
8
+ def version_command() -> None:
9
+ """Print the CLI version."""
10
+ try:
11
+ console.print(f"[bold white]cartha-cli[/] {version('cartha-cli')}")
12
+ except PackageNotFoundError: # pragma: no cover
13
+ console.print("[bold white]cartha-cli[/] 0.0.0")
14
+ console.print("[dim]Cartha is the Liquidity Provider for 0xMarkets DEX[/]")
15
+
cartha_cli/config.py ADDED
@@ -0,0 +1,75 @@
1
+ """Runtime configuration for the Cartha CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from functools import lru_cache
7
+ from typing import Any
8
+
9
+ from pydantic import Field
10
+ from pydantic_settings import BaseSettings
11
+
12
+
13
+ # Network to verifier URL mapping
14
+ NETWORK_VERIFIER_MAP = {
15
+ "test": "https://cartha-verifier-826542474079.us-central1.run.app",
16
+ "finney": None, # No mainnet verifier yet - use default or env var
17
+ }
18
+
19
+
20
+ def get_verifier_url_for_network(network: str) -> str:
21
+ """Get the appropriate verifier URL for a given network.
22
+
23
+ Args:
24
+ network: Network name ("test" or "finney")
25
+
26
+ Returns:
27
+ Verifier URL for the network
28
+ """
29
+ # Check if user set CARTHA_VERIFIER_URL explicitly
30
+ env_url = os.getenv("CARTHA_VERIFIER_URL")
31
+ if env_url:
32
+ return env_url
33
+
34
+ # Auto-map based on network
35
+ mapped_url = NETWORK_VERIFIER_MAP.get(network)
36
+ if mapped_url:
37
+ return mapped_url
38
+
39
+ # Default fallback (testnet for now since no mainnet)
40
+ return "https://cartha-verifier-826542474079.us-central1.run.app"
41
+
42
+
43
+ class Settings(BaseSettings):
44
+ verifier_url: str = Field(
45
+ "https://cartha-verifier-826542474079.us-central1.run.app", alias="CARTHA_VERIFIER_URL"
46
+ )
47
+ network: str = Field("finney", alias="CARTHA_NETWORK")
48
+ netuid: int = Field(35, alias="CARTHA_NETUID")
49
+ evm_private_key: str | None = Field(None, alias="CARTHA_EVM_PK")
50
+ # Retry configuration
51
+ retry_max_attempts: int = Field(3, alias="CARTHA_RETRY_MAX_ATTEMPTS")
52
+ retry_backoff_factor: float = Field(1.5, alias="CARTHA_RETRY_BACKOFF_FACTOR")
53
+ # Note: retry_on_status cannot be set via env var easily (would need JSON parsing)
54
+ # For now, it's hardcoded but can be overridden programmatically
55
+ retry_on_status: list[int] = Field(default_factory=lambda: [500, 502, 503, 504])
56
+ # Frontend lock UI URL
57
+ lock_ui_url: str = Field(
58
+ "https://cartha.finance", alias="CARTHA_LOCK_UI_URL"
59
+ )
60
+
61
+ model_config = {
62
+ "env_file": ".env",
63
+ "env_file_encoding": "utf-8",
64
+ "env_nested_delimiter": "__",
65
+ }
66
+
67
+
68
+ @lru_cache(maxsize=1)
69
+ def get_settings(**overrides: Any) -> Settings:
70
+ return Settings(**overrides)
71
+
72
+
73
+ settings = get_settings()
74
+
75
+ __all__ = ["settings", "Settings", "get_settings"]
cartha_cli/display.py ADDED
@@ -0,0 +1,62 @@
1
+ """Display and formatting utilities for the Cartha CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import UTC, datetime
6
+
7
+ from rich import box
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ from .utils import format_countdown, get_local_timezone, get_next_epoch_freeze_time
12
+
13
+ console = Console()
14
+
15
+
16
+ def get_clock_table() -> Table:
17
+ """Create a table with current time (UTC and local) and countdown to next epoch freeze.
18
+
19
+ Returns:
20
+ Table with clock and countdown information
21
+ """
22
+ now_utc = datetime.now(tz=UTC)
23
+ local_tz = get_local_timezone()
24
+ now_local = now_utc.astimezone(local_tz)
25
+
26
+ # Format current time
27
+ utc_str = now_utc.strftime("%Y-%m-%d %H:%M:%S UTC")
28
+ local_str = now_local.strftime("%Y-%m-%d %H:%M:%S %Z")
29
+
30
+ # Calculate next epoch freeze
31
+ next_freeze_utc = get_next_epoch_freeze_time(now_utc)
32
+ next_freeze_local = next_freeze_utc.astimezone(local_tz)
33
+
34
+ # Calculate countdown
35
+ time_until_freeze = (next_freeze_utc - now_utc).total_seconds()
36
+ countdown_str = format_countdown(time_until_freeze)
37
+
38
+ # Format next freeze times
39
+ next_freeze_utc_str = next_freeze_utc.strftime("%Y-%m-%d %H:%M:%S UTC")
40
+ next_freeze_local_str = next_freeze_local.strftime("%Y-%m-%d %H:%M:%S %Z")
41
+
42
+ # Create table
43
+ clock_table = Table(show_header=False, box=box.SIMPLE)
44
+ clock_table.add_column(style="cyan")
45
+ clock_table.add_column(style="yellow")
46
+
47
+ clock_table.add_row("Current time (UTC)", utc_str)
48
+ clock_table.add_row("Current time (Local)", local_str)
49
+ clock_table.add_row("", "") # Spacer
50
+ clock_table.add_row("Next epoch freeze (UTC)", next_freeze_utc_str)
51
+ clock_table.add_row("Next epoch freeze (Local)", next_freeze_local_str)
52
+ clock_table.add_row("Countdown", countdown_str)
53
+
54
+ return clock_table
55
+
56
+
57
+ def display_clock_and_countdown() -> None:
58
+ """Display the clock table with current time and countdown."""
59
+ clock_table = get_clock_table()
60
+ console.print(clock_table)
61
+ console.print() # Empty line after table
62
+
cartha_cli/eth712.py ADDED
@@ -0,0 +1,7 @@
1
+ """EIP-712 helpers (deprecated - LockProof signing moved to verifier).
2
+
3
+ This file is kept for backward compatibility but is no longer used.
4
+ LockRequest EIP-712 signing is now handled server-side by the verifier.
5
+ """
6
+
7
+ __all__: list[str] = []