@agentlayer.tech/wallet 0.1.28 → 0.1.32

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 (71) hide show
  1. package/.openclaw/extensions/agent-wallet/README.md +5 -7
  2. package/.openclaw/extensions/agent-wallet/dist/index.js +35 -360
  3. package/.openclaw/extensions/agent-wallet/index.ts +35 -360
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +2 -45
  5. package/.openclaw/extensions/agent-wallet/package.json +1 -1
  6. package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +1 -3
  7. package/CHANGELOG.md +73 -0
  8. package/README.md +4 -0
  9. package/agent-wallet/.env.example +0 -12
  10. package/agent-wallet/README.md +18 -57
  11. package/agent-wallet/agent_wallet/bootstrap.py +28 -12
  12. package/agent-wallet/agent_wallet/btc_user_wallets.py +33 -7
  13. package/agent-wallet/agent_wallet/config.py +110 -29
  14. package/agent-wallet/agent_wallet/evm_user_wallets.py +4 -14
  15. package/agent-wallet/agent_wallet/openclaw_adapter.py +29 -687
  16. package/agent-wallet/agent_wallet/openclaw_cli.py +0 -7
  17. package/agent-wallet/agent_wallet/openclaw_runtime.py +3 -12
  18. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +18 -42
  19. package/agent-wallet/agent_wallet/providers/jupiter.py +1 -307
  20. package/agent-wallet/agent_wallet/providers/kamino.py +21 -4
  21. package/agent-wallet/agent_wallet/providers/solana_rpc.py +0 -23
  22. package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +31 -3
  23. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +37 -3
  24. package/agent-wallet/agent_wallet/providers/x402.py +4 -9
  25. package/agent-wallet/agent_wallet/transaction_policy.py +0 -262
  26. package/agent-wallet/agent_wallet/user_wallets.py +4 -3
  27. package/agent-wallet/agent_wallet/wallet_layer/base.py +3 -103
  28. package/agent-wallet/agent_wallet/wallet_layer/factory.py +8 -5
  29. package/agent-wallet/agent_wallet/wallet_layer/solana.py +453 -1177
  30. package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +2 -8
  31. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +2 -12
  32. package/agent-wallet/examples/openclaw_runtime_onboarding.py +1 -1
  33. package/agent-wallet/examples/openclaw_user_wallet_example.py +1 -1
  34. package/agent-wallet/openclaw.plugin.json +1 -5
  35. package/agent-wallet/pyproject.toml +2 -1
  36. package/agent-wallet/scripts/bootstrap_openclaw_btc.py +3 -5
  37. package/agent-wallet/scripts/bootstrap_openclaw_evm.py +2 -12
  38. package/agent-wallet/scripts/build_release_bundle.py +1 -0
  39. package/agent-wallet/scripts/flash-sdk-bridge/bridge.mjs +1 -4
  40. package/agent-wallet/scripts/install_agent_wallet.py +114 -6
  41. package/agent-wallet/scripts/install_openclaw_local_config.py +10 -10
  42. package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +2 -4
  43. package/agent-wallet/scripts/manage_openclaw_evm_wallet.py +2 -15
  44. package/agent-wallet/scripts/reveal_btc_seed.sh +7 -16
  45. package/agent-wallet/scripts/setup_btc_wallet.sh +7 -16
  46. package/agent-wallet/scripts/setup_evm_wallet.sh +1 -11
  47. package/agent-wallet/scripts/switch_openclaw_wallet_network.py +4 -1
  48. package/agent-wallet/skills/wallet-operator/SKILL.md +1 -6
  49. package/bin/openclaw-agent-wallet.mjs +356 -0
  50. package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +20 -0
  51. package/claude-code/plugins/agent-wallet/.mcp.json +14 -0
  52. package/claude-code/plugins/agent-wallet/README.md +65 -0
  53. package/claude-code/plugins/agent-wallet/scripts/run_mcp.sh +39 -0
  54. package/claude-code/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
  55. package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +38 -0
  56. package/codex/plugins/agent-wallet/.mcp.json +15 -0
  57. package/codex/plugins/agent-wallet/README.md +39 -0
  58. package/codex/plugins/agent-wallet/scripts/run_mcp.sh +21 -0
  59. package/codex/plugins/agent-wallet/server.py +961 -0
  60. package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
  61. package/hermes/plugins/agent_wallet/schemas.py +2 -2
  62. package/hermes/plugins/agent_wallet/tools.py +18 -4
  63. package/package.json +6 -1
  64. package/setup.sh +2 -0
  65. package/wdk-btc-wallet/src/local_vault.js +45 -68
  66. package/wdk-btc-wallet/src/server.js +1 -0
  67. package/wdk-evm-wallet/README.md +4 -3
  68. package/wdk-evm-wallet/src/config.js +15 -0
  69. package/wdk-evm-wallet/src/local_vault.js +45 -68
  70. package/wdk-evm-wallet/src/server.js +1 -0
  71. package/agent-wallet/agent_wallet/providers/houdini.py +0 -539
@@ -101,9 +101,10 @@ class OpenClawWalletAdapter:
101
101
  "eth": "ethereum",
102
102
  "eth-mainnet": "ethereum",
103
103
  "base-mainnet": "base",
104
- "base_sepolia": "base-sepolia",
105
104
  }
106
105
  network = aliases.get(network, network)
106
+ if network in {"sepolia", "base-sepolia", "base_sepolia"}:
107
+ raise WalletBackendError("EVM testnets are no longer supported. Use ethereum or base.")
107
108
  if network not in {"ethereum", "base"}:
108
109
  raise WalletBackendError("EVM network must be 'ethereum' or 'base'.")
109
110
  return network
@@ -388,27 +389,6 @@ class OpenClawWalletAdapter:
388
389
  "transaction_data_hash": payload.get("transaction_data_hash"),
389
390
  }
390
391
 
391
- if asset_type == "solana-private-swap":
392
- return {
393
- "operation": action_label,
394
- "network": str(payload.get("network") or getattr(self.backend, "network", "unknown")),
395
- "swap_provider": payload.get("source") or "houdini",
396
- "owner": payload.get("owner"),
397
- "destination_address": payload.get("destination_address"),
398
- "input_token_id": payload.get("input_token_id"),
399
- "output_token_id": payload.get("output_token_id"),
400
- "input_token_symbol": payload.get("input_token_symbol"),
401
- "output_token_symbol": payload.get("output_token_symbol"),
402
- "input_token_address": payload.get("input_token_address"),
403
- "output_token_address": payload.get("output_token_address"),
404
- "input_amount_ui": payload.get("input_amount_ui"),
405
- "estimated_output_amount_ui": payload.get("estimated_output_amount_ui"),
406
- "private_duration_minutes": payload.get("private_duration_minutes"),
407
- "quote_id": payload.get("quote_id"),
408
- "anonymous": payload.get("anonymous"),
409
- "use_xmr": payload.get("use_xmr"),
410
- }
411
-
412
392
  if asset_type == "evm-lifi-cross-chain-swap":
413
393
  return {
414
394
  "operation": action_label,
@@ -2044,56 +2024,6 @@ class OpenClawWalletAdapter:
2044
2024
  read_only=True,
2045
2025
  risk_level="low",
2046
2026
  ),
2047
- AgentToolSpec(
2048
- name="get_jupiter_earn_tokens",
2049
- description="List Jupiter Earn vault tokens currently supported on Solana mainnet.",
2050
- input_schema={
2051
- "type": "object",
2052
- "properties": {},
2053
- "additionalProperties": False,
2054
- },
2055
- read_only=True,
2056
- risk_level="low",
2057
- ),
2058
- AgentToolSpec(
2059
- name="get_jupiter_earn_positions",
2060
- description="Get Jupiter Earn positions for one or more Solana wallet addresses on mainnet.",
2061
- input_schema={
2062
- "type": "object",
2063
- "properties": {
2064
- "users": {
2065
- "type": "array",
2066
- "items": {"type": "string"},
2067
- "description": "Optional list of Solana wallet addresses. If omitted, use the configured wallet address.",
2068
- }
2069
- },
2070
- "additionalProperties": False,
2071
- },
2072
- read_only=True,
2073
- risk_level="low",
2074
- ),
2075
- AgentToolSpec(
2076
- name="get_jupiter_earn_earnings",
2077
- description="Get Jupiter Earn earnings for a wallet and one or more position addresses on mainnet.",
2078
- input_schema={
2079
- "type": "object",
2080
- "properties": {
2081
- "user": {
2082
- "type": "string",
2083
- "description": "Optional Solana wallet address override. If omitted, use the configured wallet.",
2084
- },
2085
- "positions": {
2086
- "type": "array",
2087
- "items": {"type": "string"},
2088
- "description": "List of Jupiter Earn position addresses.",
2089
- },
2090
- },
2091
- "required": ["positions"],
2092
- "additionalProperties": False,
2093
- },
2094
- read_only=True,
2095
- risk_level="low",
2096
- ),
2097
2027
  AgentToolSpec(
2098
2028
  name="get_flash_trade_markets",
2099
2029
  description="List Flash Trade perpetual markets currently available on Solana mainnet.",
@@ -2314,6 +2244,25 @@ class OpenClawWalletAdapter:
2314
2244
  read_only=True,
2315
2245
  risk_level="low",
2316
2246
  ),
2247
+ AgentToolSpec(
2248
+ name="get_kamino_open_positions",
2249
+ description=(
2250
+ "Get all open Kamino lending positions for a Solana wallet on mainnet, "
2251
+ "aggregated across markets with loan details, reserve APYs, and rewards."
2252
+ ),
2253
+ input_schema={
2254
+ "type": "object",
2255
+ "properties": {
2256
+ "user": {
2257
+ "type": "string",
2258
+ "description": "Optional Solana wallet address override. If omitted, use the configured wallet.",
2259
+ },
2260
+ },
2261
+ "additionalProperties": False,
2262
+ },
2263
+ read_only=True,
2264
+ risk_level="low",
2265
+ ),
2317
2266
  ]
2318
2267
 
2319
2268
  if capabilities.can_sign_message:
@@ -2564,112 +2513,6 @@ class OpenClawWalletAdapter:
2564
2513
  )
2565
2514
  )
2566
2515
 
2567
- tools.append(
2568
- AgentToolSpec(
2569
- name="swap_solana_privately",
2570
- description=(
2571
- "Preview or create a Solana private payout through Houdini's anonymous routing. "
2572
- "The initial implementation supports same-token private payouts only, such as SOL->SOL or USDC->USDC. "
2573
- "Use preview first, then execute after explicit approval. "
2574
- "The first execute creates the Houdini order and returns the deposit address; use continue_solana_private_swap to submit the funding transfer."
2575
- ),
2576
- input_schema={
2577
- "type": "object",
2578
- "properties": {
2579
- "input_token": {
2580
- "type": "string",
2581
- "description": "Source Solana token identifier. Symbol, name, mint address, or Houdini token id.",
2582
- },
2583
- "output_token": {
2584
- "type": "string",
2585
- "description": "Destination Solana token identifier. For the initial implementation, this must resolve to the same token as input_token.",
2586
- },
2587
- "destination_address": {
2588
- "type": "string",
2589
- "description": "Destination Solana wallet address that should receive the privately routed payout.",
2590
- },
2591
- "amount": {
2592
- "type": "number",
2593
- "description": "Input token amount in UI units.",
2594
- },
2595
- "use_xmr": {
2596
- "type": "boolean",
2597
- "description": "Optional. Force Houdini's XMR privacy hop when available.",
2598
- },
2599
- "mode": {
2600
- "type": "string",
2601
- "enum": ["preview", "execute"],
2602
- },
2603
- "purpose": {"type": "string"},
2604
- "user_intent": {"type": "boolean"},
2605
- "approval_token": {"type": "string"},
2606
- },
2607
- "required": [
2608
- "input_token",
2609
- "output_token",
2610
- "destination_address",
2611
- "amount",
2612
- "mode",
2613
- "purpose",
2614
- ],
2615
- "additionalProperties": False,
2616
- },
2617
- read_only=False,
2618
- requires_explicit_user_intent=True,
2619
- risk_level="high",
2620
- )
2621
- )
2622
-
2623
- tools.append(
2624
- AgentToolSpec(
2625
- name="continue_solana_private_swap",
2626
- description=(
2627
- "Continue a previously created Houdini Solana private payout and submit the funding transfer "
2628
- "to the saved deposit address. Use this only after swap_solana_privately execute has returned "
2629
- "a pending order with deposit address details."
2630
- ),
2631
- input_schema={
2632
- "type": "object",
2633
- "properties": {
2634
- "houdini_id": {
2635
- "type": "string",
2636
- "description": "Optional Houdini order id for the pending private payout. If omitted, the host may use the latest cached pending order.",
2637
- },
2638
- "approval_token": {
2639
- "type": "string",
2640
- "description": "Approval token issued from the original private swap preview.",
2641
- },
2642
- },
2643
- "required": ["approval_token"],
2644
- "additionalProperties": False,
2645
- },
2646
- read_only=False,
2647
- requires_explicit_user_intent=True,
2648
- risk_level="high",
2649
- )
2650
- )
2651
-
2652
- tools.append(
2653
- AgentToolSpec(
2654
- name="get_solana_private_swap_status",
2655
- description=(
2656
- "Check Houdini status for a Solana private payout created by swap_solana_privately. "
2657
- "Use houdini_id from the execute result. multi_id is still accepted for legacy multi-order flows."
2658
- ),
2659
- input_schema={
2660
- "type": "object",
2661
- "properties": {
2662
- "multi_id": {"type": "string"},
2663
- "houdini_id": {"type": "string"},
2664
- },
2665
- "anyOf": [{"required": ["multi_id"]}, {"required": ["houdini_id"]}],
2666
- "additionalProperties": False,
2667
- },
2668
- read_only=True,
2669
- risk_level="low",
2670
- )
2671
- )
2672
-
2673
2516
  tools.append(
2674
2517
  AgentToolSpec(
2675
2518
  name="claim_bags_fees",
@@ -2711,6 +2554,7 @@ class OpenClawWalletAdapter:
2711
2554
  )
2712
2555
  )
2713
2556
 
2557
+
2714
2558
  tools.append(
2715
2559
  AgentToolSpec(
2716
2560
  name="swap_solana_lifi_cross_chain_tokens",
@@ -2854,96 +2698,6 @@ class OpenClawWalletAdapter:
2854
2698
  )
2855
2699
  )
2856
2700
 
2857
- tools.append(
2858
- AgentToolSpec(
2859
- name="jupiter_earn_deposit",
2860
- description=(
2861
- "Preview, prepare, or execute a Jupiter Earn deposit using a raw base-unit amount. "
2862
- "Use preview first, then execute only after explicit user approval."
2863
- ),
2864
- input_schema={
2865
- "type": "object",
2866
- "properties": {
2867
- "asset": {
2868
- "type": "string",
2869
- "description": "Solana mint address for the Earn asset.",
2870
- },
2871
- "amount_raw": {
2872
- "type": "string",
2873
- "description": "Deposit amount in raw base units as an integer string.",
2874
- },
2875
- "mode": {
2876
- "type": "string",
2877
- "enum": ["preview", "prepare", "execute"],
2878
- "description": "preview returns a summary, prepare returns an execution plan without signed transaction bytes, execute attempts to submit the Earn deposit transaction.",
2879
- },
2880
- "purpose": {
2881
- "type": "string",
2882
- "description": "Short explanation of why the Earn deposit is being made.",
2883
- },
2884
- "user_intent": {
2885
- "type": "boolean",
2886
- "description": "Must be true for prepare mode.",
2887
- },
2888
- "approval_token": {
2889
- "type": "string",
2890
- "description": "Host-issued approval token required for execute mode.",
2891
- },
2892
- },
2893
- "required": ["asset", "amount_raw", "mode", "purpose"],
2894
- "additionalProperties": False,
2895
- },
2896
- read_only=False,
2897
- requires_explicit_user_intent=True,
2898
- risk_level="high",
2899
- )
2900
- )
2901
-
2902
- tools.append(
2903
- AgentToolSpec(
2904
- name="jupiter_earn_withdraw",
2905
- description=(
2906
- "Preview, prepare, or execute a Jupiter Earn withdraw using a raw base-unit amount. "
2907
- "Use preview first, then execute only after explicit user approval."
2908
- ),
2909
- input_schema={
2910
- "type": "object",
2911
- "properties": {
2912
- "asset": {
2913
- "type": "string",
2914
- "description": "Solana mint address for the Earn asset.",
2915
- },
2916
- "amount_raw": {
2917
- "type": "string",
2918
- "description": "Withdraw amount in raw base units as an integer string.",
2919
- },
2920
- "mode": {
2921
- "type": "string",
2922
- "enum": ["preview", "prepare", "execute"],
2923
- "description": "preview returns a summary, prepare returns an execution plan without signed transaction bytes, execute attempts to submit the Earn withdraw transaction.",
2924
- },
2925
- "purpose": {
2926
- "type": "string",
2927
- "description": "Short explanation of why the Earn withdraw is being made.",
2928
- },
2929
- "user_intent": {
2930
- "type": "boolean",
2931
- "description": "Must be true for prepare mode.",
2932
- },
2933
- "approval_token": {
2934
- "type": "string",
2935
- "description": "Host-issued approval token required for execute mode.",
2936
- },
2937
- },
2938
- "required": ["asset", "amount_raw", "mode", "purpose"],
2939
- "additionalProperties": False,
2940
- },
2941
- read_only=False,
2942
- requires_explicit_user_intent=True,
2943
- risk_level="high",
2944
- )
2945
- )
2946
-
2947
2701
  tools.append(
2948
2702
  AgentToolSpec(
2949
2703
  name="kamino_lend_deposit",
@@ -3221,30 +2975,6 @@ class OpenClawWalletAdapter:
3221
2975
  )
3222
2976
  )
3223
2977
 
3224
- tools.append(
3225
- AgentToolSpec(
3226
- name="request_devnet_airdrop",
3227
- description=(
3228
- "Request SOL from the Solana faucet on devnet or testnet. "
3229
- "Only available outside mainnet."
3230
- ),
3231
- input_schema={
3232
- "type": "object",
3233
- "properties": {
3234
- "amount": {
3235
- "type": "number",
3236
- "description": "Amount of SOL to request from faucet.",
3237
- }
3238
- },
3239
- "required": ["amount"],
3240
- "additionalProperties": False,
3241
- },
3242
- read_only=False,
3243
- requires_explicit_user_intent=True,
3244
- risk_level="low",
3245
- )
3246
- )
3247
-
3248
2978
  tools.extend(self._x402_tool_specs())
3249
2979
  return [tool for tool in tools if tool.name not in TEMPORARILY_DISABLED_TOOLS]
3250
2980
 
@@ -4295,33 +4025,6 @@ class OpenClawWalletAdapter:
4295
4025
  data = await self.backend.get_jupiter_staked_jup(address=address)
4296
4026
  return AgentToolResult(tool=tool_name, ok=True, data=data)
4297
4027
 
4298
- if tool_name == "get_jupiter_earn_tokens":
4299
- data = await self.backend.get_jupiter_earn_tokens()
4300
- return AgentToolResult(tool=tool_name, ok=True, data=data)
4301
-
4302
- if tool_name == "get_jupiter_earn_positions":
4303
- users = args.get("users")
4304
- if users is not None:
4305
- if not isinstance(users, list) or not all(isinstance(item, str) for item in users):
4306
- raise WalletBackendError("users must be an array of strings.")
4307
- data = await self.backend.get_jupiter_earn_positions(users=users)
4308
- return AgentToolResult(tool=tool_name, ok=True, data=data)
4309
-
4310
- if tool_name == "get_jupiter_earn_earnings":
4311
- user = args.get("user")
4312
- positions = args.get("positions")
4313
- if user is not None and not isinstance(user, str):
4314
- raise WalletBackendError("user must be a string when provided.")
4315
- if not isinstance(positions, list) or not positions:
4316
- raise WalletBackendError("positions must be a non-empty array of strings.")
4317
- if not all(isinstance(item, str) for item in positions):
4318
- raise WalletBackendError("Each position must be a string.")
4319
- data = await self.backend.get_jupiter_earn_earnings(
4320
- user=user,
4321
- positions=positions,
4322
- )
4323
- return AgentToolResult(tool=tool_name, ok=True, data=data)
4324
-
4325
4028
  if tool_name == "get_flash_trade_markets":
4326
4029
  pool_name = args.get("pool_name")
4327
4030
  if pool_name is not None and not isinstance(pool_name, str):
@@ -4637,6 +4340,13 @@ class OpenClawWalletAdapter:
4637
4340
  data = await self.backend.get_kamino_lend_user_rewards(user=user)
4638
4341
  return AgentToolResult(tool=tool_name, ok=True, data=data)
4639
4342
 
4343
+ if tool_name == "get_kamino_open_positions":
4344
+ user = args.get("user")
4345
+ if user is not None and not isinstance(user, str):
4346
+ raise WalletBackendError("user must be a string when provided.")
4347
+ data = await self.backend.get_kamino_open_positions(user=user)
4348
+ return AgentToolResult(tool=tool_name, ok=True, data=data)
4349
+
4640
4350
  if tool_name == "sign_wallet_message":
4641
4351
  user_confirmed = args.get("user_confirmed")
4642
4352
  if user_confirmed is not True:
@@ -5199,13 +4909,6 @@ class OpenClawWalletAdapter:
5199
4909
  ),
5200
4910
  )
5201
4911
 
5202
- if tool_name == "request_devnet_airdrop":
5203
- amount = args.get("amount")
5204
- if not isinstance(amount, (int, float)) or amount <= 0:
5205
- raise WalletBackendError("amount must be a positive number.")
5206
- result = await self.backend.request_testnet_airdrop(float(amount))
5207
- return AgentToolResult(tool=tool_name, ok=True, data=result)
5208
-
5209
4912
  if tool_name == "transfer_spl_token":
5210
4913
  recipient = args.get("recipient")
5211
4914
  mint = args.get("mint")
@@ -5571,211 +5274,6 @@ class OpenClawWalletAdapter:
5571
5274
  ),
5572
5275
  )
5573
5276
 
5574
- if tool_name == "swap_solana_privately":
5575
- input_token = args.get("input_token")
5576
- output_token = args.get("output_token")
5577
- destination_address = args.get("destination_address")
5578
- amount = args.get("amount")
5579
- use_xmr = args.get("use_xmr", False)
5580
- mode = args.get("mode")
5581
- purpose = args.get("purpose")
5582
- user_intent = args.get("user_intent", False)
5583
- approval_token = args.get("approval_token")
5584
-
5585
- if not isinstance(input_token, str) or not input_token.strip():
5586
- raise WalletBackendError("input_token is required.")
5587
- if not isinstance(output_token, str) or not output_token.strip():
5588
- raise WalletBackendError("output_token is required.")
5589
- if not isinstance(destination_address, str) or not destination_address.strip():
5590
- raise WalletBackendError("destination_address is required.")
5591
- if not isinstance(amount, (int, float)) or amount <= 0:
5592
- raise WalletBackendError("amount must be a positive number.")
5593
- if not isinstance(use_xmr, bool):
5594
- raise WalletBackendError("use_xmr must be a boolean when provided.")
5595
- if mode not in {"preview", "prepare", "execute"}:
5596
- raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
5597
- if not isinstance(purpose, str) or not purpose.strip():
5598
- raise WalletBackendError("purpose is required.")
5599
-
5600
- preview_kwargs = {
5601
- "input_token": input_token.strip(),
5602
- "output_token": output_token.strip(),
5603
- "destination_address": destination_address.strip(),
5604
- "amount_ui": float(amount),
5605
- "use_xmr": use_xmr,
5606
- }
5607
-
5608
- if mode == "preview":
5609
- preview = await self.backend.preview_solana_private_swap(**preview_kwargs)
5610
- return AgentToolResult(
5611
- tool=tool_name,
5612
- ok=True,
5613
- data=self._annotate_sensitive_payload(
5614
- preview,
5615
- action_label="Solana private swap",
5616
- mode="preview",
5617
- ),
5618
- )
5619
-
5620
- if mode == "prepare":
5621
- self._require_prepare_intent(user_intent)
5622
- preview = await self.backend.preview_solana_private_swap(**preview_kwargs)
5623
- return AgentToolResult(
5624
- tool=tool_name,
5625
- ok=True,
5626
- data=self._annotate_sensitive_payload(
5627
- self._build_prepare_plan(
5628
- preview_payload=preview,
5629
- action_label="Solana private swap",
5630
- ),
5631
- action_label="Solana private swap",
5632
- mode="prepare",
5633
- ),
5634
- )
5635
-
5636
- approval_payload = inspect_approval_token(
5637
- approval_token,
5638
- tool_name=tool_name,
5639
- network=str(getattr(self.backend, "network", "unknown")),
5640
- require_mainnet_confirmation=self._is_mainnet_for_backend(self.backend),
5641
- )
5642
- approval_summary = approval_payload.get("binding", {}).get("summary")
5643
- if not isinstance(approval_summary, dict):
5644
- raise WalletBackendError(
5645
- "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
5646
- )
5647
- expected_summary = {
5648
- "operation": "Solana private swap",
5649
- "network": str(getattr(self.backend, "network", "unknown")),
5650
- "destination_address": destination_address.strip(),
5651
- "use_xmr": use_xmr,
5652
- }
5653
- for key, expected_value in expected_summary.items():
5654
- if approval_summary.get(key) != expected_value:
5655
- raise WalletBackendError(
5656
- "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
5657
- )
5658
- try:
5659
- approved_amount = float(approval_summary.get("input_amount_ui"))
5660
- except (TypeError, ValueError):
5661
- raise WalletBackendError(
5662
- "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
5663
- )
5664
- if approved_amount != float(amount):
5665
- raise WalletBackendError(
5666
- "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
5667
- )
5668
-
5669
- approval_summary_copy = dict(approval_summary)
5670
- approved_preview = args.get("_approved_preview")
5671
- resume_private_swap_order = args.get("_resume_private_swap_order")
5672
- if resume_private_swap_order is not None and not isinstance(resume_private_swap_order, dict):
5673
- raise WalletBackendError("_resume_private_swap_order must be an object when provided.")
5674
- execute_preview = None
5675
- if isinstance(approval_summary_copy.get("_preview_digest"), str):
5676
- if not isinstance(approved_preview, dict):
5677
- raise WalletBackendError(
5678
- "Approved private swap preview payload is required for execute mode. Generate a new preview and approval before execute."
5679
- )
5680
- if preview_payload_digest(approved_preview) != approval_summary_copy["_preview_digest"]:
5681
- raise WalletBackendError(
5682
- "approved preview payload does not match the approval token. Generate a new preview and approval before execute."
5683
- )
5684
- execute_preview = dict(approved_preview)
5685
-
5686
- self._require_execute_approval(
5687
- approval_token=approval_token,
5688
- tool_name=tool_name,
5689
- summary=approval_summary_copy,
5690
- action_label="Solana private swap",
5691
- )
5692
-
5693
- result = await self.backend.execute_solana_private_swap(
5694
- **preview_kwargs,
5695
- approved_preview=execute_preview,
5696
- existing_order=resume_private_swap_order,
5697
- )
5698
- return AgentToolResult(
5699
- tool=tool_name,
5700
- ok=True,
5701
- data=self._annotate_sensitive_payload(
5702
- result,
5703
- action_label="Solana private swap",
5704
- mode="execute",
5705
- ),
5706
- )
5707
-
5708
- if tool_name == "continue_solana_private_swap":
5709
- approval_token = args.get("approval_token")
5710
- approved_preview = args.get("_approved_preview")
5711
- resume_private_swap_order = args.get("_resume_private_swap_order")
5712
- if not isinstance(approved_preview, dict):
5713
- raise WalletBackendError(
5714
- "Approved private swap preview payload is required. Create the private swap order first."
5715
- )
5716
- if not isinstance(resume_private_swap_order, dict) or not resume_private_swap_order:
5717
- raise WalletBackendError(
5718
- "A pending Houdini private swap order is required. Create the private swap order first."
5719
- )
5720
-
5721
- approval_payload = inspect_approval_token(
5722
- approval_token,
5723
- tool_name="swap_solana_privately",
5724
- network=str(getattr(self.backend, "network", "unknown")),
5725
- require_mainnet_confirmation=self._is_mainnet_for_backend(self.backend),
5726
- )
5727
- approval_summary = approval_payload.get("binding", {}).get("summary")
5728
- if not isinstance(approval_summary, dict):
5729
- raise WalletBackendError(
5730
- "approval_token does not match the requested private swap. Generate a new approval from the preview first."
5731
- )
5732
-
5733
- approval_summary_copy = dict(approval_summary)
5734
- if isinstance(approval_summary_copy.get("_preview_digest"), str):
5735
- if preview_payload_digest(approved_preview) != approval_summary_copy["_preview_digest"]:
5736
- raise WalletBackendError(
5737
- "approved preview payload does not match the approval token. Generate a new preview and approval before continue."
5738
- )
5739
- self._require_execute_approval(
5740
- approval_token=approval_token,
5741
- tool_name="swap_solana_privately",
5742
- summary=approval_summary_copy,
5743
- action_label="Solana private swap",
5744
- )
5745
-
5746
- result = await self.backend.continue_solana_private_swap(
5747
- approved_preview=approved_preview,
5748
- existing_order=resume_private_swap_order,
5749
- )
5750
- return AgentToolResult(
5751
- tool=tool_name,
5752
- ok=True,
5753
- data=self._annotate_sensitive_payload(
5754
- result,
5755
- action_label="Solana private swap funding",
5756
- mode="execute",
5757
- ),
5758
- )
5759
-
5760
- if tool_name == "get_solana_private_swap_status":
5761
- multi_id = args.get("multi_id")
5762
- houdini_id = args.get("houdini_id")
5763
- if multi_id is not None and not isinstance(multi_id, str):
5764
- raise WalletBackendError("multi_id must be a string when provided.")
5765
- if houdini_id is not None and not isinstance(houdini_id, str):
5766
- raise WalletBackendError("houdini_id must be a string when provided.")
5767
- normalized_multi_id = multi_id.strip() if isinstance(multi_id, str) and multi_id.strip() else None
5768
- normalized_houdini_id = (
5769
- houdini_id.strip() if isinstance(houdini_id, str) and houdini_id.strip() else None
5770
- )
5771
- if normalized_multi_id is None and normalized_houdini_id is None:
5772
- raise WalletBackendError("multi_id or houdini_id is required.")
5773
- data = await self.backend.get_solana_private_swap_status(
5774
- multi_id=normalized_multi_id,
5775
- houdini_id=normalized_houdini_id,
5776
- )
5777
- return AgentToolResult(tool=tool_name, ok=True, data=data)
5778
-
5779
5277
  if tool_name == "swap_solana_lifi_cross_chain_tokens":
5780
5278
  input_token = args.get("input_token")
5781
5279
  destination_chain = args.get("destination_chain")
@@ -6115,162 +5613,6 @@ class OpenClawWalletAdapter:
6115
5613
  ),
6116
5614
  )
6117
5615
 
6118
- if tool_name == "jupiter_earn_deposit":
6119
- asset = args.get("asset")
6120
- amount_raw = args.get("amount_raw")
6121
- mode = args.get("mode")
6122
- purpose = args.get("purpose")
6123
- user_intent = args.get("user_intent", False)
6124
- approval_token = args.get("approval_token")
6125
-
6126
- if not isinstance(asset, str) or not asset.strip():
6127
- raise WalletBackendError("asset is required.")
6128
- if not isinstance(amount_raw, str) or not amount_raw.strip():
6129
- raise WalletBackendError("amount_raw is required.")
6130
- if mode not in {"preview", "prepare", "execute"}:
6131
- raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
6132
- if not isinstance(purpose, str) or not purpose.strip():
6133
- raise WalletBackendError("purpose is required.")
6134
-
6135
- if mode == "preview":
6136
- preview = await self.backend.preview_jupiter_earn_deposit(
6137
- asset=asset.strip(),
6138
- amount_raw=amount_raw.strip(),
6139
- )
6140
- return AgentToolResult(
6141
- tool=tool_name,
6142
- ok=True,
6143
- data=self._annotate_sensitive_payload(
6144
- preview,
6145
- action_label="Jupiter Earn deposit",
6146
- mode="preview",
6147
- ),
6148
- )
6149
-
6150
- if mode == "prepare":
6151
- self._require_prepare_intent(user_intent)
6152
- preview = await self.backend.preview_jupiter_earn_deposit(
6153
- asset=asset.strip(),
6154
- amount_raw=amount_raw.strip(),
6155
- )
6156
- return AgentToolResult(
6157
- tool=tool_name,
6158
- ok=True,
6159
- data=self._annotate_sensitive_payload(
6160
- self._build_prepare_plan(
6161
- preview_payload=preview,
6162
- action_label="Jupiter Earn deposit",
6163
- ),
6164
- action_label="Jupiter Earn deposit",
6165
- mode="prepare",
6166
- ),
6167
- )
6168
-
6169
- execute_preview = await self.backend.preview_jupiter_earn_deposit(
6170
- asset=asset.strip(),
6171
- amount_raw=amount_raw.strip(),
6172
- )
6173
- self._require_execute_approval(
6174
- approval_token=approval_token,
6175
- tool_name=tool_name,
6176
- summary=self._build_confirmation_summary(
6177
- action_label="Jupiter Earn deposit",
6178
- payload=execute_preview,
6179
- ),
6180
- action_label="Jupiter Earn deposit",
6181
- )
6182
- result = await self.backend.execute_jupiter_earn_deposit(
6183
- asset=asset.strip(),
6184
- amount_raw=amount_raw.strip(),
6185
- )
6186
- return AgentToolResult(
6187
- tool=tool_name,
6188
- ok=True,
6189
- data=self._annotate_sensitive_payload(
6190
- result,
6191
- action_label="Jupiter Earn deposit",
6192
- mode="execute",
6193
- ),
6194
- )
6195
-
6196
- if tool_name == "jupiter_earn_withdraw":
6197
- asset = args.get("asset")
6198
- amount_raw = args.get("amount_raw")
6199
- mode = args.get("mode")
6200
- purpose = args.get("purpose")
6201
- user_intent = args.get("user_intent", False)
6202
- approval_token = args.get("approval_token")
6203
-
6204
- if not isinstance(asset, str) or not asset.strip():
6205
- raise WalletBackendError("asset is required.")
6206
- if not isinstance(amount_raw, str) or not amount_raw.strip():
6207
- raise WalletBackendError("amount_raw is required.")
6208
- if mode not in {"preview", "prepare", "execute"}:
6209
- raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
6210
- if not isinstance(purpose, str) or not purpose.strip():
6211
- raise WalletBackendError("purpose is required.")
6212
-
6213
- if mode == "preview":
6214
- preview = await self.backend.preview_jupiter_earn_withdraw(
6215
- asset=asset.strip(),
6216
- amount_raw=amount_raw.strip(),
6217
- )
6218
- return AgentToolResult(
6219
- tool=tool_name,
6220
- ok=True,
6221
- data=self._annotate_sensitive_payload(
6222
- preview,
6223
- action_label="Jupiter Earn withdraw",
6224
- mode="preview",
6225
- ),
6226
- )
6227
-
6228
- if mode == "prepare":
6229
- self._require_prepare_intent(user_intent)
6230
- preview = await self.backend.preview_jupiter_earn_withdraw(
6231
- asset=asset.strip(),
6232
- amount_raw=amount_raw.strip(),
6233
- )
6234
- return AgentToolResult(
6235
- tool=tool_name,
6236
- ok=True,
6237
- data=self._annotate_sensitive_payload(
6238
- self._build_prepare_plan(
6239
- preview_payload=preview,
6240
- action_label="Jupiter Earn withdraw",
6241
- ),
6242
- action_label="Jupiter Earn withdraw",
6243
- mode="prepare",
6244
- ),
6245
- )
6246
-
6247
- execute_preview = await self.backend.preview_jupiter_earn_withdraw(
6248
- asset=asset.strip(),
6249
- amount_raw=amount_raw.strip(),
6250
- )
6251
- self._require_execute_approval(
6252
- approval_token=approval_token,
6253
- tool_name=tool_name,
6254
- summary=self._build_confirmation_summary(
6255
- action_label="Jupiter Earn withdraw",
6256
- payload=execute_preview,
6257
- ),
6258
- action_label="Jupiter Earn withdraw",
6259
- )
6260
- result = await self.backend.execute_jupiter_earn_withdraw(
6261
- asset=asset.strip(),
6262
- amount_raw=amount_raw.strip(),
6263
- )
6264
- return AgentToolResult(
6265
- tool=tool_name,
6266
- ok=True,
6267
- data=self._annotate_sensitive_payload(
6268
- result,
6269
- action_label="Jupiter Earn withdraw",
6270
- mode="execute",
6271
- ),
6272
- )
6273
-
6274
5616
  if tool_name == "close_empty_token_accounts":
6275
5617
  limit = args.get("limit", 8)
6276
5618
  mode = args.get("mode")