@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.
- package/.openclaw/extensions/agent-wallet/README.md +5 -7
- package/.openclaw/extensions/agent-wallet/dist/index.js +35 -360
- package/.openclaw/extensions/agent-wallet/index.ts +35 -360
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +2 -45
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +1 -3
- package/CHANGELOG.md +73 -0
- package/README.md +4 -0
- package/agent-wallet/.env.example +0 -12
- package/agent-wallet/README.md +18 -57
- package/agent-wallet/agent_wallet/bootstrap.py +28 -12
- package/agent-wallet/agent_wallet/btc_user_wallets.py +33 -7
- package/agent-wallet/agent_wallet/config.py +110 -29
- package/agent-wallet/agent_wallet/evm_user_wallets.py +4 -14
- package/agent-wallet/agent_wallet/openclaw_adapter.py +29 -687
- package/agent-wallet/agent_wallet/openclaw_cli.py +0 -7
- package/agent-wallet/agent_wallet/openclaw_runtime.py +3 -12
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +18 -42
- package/agent-wallet/agent_wallet/providers/jupiter.py +1 -307
- package/agent-wallet/agent_wallet/providers/kamino.py +21 -4
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +0 -23
- package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +31 -3
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +37 -3
- package/agent-wallet/agent_wallet/providers/x402.py +4 -9
- package/agent-wallet/agent_wallet/transaction_policy.py +0 -262
- package/agent-wallet/agent_wallet/user_wallets.py +4 -3
- package/agent-wallet/agent_wallet/wallet_layer/base.py +3 -103
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +8 -5
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +453 -1177
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +2 -8
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +2 -12
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +1 -1
- package/agent-wallet/examples/openclaw_user_wallet_example.py +1 -1
- package/agent-wallet/openclaw.plugin.json +1 -5
- package/agent-wallet/pyproject.toml +2 -1
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +3 -5
- package/agent-wallet/scripts/bootstrap_openclaw_evm.py +2 -12
- package/agent-wallet/scripts/build_release_bundle.py +1 -0
- package/agent-wallet/scripts/flash-sdk-bridge/bridge.mjs +1 -4
- package/agent-wallet/scripts/install_agent_wallet.py +114 -6
- package/agent-wallet/scripts/install_openclaw_local_config.py +10 -10
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +2 -4
- package/agent-wallet/scripts/manage_openclaw_evm_wallet.py +2 -15
- package/agent-wallet/scripts/reveal_btc_seed.sh +7 -16
- package/agent-wallet/scripts/setup_btc_wallet.sh +7 -16
- package/agent-wallet/scripts/setup_evm_wallet.sh +1 -11
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +4 -1
- package/agent-wallet/skills/wallet-operator/SKILL.md +1 -6
- package/bin/openclaw-agent-wallet.mjs +356 -0
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +20 -0
- package/claude-code/plugins/agent-wallet/.mcp.json +14 -0
- package/claude-code/plugins/agent-wallet/README.md +65 -0
- package/claude-code/plugins/agent-wallet/scripts/run_mcp.sh +39 -0
- package/claude-code/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +38 -0
- package/codex/plugins/agent-wallet/.mcp.json +15 -0
- package/codex/plugins/agent-wallet/README.md +39 -0
- package/codex/plugins/agent-wallet/scripts/run_mcp.sh +21 -0
- package/codex/plugins/agent-wallet/server.py +961 -0
- package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
- package/hermes/plugins/agent_wallet/schemas.py +2 -2
- package/hermes/plugins/agent_wallet/tools.py +18 -4
- package/package.json +6 -1
- package/setup.sh +2 -0
- package/wdk-btc-wallet/src/local_vault.js +45 -68
- package/wdk-btc-wallet/src/server.js +1 -0
- package/wdk-evm-wallet/README.md +4 -3
- package/wdk-evm-wallet/src/config.js +15 -0
- package/wdk-evm-wallet/src/local_vault.js +45 -68
- package/wdk-evm-wallet/src/server.js +1 -0
- package/agent-wallet/agent_wallet/providers/houdini.py +0 -539
|
@@ -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 (
|
|
335
|
-
throw new Error("Solana
|
|
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 (
|
|
351
|
-
throw new Error("Bitcoin
|
|
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
|
-
|
|
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
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
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,
|
|
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 = [
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
"tools": [
|
|
8
8
|
"claim_bags_fees",
|
|
9
9
|
"close_empty_token_accounts",
|
|
10
|
-
"continue_solana_private_swap",
|
|
11
10
|
"flash_trade_close_position",
|
|
12
11
|
"flash_trade_open_position",
|
|
13
12
|
"get_active_wallet_backend",
|
|
@@ -30,41 +29,33 @@
|
|
|
30
29
|
"get_evm_transaction_receipt",
|
|
31
30
|
"get_flash_trade_markets",
|
|
32
31
|
"get_flash_trade_positions",
|
|
33
|
-
"get_jupiter_earn_earnings",
|
|
34
|
-
"get_jupiter_earn_positions",
|
|
35
|
-
"get_jupiter_earn_tokens",
|
|
36
32
|
"get_kamino_lend_market_reserves",
|
|
37
33
|
"get_kamino_lend_markets",
|
|
34
|
+
"get_kamino_open_positions",
|
|
38
35
|
"get_kamino_lend_user_obligations",
|
|
39
36
|
"get_kamino_lend_user_rewards",
|
|
40
37
|
"get_lifi_quote",
|
|
41
38
|
"get_lifi_supported_chains",
|
|
42
39
|
"get_lifi_transfer_status",
|
|
43
|
-
"get_solana_private_swap_status",
|
|
44
40
|
"get_solana_token_prices",
|
|
45
41
|
"get_wallet_address",
|
|
46
42
|
"get_wallet_balance",
|
|
47
43
|
"get_wallet_capabilities",
|
|
48
44
|
"get_wallet_portfolio",
|
|
49
|
-
"jupiter_earn_deposit",
|
|
50
|
-
"jupiter_earn_withdraw",
|
|
51
45
|
"kamino_lend_borrow",
|
|
52
46
|
"kamino_lend_deposit",
|
|
53
47
|
"kamino_lend_repay",
|
|
54
48
|
"kamino_lend_withdraw",
|
|
55
49
|
"launch_bags_token",
|
|
56
|
-
"list_pending_solana_private_swaps",
|
|
57
50
|
"manage_evm_aave_position",
|
|
58
51
|
"manage_evm_lido_position",
|
|
59
52
|
"manage_evm_lido_withdrawal",
|
|
60
|
-
"request_devnet_airdrop",
|
|
61
53
|
"set_evm_network",
|
|
62
54
|
"set_wallet_backend",
|
|
63
55
|
"sign_wallet_message",
|
|
64
56
|
"swap_evm_lifi_cross_chain_tokens",
|
|
65
57
|
"swap_evm_tokens",
|
|
66
58
|
"swap_solana_lifi_cross_chain_tokens",
|
|
67
|
-
"swap_solana_privately",
|
|
68
59
|
"swap_solana_tokens",
|
|
69
60
|
"transfer_btc",
|
|
70
61
|
"transfer_evm_native",
|
|
@@ -92,7 +83,7 @@
|
|
|
92
83
|
},
|
|
93
84
|
"network": {
|
|
94
85
|
"type": "string",
|
|
95
|
-
"description": "Backend network selector. Solana uses mainnet
|
|
86
|
+
"description": "Backend network selector. Solana uses mainnet. BTC uses bitcoin. EVM uses ethereum/base."
|
|
96
87
|
},
|
|
97
88
|
"wdkBtcServiceUrl": {
|
|
98
89
|
"type": "string",
|
|
@@ -238,10 +229,6 @@
|
|
|
238
229
|
"type": "string",
|
|
239
230
|
"description": "Optional Jupiter Portfolio API base URL."
|
|
240
231
|
},
|
|
241
|
-
"jupiterLendBaseUrl": {
|
|
242
|
-
"type": "string",
|
|
243
|
-
"description": "Optional Jupiter Lend API base URL."
|
|
244
|
-
},
|
|
245
232
|
"jupiterApiKey": {
|
|
246
233
|
"type": "string",
|
|
247
234
|
"description": "Optional Jupiter API key.",
|
|
@@ -249,36 +236,6 @@
|
|
|
249
236
|
"sensitive": true
|
|
250
237
|
}
|
|
251
238
|
},
|
|
252
|
-
"houdiniBaseUrl": {
|
|
253
|
-
"type": "string",
|
|
254
|
-
"description": "Optional Houdini Partner API base URL for private Solana payouts."
|
|
255
|
-
},
|
|
256
|
-
"houdiniApiKey": {
|
|
257
|
-
"type": "string",
|
|
258
|
-
"description": "Optional Houdini Partner API key.",
|
|
259
|
-
"uiHints": {
|
|
260
|
-
"sensitive": true
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
"houdiniApiSecret": {
|
|
264
|
-
"type": "string",
|
|
265
|
-
"description": "Optional Houdini Partner API secret.",
|
|
266
|
-
"uiHints": {
|
|
267
|
-
"sensitive": true
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
"houdiniUserIp": {
|
|
271
|
-
"type": "string",
|
|
272
|
-
"description": "Required Houdini compliance header: end-user IP address."
|
|
273
|
-
},
|
|
274
|
-
"houdiniUserAgent": {
|
|
275
|
-
"type": "string",
|
|
276
|
-
"description": "Required Houdini compliance header: end-user agent string."
|
|
277
|
-
},
|
|
278
|
-
"houdiniUserTimezone": {
|
|
279
|
-
"type": "string",
|
|
280
|
-
"description": "Required Houdini compliance header: end-user timezone, for example Europe/Moscow."
|
|
281
|
-
},
|
|
282
239
|
"kaminoBaseUrl": {
|
|
283
240
|
"type": "string",
|
|
284
241
|
"description": "Optional Kamino REST API base URL."
|
|
@@ -7,15 +7,13 @@ Safety rules:
|
|
|
7
7
|
- Prefer read-only tools first.
|
|
8
8
|
- When a wallet tool exists for the task, do not fall back to `exec`, `solana`, `spl-token`, `bitcoin-cli`, `curl`, or any shell-based wallet workflow. If the wallet tool fails, report the tool error and stop.
|
|
9
9
|
- Jupiter Portfolio tools are temporarily disabled. Do not suggest or call them until they are re-enabled.
|
|
10
|
-
- Use Jupiter Earn read tools before Jupiter Earn writes when the user needs lending/yield context.
|
|
11
10
|
- Use Kamino market/reserve reads before Kamino writes when the user needs lending context.
|
|
12
11
|
- Use Aave account reads before Aave writes when the user needs EVM lending context.
|
|
13
|
-
- For transfers, native staking, swaps, Aave writes,
|
|
12
|
+
- For transfers, native staking, swaps, Aave writes, and Kamino writes, use `preview` before `prepare` or `execute`.
|
|
14
13
|
- For Solana Jupiter swaps through `swap_solana_tokens`, prefer `intent_preview` then `intent_execute` after explicit chat confirmation. The user confirms risk limits; the backend refreshes the quote and only executes inside those limits.
|
|
15
14
|
- Solana swap intent defaults to at least 300 bps (3%) slippage, 120 seconds validity, and 3 fresh execution attempts. The backend computes the approved minimum output from the indicative output and slippage, clamps hand-tightened minimums to that floor, then executes through Jupiter Swap API V2 `/order` + `/execute` when available.
|
|
16
15
|
- Metis `/swap` fallback builds use Jupiter dynamic slippage and a bounded `veryHigh` priority fee instead of the old `"auto"` priority mode.
|
|
17
16
|
- Do not use legacy `execute` for Solana Jupiter swaps in OpenClaw. Exact quote-bound approval is too fragile for active markets and will be rejected by the bridge.
|
|
18
|
-
- For `swap_solana_privately`, use `preview` and then `execute` after explicit user approval. Do not use `prepare` for this tool.
|
|
19
17
|
- Use `prepare` only when the user clearly intends to produce an execution plan.
|
|
20
18
|
- Use `execute` only after the user explicitly confirms the shown summary in chat. OpenClaw handles the internal approval token; do not ask for `/approve`, buttons, popups, or a manual token. For Solana swap intents, the token is bound to the approved intent limits instead of one fragile quote.
|
|
21
19
|
- On `mainnet`, require an approval token that includes explicit mainnet confirmation before any execution.
|