@agentlayer.tech/wallet 0.1.0

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 (96) hide show
  1. package/.openclaw/AGENTS.md +98 -0
  2. package/.openclaw/extensions/agent-wallet/README.md +127 -0
  3. package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
  5. package/.openclaw/extensions/agent-wallet/package.json +11 -0
  6. package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
  7. package/CHANGELOG.md +42 -0
  8. package/LICENSE +104 -0
  9. package/README.md +332 -0
  10. package/RELEASING.md +204 -0
  11. package/agent-wallet/.env.example +62 -0
  12. package/agent-wallet/AGENTS.md +129 -0
  13. package/agent-wallet/README.md +527 -0
  14. package/agent-wallet/agent_wallet/__init__.py +11 -0
  15. package/agent-wallet/agent_wallet/approval.py +161 -0
  16. package/agent-wallet/agent_wallet/bootstrap.py +178 -0
  17. package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
  18. package/agent-wallet/agent_wallet/config.py +382 -0
  19. package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
  20. package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
  21. package/agent-wallet/agent_wallet/exceptions.py +9 -0
  22. package/agent-wallet/agent_wallet/file_ops.py +34 -0
  23. package/agent-wallet/agent_wallet/http_client.py +25 -0
  24. package/agent-wallet/agent_wallet/models.py +66 -0
  25. package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
  26. package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
  27. package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
  28. package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
  29. package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
  30. package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
  31. package/agent-wallet/agent_wallet/providers/bags.py +259 -0
  32. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
  33. package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
  34. package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
  35. package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
  36. package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
  37. package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
  38. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
  39. package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
  40. package/agent-wallet/agent_wallet/solana_stake.py +103 -0
  41. package/agent-wallet/agent_wallet/solana_tx.py +93 -0
  42. package/agent-wallet/agent_wallet/spending_limits.py +101 -0
  43. package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
  44. package/agent-wallet/agent_wallet/user_wallets.py +355 -0
  45. package/agent-wallet/agent_wallet/validation.py +31 -0
  46. package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
  47. package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
  48. package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
  49. package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
  50. package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
  51. package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
  52. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
  53. package/agent-wallet/examples/bootstrap_wallet.py +21 -0
  54. package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
  55. package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
  56. package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
  57. package/agent-wallet/openclaw.plugin.json +138 -0
  58. package/agent-wallet/pyproject.toml +31 -0
  59. package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
  60. package/agent-wallet/scripts/build_release_bundle.py +188 -0
  61. package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
  62. package/agent-wallet/scripts/install_agent_wallet.py +505 -0
  63. package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
  64. package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
  65. package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
  66. package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
  67. package/agent-wallet/scripts/security_utils.py +37 -0
  68. package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
  69. package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
  70. package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
  71. package/bin/openclaw-agent-wallet.mjs +487 -0
  72. package/install-from-github.sh +134 -0
  73. package/package.json +61 -0
  74. package/setup.sh +40 -0
  75. package/wdk-btc-wallet/README.md +325 -0
  76. package/wdk-btc-wallet/bootstrap.sh +22 -0
  77. package/wdk-btc-wallet/package-lock.json +1839 -0
  78. package/wdk-btc-wallet/package.json +18 -0
  79. package/wdk-btc-wallet/run-local.sh +21 -0
  80. package/wdk-btc-wallet/src/config.js +160 -0
  81. package/wdk-btc-wallet/src/json.js +35 -0
  82. package/wdk-btc-wallet/src/local_vault.js +432 -0
  83. package/wdk-btc-wallet/src/network_state.js +84 -0
  84. package/wdk-btc-wallet/src/server.js +257 -0
  85. package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
  86. package/wdk-evm-wallet/README.md +183 -0
  87. package/wdk-evm-wallet/bootstrap.sh +8 -0
  88. package/wdk-evm-wallet/package-lock.json +2340 -0
  89. package/wdk-evm-wallet/package.json +23 -0
  90. package/wdk-evm-wallet/run-local.sh +12 -0
  91. package/wdk-evm-wallet/src/config.js +274 -0
  92. package/wdk-evm-wallet/src/json.js +35 -0
  93. package/wdk-evm-wallet/src/local_vault.js +430 -0
  94. package/wdk-evm-wallet/src/network_state.js +92 -0
  95. package/wdk-evm-wallet/src/server.js +575 -0
  96. package/wdk-evm-wallet/src/wdk_evm_wallet.js +4981 -0
@@ -0,0 +1,626 @@
1
+ """CLI bridge for the official OpenClaw TypeScript plugin."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import asyncio
7
+ import json
8
+ import os
9
+ import sys
10
+ from typing import Any
11
+
12
+ from agent_wallet.wallet_layer.base import WalletBackendError
13
+
14
+
15
+ def _parse_bool(value: Any) -> str:
16
+ if value is None:
17
+ return ""
18
+ return "true" if value is True else "false"
19
+
20
+
21
+ def _parse_csv(value: Any) -> str:
22
+ if value is None:
23
+ return ""
24
+ if isinstance(value, list):
25
+ return ",".join(str(item).strip() for item in value if str(item).strip())
26
+ return str(value).strip()
27
+
28
+
29
+ SECRET_CONFIG_KEYS = {"privateKey", "masterKey", "approvalSecret"}
30
+
31
+
32
+ def _reject_secret_config_json(config: dict[str, Any]) -> None:
33
+ present = sorted(key for key in SECRET_CONFIG_KEYS if str(config.get(key) or "").strip())
34
+ if present:
35
+ joined = ", ".join(present)
36
+ raise WalletBackendError(
37
+ f"Sensitive keys are not allowed in --config-json: {joined}. "
38
+ "Pass secrets via protected environment injection instead."
39
+ )
40
+
41
+
42
+ def _apply_config_overrides(config: dict[str, Any]) -> None:
43
+ _reject_secret_config_json(config)
44
+ rpc_env_locked = bool(os.getenv("SOLANA_RPC_URL", "").strip() or os.getenv("SOLANA_RPC_URLS", "").strip())
45
+ env_map: dict[str, tuple[str, Any, bool]] = {
46
+ "backend": ("AGENT_WALLET_BACKEND", config.get("backend"), True),
47
+ "signOnly": ("AGENT_WALLET_SIGN_ONLY", _parse_bool(config.get("signOnly")), True),
48
+ "network": ("SOLANA_NETWORK", config.get("network"), True),
49
+ # Deployment-owned RPC env must win over plugin config.
50
+ "rpcUrl": ("SOLANA_RPC_URL", config.get("rpcUrl"), False),
51
+ "rpcUrls": ("SOLANA_RPC_URLS", _parse_csv(config.get("rpcUrls")), False),
52
+ "rpcProviderMode": ("SOLANA_RPC_PROVIDER_MODE", config.get("rpcProviderMode"), True),
53
+ "providerGatewayUrl": ("PROVIDER_GATEWAY_URL", config.get("providerGatewayUrl"), True),
54
+ "providerGatewayRpcProvider": (
55
+ "PROVIDER_GATEWAY_RPC_PROVIDER",
56
+ config.get("providerGatewayRpcProvider"),
57
+ True,
58
+ ),
59
+ "wdkBtcServiceUrl": ("WDK_BTC_SERVICE_URL", config.get("wdkBtcServiceUrl"), True),
60
+ "wdkBtcWalletId": ("WDK_BTC_WALLET_ID", config.get("wdkBtcWalletId"), True),
61
+ "wdkBtcAccountIndex": (
62
+ "WDK_BTC_ACCOUNT_INDEX",
63
+ config.get("wdkBtcAccountIndex"),
64
+ True,
65
+ ),
66
+ "wdkEvmServiceUrl": ("WDK_EVM_SERVICE_URL", config.get("wdkEvmServiceUrl"), True),
67
+ "wdkEvmWalletId": ("WDK_EVM_WALLET_ID", config.get("wdkEvmWalletId"), True),
68
+ "wdkEvmAccountIndex": (
69
+ "WDK_EVM_ACCOUNT_INDEX",
70
+ config.get("wdkEvmAccountIndex"),
71
+ True,
72
+ ),
73
+ "swapProvider": ("SOLANA_SWAP_PROVIDER", config.get("swapProvider"), True),
74
+ "heliusApiKey": ("HELIUS_API_KEY", config.get("heliusApiKey"), True),
75
+ "alchemyApiKey": ("ALCHEMY_API_KEY", config.get("alchemyApiKey"), True),
76
+ "publicKey": ("SOLANA_AGENT_PUBLIC_KEY", config.get("publicKey"), True),
77
+ "keypairPath": ("SOLANA_AGENT_KEYPAIR_PATH", config.get("keypairPath"), True),
78
+ "autoCreateWallet": ("SOLANA_AUTO_CREATE_WALLET", _parse_bool(config.get("autoCreateWallet")), True),
79
+ "encryptUserWallets": (
80
+ "AGENT_WALLET_ENCRYPT_USER_WALLETS",
81
+ _parse_bool(config.get("encryptUserWallets")),
82
+ True,
83
+ ),
84
+ "migratePlaintextUserWallets": (
85
+ "AGENT_WALLET_MIGRATE_PLAINTEXT_USER_WALLETS",
86
+ _parse_bool(config.get("migratePlaintextUserWallets")),
87
+ True,
88
+ ),
89
+ "refuseMainnetWalletRecreation": (
90
+ "AGENT_WALLET_REFUSE_MAINNET_WALLET_RECREATION",
91
+ _parse_bool(config.get("refuseMainnetWalletRecreation")),
92
+ True,
93
+ ),
94
+ "openclawHome": ("OPENCLAW_HOME", config.get("openclawHome"), True),
95
+ "jupiterBaseUrl": ("JUPITER_API_BASE_URL", config.get("jupiterBaseUrl"), True),
96
+ "jupiterUltraBaseUrl": ("JUPITER_ULTRA_API_BASE_URL", config.get("jupiterUltraBaseUrl"), True),
97
+ "jupiterPriceBaseUrl": ("JUPITER_PRICE_API_BASE_URL", config.get("jupiterPriceBaseUrl"), True),
98
+ "jupiterPortfolioBaseUrl": (
99
+ "JUPITER_PORTFOLIO_API_BASE_URL",
100
+ config.get("jupiterPortfolioBaseUrl"),
101
+ True,
102
+ ),
103
+ "jupiterLendBaseUrl": ("JUPITER_LEND_API_BASE_URL", config.get("jupiterLendBaseUrl"), True),
104
+ "jupiterApiKey": ("JUPITER_API_KEY", config.get("jupiterApiKey"), True),
105
+ "kaminoBaseUrl": ("KAMINO_API_BASE_URL", config.get("kaminoBaseUrl"), True),
106
+ "kaminoProgramId": ("KAMINO_PROGRAM_ID", config.get("kaminoProgramId"), True),
107
+ }
108
+ for _, (env_name, value, allow_override) in env_map.items():
109
+ if value is None:
110
+ continue
111
+ text = str(value).strip()
112
+ if not text:
113
+ continue
114
+ if env_name in {"SOLANA_RPC_URL", "SOLANA_RPC_URLS"} and rpc_env_locked:
115
+ continue
116
+ if not allow_override and os.getenv(env_name, "").strip():
117
+ continue
118
+ os.environ[env_name] = text
119
+
120
+
121
+ def _load_json(raw: str | None, default: dict[str, Any] | None = None) -> dict[str, Any]:
122
+ if not raw:
123
+ return {} if default is None else dict(default)
124
+ parsed = json.loads(raw)
125
+ if not isinstance(parsed, dict):
126
+ raise ValueError("Expected a JSON object.")
127
+ return parsed
128
+
129
+
130
+ def _read_stdin_secret(field_name: str) -> str:
131
+ value = sys.stdin.read().strip()
132
+ if not value:
133
+ raise WalletBackendError(f"{field_name} is required on stdin.")
134
+ return value
135
+
136
+
137
+ async def _run_onboard(user_id: str, config: dict[str, Any]) -> dict[str, Any]:
138
+ from agent_wallet.openclaw_runtime import onboard_openclaw_user_wallet
139
+
140
+ context = onboard_openclaw_user_wallet(
141
+ user_id,
142
+ backend=config.get("backend"),
143
+ sign_only=config.get("signOnly"),
144
+ network=config.get("network"),
145
+ rpc_url=config.get("rpcUrl"),
146
+ wdk_btc_service_url=config.get("wdkBtcServiceUrl"),
147
+ wdk_btc_wallet_id=config.get("wdkBtcWalletId"),
148
+ wdk_btc_account_index=config.get("wdkBtcAccountIndex"),
149
+ wdk_evm_service_url=config.get("wdkEvmServiceUrl"),
150
+ wdk_evm_wallet_id=config.get("wdkEvmWalletId"),
151
+ wdk_evm_account_index=config.get("wdkEvmAccountIndex"),
152
+ )
153
+ return context.serializable_bundle()
154
+
155
+
156
+ async def _run_invoke(
157
+ user_id: str,
158
+ tool_name: str,
159
+ arguments: dict[str, Any],
160
+ config: dict[str, Any],
161
+ ) -> dict[str, Any]:
162
+ from agent_wallet.openclaw_runtime import onboard_openclaw_user_wallet
163
+
164
+ context = onboard_openclaw_user_wallet(
165
+ user_id,
166
+ backend=config.get("backend"),
167
+ sign_only=config.get("signOnly"),
168
+ network=config.get("network"),
169
+ rpc_url=config.get("rpcUrl"),
170
+ wdk_btc_service_url=config.get("wdkBtcServiceUrl"),
171
+ wdk_btc_wallet_id=config.get("wdkBtcWalletId"),
172
+ wdk_btc_account_index=config.get("wdkBtcAccountIndex"),
173
+ wdk_evm_service_url=config.get("wdkEvmServiceUrl"),
174
+ wdk_evm_wallet_id=config.get("wdkEvmWalletId"),
175
+ wdk_evm_account_index=config.get("wdkEvmAccountIndex"),
176
+ )
177
+ result = await context.adapter.invoke(tool_name, arguments)
178
+ return result.model_dump()
179
+
180
+
181
+ async def _run_issue_approval(
182
+ user_id: str,
183
+ tool_name: str,
184
+ summary: dict[str, Any],
185
+ config: dict[str, Any],
186
+ *,
187
+ mainnet_confirmed: bool = False,
188
+ ttl_seconds: int | None = None,
189
+ ) -> dict[str, Any]:
190
+ from agent_wallet.openclaw_runtime import onboard_openclaw_user_wallet
191
+
192
+ context = onboard_openclaw_user_wallet(
193
+ user_id,
194
+ backend=config.get("backend"),
195
+ sign_only=config.get("signOnly"),
196
+ network=config.get("network"),
197
+ rpc_url=config.get("rpcUrl"),
198
+ wdk_btc_service_url=config.get("wdkBtcServiceUrl"),
199
+ wdk_btc_wallet_id=config.get("wdkBtcWalletId"),
200
+ wdk_btc_account_index=config.get("wdkBtcAccountIndex"),
201
+ wdk_evm_service_url=config.get("wdkEvmServiceUrl"),
202
+ wdk_evm_wallet_id=config.get("wdkEvmWalletId"),
203
+ wdk_evm_account_index=config.get("wdkEvmAccountIndex"),
204
+ )
205
+ token = context.issue_execute_approval(
206
+ tool_name=tool_name,
207
+ confirmation_summary=summary,
208
+ mainnet_confirmed=mainnet_confirmed,
209
+ ttl_seconds=ttl_seconds,
210
+ )
211
+ return {
212
+ "ok": True,
213
+ "tool": tool_name,
214
+ "network": str(getattr(context.backend, "network", "unknown")),
215
+ "approval_token": token,
216
+ "confirmation_summary": summary,
217
+ "mainnet_confirmed": bool(mainnet_confirmed),
218
+ "ttl_seconds": ttl_seconds,
219
+ }
220
+
221
+
222
+ async def _run_btc_wallet_get(user_id: str, config: dict[str, Any]) -> dict[str, Any]:
223
+ from agent_wallet.btc_user_wallets import get_user_btc_wallet_binding
224
+
225
+ return {
226
+ "ok": True,
227
+ "wallet": get_user_btc_wallet_binding(
228
+ user_id,
229
+ network=config.get("network"),
230
+ ),
231
+ }
232
+
233
+
234
+ async def _run_btc_wallet_create(
235
+ user_id: str,
236
+ config: dict[str, Any],
237
+ *,
238
+ label: str | None,
239
+ reveal_seed: bool,
240
+ password: str,
241
+ ) -> dict[str, Any]:
242
+ from agent_wallet.btc_user_wallets import create_user_btc_wallet
243
+
244
+ return {
245
+ "ok": True,
246
+ "wallet": create_user_btc_wallet(
247
+ user_id,
248
+ password=password,
249
+ label=label,
250
+ network=config.get("network"),
251
+ service_url=config.get("wdkBtcServiceUrl"),
252
+ reveal_seed_phrase=reveal_seed,
253
+ account_index=config.get("wdkBtcAccountIndex"),
254
+ ),
255
+ }
256
+
257
+
258
+ async def _run_btc_wallet_import(
259
+ user_id: str,
260
+ config: dict[str, Any],
261
+ *,
262
+ label: str | None,
263
+ password: str,
264
+ seed_phrase: str,
265
+ ) -> dict[str, Any]:
266
+ from agent_wallet.btc_user_wallets import import_user_btc_wallet
267
+
268
+ return {
269
+ "ok": True,
270
+ "wallet": import_user_btc_wallet(
271
+ user_id,
272
+ password=password,
273
+ seed_phrase=seed_phrase,
274
+ label=label,
275
+ network=config.get("network"),
276
+ service_url=config.get("wdkBtcServiceUrl"),
277
+ account_index=config.get("wdkBtcAccountIndex"),
278
+ ),
279
+ }
280
+
281
+
282
+ async def _run_btc_wallet_unlock(
283
+ user_id: str,
284
+ config: dict[str, Any],
285
+ *,
286
+ password: str,
287
+ ) -> dict[str, Any]:
288
+ from agent_wallet.btc_user_wallets import unlock_user_btc_wallet
289
+
290
+ return {
291
+ "ok": True,
292
+ "wallet": unlock_user_btc_wallet(
293
+ user_id,
294
+ password=password,
295
+ network=config.get("network"),
296
+ service_url=config.get("wdkBtcServiceUrl"),
297
+ ),
298
+ }
299
+
300
+
301
+ async def _run_btc_wallet_lock(user_id: str, config: dict[str, Any]) -> dict[str, Any]:
302
+ from agent_wallet.btc_user_wallets import lock_user_btc_wallet
303
+
304
+ return {
305
+ "ok": True,
306
+ "wallet": lock_user_btc_wallet(
307
+ user_id,
308
+ network=config.get("network"),
309
+ service_url=config.get("wdkBtcServiceUrl"),
310
+ ),
311
+ }
312
+
313
+
314
+ async def _run_evm_wallet_get(user_id: str, config: dict[str, Any]) -> dict[str, Any]:
315
+ from agent_wallet.evm_user_wallets import resolve_user_evm_wallet_binding
316
+
317
+ return {
318
+ "ok": True,
319
+ "wallet": resolve_user_evm_wallet_binding(
320
+ user_id,
321
+ network=config.get("network"),
322
+ service_url=config.get("wdkEvmServiceUrl"),
323
+ wallet_id=config.get("wdkEvmWalletId"),
324
+ account_index=config.get("wdkEvmAccountIndex"),
325
+ ),
326
+ }
327
+
328
+
329
+ async def _run_evm_wallet_create(
330
+ user_id: str,
331
+ config: dict[str, Any],
332
+ *,
333
+ label: str | None,
334
+ reveal_seed: bool,
335
+ password: str,
336
+ ) -> dict[str, Any]:
337
+ from agent_wallet.evm_user_wallets import create_user_evm_wallet
338
+
339
+ return {
340
+ "ok": True,
341
+ "wallet": create_user_evm_wallet(
342
+ user_id,
343
+ password=password,
344
+ label=label,
345
+ network=config.get("network"),
346
+ service_url=config.get("wdkEvmServiceUrl"),
347
+ reveal_seed_phrase=reveal_seed,
348
+ account_index=config.get("wdkEvmAccountIndex"),
349
+ ),
350
+ }
351
+
352
+
353
+ async def _run_evm_wallet_import(
354
+ user_id: str,
355
+ config: dict[str, Any],
356
+ *,
357
+ label: str | None,
358
+ password: str,
359
+ seed_phrase: str,
360
+ ) -> dict[str, Any]:
361
+ from agent_wallet.evm_user_wallets import import_user_evm_wallet
362
+
363
+ return {
364
+ "ok": True,
365
+ "wallet": import_user_evm_wallet(
366
+ user_id,
367
+ password=password,
368
+ seed_phrase=seed_phrase,
369
+ label=label,
370
+ network=config.get("network"),
371
+ service_url=config.get("wdkEvmServiceUrl"),
372
+ account_index=config.get("wdkEvmAccountIndex"),
373
+ ),
374
+ }
375
+
376
+
377
+ async def _run_evm_wallet_unlock(
378
+ user_id: str,
379
+ config: dict[str, Any],
380
+ *,
381
+ password: str,
382
+ ) -> dict[str, Any]:
383
+ from agent_wallet.evm_user_wallets import unlock_user_evm_wallet
384
+
385
+ return {
386
+ "ok": True,
387
+ "wallet": unlock_user_evm_wallet(
388
+ user_id,
389
+ password=password,
390
+ network=config.get("network"),
391
+ service_url=config.get("wdkEvmServiceUrl"),
392
+ wallet_id=config.get("wdkEvmWalletId"),
393
+ account_index=config.get("wdkEvmAccountIndex"),
394
+ ),
395
+ }
396
+
397
+
398
+ async def _run_evm_wallet_lock(user_id: str, config: dict[str, Any]) -> dict[str, Any]:
399
+ from agent_wallet.evm_user_wallets import lock_user_evm_wallet
400
+
401
+ return {
402
+ "ok": True,
403
+ "wallet": lock_user_evm_wallet(
404
+ user_id,
405
+ network=config.get("network"),
406
+ service_url=config.get("wdkEvmServiceUrl"),
407
+ wallet_id=config.get("wdkEvmWalletId"),
408
+ account_index=config.get("wdkEvmAccountIndex"),
409
+ ),
410
+ }
411
+
412
+
413
+ def main() -> int:
414
+ parser = argparse.ArgumentParser(description="OpenClaw wallet bridge CLI")
415
+ subparsers = parser.add_subparsers(dest="command", required=True)
416
+
417
+ onboard_parser = subparsers.add_parser("onboard")
418
+ onboard_parser.add_argument("--user-id", required=True)
419
+ onboard_parser.add_argument("--config-json", default="{}")
420
+
421
+ invoke_parser = subparsers.add_parser("invoke")
422
+ invoke_parser.add_argument("--user-id", required=True)
423
+ invoke_parser.add_argument("--tool", required=True)
424
+ invoke_parser.add_argument("--arguments-json", default="{}")
425
+ invoke_parser.add_argument("--config-json", default="{}")
426
+
427
+ approval_parser = subparsers.add_parser("issue-approval")
428
+ approval_parser.add_argument("--user-id", required=True)
429
+ approval_parser.add_argument("--tool", required=True)
430
+ approval_parser.add_argument("--summary-json", required=True)
431
+ approval_parser.add_argument("--mainnet-confirmed", action="store_true")
432
+ approval_parser.add_argument("--ttl-seconds", type=int)
433
+ approval_parser.add_argument("--config-json", default="{}")
434
+
435
+ btc_get_parser = subparsers.add_parser("btc-wallet-get")
436
+ btc_get_parser.add_argument("--user-id", required=True)
437
+ btc_get_parser.add_argument("--config-json", default="{}")
438
+
439
+ btc_create_parser = subparsers.add_parser("btc-wallet-create")
440
+ btc_create_parser.add_argument("--user-id", required=True)
441
+ btc_create_parser.add_argument("--label")
442
+ btc_create_parser.add_argument("--reveal-seed", action="store_true")
443
+ btc_create_parser.add_argument("--password-stdin", action="store_true")
444
+ btc_create_parser.add_argument("--config-json", default="{}")
445
+
446
+ btc_import_parser = subparsers.add_parser("btc-wallet-import")
447
+ btc_import_parser.add_argument("--user-id", required=True)
448
+ btc_import_parser.add_argument("--label")
449
+ btc_import_parser.add_argument("--password-stdin", action="store_true")
450
+ btc_import_parser.add_argument("--seed-stdin", action="store_true")
451
+ btc_import_parser.add_argument("--config-json", default="{}")
452
+
453
+ btc_unlock_parser = subparsers.add_parser("btc-wallet-unlock")
454
+ btc_unlock_parser.add_argument("--user-id", required=True)
455
+ btc_unlock_parser.add_argument("--password-stdin", action="store_true")
456
+ btc_unlock_parser.add_argument("--config-json", default="{}")
457
+
458
+ btc_lock_parser = subparsers.add_parser("btc-wallet-lock")
459
+ btc_lock_parser.add_argument("--user-id", required=True)
460
+ btc_lock_parser.add_argument("--config-json", default="{}")
461
+
462
+ evm_get_parser = subparsers.add_parser("evm-wallet-get")
463
+ evm_get_parser.add_argument("--user-id", required=True)
464
+ evm_get_parser.add_argument("--config-json", default="{}")
465
+
466
+ evm_create_parser = subparsers.add_parser("evm-wallet-create")
467
+ evm_create_parser.add_argument("--user-id", required=True)
468
+ evm_create_parser.add_argument("--label")
469
+ evm_create_parser.add_argument("--reveal-seed", action="store_true")
470
+ evm_create_parser.add_argument("--password-stdin", action="store_true")
471
+ evm_create_parser.add_argument("--config-json", default="{}")
472
+
473
+ evm_import_parser = subparsers.add_parser("evm-wallet-import")
474
+ evm_import_parser.add_argument("--user-id", required=True)
475
+ evm_import_parser.add_argument("--label")
476
+ evm_import_parser.add_argument("--password-stdin", action="store_true")
477
+ evm_import_parser.add_argument("--seed-stdin", action="store_true")
478
+ evm_import_parser.add_argument("--config-json", default="{}")
479
+
480
+ evm_unlock_parser = subparsers.add_parser("evm-wallet-unlock")
481
+ evm_unlock_parser.add_argument("--user-id", required=True)
482
+ evm_unlock_parser.add_argument("--password-stdin", action="store_true")
483
+ evm_unlock_parser.add_argument("--config-json", default="{}")
484
+
485
+ evm_lock_parser = subparsers.add_parser("evm-wallet-lock")
486
+ evm_lock_parser.add_argument("--user-id", required=True)
487
+ evm_lock_parser.add_argument("--config-json", default="{}")
488
+
489
+ args = parser.parse_args()
490
+
491
+ try:
492
+ config = _load_json(getattr(args, "config_json", "{}"))
493
+ _apply_config_overrides(config)
494
+
495
+ if args.command == "onboard":
496
+ payload = asyncio.run(_run_onboard(args.user_id, config))
497
+ elif args.command == "issue-approval":
498
+ payload = asyncio.run(
499
+ _run_issue_approval(
500
+ args.user_id,
501
+ args.tool,
502
+ _load_json(args.summary_json),
503
+ config,
504
+ mainnet_confirmed=bool(args.mainnet_confirmed),
505
+ ttl_seconds=args.ttl_seconds,
506
+ )
507
+ )
508
+ elif args.command == "btc-wallet-get":
509
+ payload = asyncio.run(_run_btc_wallet_get(args.user_id, config))
510
+ elif args.command == "btc-wallet-create":
511
+ if not args.password_stdin:
512
+ raise WalletBackendError("btc-wallet-create requires --password-stdin.")
513
+ payload = asyncio.run(
514
+ _run_btc_wallet_create(
515
+ args.user_id,
516
+ config,
517
+ label=args.label,
518
+ reveal_seed=bool(args.reveal_seed),
519
+ password=_read_stdin_secret("password"),
520
+ )
521
+ )
522
+ elif args.command == "btc-wallet-import":
523
+ if not args.password_stdin:
524
+ raise WalletBackendError("btc-wallet-import requires --password-stdin.")
525
+ if not args.seed_stdin:
526
+ raise WalletBackendError("btc-wallet-import requires --seed-stdin.")
527
+ raw = _read_stdin_secret("password and seed phrase payload")
528
+ lines = raw.splitlines()
529
+ if len(lines) < 2:
530
+ raise WalletBackendError(
531
+ "btc-wallet-import stdin must contain password on the first line and seed phrase on the remaining lines."
532
+ )
533
+ password = lines[0].strip()
534
+ seed_phrase = " ".join(line.strip() for line in lines[1:] if line.strip())
535
+ if not password or not seed_phrase:
536
+ raise WalletBackendError("btc-wallet-import requires both password and seed phrase on stdin.")
537
+ payload = asyncio.run(
538
+ _run_btc_wallet_import(
539
+ args.user_id,
540
+ config,
541
+ label=args.label,
542
+ password=password,
543
+ seed_phrase=seed_phrase,
544
+ )
545
+ )
546
+ elif args.command == "btc-wallet-unlock":
547
+ if not args.password_stdin:
548
+ raise WalletBackendError("btc-wallet-unlock requires --password-stdin.")
549
+ payload = asyncio.run(
550
+ _run_btc_wallet_unlock(
551
+ args.user_id,
552
+ config,
553
+ password=_read_stdin_secret("password"),
554
+ )
555
+ )
556
+ elif args.command == "btc-wallet-lock":
557
+ payload = asyncio.run(_run_btc_wallet_lock(args.user_id, config))
558
+ elif args.command == "evm-wallet-get":
559
+ payload = asyncio.run(_run_evm_wallet_get(args.user_id, config))
560
+ elif args.command == "evm-wallet-create":
561
+ if not args.password_stdin:
562
+ raise WalletBackendError("evm-wallet-create requires --password-stdin.")
563
+ payload = asyncio.run(
564
+ _run_evm_wallet_create(
565
+ args.user_id,
566
+ config,
567
+ label=args.label,
568
+ reveal_seed=bool(args.reveal_seed),
569
+ password=_read_stdin_secret("password"),
570
+ )
571
+ )
572
+ elif args.command == "evm-wallet-import":
573
+ if not args.password_stdin:
574
+ raise WalletBackendError("evm-wallet-import requires --password-stdin.")
575
+ if not args.seed_stdin:
576
+ raise WalletBackendError("evm-wallet-import requires --seed-stdin.")
577
+ raw = _read_stdin_secret("password and seed phrase payload")
578
+ lines = raw.splitlines()
579
+ if len(lines) < 2:
580
+ raise WalletBackendError(
581
+ "evm-wallet-import stdin must contain password on the first line and seed phrase on the remaining lines."
582
+ )
583
+ password = lines[0].strip()
584
+ seed_phrase = " ".join(line.strip() for line in lines[1:] if line.strip())
585
+ if not password or not seed_phrase:
586
+ raise WalletBackendError("evm-wallet-import requires both password and seed phrase on stdin.")
587
+ payload = asyncio.run(
588
+ _run_evm_wallet_import(
589
+ args.user_id,
590
+ config,
591
+ label=args.label,
592
+ password=password,
593
+ seed_phrase=seed_phrase,
594
+ )
595
+ )
596
+ elif args.command == "evm-wallet-unlock":
597
+ if not args.password_stdin:
598
+ raise WalletBackendError("evm-wallet-unlock requires --password-stdin.")
599
+ payload = asyncio.run(
600
+ _run_evm_wallet_unlock(
601
+ args.user_id,
602
+ config,
603
+ password=_read_stdin_secret("password"),
604
+ )
605
+ )
606
+ elif args.command == "evm-wallet-lock":
607
+ payload = asyncio.run(_run_evm_wallet_lock(args.user_id, config))
608
+ else:
609
+ payload = asyncio.run(
610
+ _run_invoke(
611
+ args.user_id,
612
+ args.tool,
613
+ _load_json(args.arguments_json),
614
+ config,
615
+ )
616
+ )
617
+ except Exception as exc:
618
+ print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)
619
+ return 1
620
+
621
+ print(json.dumps(payload))
622
+ return 0
623
+
624
+
625
+ if __name__ == "__main__":
626
+ raise SystemExit(main())