@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.
- package/.openclaw/AGENTS.md +98 -0
- package/.openclaw/extensions/agent-wallet/README.md +127 -0
- package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
- package/.openclaw/extensions/agent-wallet/package.json +11 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
- package/CHANGELOG.md +42 -0
- package/LICENSE +104 -0
- package/README.md +332 -0
- package/RELEASING.md +204 -0
- package/agent-wallet/.env.example +62 -0
- package/agent-wallet/AGENTS.md +129 -0
- package/agent-wallet/README.md +527 -0
- package/agent-wallet/agent_wallet/__init__.py +11 -0
- package/agent-wallet/agent_wallet/approval.py +161 -0
- package/agent-wallet/agent_wallet/bootstrap.py +178 -0
- package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
- package/agent-wallet/agent_wallet/config.py +382 -0
- package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
- package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
- package/agent-wallet/agent_wallet/exceptions.py +9 -0
- package/agent-wallet/agent_wallet/file_ops.py +34 -0
- package/agent-wallet/agent_wallet/http_client.py +25 -0
- package/agent-wallet/agent_wallet/models.py +66 -0
- package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
- package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
- package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
- package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
- package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
- package/agent-wallet/agent_wallet/providers/bags.py +259 -0
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
- package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
- package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
- package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
- package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
- package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
- package/agent-wallet/agent_wallet/solana_stake.py +103 -0
- package/agent-wallet/agent_wallet/solana_tx.py +93 -0
- package/agent-wallet/agent_wallet/spending_limits.py +101 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
- package/agent-wallet/agent_wallet/user_wallets.py +355 -0
- package/agent-wallet/agent_wallet/validation.py +31 -0
- package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
- package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
- package/agent-wallet/examples/bootstrap_wallet.py +21 -0
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
- package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
- package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
- package/agent-wallet/openclaw.plugin.json +138 -0
- package/agent-wallet/pyproject.toml +31 -0
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
- package/agent-wallet/scripts/build_release_bundle.py +188 -0
- package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
- package/agent-wallet/scripts/install_agent_wallet.py +505 -0
- package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
- package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
- package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
- package/agent-wallet/scripts/security_utils.py +37 -0
- package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
- package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
- package/bin/openclaw-agent-wallet.mjs +487 -0
- package/install-from-github.sh +134 -0
- package/package.json +61 -0
- package/setup.sh +40 -0
- package/wdk-btc-wallet/README.md +325 -0
- package/wdk-btc-wallet/bootstrap.sh +22 -0
- package/wdk-btc-wallet/package-lock.json +1839 -0
- package/wdk-btc-wallet/package.json +18 -0
- package/wdk-btc-wallet/run-local.sh +21 -0
- package/wdk-btc-wallet/src/config.js +160 -0
- package/wdk-btc-wallet/src/json.js +35 -0
- package/wdk-btc-wallet/src/local_vault.js +432 -0
- package/wdk-btc-wallet/src/network_state.js +84 -0
- package/wdk-btc-wallet/src/server.js +257 -0
- package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
- package/wdk-evm-wallet/README.md +183 -0
- package/wdk-evm-wallet/bootstrap.sh +8 -0
- package/wdk-evm-wallet/package-lock.json +2340 -0
- package/wdk-evm-wallet/package.json +23 -0
- package/wdk-evm-wallet/run-local.sh +12 -0
- package/wdk-evm-wallet/src/config.js +274 -0
- package/wdk-evm-wallet/src/json.js +35 -0
- package/wdk-evm-wallet/src/local_vault.js +430 -0
- package/wdk-evm-wallet/src/network_state.js +92 -0
- package/wdk-evm-wallet/src/server.js +575 -0
- 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())
|