@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
@@ -18,7 +18,6 @@ In practice this means the agent works through explicit tools for:
18
18
  - wallet address, balances, and portfolio reads
19
19
  - native SOL and SPL token transfers
20
20
  - Jupiter swap and price lookup, including Solana swap intent execution that refreshes quotes inside user-approved limits
21
- - Jupiter Earn read/deposit/withdraw flows
22
21
  - Kamino lending read/deposit/withdraw/borrow/repay flows
23
22
  - native Solana staking, stake deactivation, and stake withdrawal
24
23
 
@@ -79,7 +78,7 @@ If that runtime is not present, set `plugins.entries.agent-wallet.config.package
79
78
 
80
79
  That installs the Python backend, Node dependencies for the local BTC/EVM runtimes, patches the OpenClaw plugin config, and provisions the first encrypted per-user Solana mainnet wallet when no explicit signer is already configured. EVM readiness can still be auto-healed during normal wallet switching when the runtime has sealed local vault credentials.
81
80
 
82
- For self-hosted installs, prefer `SOLANA_RPC_URL` / `SOLANA_RPC_URLS` in local env and treat the plugin `rpcUrl` / `rpcUrls` fields as fallback only. If the local runtime exposes `ALCHEMY_API_KEY` or `HELIUS_API_KEY`, the wallet can derive the Solana RPC URL automatically for `mainnet` or `devnet`. Local env always takes precedence over `openclaw.json`.
81
+ For self-hosted installs, prefer `SOLANA_RPC_URL` / `SOLANA_RPC_URLS` in local env and treat the plugin `rpcUrl` / `rpcUrls` fields as fallback only. If the local runtime exposes `ALCHEMY_API_KEY` or `HELIUS_API_KEY`, the wallet can derive the Solana RPC URL automatically for `mainnet`. Local env always takes precedence over `openclaw.json`.
83
82
 
84
83
  Provide only `AGENT_WALLET_BOOT_KEY` to the runtime. Provision `master_key`, `approval_secret`, and any signer `private_key` into `sealed_keys.json`, not `openclaw.json`.
85
84
 
@@ -103,7 +102,7 @@ Important:
103
102
  - `get_wallet_balance` returns an enriched wallet overview for Solana and EVM: native balance, discovered token balances, per-asset USD values when pricing is available, and `total_value_usd`.
104
103
  - Solana wallet overview uses Solana RPC only for balance and token-account discovery. Token prices come from Jupiter, not RPC, and internal transfer/staking checks continue to use native-only balance reads.
105
104
  - If the user needs to recover the mnemonic later, host-side reveal stays outside the agent tool surface via `agent-wallet/scripts/manage_openclaw_btc_wallet.py reveal-seed`.
106
- - Optional Jupiter overrides are available via `jupiterBaseUrl`, `jupiterUltraBaseUrl`, `jupiterPriceBaseUrl`, `jupiterPortfolioBaseUrl`, `jupiterLendBaseUrl`, and `jupiterApiKey`.
105
+ - Optional Jupiter overrides are available via `jupiterBaseUrl`, `jupiterUltraBaseUrl`, `jupiterPriceBaseUrl`, `jupiterPortfolioBaseUrl`, and `jupiterApiKey`.
107
106
  - Optional Kamino overrides are available via `kaminoBaseUrl` and `kaminoProgramId`.
108
107
  - Jupiter `Portfolio` implementation remains in the backend, but those agent-facing tools are temporarily disabled for now.
109
108
  - Mainnet wallets are pinned by address. If a pinned mainnet wallet file disappears, the runtime refuses to silently create a replacement wallet.
@@ -134,14 +133,13 @@ For staking specifically, the normal agent flow should be:
134
133
 
135
134
  The extension is already network-aware:
136
135
 
137
- - `plugins.entries.agent-wallet.config.network` selects `mainnet`, `devnet`, or `testnet`
138
- - each network uses a separate wallet file for the same `userId`
139
- - switching networks does not merge balances across clusters
136
+ - `plugins.entries.agent-wallet.config.network` selects `mainnet` for Solana, `bitcoin` for BTC, or the supported EVM networks
137
+ - Solana mainnet wallets keep the same per-user file layout
138
+ - switching the configured backend network does not merge balances across chains
140
139
 
141
140
  Recommended local switch helper:
142
141
 
143
142
  ```bash
144
- python agent-wallet/scripts/switch_openclaw_wallet_network.py --network devnet
145
143
  python agent-wallet/scripts/switch_openclaw_wallet_network.py --network mainnet
146
144
  ```
147
145
 
@@ -13,16 +13,12 @@ let selectedSolanaNetwork = null;
13
13
  let selectedEvmNetwork = null;
14
14
  let selectedBtcNetwork = null;
15
15
  const PREVIEW_CACHE_TTL_MS = 15 * 60 * 1000;
16
- const PRIVATE_SWAP_CACHE_TTL_MS = 35 * 60 * 1000;
17
16
  const PREVIEW_BOUND_SWAP_TOOLS = new Set([
18
17
  "swap_solana_tokens",
19
- "swap_solana_privately",
20
18
  "flash_trade_open_position",
21
19
  "flash_trade_close_position",
22
20
  ]);
23
- const PRIVATE_SWAP_APPROVAL_TOOL_NAME = "swap_solana_privately";
24
21
  const approvalPreviewCache = new Map();
25
- const privateSwapOrderCache = new Map();
26
22
  const WALLET_TOOL_ONLY_GUIDANCE =
27
23
  "Use this wallet tool instead of shelling out to solana CLI, spl-token CLI, curl, or exec. If it fails, surface the wallet-tool error and stop rather than falling back to terminal commands.";
28
24
  const OPENCLAW_EXECUTE_APPROVAL_GUIDANCE =
@@ -82,16 +78,10 @@ function cachePreviewForApproval(userId, toolName, payload) {
82
78
  const digest = previewDigest(approvalSource);
83
79
  approvalPreviewCache.set(approvalCacheKey(userId, cacheToolName), {
84
80
  digest,
85
- expiresAt:
86
- cacheToolName === "swap_solana_privately"
87
- ? Date.now() + PRIVATE_SWAP_CACHE_TTL_MS
88
- : Date.now() + PREVIEW_CACHE_TTL_MS,
81
+ expiresAt: Date.now() + PREVIEW_CACHE_TTL_MS,
89
82
  preview: approvalSource,
90
83
  summary: approvalSource.confirmation_summary,
91
84
  });
92
- if (cacheToolName === "swap_solana_privately") {
93
- privateSwapOrderCache.delete(approvalCacheKey(userId, cacheToolName));
94
- }
95
85
  }
96
86
 
97
87
  function latestCachedPreview(userId, toolName) {
@@ -158,93 +148,6 @@ function normalizeApprovalContextError(error) {
158
148
  return wrapped;
159
149
  }
160
150
 
161
- function cachePendingPrivateSwapOrder(userId, toolName, preview, details) {
162
- if (toolName !== "swap_solana_privately") return;
163
- if (!preview || typeof preview !== "object") return;
164
- if (!details || typeof details !== "object") return;
165
- const houdiniId = typeof details.houdini_id === "string" ? details.houdini_id.trim() : "";
166
- const depositAddress =
167
- typeof details.deposit_address === "string" ? details.deposit_address.trim() : "";
168
- if (!houdiniId || !depositAddress) return;
169
- privateSwapOrderCache.set(approvalCacheKey(userId, toolName), {
170
- digest: previewDigest(preview),
171
- expiresAt: Date.now() + PRIVATE_SWAP_CACHE_TTL_MS,
172
- order: {
173
- multi_id: typeof details.multi_id === "string" ? details.multi_id.trim() : null,
174
- houdini_id: houdiniId,
175
- deposit_address: depositAddress,
176
- order: details.order && typeof details.order === "object" ? details.order : {},
177
- },
178
- });
179
- }
180
-
181
- function latestPendingPrivateSwapOrder(userId, toolName, preview) {
182
- if (toolName !== "swap_solana_privately") return null;
183
- const cached = privateSwapOrderCache.get(approvalCacheKey(userId, toolName));
184
- if (!cached || typeof cached !== "object") return null;
185
- if (Number(cached.expiresAt || 0) <= Date.now()) {
186
- privateSwapOrderCache.delete(approvalCacheKey(userId, toolName));
187
- return null;
188
- }
189
- if (!preview || typeof preview !== "object") return null;
190
- if (cached.digest !== previewDigest(preview)) return null;
191
- return cached.order && typeof cached.order === "object" ? cached.order : null;
192
- }
193
-
194
- function clearPendingPrivateSwapOrder(userId, toolName) {
195
- if (toolName !== "swap_solana_privately") return;
196
- privateSwapOrderCache.delete(approvalCacheKey(userId, toolName));
197
- }
198
-
199
- function formatPrivateSwapPendingOrderError(details) {
200
- const houdiniId = typeof details?.houdini_id === "string" ? details.houdini_id.trim() : "";
201
- const multiId = typeof details?.multi_id === "string" ? details.multi_id.trim() : "";
202
- const depositAddress =
203
- typeof details?.deposit_address === "string" ? details.deposit_address.trim() : "";
204
- const orderStatus =
205
- typeof details?.order_status === "string" ? details.order_status.trim() : "";
206
- const parts = [
207
- "Houdini order was created, but the Solana deposit account is not ready yet.",
208
- ];
209
- if (houdiniId) parts.push(`houdini_id=${houdiniId}`);
210
- if (multiId) parts.push(`multi_id=${multiId}`);
211
- if (depositAddress) parts.push(`deposit_address=${depositAddress}`);
212
- if (orderStatus) parts.push(`status=${orderStatus}`);
213
- parts.push("Retry execute for this existing order instead of generating a new preview.");
214
- return parts.join(" ");
215
- }
216
-
217
- function formatPrivateSwapRateLimitError(details) {
218
- const retryAfter =
219
- typeof details?.retry_after === "number"
220
- ? details.retry_after
221
- : typeof details?.retry_after === "string"
222
- ? details.retry_after
223
- : "";
224
- const quoteId = typeof details?.quote_id === "string" ? details.quote_id.trim() : "";
225
- const parts = [
226
- "Houdini exchange create is rate-limited right now.",
227
- ];
228
- if (retryAfter !== "") parts.push(`retry_after=${retryAfter}s`);
229
- if (quoteId) parts.push(`quote_id=${quoteId}`);
230
- parts.push("Do not generate a new preview yet; wait, then retry execute.");
231
- return parts.join(" ");
232
- }
233
-
234
- function listPendingPrivateSwapOrders(userId) {
235
- const key = approvalCacheKey(userId, PRIVATE_SWAP_APPROVAL_TOOL_NAME);
236
- const pending = privateSwapOrderCache.get(key);
237
- if (!pending || typeof pending !== "object" || Number(pending.expiresAt || 0) <= Date.now()) {
238
- privateSwapOrderCache.delete(key);
239
- return [];
240
- }
241
- return [
242
- {
243
- ...(pending.order && typeof pending.order === "object" ? pending.order : {}),
244
- expires_at_ms: Number(pending.expiresAt || 0),
245
- },
246
- ];
247
- }
248
151
 
249
152
  function resolvePluginConfig(api) {
250
153
  const globalConfig = api?.config ?? {};
@@ -308,13 +211,15 @@ function normalizeEvmNetwork(value) {
308
211
  eth: "ethereum",
309
212
  "eth-mainnet": "ethereum",
310
213
  "base-mainnet": "base",
311
- base_sepolia: "base-sepolia",
312
214
  };
313
215
  return aliases[normalized] || normalized;
314
216
  }
315
217
 
316
218
  function normalizeSelectableEvmNetwork(value) {
317
219
  const network = normalizeEvmNetwork(value);
220
+ if (["sepolia", "base-sepolia", "base_sepolia"].includes(network)) {
221
+ throw new Error("EVM testnets are no longer supported. Use ethereum or base.");
222
+ }
318
223
  if (!["ethereum", "base"].includes(network)) {
319
224
  throw new Error("EVM network must be 'ethereum' or 'base'.");
320
225
  }
@@ -331,8 +236,11 @@ function normalizeSolanaNetwork(value) {
331
236
  "mainnet-beta": "mainnet",
332
237
  };
333
238
  const normalized = aliases[network] || network;
334
- if (!["mainnet", "devnet", "testnet"].includes(normalized)) {
335
- throw new Error("Solana network must be mainnet, devnet, or testnet.");
239
+ if (["devnet", "testnet"].includes(normalized)) {
240
+ throw new Error("Solana devnet/testnet are no longer supported. Use mainnet.");
241
+ }
242
+ if (normalized !== "mainnet") {
243
+ throw new Error("Solana network must be mainnet.");
336
244
  }
337
245
  return normalized;
338
246
  }
@@ -347,8 +255,11 @@ function normalizeBtcNetwork(value) {
347
255
  mainnet: "bitcoin",
348
256
  };
349
257
  const normalized = aliases[network] || network;
350
- if (!["bitcoin", "testnet", "regtest"].includes(normalized)) {
351
- throw new Error("Bitcoin network must be bitcoin, testnet, or regtest.");
258
+ if (["testnet", "regtest"].includes(normalized)) {
259
+ throw new Error("Bitcoin testnet/regtest are no longer supported. Use bitcoin.");
260
+ }
261
+ if (normalized !== "bitcoin") {
262
+ throw new Error("Bitcoin network must be bitcoin.");
352
263
  }
353
264
  return normalized;
354
265
  }
@@ -399,7 +310,6 @@ function inferBackendForTool(toolName) {
399
310
  toolName === "transfer_spl_token" ||
400
311
  toolName === "sign_wallet_message" ||
401
312
  toolName === "close_empty_token_accounts" ||
402
- toolName === "request_devnet_airdrop" ||
403
313
  toolName === "get_wallet_portfolio" ||
404
314
  toolName === "get_solana_token_prices"
405
315
  ) {
@@ -562,9 +472,6 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
562
472
  if (previewPayload?.is_mainnet === true) {
563
473
  extraArgs.push("--mainnet-confirmed");
564
474
  }
565
- if (toolName === "swap_solana_privately") {
566
- extraArgs.push("--ttl-seconds", "1800");
567
- }
568
475
  const payload = await callWalletCli(api, "issue-approval", extraArgs, config);
569
476
  const token = String(payload?.approval_token || "").trim();
570
477
  if (!token) {
@@ -726,12 +633,6 @@ function registerTool(api, definition) {
726
633
  });
727
634
  }
728
635
 
729
- if (definition.name === "list_pending_solana_private_swaps") {
730
- return asContent({
731
- orders: listPendingPrivateSwapOrders(resolveUserId(api, resolvePluginConfig(api))),
732
- });
733
- }
734
-
735
636
  const effectiveParams = { ...(params ?? {}) };
736
637
  const activeBackend = activeBackendForTool(api, definition.name);
737
638
  const userId = resolveUserId(api, resolvePluginConfig(api));
@@ -747,43 +648,7 @@ function registerTool(api, definition) {
747
648
  if (activeBackend === "wdk_evm_local" && effectiveParams.network !== undefined) {
748
649
  configOverride.network = normalizeSelectableEvmNetwork(effectiveParams.network);
749
650
  }
750
- if (definition.name !== "continue_solana_private_swap") {
751
- await attachApprovalForExecute(api, configOverride, userId, definition.name, effectiveParams);
752
- }
753
- if (definition.name === "continue_solana_private_swap") {
754
- const cached = latestCachedPreview(userId, PRIVATE_SWAP_APPROVAL_TOOL_NAME);
755
- if (cached?.preview) {
756
- effectiveParams._approved_preview = cached.preview;
757
- }
758
- if (cached?.preview && cached?.summary) {
759
- effectiveParams.approval_token = await issueApprovalToken(
760
- api,
761
- configOverride,
762
- userId,
763
- PRIVATE_SWAP_APPROVAL_TOOL_NAME,
764
- cached.preview
765
- );
766
- } else if (!effectiveParams.approval_token) {
767
- throw new Error(APPROVAL_CONTEXT_MISSING_MESSAGE);
768
- }
769
- if (effectiveParams._resume_private_swap_order === undefined && cached?.preview) {
770
- const pendingOrder = latestPendingPrivateSwapOrder(
771
- userId,
772
- PRIVATE_SWAP_APPROVAL_TOOL_NAME,
773
- cached.preview
774
- );
775
- if (pendingOrder) {
776
- if (
777
- effectiveParams.houdini_id &&
778
- pendingOrder.houdini_id &&
779
- String(effectiveParams.houdini_id).trim() !== String(pendingOrder.houdini_id).trim()
780
- ) {
781
- throw new Error("The requested houdini_id does not match the cached pending private swap order.");
782
- }
783
- effectiveParams._resume_private_swap_order = pendingOrder;
784
- }
785
- }
786
- }
651
+ await attachApprovalForExecute(api, configOverride, userId, definition.name, effectiveParams);
787
652
  const executeWalletTool = async () =>
788
653
  callWalletCli(api, "invoke", [
789
654
  "--tool",
@@ -793,75 +658,10 @@ function registerTool(api, definition) {
793
658
  ], configOverride);
794
659
 
795
660
  let payload;
796
- if (definition.name === "swap_solana_privately" && String(effectiveParams.mode || "") === "execute") {
797
- const approvedPreview =
798
- effectiveParams._approved_preview && typeof effectiveParams._approved_preview === "object"
799
- ? effectiveParams._approved_preview
800
- : null;
801
- const pendingOrder = approvedPreview
802
- ? latestPendingPrivateSwapOrder(userId, definition.name, approvedPreview)
803
- : null;
804
- if (pendingOrder && effectiveParams._resume_private_swap_order === undefined) {
805
- effectiveParams._resume_private_swap_order = pendingOrder;
806
- }
807
-
808
- let remainingRetries = 3;
809
- while (true) {
810
- try {
811
- payload = await executeWalletTool();
812
- const executionState = payload?.data?.execution_state;
813
- if (executionState === "awaiting_deposit_funding" && approvedPreview) {
814
- cachePendingPrivateSwapOrder(userId, definition.name, approvedPreview, payload.data);
815
- } else {
816
- clearPendingPrivateSwapOrder(userId, definition.name);
817
- }
818
- break;
819
- } catch (error) {
820
- const errorCode = typeof error?.code === "string" ? error.code : "";
821
- const errorDetails =
822
- error?.details && typeof error.details === "object" ? error.details : null;
823
- if (
824
- (errorCode === "houdini_deposit_not_ready" ||
825
- errorCode === "houdini_order_initializing_timeout") &&
826
- approvedPreview &&
827
- errorDetails &&
828
- remainingRetries > 0
829
- ) {
830
- cachePendingPrivateSwapOrder(userId, definition.name, approvedPreview, errorDetails);
831
- effectiveParams._resume_private_swap_order =
832
- latestPendingPrivateSwapOrder(userId, definition.name, approvedPreview) || undefined;
833
- remainingRetries -= 1;
834
- continue;
835
- }
836
- if (
837
- (errorCode === "houdini_deposit_not_ready" ||
838
- errorCode === "houdini_order_initializing_timeout") &&
839
- errorDetails
840
- ) {
841
- cachePendingPrivateSwapOrder(userId, definition.name, approvedPreview, errorDetails);
842
- throw new Error(formatPrivateSwapPendingOrderError(errorDetails));
843
- }
844
- if (errorCode === "houdini_exchange_rate_limited" && errorDetails) {
845
- throw new Error(formatPrivateSwapRateLimitError(errorDetails));
846
- }
847
- throw normalizeApprovalContextError(error);
848
- }
849
- }
850
- } else if (definition.name === "continue_solana_private_swap") {
851
- try {
852
- payload = await executeWalletTool();
853
- } catch (error) {
854
- throw normalizeApprovalContextError(error);
855
- }
856
- if (payload?.data?.execution_state === "funding_submitted") {
857
- clearPendingPrivateSwapOrder(userId, PRIVATE_SWAP_APPROVAL_TOOL_NAME);
858
- }
859
- } else {
860
- try {
861
- payload = await executeWalletTool();
862
- } catch (error) {
863
- throw normalizeApprovalContextError(error);
864
- }
661
+ try {
662
+ payload = await executeWalletTool();
663
+ } catch (error) {
664
+ throw normalizeApprovalContextError(error);
865
665
  }
866
666
  cachePreviewForApproval(userId, definition.name, payload);
867
667
  if (payload?.ok === false) {
@@ -991,7 +791,7 @@ const walletSessionToolDefinitions = [
991
791
  },
992
792
  network: {
993
793
  type: "string",
994
- description: "Optional network for the selected wallet. Examples: mainnet, devnet, ethereum, base, bitcoin, testnet.",
794
+ description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, bitcoin.",
995
795
  },
996
796
  },
997
797
  required: ["backend"],
@@ -1001,12 +801,6 @@ const walletSessionToolDefinitions = [
1001
801
  ];
1002
802
 
1003
803
  const solanaToolDefinitions = [
1004
- {
1005
- name: "list_pending_solana_private_swaps",
1006
- description:
1007
- "List cached pending Houdini private Solana orders from this OpenClaw session, including houdini_id, multi_id, deposit_address, and the last known order payload.",
1008
- parameters: { type: "object", properties: {}, additionalProperties: false },
1009
- },
1010
804
  {
1011
805
  name: "get_wallet_capabilities",
1012
806
  description: "Describe the connected wallet backend, chain, and safety limits.",
@@ -1144,46 +938,6 @@ const solanaToolDefinitions = [
1144
938
  additionalProperties: false,
1145
939
  },
1146
940
  },
1147
- {
1148
- name: "get_jupiter_earn_tokens",
1149
- description: "List Jupiter Earn vault tokens currently supported on Solana mainnet.",
1150
- parameters: { type: "object", properties: {}, additionalProperties: false },
1151
- },
1152
- {
1153
- name: "get_jupiter_earn_positions",
1154
- description: "Get Jupiter Earn positions for one or more Solana wallet addresses on mainnet.",
1155
- parameters: {
1156
- type: "object",
1157
- properties: {
1158
- users: {
1159
- type: "array",
1160
- items: { type: "string" },
1161
- description: "Optional list of Solana wallet addresses. If omitted, use the configured wallet address.",
1162
- },
1163
- },
1164
- additionalProperties: false,
1165
- },
1166
- },
1167
- {
1168
- name: "get_jupiter_earn_earnings",
1169
- description: "Get Jupiter Earn earnings for a wallet and one or more position addresses on mainnet.",
1170
- parameters: {
1171
- type: "object",
1172
- properties: {
1173
- user: {
1174
- type: "string",
1175
- description: "Optional Solana wallet address override.",
1176
- },
1177
- positions: {
1178
- type: "array",
1179
- items: { type: "string" },
1180
- description: "List of Jupiter Earn position addresses.",
1181
- },
1182
- },
1183
- required: ["positions"],
1184
- additionalProperties: false,
1185
- },
1186
- },
1187
941
  {
1188
942
  name: "get_flash_trade_markets",
1189
943
  description: "List Flash Trade perpetual markets currently available on Solana mainnet.",
@@ -1269,6 +1023,21 @@ const solanaToolDefinitions = [
1269
1023
  additionalProperties: false,
1270
1024
  },
1271
1025
  },
1026
+ {
1027
+ name: "get_kamino_open_positions",
1028
+ description:
1029
+ "Get all open Kamino lending positions for a Solana wallet on mainnet, aggregated across markets with loan details, reserve APYs, and rewards.",
1030
+ parameters: {
1031
+ type: "object",
1032
+ properties: {
1033
+ user: {
1034
+ type: "string",
1035
+ description: "Optional Solana wallet address override.",
1036
+ },
1037
+ },
1038
+ additionalProperties: false,
1039
+ },
1040
+ },
1272
1041
  {
1273
1042
  name: "sign_wallet_message",
1274
1043
  description: "Sign an arbitrary message with the connected wallet after explicit user confirmation in chat.",
@@ -1343,53 +1112,6 @@ const solanaToolDefinitions = [
1343
1112
  additionalProperties: false,
1344
1113
  },
1345
1114
  },
1346
- {
1347
- name: "swap_solana_privately",
1348
- description: `Preview or create a Solana private payout through Houdini's anonymous routing. The initial implementation supports same-token private payouts only, such as SOL->SOL or USDC->USDC. Use preview first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically. The first execute creates the Houdini order and returns its deposit address; use continue_solana_private_swap to submit the funding transfer. ${WALLET_TOOL_ONLY_GUIDANCE}`,
1349
- optional: true,
1350
- parameters: {
1351
- type: "object",
1352
- properties: {
1353
- input_token: { type: "string" },
1354
- output_token: { type: "string" },
1355
- destination_address: { type: "string" },
1356
- amount: { type: "number" },
1357
- use_xmr: { type: "boolean" },
1358
- mode: { type: "string", enum: ["preview", "execute"] },
1359
- purpose: { type: "string" },
1360
- user_intent: { type: "boolean" },
1361
- },
1362
- required: ["input_token", "output_token", "destination_address", "amount", "mode", "purpose"],
1363
- additionalProperties: false,
1364
- },
1365
- },
1366
- {
1367
- name: "continue_solana_private_swap",
1368
- description:
1369
- "Continue a previously created Houdini private Solana payout and submit the funding transfer to the cached deposit address. Use this after swap_solana_privately execute has returned a pending order; the OpenClaw plugin reuses the cached confirmation context automatically.",
1370
- optional: true,
1371
- parameters: {
1372
- type: "object",
1373
- properties: {
1374
- houdini_id: { type: "string" },
1375
- },
1376
- additionalProperties: false,
1377
- },
1378
- },
1379
- {
1380
- name: "get_solana_private_swap_status",
1381
- description: "Check Houdini status for a Solana private payout created by swap_solana_privately. Prefer houdini_id from the execute result; multi_id is only needed for legacy multi-order flows.",
1382
- optional: true,
1383
- parameters: {
1384
- type: "object",
1385
- properties: {
1386
- multi_id: { type: "string" },
1387
- houdini_id: { type: "string" },
1388
- },
1389
- anyOf: [{ required: ["multi_id"] }, { required: ["houdini_id"] }],
1390
- additionalProperties: false,
1391
- },
1392
- },
1393
1115
  {
1394
1116
  name: "swap_solana_lifi_cross_chain_tokens",
1395
1117
  description: "Preview, prepare, or execute a Solana-origin cross-chain swap through LI.FI. This currently supports Solana as the source chain and ethereum/base as the destination chain. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
@@ -1482,40 +1204,6 @@ const solanaToolDefinitions = [
1482
1204
  additionalProperties: false,
1483
1205
  },
1484
1206
  },
1485
- {
1486
- name: "jupiter_earn_deposit",
1487
- description: "Preview, prepare, or execute a Jupiter Earn deposit using a raw base-unit amount. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
1488
- optional: true,
1489
- parameters: {
1490
- type: "object",
1491
- properties: {
1492
- asset: { type: "string" },
1493
- amount_raw: { type: "string" },
1494
- mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1495
- purpose: { type: "string" },
1496
- user_intent: { type: "boolean" },
1497
- },
1498
- required: ["asset", "amount_raw", "mode", "purpose"],
1499
- additionalProperties: false,
1500
- },
1501
- },
1502
- {
1503
- name: "jupiter_earn_withdraw",
1504
- description: "Preview, prepare, or execute a Jupiter Earn withdraw using a raw base-unit amount. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
1505
- optional: true,
1506
- parameters: {
1507
- type: "object",
1508
- properties: {
1509
- asset: { type: "string" },
1510
- amount_raw: { type: "string" },
1511
- mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1512
- purpose: { type: "string" },
1513
- user_intent: { type: "boolean" },
1514
- },
1515
- required: ["asset", "amount_raw", "mode", "purpose"],
1516
- additionalProperties: false,
1517
- },
1518
- },
1519
1207
  {
1520
1208
  name: "kamino_lend_deposit",
1521
1209
  description: "Preview, prepare, or execute a Kamino lending deposit using a decimal token amount. Preview or prepare first. After the user explicitly confirms the shown summary in chat, call execute; the OpenClaw plugin handles the internal execution authorization automatically.",
@@ -1683,19 +1371,6 @@ const solanaToolDefinitions = [
1683
1371
  additionalProperties: false,
1684
1372
  },
1685
1373
  },
1686
- {
1687
- name: "request_devnet_airdrop",
1688
- description: "Request devnet or testnet SOL from the faucet.",
1689
- optional: true,
1690
- parameters: {
1691
- type: "object",
1692
- properties: {
1693
- amount: { type: "number" },
1694
- },
1695
- required: ["amount"],
1696
- additionalProperties: false,
1697
- },
1698
- },
1699
1374
  ];
1700
1375
 
1701
1376
  const btcToolDefinitions = [