@agentlayer.tech/wallet 0.1.25 → 0.1.27

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.
@@ -17,7 +17,7 @@ In practice this means the agent works through explicit tools for:
17
17
  - EVM native balance, ERC-20 balance/metadata, fee-rate, receipt, Velora swap quote/execute, Aave V3 account/reserve/position flows, and transfer flows through the local `wdk-evm-wallet` backend
18
18
  - wallet address, balances, and portfolio reads
19
19
  - native SOL and SPL token transfers
20
- - Jupiter swap and price lookup
20
+ - Jupiter swap and price lookup, including Solana swap intent execution that refreshes quotes inside user-approved limits
21
21
  - Jupiter Earn read/deposit/withdraw flows
22
22
  - Kamino lending read/deposit/withdraw/borrow/repay flows
23
23
  - native Solana staking, stake deactivation, and stake withdrawal
@@ -76,7 +76,7 @@ function cachePreviewForApproval(userId, toolName, payload) {
76
76
  const cacheToolName = approvalPreviewToolName(toolName);
77
77
  if (!payload || payload.ok !== true || !payload.data || typeof payload.data !== "object") return;
78
78
  const approvalSource = payload.data;
79
- if (!["preview", "prepare"].includes(String(approvalSource.mode || ""))) return;
79
+ if (!["preview", "prepare", "intent_preview"].includes(String(approvalSource.mode || ""))) return;
80
80
  if (!approvalSource.confirmation_summary || typeof approvalSource.confirmation_summary !== "object") return;
81
81
  pruneApprovalPreviewCache();
82
82
  const digest = previewDigest(approvalSource);
@@ -119,7 +119,21 @@ function cachedPreviewForToken(userId, toolName, token) {
119
119
  return cached.preview && typeof cached.preview === "object" ? cached.preview : null;
120
120
  }
121
121
 
122
- function requiresApprovedPreviewPayload(toolName) {
122
+ function isSolanaSwapIntentPayload(payload) {
123
+ return (
124
+ payload &&
125
+ typeof payload === "object" &&
126
+ (String(payload.asset_type || "") === "solana-swap-intent" ||
127
+ String(payload.mode || "") === "intent_preview")
128
+ );
129
+ }
130
+
131
+ function isSolanaSwapIntentExecute(params) {
132
+ return String(params?.mode || "") === "intent_execute";
133
+ }
134
+
135
+ function requiresApprovedPreviewPayload(toolName, params = null) {
136
+ if (toolName === "swap_solana_tokens" && isSolanaSwapIntentExecute(params)) return false;
123
137
  return PREVIEW_BOUND_SWAP_TOOLS.has(toolName);
124
138
  }
125
139
 
@@ -536,7 +550,7 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
536
550
  if (!summary || typeof summary !== "object") {
537
551
  throw new Error(`No confirmation_summary available for ${toolName}.`);
538
552
  }
539
- const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName)
553
+ const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName) && !isSolanaSwapIntentPayload(previewPayload)
540
554
  ? { ...summary, _preview_digest: previewDigest(previewPayload) }
541
555
  : { ...summary };
542
556
  const extraArgs = [
@@ -560,7 +574,12 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
560
574
  }
561
575
 
562
576
  async function attachApprovalForExecute(api, config, userId, toolName, effectiveParams) {
563
- if (String(effectiveParams.mode || "") !== "execute") return null;
577
+ if (!["execute", "intent_execute"].includes(String(effectiveParams.mode || ""))) return null;
578
+ if (toolName === "swap_solana_tokens" && String(effectiveParams.mode || "") === "execute") {
579
+ throw new Error(
580
+ "Legacy exact-preview execute is disabled for Solana Jupiter swaps in OpenClaw. Use intent_preview, ask for explicit chat confirmation, then call intent_execute. The intent path binds approval to risk limits instead of a fragile Jupiter quote payload."
581
+ );
582
+ }
564
583
 
565
584
  const cached = latestCachedPreview(userId, toolName);
566
585
  if (cached?.preview && cached?.summary) {
@@ -571,14 +590,14 @@ async function attachApprovalForExecute(api, config, userId, toolName, effective
571
590
  toolName,
572
591
  cached.preview
573
592
  );
574
- if (requiresApprovedPreviewPayload(toolName)) {
593
+ if (requiresApprovedPreviewPayload(toolName, effectiveParams)) {
575
594
  effectiveParams._approved_preview = cached.preview;
576
595
  }
577
596
  return cached;
578
597
  }
579
598
 
580
599
  if (
581
- requiresApprovedPreviewPayload(toolName) &&
600
+ requiresApprovedPreviewPayload(toolName, effectiveParams) &&
582
601
  typeof effectiveParams.approval_token === "string" &&
583
602
  effectiveParams.approval_token.trim() &&
584
603
  effectiveParams._approved_preview === undefined
@@ -1312,7 +1331,7 @@ const solanaToolDefinitions = [
1312
1331
  },
1313
1332
  {
1314
1333
  name: "swap_solana_tokens",
1315
- description: `Preview, prepare, or execute a Solana token swap via Jupiter. 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. ${WALLET_TOOL_ONLY_GUIDANCE}`,
1334
+ description: `Preview or execute a Solana token swap via Jupiter. Use intent_preview followed by intent_execute after the user explicitly confirms the intent summary in chat; intent_execute fetches a fresh quote and only executes inside the approved limits. Do not use legacy execute for Solana swaps. The OpenClaw plugin handles internal execution authorization automatically. ${WALLET_TOOL_ONLY_GUIDANCE}`,
1316
1335
  optional: true,
1317
1336
  parameters: {
1318
1337
  type: "object",
@@ -1320,8 +1339,12 @@ const solanaToolDefinitions = [
1320
1339
  input_mint: { type: "string" },
1321
1340
  output_mint: { type: "string" },
1322
1341
  amount: { type: "number" },
1323
- slippage_bps: { type: "integer" },
1324
- mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1342
+ slippage_bps: { type: "integer", description: "Optional slippage tolerance in basis points. Defaults to 300 (3%) for Solana swaps." },
1343
+ minimum_output_amount_raw: { type: "integer", description: "Optional approved minimum output in raw output token units for intent_preview. For intent swaps, overly strict values are clamped to the slippage floor." },
1344
+ max_fee_lamports: { type: "integer" },
1345
+ valid_for_seconds: { type: "integer", description: "Optional intent validity window in seconds. Intent swaps use at least 120 seconds, max 120." },
1346
+ max_attempts: { type: "integer", description: "Optional number of fresh quote/simulate/execute attempts. Intent swaps use at least 3 attempts, max 5." },
1347
+ mode: { type: "string", enum: ["preview", "intent_preview", "intent_execute"] },
1325
1348
  purpose: { type: "string" },
1326
1349
  user_intent: { type: "boolean" },
1327
1350
  },
@@ -1512,6 +1535,7 @@ const solanaToolDefinitions = [
1512
1535
  market: { type: "string" },
1513
1536
  reserve: { type: "string" },
1514
1537
  amount_ui: { type: "string" },
1538
+ obligation_address: { type: "string" },
1515
1539
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1516
1540
  purpose: { type: "string" },
1517
1541
  user_intent: { type: "boolean" },
@@ -1530,6 +1554,7 @@ const solanaToolDefinitions = [
1530
1554
  market: { type: "string" },
1531
1555
  reserve: { type: "string" },
1532
1556
  amount_ui: { type: "string" },
1557
+ obligation_address: { type: "string" },
1533
1558
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1534
1559
  purpose: { type: "string" },
1535
1560
  user_intent: { type: "boolean" },
@@ -1548,6 +1573,7 @@ const solanaToolDefinitions = [
1548
1573
  market: { type: "string" },
1549
1574
  reserve: { type: "string" },
1550
1575
  amount_ui: { type: "string" },
1576
+ obligation_address: { type: "string" },
1551
1577
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1552
1578
  purpose: { type: "string" },
1553
1579
  user_intent: { type: "boolean" },
@@ -76,7 +76,7 @@ function cachePreviewForApproval(userId, toolName, payload) {
76
76
  const cacheToolName = approvalPreviewToolName(toolName);
77
77
  if (!payload || payload.ok !== true || !payload.data || typeof payload.data !== "object") return;
78
78
  const approvalSource = payload.data;
79
- if (!["preview", "prepare"].includes(String(approvalSource.mode || ""))) return;
79
+ if (!["preview", "prepare", "intent_preview"].includes(String(approvalSource.mode || ""))) return;
80
80
  if (!approvalSource.confirmation_summary || typeof approvalSource.confirmation_summary !== "object") return;
81
81
  pruneApprovalPreviewCache();
82
82
  const digest = previewDigest(approvalSource);
@@ -119,7 +119,21 @@ function cachedPreviewForToken(userId, toolName, token) {
119
119
  return cached.preview && typeof cached.preview === "object" ? cached.preview : null;
120
120
  }
121
121
 
122
- function requiresApprovedPreviewPayload(toolName) {
122
+ function isSolanaSwapIntentPayload(payload) {
123
+ return (
124
+ payload &&
125
+ typeof payload === "object" &&
126
+ (String(payload.asset_type || "") === "solana-swap-intent" ||
127
+ String(payload.mode || "") === "intent_preview")
128
+ );
129
+ }
130
+
131
+ function isSolanaSwapIntentExecute(params) {
132
+ return String(params?.mode || "") === "intent_execute";
133
+ }
134
+
135
+ function requiresApprovedPreviewPayload(toolName, params = null) {
136
+ if (toolName === "swap_solana_tokens" && isSolanaSwapIntentExecute(params)) return false;
123
137
  return PREVIEW_BOUND_SWAP_TOOLS.has(toolName);
124
138
  }
125
139
 
@@ -536,7 +550,7 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
536
550
  if (!summary || typeof summary !== "object") {
537
551
  throw new Error(`No confirmation_summary available for ${toolName}.`);
538
552
  }
539
- const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName)
553
+ const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName) && !isSolanaSwapIntentPayload(previewPayload)
540
554
  ? { ...summary, _preview_digest: previewDigest(previewPayload) }
541
555
  : { ...summary };
542
556
  const extraArgs = [
@@ -560,7 +574,12 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
560
574
  }
561
575
 
562
576
  async function attachApprovalForExecute(api, config, userId, toolName, effectiveParams) {
563
- if (String(effectiveParams.mode || "") !== "execute") return null;
577
+ if (!["execute", "intent_execute"].includes(String(effectiveParams.mode || ""))) return null;
578
+ if (toolName === "swap_solana_tokens" && String(effectiveParams.mode || "") === "execute") {
579
+ throw new Error(
580
+ "Legacy exact-preview execute is disabled for Solana Jupiter swaps in OpenClaw. Use intent_preview, ask for explicit chat confirmation, then call intent_execute. The intent path binds approval to risk limits instead of a fragile Jupiter quote payload."
581
+ );
582
+ }
564
583
 
565
584
  const cached = latestCachedPreview(userId, toolName);
566
585
  if (cached?.preview && cached?.summary) {
@@ -571,14 +590,14 @@ async function attachApprovalForExecute(api, config, userId, toolName, effective
571
590
  toolName,
572
591
  cached.preview
573
592
  );
574
- if (requiresApprovedPreviewPayload(toolName)) {
593
+ if (requiresApprovedPreviewPayload(toolName, effectiveParams)) {
575
594
  effectiveParams._approved_preview = cached.preview;
576
595
  }
577
596
  return cached;
578
597
  }
579
598
 
580
599
  if (
581
- requiresApprovedPreviewPayload(toolName) &&
600
+ requiresApprovedPreviewPayload(toolName, effectiveParams) &&
582
601
  typeof effectiveParams.approval_token === "string" &&
583
602
  effectiveParams.approval_token.trim() &&
584
603
  effectiveParams._approved_preview === undefined
@@ -1312,7 +1331,7 @@ const solanaToolDefinitions = [
1312
1331
  },
1313
1332
  {
1314
1333
  name: "swap_solana_tokens",
1315
- description: `Preview, prepare, or execute a Solana token swap via Jupiter. 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. ${WALLET_TOOL_ONLY_GUIDANCE}`,
1334
+ description: `Preview or execute a Solana token swap via Jupiter. Use intent_preview followed by intent_execute after the user explicitly confirms the intent summary in chat; intent_execute fetches a fresh quote and only executes inside the approved limits. Do not use legacy execute for Solana swaps. The OpenClaw plugin handles internal execution authorization automatically. ${WALLET_TOOL_ONLY_GUIDANCE}`,
1316
1335
  optional: true,
1317
1336
  parameters: {
1318
1337
  type: "object",
@@ -1320,8 +1339,12 @@ const solanaToolDefinitions = [
1320
1339
  input_mint: { type: "string" },
1321
1340
  output_mint: { type: "string" },
1322
1341
  amount: { type: "number" },
1323
- slippage_bps: { type: "integer" },
1324
- mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1342
+ slippage_bps: { type: "integer", description: "Optional slippage tolerance in basis points. Defaults to 300 (3%) for Solana swaps." },
1343
+ minimum_output_amount_raw: { type: "integer", description: "Optional approved minimum output in raw output token units for intent_preview. For intent swaps, overly strict values are clamped to the slippage floor." },
1344
+ max_fee_lamports: { type: "integer" },
1345
+ valid_for_seconds: { type: "integer", description: "Optional intent validity window in seconds. Intent swaps use at least 120 seconds, max 120." },
1346
+ max_attempts: { type: "integer", description: "Optional number of fresh quote/simulate/execute attempts. Intent swaps use at least 3 attempts, max 5." },
1347
+ mode: { type: "string", enum: ["preview", "intent_preview", "intent_execute"] },
1325
1348
  purpose: { type: "string" },
1326
1349
  user_intent: { type: "boolean" },
1327
1350
  },
@@ -1512,6 +1535,7 @@ const solanaToolDefinitions = [
1512
1535
  market: { type: "string" },
1513
1536
  reserve: { type: "string" },
1514
1537
  amount_ui: { type: "string" },
1538
+ obligation_address: { type: "string" },
1515
1539
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1516
1540
  purpose: { type: "string" },
1517
1541
  user_intent: { type: "boolean" },
@@ -1530,6 +1554,7 @@ const solanaToolDefinitions = [
1530
1554
  market: { type: "string" },
1531
1555
  reserve: { type: "string" },
1532
1556
  amount_ui: { type: "string" },
1557
+ obligation_address: { type: "string" },
1533
1558
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1534
1559
  purpose: { type: "string" },
1535
1560
  user_intent: { type: "boolean" },
@@ -1548,6 +1573,7 @@ const solanaToolDefinitions = [
1548
1573
  market: { type: "string" },
1549
1574
  reserve: { type: "string" },
1550
1575
  amount_ui: { type: "string" },
1576
+ obligation_address: { type: "string" },
1551
1577
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
1552
1578
  purpose: { type: "string" },
1553
1579
  user_intent: { type: "boolean" },
@@ -222,6 +222,10 @@
222
222
  "type": "string",
223
223
  "description": "Optional Jupiter Swap API base URL."
224
224
  },
225
+ "jupiterSwapV2BaseUrl": {
226
+ "type": "string",
227
+ "description": "Optional Jupiter Swap API V2 base URL."
228
+ },
225
229
  "jupiterUltraBaseUrl": {
226
230
  "type": "string",
227
231
  "description": "Optional Jupiter Ultra API base URL."
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.24",
3
+ "version": "0.1.27",
4
4
  "description": "OpenClaw plugin bridge for the AgentLayer wallet runtime.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN ../../../LICENSE",
@@ -11,9 +11,13 @@ Safety rules:
11
11
  - Use Kamino market/reserve reads before Kamino writes when the user needs lending context.
12
12
  - Use Aave account reads before Aave writes when the user needs EVM lending context.
13
13
  - For transfers, native staking, swaps, Aave writes, Jupiter Earn writes, and Kamino writes, use `preview` before `prepare` or `execute`.
14
+ - 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
+ - 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
+ - Metis `/swap` fallback builds use Jupiter dynamic slippage and a bounded `veryHigh` priority fee instead of the old `"auto"` priority mode.
17
+ - 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.
14
18
  - For `swap_solana_privately`, use `preview` and then `execute` after explicit user approval. Do not use `prepare` for this tool.
15
19
  - Use `prepare` only when the user clearly intends to produce an execution plan.
16
- - Use `execute` only after the host issues an `approval_token` bound to the exact previewed operation.
20
+ - 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.
17
21
  - On `mainnet`, require an approval token that includes explicit mainnet confirmation before any execution.
18
22
  - Before any `mainnet` execute, restate the network, operation type, asset, amount, and destination, validator, or stake account.
19
23
  - If a preview or prepare result includes `confirmation_summary` or `mainnet_warning`, surface that summary before asking for confirmation.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.1.27 - 2026-05-27
6
+
7
+ - Improved Solana swap fallback landing by enabling Jupiter dynamic slippage
8
+ and bounded `veryHigh` priority fees on the Metis `/swap` fallback path.
9
+ - Hardened Kamino transaction execution with local simulation before send,
10
+ Kamino-specific build timeouts, and longer confirmation polling on mainnet.
11
+ - Reused approved Kamino preview payloads during execute so OpenClaw no longer
12
+ needs to rebuild the same write path just to satisfy approval binding.
13
+ - Added Kamino obligation pinning for `withdraw`, `borrow`, and `repay`, so
14
+ preview can require an explicit `obligation_address` and execute verifies the
15
+ built transaction references the selected obligation before signing.
16
+
17
+ ## v0.1.26 - 2026-05-26
18
+
19
+ - Reworked Solana Jupiter swaps to prefer intent approvals, so OpenClaw confirms
20
+ risk limits and executes against a fresh quote instead of binding approval to
21
+ a fragile exact quote payload.
22
+ - Added Jupiter Swap API V2 `/order` + `/execute` routing with managed landing
23
+ support and fallback routing for Solana swaps.
24
+ - Hardened Solana swap intent defaults to 3% slippage, a 120-second execution
25
+ window, three fresh execution attempts, and safer minimum-output handling.
26
+ - Fixed Jupiter V2 execution payload compatibility by sending
27
+ `lastValidBlockHeight` in the string form expected by the API.
28
+ - Disabled legacy exact-preview Solana swap execute in the OpenClaw bridge to
29
+ prevent stale approval-token mismatches on active markets.
30
+
5
31
  ## v0.1.24 - 2026-05-23
6
32
 
7
33
  - Fixed the published npm package CLI metadata so
@@ -88,7 +88,7 @@ Current safe tools:
88
88
  - `transfer_sol`
89
89
  - `stake_sol_native`
90
90
  - `transfer_spl_token`
91
- - `swap_solana_tokens`
91
+ - `swap_solana_tokens` - Solana Jupiter swaps; prefer `intent_preview` -> chat confirmation -> `intent_execute` so execution refreshes the quote inside approved limits.
92
92
  - `swap_solana_privately` - Houdini-backed private Solana payout flow for same-token `SOL->SOL` or `USDC->USDC` transfers to a destination wallet.
93
93
  - `get_solana_private_swap_status`
94
94
  - `get_jupiter_earn_tokens`
@@ -45,6 +45,7 @@ class Settings(BaseSettings):
45
45
  wdk_evm_account_index: int = 0
46
46
 
47
47
  jupiter_api_base_url: str = "https://lite-api.jup.ag/swap/v1"
48
+ jupiter_swap_v2_api_base_url: str = "https://api.jup.ag/swap/v2"
48
49
  jupiter_ultra_api_base_url: str = "https://lite-api.jup.ag/ultra/v1"
49
50
  jupiter_price_api_base_url: str = "https://lite-api.jup.ag/price/v3"
50
51
  jupiter_portfolio_api_base_url: str = "https://api.jup.ag/portfolio/v1"