@agentlayer.tech/wallet 0.1.11 → 0.1.13
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/extensions/agent-wallet/index.ts +454 -18
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +96 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +2 -0
- package/CHANGELOG.md +25 -0
- package/README.md +43 -51
- package/agent-wallet/.env.example +11 -0
- package/agent-wallet/README.md +53 -0
- package/agent-wallet/agent_wallet/approval.py +4 -0
- package/agent-wallet/agent_wallet/config.py +6 -0
- package/agent-wallet/agent_wallet/exceptions.py +2 -1
- package/agent-wallet/agent_wallet/openclaw_adapter.py +361 -2
- package/agent-wallet/agent_wallet/openclaw_cli.py +13 -1
- package/agent-wallet/agent_wallet/openclaw_runtime.py +2 -5
- package/agent-wallet/agent_wallet/providers/houdini.py +539 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +251 -0
- package/agent-wallet/agent_wallet/user_wallets.py +83 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +40 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +885 -16
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/bootstrap_openclaw_evm.py +291 -0
- package/agent-wallet/scripts/install_agent_wallet.py +54 -2
- package/agent-wallet/scripts/install_openclaw_local_config.py +84 -4
- package/agent-wallet/scripts/manage_openclaw_evm_wallet.py +343 -0
- package/agent-wallet/scripts/setup_evm_wallet.sh +151 -0
- package/hermes/plugins/agent_wallet/__init__.py +28 -2
- package/hermes/plugins/agent_wallet/plugin.yaml +2 -0
- package/hermes/plugins/agent_wallet/schemas.py +72 -0
- package/hermes/plugins/agent_wallet/tools.py +193 -9
- package/package.json +2 -2
|
@@ -265,6 +265,27 @@ class OpenClawWalletAdapter:
|
|
|
265
265
|
"transaction_data_hash": payload.get("transaction_data_hash"),
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
if asset_type == "solana-private-swap":
|
|
269
|
+
return {
|
|
270
|
+
"operation": action_label,
|
|
271
|
+
"network": str(payload.get("network") or getattr(self.backend, "network", "unknown")),
|
|
272
|
+
"swap_provider": payload.get("source") or "houdini",
|
|
273
|
+
"owner": payload.get("owner"),
|
|
274
|
+
"destination_address": payload.get("destination_address"),
|
|
275
|
+
"input_token_id": payload.get("input_token_id"),
|
|
276
|
+
"output_token_id": payload.get("output_token_id"),
|
|
277
|
+
"input_token_symbol": payload.get("input_token_symbol"),
|
|
278
|
+
"output_token_symbol": payload.get("output_token_symbol"),
|
|
279
|
+
"input_token_address": payload.get("input_token_address"),
|
|
280
|
+
"output_token_address": payload.get("output_token_address"),
|
|
281
|
+
"input_amount_ui": payload.get("input_amount_ui"),
|
|
282
|
+
"estimated_output_amount_ui": payload.get("estimated_output_amount_ui"),
|
|
283
|
+
"private_duration_minutes": payload.get("private_duration_minutes"),
|
|
284
|
+
"quote_id": payload.get("quote_id"),
|
|
285
|
+
"anonymous": payload.get("anonymous"),
|
|
286
|
+
"use_xmr": payload.get("use_xmr"),
|
|
287
|
+
}
|
|
288
|
+
|
|
268
289
|
if asset_type == "evm-lifi-cross-chain-swap":
|
|
269
290
|
return {
|
|
270
291
|
"operation": action_label,
|
|
@@ -644,8 +665,8 @@ class OpenClawWalletAdapter:
|
|
|
644
665
|
)
|
|
645
666
|
annotated["confirmation_requirements"] = {
|
|
646
667
|
"prepare_requires_user_intent": mode == "prepare",
|
|
647
|
-
"execute_requires_approval_token":
|
|
648
|
-
"execute_requires_mainnet_confirmed_in_token":
|
|
668
|
+
"execute_requires_approval_token": True,
|
|
669
|
+
"execute_requires_mainnet_confirmed_in_token": is_mainnet,
|
|
649
670
|
}
|
|
650
671
|
if mode == "preview":
|
|
651
672
|
annotated["approval_hint"] = {
|
|
@@ -2154,6 +2175,112 @@ class OpenClawWalletAdapter:
|
|
|
2154
2175
|
)
|
|
2155
2176
|
)
|
|
2156
2177
|
|
|
2178
|
+
tools.append(
|
|
2179
|
+
AgentToolSpec(
|
|
2180
|
+
name="swap_solana_privately",
|
|
2181
|
+
description=(
|
|
2182
|
+
"Preview or create a Solana private payout through Houdini's anonymous routing. "
|
|
2183
|
+
"The initial implementation supports same-token private payouts only, such as SOL->SOL or USDC->USDC. "
|
|
2184
|
+
"Use preview first, then execute after explicit approval. "
|
|
2185
|
+
"The first execute creates the Houdini order and returns the deposit address; use continue_solana_private_swap to submit the funding transfer."
|
|
2186
|
+
),
|
|
2187
|
+
input_schema={
|
|
2188
|
+
"type": "object",
|
|
2189
|
+
"properties": {
|
|
2190
|
+
"input_token": {
|
|
2191
|
+
"type": "string",
|
|
2192
|
+
"description": "Source Solana token identifier. Symbol, name, mint address, or Houdini token id.",
|
|
2193
|
+
},
|
|
2194
|
+
"output_token": {
|
|
2195
|
+
"type": "string",
|
|
2196
|
+
"description": "Destination Solana token identifier. For the initial implementation, this must resolve to the same token as input_token.",
|
|
2197
|
+
},
|
|
2198
|
+
"destination_address": {
|
|
2199
|
+
"type": "string",
|
|
2200
|
+
"description": "Destination Solana wallet address that should receive the privately routed payout.",
|
|
2201
|
+
},
|
|
2202
|
+
"amount": {
|
|
2203
|
+
"type": "number",
|
|
2204
|
+
"description": "Input token amount in UI units.",
|
|
2205
|
+
},
|
|
2206
|
+
"use_xmr": {
|
|
2207
|
+
"type": "boolean",
|
|
2208
|
+
"description": "Optional. Force Houdini's XMR privacy hop when available.",
|
|
2209
|
+
},
|
|
2210
|
+
"mode": {
|
|
2211
|
+
"type": "string",
|
|
2212
|
+
"enum": ["preview", "execute"],
|
|
2213
|
+
},
|
|
2214
|
+
"purpose": {"type": "string"},
|
|
2215
|
+
"user_intent": {"type": "boolean"},
|
|
2216
|
+
"approval_token": {"type": "string"},
|
|
2217
|
+
},
|
|
2218
|
+
"required": [
|
|
2219
|
+
"input_token",
|
|
2220
|
+
"output_token",
|
|
2221
|
+
"destination_address",
|
|
2222
|
+
"amount",
|
|
2223
|
+
"mode",
|
|
2224
|
+
"purpose",
|
|
2225
|
+
],
|
|
2226
|
+
"additionalProperties": False,
|
|
2227
|
+
},
|
|
2228
|
+
read_only=False,
|
|
2229
|
+
requires_explicit_user_intent=True,
|
|
2230
|
+
risk_level="high",
|
|
2231
|
+
)
|
|
2232
|
+
)
|
|
2233
|
+
|
|
2234
|
+
tools.append(
|
|
2235
|
+
AgentToolSpec(
|
|
2236
|
+
name="continue_solana_private_swap",
|
|
2237
|
+
description=(
|
|
2238
|
+
"Continue a previously created Houdini Solana private payout and submit the funding transfer "
|
|
2239
|
+
"to the saved deposit address. Use this only after swap_solana_privately execute has returned "
|
|
2240
|
+
"a pending order with deposit address details."
|
|
2241
|
+
),
|
|
2242
|
+
input_schema={
|
|
2243
|
+
"type": "object",
|
|
2244
|
+
"properties": {
|
|
2245
|
+
"houdini_id": {
|
|
2246
|
+
"type": "string",
|
|
2247
|
+
"description": "Optional Houdini order id for the pending private payout. If omitted, the host may use the latest cached pending order.",
|
|
2248
|
+
},
|
|
2249
|
+
"approval_token": {
|
|
2250
|
+
"type": "string",
|
|
2251
|
+
"description": "Approval token issued from the original private swap preview.",
|
|
2252
|
+
},
|
|
2253
|
+
},
|
|
2254
|
+
"required": ["approval_token"],
|
|
2255
|
+
"additionalProperties": False,
|
|
2256
|
+
},
|
|
2257
|
+
read_only=False,
|
|
2258
|
+
requires_explicit_user_intent=True,
|
|
2259
|
+
risk_level="high",
|
|
2260
|
+
)
|
|
2261
|
+
)
|
|
2262
|
+
|
|
2263
|
+
tools.append(
|
|
2264
|
+
AgentToolSpec(
|
|
2265
|
+
name="get_solana_private_swap_status",
|
|
2266
|
+
description=(
|
|
2267
|
+
"Check Houdini status for a Solana private payout created by swap_solana_privately. "
|
|
2268
|
+
"Use houdini_id from the execute result. multi_id is still accepted for legacy multi-order flows."
|
|
2269
|
+
),
|
|
2270
|
+
input_schema={
|
|
2271
|
+
"type": "object",
|
|
2272
|
+
"properties": {
|
|
2273
|
+
"multi_id": {"type": "string"},
|
|
2274
|
+
"houdini_id": {"type": "string"},
|
|
2275
|
+
},
|
|
2276
|
+
"anyOf": [{"required": ["multi_id"]}, {"required": ["houdini_id"]}],
|
|
2277
|
+
"additionalProperties": False,
|
|
2278
|
+
},
|
|
2279
|
+
read_only=True,
|
|
2280
|
+
risk_level="low",
|
|
2281
|
+
)
|
|
2282
|
+
)
|
|
2283
|
+
|
|
2157
2284
|
tools.append(
|
|
2158
2285
|
AgentToolSpec(
|
|
2159
2286
|
name="claim_bags_fees",
|
|
@@ -4490,6 +4617,238 @@ class OpenClawWalletAdapter:
|
|
|
4490
4617
|
),
|
|
4491
4618
|
)
|
|
4492
4619
|
|
|
4620
|
+
if tool_name == "swap_solana_privately":
|
|
4621
|
+
input_token = args.get("input_token")
|
|
4622
|
+
output_token = args.get("output_token")
|
|
4623
|
+
destination_address = args.get("destination_address")
|
|
4624
|
+
amount = args.get("amount")
|
|
4625
|
+
use_xmr = args.get("use_xmr", False)
|
|
4626
|
+
mode = args.get("mode")
|
|
4627
|
+
purpose = args.get("purpose")
|
|
4628
|
+
user_intent = args.get("user_intent", False)
|
|
4629
|
+
approval_token = args.get("approval_token")
|
|
4630
|
+
|
|
4631
|
+
if not isinstance(input_token, str) or not input_token.strip():
|
|
4632
|
+
raise WalletBackendError("input_token is required.")
|
|
4633
|
+
if not isinstance(output_token, str) or not output_token.strip():
|
|
4634
|
+
raise WalletBackendError("output_token is required.")
|
|
4635
|
+
if not isinstance(destination_address, str) or not destination_address.strip():
|
|
4636
|
+
raise WalletBackendError("destination_address is required.")
|
|
4637
|
+
if not isinstance(amount, (int, float)) or amount <= 0:
|
|
4638
|
+
raise WalletBackendError("amount must be a positive number.")
|
|
4639
|
+
if not isinstance(use_xmr, bool):
|
|
4640
|
+
raise WalletBackendError("use_xmr must be a boolean when provided.")
|
|
4641
|
+
if mode not in {"preview", "prepare", "execute"}:
|
|
4642
|
+
raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
|
|
4643
|
+
if not isinstance(purpose, str) or not purpose.strip():
|
|
4644
|
+
raise WalletBackendError("purpose is required.")
|
|
4645
|
+
|
|
4646
|
+
preview_kwargs = {
|
|
4647
|
+
"input_token": input_token.strip(),
|
|
4648
|
+
"output_token": output_token.strip(),
|
|
4649
|
+
"destination_address": destination_address.strip(),
|
|
4650
|
+
"amount_ui": float(amount),
|
|
4651
|
+
"use_xmr": use_xmr,
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4654
|
+
if mode == "preview":
|
|
4655
|
+
preview = await self.backend.preview_solana_private_swap(**preview_kwargs)
|
|
4656
|
+
return AgentToolResult(
|
|
4657
|
+
tool=tool_name,
|
|
4658
|
+
ok=True,
|
|
4659
|
+
data=self._annotate_sensitive_payload(
|
|
4660
|
+
preview,
|
|
4661
|
+
action_label="Solana private swap",
|
|
4662
|
+
mode="preview",
|
|
4663
|
+
),
|
|
4664
|
+
)
|
|
4665
|
+
|
|
4666
|
+
if mode == "prepare":
|
|
4667
|
+
self._require_prepare_intent(user_intent)
|
|
4668
|
+
preview = await self.backend.preview_solana_private_swap(**preview_kwargs)
|
|
4669
|
+
return AgentToolResult(
|
|
4670
|
+
tool=tool_name,
|
|
4671
|
+
ok=True,
|
|
4672
|
+
data=self._annotate_sensitive_payload(
|
|
4673
|
+
self._build_prepare_plan(
|
|
4674
|
+
preview_payload=preview,
|
|
4675
|
+
action_label="Solana private swap",
|
|
4676
|
+
),
|
|
4677
|
+
action_label="Solana private swap",
|
|
4678
|
+
mode="prepare",
|
|
4679
|
+
),
|
|
4680
|
+
)
|
|
4681
|
+
|
|
4682
|
+
approval_payload = inspect_approval_token(
|
|
4683
|
+
approval_token,
|
|
4684
|
+
tool_name=tool_name,
|
|
4685
|
+
network=str(getattr(self.backend, "network", "unknown")),
|
|
4686
|
+
require_mainnet_confirmation=self._is_mainnet_for_backend(self.backend),
|
|
4687
|
+
)
|
|
4688
|
+
approval_summary = approval_payload.get("binding", {}).get("summary")
|
|
4689
|
+
if not isinstance(approval_summary, dict):
|
|
4690
|
+
raise WalletBackendError(
|
|
4691
|
+
"approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
|
|
4692
|
+
)
|
|
4693
|
+
expected_summary = {
|
|
4694
|
+
"operation": "Solana private swap",
|
|
4695
|
+
"network": str(getattr(self.backend, "network", "unknown")),
|
|
4696
|
+
"destination_address": destination_address.strip(),
|
|
4697
|
+
"use_xmr": use_xmr,
|
|
4698
|
+
}
|
|
4699
|
+
for key, expected_value in expected_summary.items():
|
|
4700
|
+
if approval_summary.get(key) != expected_value:
|
|
4701
|
+
raise WalletBackendError(
|
|
4702
|
+
"approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
|
|
4703
|
+
)
|
|
4704
|
+
try:
|
|
4705
|
+
approved_amount = float(approval_summary.get("input_amount_ui"))
|
|
4706
|
+
except (TypeError, ValueError):
|
|
4707
|
+
raise WalletBackendError(
|
|
4708
|
+
"approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
|
|
4709
|
+
)
|
|
4710
|
+
if approved_amount != float(amount):
|
|
4711
|
+
raise WalletBackendError(
|
|
4712
|
+
"approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
|
|
4713
|
+
)
|
|
4714
|
+
|
|
4715
|
+
approval_summary_copy = dict(approval_summary)
|
|
4716
|
+
approved_preview = args.get("_approved_preview")
|
|
4717
|
+
resume_private_swap_order = args.get("_resume_private_swap_order")
|
|
4718
|
+
if resume_private_swap_order is not None and not isinstance(resume_private_swap_order, dict):
|
|
4719
|
+
raise WalletBackendError("_resume_private_swap_order must be an object when provided.")
|
|
4720
|
+
execute_preview = None
|
|
4721
|
+
if isinstance(approval_summary_copy.get("_preview_digest"), str):
|
|
4722
|
+
if not isinstance(approved_preview, dict):
|
|
4723
|
+
raise WalletBackendError(
|
|
4724
|
+
"Approved private swap preview payload is required for execute mode. Generate a new preview and approval before execute."
|
|
4725
|
+
)
|
|
4726
|
+
if preview_payload_digest(approved_preview) != approval_summary_copy["_preview_digest"]:
|
|
4727
|
+
raise WalletBackendError(
|
|
4728
|
+
"approved preview payload does not match the approval token. Generate a new preview and approval before execute."
|
|
4729
|
+
)
|
|
4730
|
+
preview_summary = self._build_confirmation_summary(
|
|
4731
|
+
action_label="Solana private swap",
|
|
4732
|
+
payload=approved_preview,
|
|
4733
|
+
)
|
|
4734
|
+
summary_without_digest = {
|
|
4735
|
+
key: value
|
|
4736
|
+
for key, value in approval_summary_copy.items()
|
|
4737
|
+
if key != "_preview_digest"
|
|
4738
|
+
}
|
|
4739
|
+
if preview_summary != summary_without_digest:
|
|
4740
|
+
raise WalletBackendError(
|
|
4741
|
+
"approved preview payload does not match the approval token. Generate a new preview and approval before execute."
|
|
4742
|
+
)
|
|
4743
|
+
execute_preview = dict(approved_preview)
|
|
4744
|
+
|
|
4745
|
+
self._require_execute_approval(
|
|
4746
|
+
approval_token=approval_token,
|
|
4747
|
+
tool_name=tool_name,
|
|
4748
|
+
summary=approval_summary_copy,
|
|
4749
|
+
action_label="Solana private swap",
|
|
4750
|
+
)
|
|
4751
|
+
|
|
4752
|
+
result = await self.backend.execute_solana_private_swap(
|
|
4753
|
+
**preview_kwargs,
|
|
4754
|
+
approved_preview=execute_preview,
|
|
4755
|
+
existing_order=resume_private_swap_order,
|
|
4756
|
+
)
|
|
4757
|
+
return AgentToolResult(
|
|
4758
|
+
tool=tool_name,
|
|
4759
|
+
ok=True,
|
|
4760
|
+
data=self._annotate_sensitive_payload(
|
|
4761
|
+
result,
|
|
4762
|
+
action_label="Solana private swap",
|
|
4763
|
+
mode="execute",
|
|
4764
|
+
),
|
|
4765
|
+
)
|
|
4766
|
+
|
|
4767
|
+
if tool_name == "continue_solana_private_swap":
|
|
4768
|
+
approval_token = args.get("approval_token")
|
|
4769
|
+
approved_preview = args.get("_approved_preview")
|
|
4770
|
+
resume_private_swap_order = args.get("_resume_private_swap_order")
|
|
4771
|
+
if not isinstance(approved_preview, dict):
|
|
4772
|
+
raise WalletBackendError(
|
|
4773
|
+
"Approved private swap preview payload is required. Create the private swap order first."
|
|
4774
|
+
)
|
|
4775
|
+
if not isinstance(resume_private_swap_order, dict) or not resume_private_swap_order:
|
|
4776
|
+
raise WalletBackendError(
|
|
4777
|
+
"A pending Houdini private swap order is required. Create the private swap order first."
|
|
4778
|
+
)
|
|
4779
|
+
|
|
4780
|
+
approval_payload = inspect_approval_token(
|
|
4781
|
+
approval_token,
|
|
4782
|
+
tool_name="swap_solana_privately",
|
|
4783
|
+
network=str(getattr(self.backend, "network", "unknown")),
|
|
4784
|
+
require_mainnet_confirmation=self._is_mainnet_for_backend(self.backend),
|
|
4785
|
+
)
|
|
4786
|
+
approval_summary = approval_payload.get("binding", {}).get("summary")
|
|
4787
|
+
if not isinstance(approval_summary, dict):
|
|
4788
|
+
raise WalletBackendError(
|
|
4789
|
+
"approval_token does not match the requested private swap. Generate a new approval from the preview first."
|
|
4790
|
+
)
|
|
4791
|
+
|
|
4792
|
+
approval_summary_copy = dict(approval_summary)
|
|
4793
|
+
if isinstance(approval_summary_copy.get("_preview_digest"), str):
|
|
4794
|
+
if preview_payload_digest(approved_preview) != approval_summary_copy["_preview_digest"]:
|
|
4795
|
+
raise WalletBackendError(
|
|
4796
|
+
"approved preview payload does not match the approval token. Generate a new preview and approval before continue."
|
|
4797
|
+
)
|
|
4798
|
+
preview_summary = self._build_confirmation_summary(
|
|
4799
|
+
action_label="Solana private swap",
|
|
4800
|
+
payload=approved_preview,
|
|
4801
|
+
)
|
|
4802
|
+
summary_without_digest = {
|
|
4803
|
+
key: value
|
|
4804
|
+
for key, value in approval_summary_copy.items()
|
|
4805
|
+
if key != "_preview_digest"
|
|
4806
|
+
}
|
|
4807
|
+
if preview_summary != summary_without_digest:
|
|
4808
|
+
raise WalletBackendError(
|
|
4809
|
+
"approved preview payload does not match the approval token. Generate a new preview and approval before continue."
|
|
4810
|
+
)
|
|
4811
|
+
|
|
4812
|
+
self._require_execute_approval(
|
|
4813
|
+
approval_token=approval_token,
|
|
4814
|
+
tool_name="swap_solana_privately",
|
|
4815
|
+
summary=approval_summary_copy,
|
|
4816
|
+
action_label="Solana private swap",
|
|
4817
|
+
)
|
|
4818
|
+
|
|
4819
|
+
result = await self.backend.continue_solana_private_swap(
|
|
4820
|
+
approved_preview=approved_preview,
|
|
4821
|
+
existing_order=resume_private_swap_order,
|
|
4822
|
+
)
|
|
4823
|
+
return AgentToolResult(
|
|
4824
|
+
tool=tool_name,
|
|
4825
|
+
ok=True,
|
|
4826
|
+
data=self._annotate_sensitive_payload(
|
|
4827
|
+
result,
|
|
4828
|
+
action_label="Solana private swap funding",
|
|
4829
|
+
mode="execute",
|
|
4830
|
+
),
|
|
4831
|
+
)
|
|
4832
|
+
|
|
4833
|
+
if tool_name == "get_solana_private_swap_status":
|
|
4834
|
+
multi_id = args.get("multi_id")
|
|
4835
|
+
houdini_id = args.get("houdini_id")
|
|
4836
|
+
if multi_id is not None and not isinstance(multi_id, str):
|
|
4837
|
+
raise WalletBackendError("multi_id must be a string when provided.")
|
|
4838
|
+
if houdini_id is not None and not isinstance(houdini_id, str):
|
|
4839
|
+
raise WalletBackendError("houdini_id must be a string when provided.")
|
|
4840
|
+
normalized_multi_id = multi_id.strip() if isinstance(multi_id, str) and multi_id.strip() else None
|
|
4841
|
+
normalized_houdini_id = (
|
|
4842
|
+
houdini_id.strip() if isinstance(houdini_id, str) and houdini_id.strip() else None
|
|
4843
|
+
)
|
|
4844
|
+
if normalized_multi_id is None and normalized_houdini_id is None:
|
|
4845
|
+
raise WalletBackendError("multi_id or houdini_id is required.")
|
|
4846
|
+
data = await self.backend.get_solana_private_swap_status(
|
|
4847
|
+
multi_id=normalized_multi_id,
|
|
4848
|
+
houdini_id=normalized_houdini_id,
|
|
4849
|
+
)
|
|
4850
|
+
return AgentToolResult(tool=tool_name, ok=True, data=data)
|
|
4851
|
+
|
|
4493
4852
|
if tool_name == "swap_solana_lifi_cross_chain_tokens":
|
|
4494
4853
|
input_token = args.get("input_token")
|
|
4495
4854
|
destination_chain = args.get("destination_chain")
|
|
@@ -102,6 +102,12 @@ def _apply_config_overrides(config: dict[str, Any]) -> None:
|
|
|
102
102
|
),
|
|
103
103
|
"jupiterLendBaseUrl": ("JUPITER_LEND_API_BASE_URL", config.get("jupiterLendBaseUrl"), True),
|
|
104
104
|
"jupiterApiKey": ("JUPITER_API_KEY", config.get("jupiterApiKey"), True),
|
|
105
|
+
"houdiniBaseUrl": ("HOUDINI_API_BASE_URL", config.get("houdiniBaseUrl"), True),
|
|
106
|
+
"houdiniApiKey": ("HOUDINI_API_KEY", config.get("houdiniApiKey"), True),
|
|
107
|
+
"houdiniApiSecret": ("HOUDINI_API_SECRET", config.get("houdiniApiSecret"), True),
|
|
108
|
+
"houdiniUserIp": ("HOUDINI_USER_IP", config.get("houdiniUserIp"), True),
|
|
109
|
+
"houdiniUserAgent": ("HOUDINI_USER_AGENT", config.get("houdiniUserAgent"), True),
|
|
110
|
+
"houdiniUserTimezone": ("HOUDINI_USER_TIMEZONE", config.get("houdiniUserTimezone"), True),
|
|
105
111
|
"kaminoBaseUrl": ("KAMINO_API_BASE_URL", config.get("kaminoBaseUrl"), True),
|
|
106
112
|
"kaminoProgramId": ("KAMINO_PROGRAM_ID", config.get("kaminoProgramId"), True),
|
|
107
113
|
}
|
|
@@ -615,7 +621,13 @@ def main() -> int:
|
|
|
615
621
|
)
|
|
616
622
|
)
|
|
617
623
|
except Exception as exc:
|
|
618
|
-
|
|
624
|
+
error_payload: dict[str, Any] = {"ok": False, "error": str(exc)}
|
|
625
|
+
if isinstance(exc, WalletBackendError):
|
|
626
|
+
if exc.code:
|
|
627
|
+
error_payload["code"] = exc.code
|
|
628
|
+
if exc.details is not None:
|
|
629
|
+
error_payload["details"] = exc.details
|
|
630
|
+
print(json.dumps(error_payload), file=sys.stderr)
|
|
619
631
|
return 1
|
|
620
632
|
|
|
621
633
|
print(json.dumps(payload))
|
|
@@ -14,7 +14,7 @@ from agent_wallet.openclaw_adapter import OpenClawWalletAdapter
|
|
|
14
14
|
from agent_wallet.plugin_bundle import build_openclaw_plugin_bundle
|
|
15
15
|
from agent_wallet.providers.wdk_btc_local import WdkBtcLocalClient
|
|
16
16
|
from agent_wallet.providers.wdk_evm_local import WdkEvmLocalClient
|
|
17
|
-
from agent_wallet.user_wallets import
|
|
17
|
+
from agent_wallet.user_wallets import create_openclaw_solana_backend
|
|
18
18
|
from agent_wallet.wallet_layer.base import AgentWalletBackend, WalletBackendError
|
|
19
19
|
from agent_wallet.wallet_layer.wdk_evm import WdkEvmLocalWalletBackend
|
|
20
20
|
from agent_wallet.wallet_layer.wdk_btc import WdkBtcLocalWalletBackend
|
|
@@ -251,10 +251,7 @@ def onboard_openclaw_user_wallet(
|
|
|
251
251
|
plugin_bundle=plugin_bundle,
|
|
252
252
|
)
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
created_now = not wallet_path.exists()
|
|
256
|
-
wallet_info = ensure_user_solana_wallet(user_id, network=network)
|
|
257
|
-
backend = create_wallet_backend_for_user(
|
|
254
|
+
backend, wallet_info, created_now = create_openclaw_solana_backend(
|
|
258
255
|
user_id,
|
|
259
256
|
sign_only=sign_only,
|
|
260
257
|
network=network,
|