@agentlayer.tech/wallet 0.1.92 → 0.1.94

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 (33) hide show
  1. package/.openclaw/extensions/agent-wallet/dist/index.js +41 -0
  2. package/.openclaw/extensions/agent-wallet/index.ts +41 -0
  3. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +4 -1
  4. package/.openclaw/extensions/agent-wallet/package.json +1 -1
  5. package/CHANGELOG.md +35 -0
  6. package/VERSION +1 -1
  7. package/agent-wallet/agent_wallet/__init__.py +1 -1
  8. package/agent-wallet/agent_wallet/autonomous_permissions.py +1 -0
  9. package/agent-wallet/agent_wallet/openclaw_adapter.py +136 -0
  10. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +2 -0
  11. package/agent-wallet/agent_wallet/providers/x402.py +9 -1
  12. package/agent-wallet/agent_wallet/user_wallets.py +2 -0
  13. package/agent-wallet/agent_wallet/wallet_layer/base.py +18 -0
  14. package/agent-wallet/agent_wallet/wallet_layer/solana.py +2 -0
  15. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +97 -0
  16. package/agent-wallet/openclaw.plugin.json +1 -1
  17. package/agent-wallet/pyproject.toml +1 -1
  18. package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
  19. package/claude-code/plugins/agent-wallet/README.md +2 -0
  20. package/claude-code/plugins/agent-wallet/commands/cards.md +129 -0
  21. package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
  22. package/codex/plugins/agent-wallet/README.md +6 -2
  23. package/codex/plugins/agent-wallet/server.py +1 -0
  24. package/codex/plugins/agent-wallet/skills/cards/SKILL.md +119 -0
  25. package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
  26. package/package.json +1 -1
  27. package/wdk-btc-wallet/package.json +1 -1
  28. package/wdk-evm-wallet/.env.example +3 -0
  29. package/wdk-evm-wallet/README.md +6 -0
  30. package/wdk-evm-wallet/package.json +1 -1
  31. package/wdk-evm-wallet/src/config.js +9 -0
  32. package/wdk-evm-wallet/src/server.js +12 -0
  33. package/wdk-evm-wallet/src/wdk_evm_wallet.js +345 -0
@@ -29,6 +29,7 @@ const AUTONOMOUS_DEFI_TOOLS = new Set([
29
29
  "manage_evm_lido_withdrawal",
30
30
  "manage_evm_morpho_market_position",
31
31
  "manage_evm_morpho_vault_position",
32
+ "manage_evm_uniswap_liquidity",
32
33
  ]);
33
34
  const approvalPreviewCache = new Map();
34
35
  const WALLET_TOOL_ONLY_GUIDANCE =
@@ -1977,6 +1978,23 @@ const evmToolDefinitions = [
1977
1978
  additionalProperties: false,
1978
1979
  },
1979
1980
  },
1981
+ {
1982
+ name: "search_uniswap_pairs",
1983
+ description: "Search read-only onchain Uniswap-tradeable pairs by name, ticker, or ERC-20 address. Verify any returned token address independently before quoting or trading.",
1984
+ parameters: {
1985
+ type: "object",
1986
+ properties: {
1987
+ query: { type: "string" },
1988
+ token_address: { type: "string" },
1989
+ chain: { type: "string" },
1990
+ dex_id: { type: "string" },
1991
+ all_chains: { type: "boolean" },
1992
+ limit: { type: "integer" },
1993
+ network: { type: "string", enum: EVM_CORE_NETWORKS },
1994
+ },
1995
+ additionalProperties: false,
1996
+ },
1997
+ },
1980
1998
  {
1981
1999
  name: "swap_evm_uniswap_tokens",
1982
2000
  description: "Preview, prepare, or execute a supported Uniswap path on ethereum, base, or robinhood: CLASSIC, UniswapX orders, or canonical ETH↔WETH wrap/unwrap. ERC-20 paths may use Permit2 EIP-712 or an UniswapX order signature. 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.",
@@ -1997,6 +2015,29 @@ const evmToolDefinitions = [
1997
2015
  additionalProperties: false,
1998
2016
  },
1999
2017
  },
2018
+ {
2019
+ name: "manage_evm_uniswap_liquidity",
2020
+ description: "Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. Supported actions are create, increase, decrease, and claim_fees. The official Liquidity API builds the transaction again immediately before signing, so confirmation is scoped to the LP intent rather than fragile ticks or calldata.",
2021
+ optional: true,
2022
+ parameters: {
2023
+ type: "object",
2024
+ properties: {
2025
+ action: { type: "string", enum: ["create", "increase", "decrease", "claim_fees"] },
2026
+ protocol: { type: "string", enum: ["V3", "V4"] },
2027
+ request: {
2028
+ type: "object",
2029
+ description: "Official Uniswap Liquidity API fields. walletAddress, chainId, protocol, simulateTransaction, and permit/signature fields are controlled by the wallet.",
2030
+ additionalProperties: true,
2031
+ },
2032
+ mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2033
+ purpose: { type: "string" },
2034
+ user_intent: { type: "boolean" },
2035
+ network: { type: "string", enum: EVM_CORE_NETWORKS },
2036
+ },
2037
+ required: ["action", "protocol", "request", "mode", "purpose"],
2038
+ additionalProperties: false,
2039
+ },
2040
+ },
2000
2041
  {
2001
2042
  name: "swap_evm_lifi_cross_chain_tokens",
2002
2043
  description: "Preview, prepare, or execute an EVM-origin cross-chain swap through LI.FI. This currently supports ethereum/base as the source network and ethereum/base/solana 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.",
@@ -29,6 +29,7 @@ const AUTONOMOUS_DEFI_TOOLS = new Set([
29
29
  "manage_evm_lido_withdrawal",
30
30
  "manage_evm_morpho_market_position",
31
31
  "manage_evm_morpho_vault_position",
32
+ "manage_evm_uniswap_liquidity",
32
33
  ]);
33
34
  const approvalPreviewCache = new Map();
34
35
  const WALLET_TOOL_ONLY_GUIDANCE =
@@ -1977,6 +1978,23 @@ const evmToolDefinitions = [
1977
1978
  additionalProperties: false,
1978
1979
  },
1979
1980
  },
1981
+ {
1982
+ name: "search_uniswap_pairs",
1983
+ description: "Search read-only onchain Uniswap-tradeable pairs by name, ticker, or ERC-20 address. Verify any returned token address independently before quoting or trading.",
1984
+ parameters: {
1985
+ type: "object",
1986
+ properties: {
1987
+ query: { type: "string" },
1988
+ token_address: { type: "string" },
1989
+ chain: { type: "string" },
1990
+ dex_id: { type: "string" },
1991
+ all_chains: { type: "boolean" },
1992
+ limit: { type: "integer" },
1993
+ network: { type: "string", enum: EVM_CORE_NETWORKS },
1994
+ },
1995
+ additionalProperties: false,
1996
+ },
1997
+ },
1980
1998
  {
1981
1999
  name: "swap_evm_uniswap_tokens",
1982
2000
  description: "Preview, prepare, or execute a supported Uniswap path on ethereum, base, or robinhood: CLASSIC, UniswapX orders, or canonical ETH↔WETH wrap/unwrap. ERC-20 paths may use Permit2 EIP-712 or an UniswapX order signature. 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.",
@@ -1997,6 +2015,29 @@ const evmToolDefinitions = [
1997
2015
  additionalProperties: false,
1998
2016
  },
1999
2017
  },
2018
+ {
2019
+ name: "manage_evm_uniswap_liquidity",
2020
+ description: "Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. Supported actions are create, increase, decrease, and claim_fees. The official Liquidity API builds the transaction again immediately before signing, so confirmation is scoped to the LP intent rather than fragile ticks or calldata.",
2021
+ optional: true,
2022
+ parameters: {
2023
+ type: "object",
2024
+ properties: {
2025
+ action: { type: "string", enum: ["create", "increase", "decrease", "claim_fees"] },
2026
+ protocol: { type: "string", enum: ["V3", "V4"] },
2027
+ request: {
2028
+ type: "object",
2029
+ description: "Official Uniswap Liquidity API fields. walletAddress, chainId, protocol, simulateTransaction, and permit/signature fields are controlled by the wallet.",
2030
+ additionalProperties: true,
2031
+ },
2032
+ mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2033
+ purpose: { type: "string" },
2034
+ user_intent: { type: "boolean" },
2035
+ network: { type: "string", enum: EVM_CORE_NETWORKS },
2036
+ },
2037
+ required: ["action", "protocol", "request", "mode", "purpose"],
2038
+ additionalProperties: false,
2039
+ },
2040
+ },
2000
2041
  {
2001
2042
  name: "swap_evm_lifi_cross_chain_tokens",
2002
2043
  description: "Preview, prepare, or execute an EVM-origin cross-chain swap through LI.FI. This currently supports ethereum/base as the source network and ethereum/base/solana 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.",
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Official OpenClaw plugin bridge for the agent-wallet backends, including Solana, local BTC, and local EVM.",
5
- "version": "0.1.92",
5
+ "version": "0.1.94",
6
6
  "contracts": {
7
7
  "tools": [
8
8
  "agentlayer_autonomous_approve",
@@ -30,6 +30,7 @@
30
30
  "get_evm_token_balance",
31
31
  "get_evm_token_metadata",
32
32
  "get_evm_transaction_receipt",
33
+ "get_uniswap_swap_quote",
33
34
  "get_flash_trade_markets",
34
35
  "get_flash_trade_positions",
35
36
  "get_kamino_earn_positions",
@@ -61,11 +62,13 @@
61
62
  "manage_evm_morpho_vault_position",
62
63
  "manage_evm_lido_position",
63
64
  "manage_evm_lido_withdrawal",
65
+ "manage_evm_uniswap_liquidity",
64
66
  "search_uniswap_pairs",
65
67
  "set_evm_network",
66
68
  "set_wallet_backend",
67
69
  "sign_wallet_message",
68
70
  "swap_evm_lifi_cross_chain_tokens",
71
+ "swap_evm_uniswap_tokens",
69
72
  "swap_evm_tokens",
70
73
  "swap_solana_lifi_cross_chain_tokens",
71
74
  "swap_solana_tokens",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.92",
3
+ "version": "0.1.94",
4
4
  "description": "OpenClaw plugin bridge for the AgentLayer wallet runtime.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN ../../../LICENSE",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.1.94 - 2026-08-13
6
+
7
+ - **Added Uniswap V3/V4 liquidity provisioning for Ethereum, Base, and
8
+ Robinhood Chain.** The EVM wallet now previews, prepares, and executes
9
+ create, increase, decrease, and fee-claim actions through Uniswap's
10
+ Liquidity API. Final LP calldata is refreshed and simulated immediately
11
+ before signing; executable transactions are accepted only for pinned
12
+ PositionManager deployments and matching wallet/network fields.
13
+ - **Added bounded LP approval handling and intent-safe confirmations.** Token
14
+ approvals are restricted to LP-request assets and approved spenders, while
15
+ confirmations bind the action, network, protocol, pool/position, and assets
16
+ rather than fast-expiring ticks or calldata. Single-sided concentrated
17
+ positions with a zero amount on one ERC-20 side no longer fail approval
18
+ discovery.
19
+ - **Exposed LP actions through the provider gateway, OpenClaw, and Codex.**
20
+ The provider gateway forwards the existing shared Uniswap API key to the
21
+ Liquidity API; OpenClaw's pair-search contract was restored and registered.
22
+
23
+ ## v0.1.93 - 2026-08-10
24
+
25
+ - **Added `/cards` (Claude Code) and `cards` (Codex) for Laso Finance card
26
+ issuance.** Issue a US or international prepaid card, paid via x402 from
27
+ the wallet already connected in the session (Solana or Base/EVM). Both
28
+ files hardcode the `laso.finance` endpoints and never accept a URL
29
+ override from user input, search results, or page content; the flow
30
+ always previews the live payment terms and requires explicit confirmation
31
+ of the total debit (including any fee) before calling `x402_pay_request`.
32
+ - **Fixed a misleading Solana compatibility message in
33
+ `x402_preview_request`.** Preview runs through a read-only worker that
34
+ deliberately skips loading the Solana signer for speed; the compatibility
35
+ reason used to word this as "does not yet expose a supported x402 signer
36
+ path," which reads as unsupported. It now says the signer isn't loaded in
37
+ this read-only preview context by design, and that the real
38
+ `x402_pay_request` call can still succeed.
39
+
5
40
  ## v0.1.92 - 2026-07-29
6
41
 
7
42
  - **EVM daemon restart after updates.** The installer now stops a verified
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.92
1
+ 0.1.94
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep in sync with package.json, pyproject.toml, and the npm installer version.
4
4
  # scripts/check_release_version.mjs enforces this on release.
5
- __version__ = "0.1.92"
5
+ __version__ = "0.1.94"
6
6
 
7
7
  __all__ = [
8
8
  "config",
@@ -31,6 +31,7 @@ DEFI_TOOLS = frozenset(
31
31
  "manage_evm_lido_withdrawal",
32
32
  "manage_evm_morpho_market_position",
33
33
  "manage_evm_morpho_vault_position",
34
+ "manage_evm_uniswap_liquidity",
34
35
  }
35
36
  )
36
37
  DEFI_TOOLS_ISSUER = "autonomous-permission:defi-tools"
@@ -751,6 +751,28 @@ class OpenClawWalletAdapter:
751
751
  "quote_fingerprint": provided_fingerprint,
752
752
  }
753
753
 
754
+ if asset_type == "evm-uniswap-liquidity":
755
+ request = payload.get("request") if isinstance(payload.get("request"), dict) else {}
756
+ existing_pool = request.get("existingPool") if isinstance(request.get("existingPool"), dict) else {}
757
+ return {
758
+ "operation": action_label,
759
+ "network": str(payload.get("network") or getattr(self.backend, "network", "unknown")),
760
+ "from_address": payload.get("from_address"),
761
+ "protocol": payload.get("protocol"),
762
+ "liquidity_action": payload.get("liquidity_action"),
763
+ "liquidity_protocol": payload.get("liquidity_protocol"),
764
+ # Intent binds to the action and caller-provided LP scope, not a
765
+ # per-block transaction hash, adjusted ticks, or calculated amount.
766
+ "token0_address": request.get("token0Address") or existing_pool.get("token0Address"),
767
+ "token1_address": request.get("token1Address") or existing_pool.get("token1Address"),
768
+ "pool_reference": existing_pool.get("poolReference"),
769
+ "position_token_id": request.get("nftTokenId") or request.get("tokenId") or payload.get("position_token_id"),
770
+ "independent_token": request.get("independentToken"),
771
+ "liquidity_percentage_to_decrease": request.get("liquidityPercentageToDecrease"),
772
+ "slippage_tolerance": request.get("slippageTolerance"),
773
+ "position_manager": payload.get("position_manager"),
774
+ }
775
+
754
776
  if asset_type == "evm-morpho-vault":
755
777
  return {
756
778
  "operation": action_label,
@@ -1722,6 +1744,35 @@ class OpenClawWalletAdapter:
1722
1744
  risk_level="low",
1723
1745
  ),
1724
1746
  )
1747
+ tools.insert(
1748
+ 13,
1749
+ AgentToolSpec(
1750
+ name="manage_evm_uniswap_liquidity",
1751
+ description=(
1752
+ "Preview, prepare, or execute a Uniswap V3/V4 liquidity action on ethereum, base, or robinhood. "
1753
+ "Supported actions are create, increase, decrease, and claim_fees. The request is passed to the "
1754
+ "official Uniswap Liquidity API; execute refreshes the transaction immediately before signing."
1755
+ ),
1756
+ input_schema={
1757
+ "type": "object",
1758
+ "properties": {
1759
+ "action": {"type": "string", "enum": ["create", "increase", "decrease", "claim_fees"]},
1760
+ "protocol": {"type": "string", "enum": ["V3", "V4"]},
1761
+ "request": {"type": "object", "description": "Uniswap LP API fields excluding walletAddress, chainId, protocol, and simulateTransaction; those are set from the active wallet.", "additionalProperties": True},
1762
+ "mode": {"type": "string", "enum": ["preview", "prepare", "execute"]},
1763
+ "purpose": {"type": "string"},
1764
+ "user_intent": {"type": "boolean"},
1765
+ "approval_token": {"type": "string"},
1766
+ "network": {"type": "string", "enum": ["ethereum", "base", "robinhood"]},
1767
+ },
1768
+ "required": ["action", "protocol", "request", "mode", "purpose"],
1769
+ "additionalProperties": False,
1770
+ },
1771
+ read_only=False,
1772
+ requires_explicit_user_intent=True,
1773
+ risk_level="high",
1774
+ ),
1775
+ )
1725
1776
  tools.insert(
1726
1777
  14,
1727
1778
  AgentToolSpec(
@@ -5757,6 +5808,91 @@ class OpenClawWalletAdapter:
5757
5808
  ),
5758
5809
  )
5759
5810
 
5811
+ if tool_name == "manage_evm_uniswap_liquidity":
5812
+ action = args.get("action")
5813
+ protocol = args.get("protocol")
5814
+ request = args.get("request")
5815
+ mode = args.get("mode")
5816
+ purpose = args.get("purpose")
5817
+ user_intent = args.get("user_intent", False)
5818
+ approval_token = args.get("approval_token")
5819
+ if action not in {"create", "increase", "decrease", "claim_fees"}:
5820
+ raise WalletBackendError("action must be create, increase, decrease, or claim_fees.")
5821
+ if protocol not in {"V3", "V4"}:
5822
+ raise WalletBackendError("protocol must be V3 or V4.")
5823
+ if not isinstance(request, dict):
5824
+ raise WalletBackendError("request must be an object.")
5825
+ if mode not in {"preview", "prepare", "execute"}:
5826
+ raise WalletBackendError("mode must be 'preview', 'prepare' or 'execute'.")
5827
+ if not isinstance(purpose, str) or not purpose.strip():
5828
+ raise WalletBackendError("purpose is required.")
5829
+ # The caller must not override values that are derived from the
5830
+ # active wallet/network in the WDK layer.
5831
+ forbidden = {"walletAddress", "chainId", "protocol", "simulateTransaction", "signature", "batchPermitData", "v4BatchPermitData", "v3NftPermitData"}
5832
+ overlap = forbidden.intersection(request)
5833
+ if overlap:
5834
+ raise WalletBackendError(f"request must not set wallet-controlled fields: {', '.join(sorted(overlap))}.")
5835
+ preview_kwargs = {"action": action, "protocol": protocol, "request": dict(request)}
5836
+ if mode == "preview":
5837
+ preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
5838
+ return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(preview, action_label="Uniswap liquidity", mode="preview"))
5839
+ if mode == "prepare":
5840
+ self._require_prepare_intent(user_intent)
5841
+ preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
5842
+ return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(self._build_prepare_plan(preview_payload=preview, action_label="Uniswap liquidity"), action_label="Uniswap liquidity", mode="prepare"))
5843
+ if isinstance(approval_token, str) and approval_token.strip():
5844
+ approval_payload = inspect_approval_token(
5845
+ approval_token,
5846
+ tool_name=tool_name,
5847
+ network=str(getattr(active_backend, "network", "unknown")),
5848
+ require_mainnet_confirmation=self._is_mainnet_for_backend(active_backend),
5849
+ )
5850
+ approval_summary = approval_payload.get("binding", {}).get("summary")
5851
+ if not isinstance(approval_summary, dict):
5852
+ raise WalletBackendError("approval_token does not match the requested LP operation. Generate a new approval after prepare.")
5853
+ approval_summary_copy = dict(approval_summary)
5854
+ else:
5855
+ fresh_preview = await active_backend.preview_uniswap_liquidity(**preview_kwargs)
5856
+ approval_summary_copy = self._build_confirmation_summary(action_label="Uniswap liquidity", payload=fresh_preview)
5857
+ expected = {
5858
+ "operation": "Uniswap liquidity",
5859
+ "network": str(getattr(active_backend, "network", "unknown")),
5860
+ "liquidity_action": action,
5861
+ "liquidity_protocol": protocol,
5862
+ }
5863
+ for key, value in expected.items():
5864
+ if approval_summary_copy.get(key) != value:
5865
+ raise WalletBackendError("approval_token does not match the requested LP operation. Generate a new approval after prepare.")
5866
+ # An LP intent deliberately does not bind API-calculated ticks,
5867
+ # price, calldata, or quote amounts: those are regenerated just
5868
+ # before broadcast. It must still be scoped to the selected
5869
+ # assets/pool/position so an approval cannot be reused for a
5870
+ # different liquidity position.
5871
+ requested_scope = self._build_confirmation_summary(
5872
+ action_label="Uniswap liquidity",
5873
+ payload={
5874
+ "asset_type": "evm-uniswap-liquidity",
5875
+ "network": str(getattr(active_backend, "network", "unknown")),
5876
+ "protocol": "uniswap",
5877
+ "liquidity_action": action,
5878
+ "liquidity_protocol": protocol,
5879
+ "request": preview_kwargs["request"],
5880
+ },
5881
+ )
5882
+ for key in ("token0_address", "token1_address", "pool_reference", "position_token_id", "independent_token"):
5883
+ requested_value = requested_scope.get(key)
5884
+ if requested_value is not None and approval_summary_copy.get(key) != requested_value:
5885
+ raise WalletBackendError("approval_token does not match the requested LP assets or position. Generate a new approval after prepare.")
5886
+ self._require_execute_approval(
5887
+ approval_token=approval_token,
5888
+ tool_name=tool_name,
5889
+ summary=approval_summary_copy,
5890
+ action_label="Uniswap liquidity",
5891
+ backend=active_backend,
5892
+ )
5893
+ result = await active_backend.send_uniswap_liquidity(**preview_kwargs)
5894
+ return AgentToolResult(tool=tool_name, ok=True, data=self._annotate_sensitive_payload(result, action_label="Uniswap liquidity", mode="execute"))
5895
+
5760
5896
  if tool_name == "issue_wallet_approval":
5761
5897
  from agent_wallet.approval import issue_approval_token
5762
5898
 
@@ -40,6 +40,8 @@ LONG_RUNNING_POST_PATHS = {
40
40
  "/v1/evm/swap/send",
41
41
  "/v1/evm/uniswap/swap/quote",
42
42
  "/v1/evm/uniswap/swap/send",
43
+ "/v1/evm/uniswap/liquidity/quote",
44
+ "/v1/evm/uniswap/liquidity/send",
43
45
  "/v1/evm/lifi/quote",
44
46
  "/v1/evm/lifi/send",
45
47
  "/v1/evm/transfer/send",
@@ -504,7 +504,15 @@ def _requirement_compatibility(requirement: dict[str, Any], backend: AgentWallet
504
504
  elif chain == "evm" and scheme == "upto" and not _evm_payment_requirement_supported(requirement):
505
505
  reason = "This EVM upto payment is missing a facilitatorAddress in its extra data, so it cannot be signed."
506
506
  elif planned_execution_supported and wallet_network_matches:
507
- reason = "Wallet network matches, but this backend does not yet expose a supported x402 signer path."
507
+ if chain == "solana" and getattr(backend, "read_only", False):
508
+ reason = (
509
+ "Signer not loaded in this read-only preview context by "
510
+ "design (avoids unnecessary key material access on cheap "
511
+ "preview calls) -- the real x402_pay_request call loads "
512
+ "the signer and can still succeed here."
513
+ )
514
+ else:
515
+ reason = "Wallet network matches, but this backend does not yet expose a supported x402 signer path."
508
516
  elif planned_execution_supported:
509
517
  reason = "Planned execution path exists, but the requirement targets a different network than the active wallet."
510
518
  else:
@@ -528,6 +528,7 @@ def create_openclaw_solana_backend(
528
528
  signer=signer,
529
529
  address=resolved_address or None,
530
530
  sign_only=effective_sign_only,
531
+ read_only=read_only,
531
532
  rpc_provider_mode=str(rpc_config["mode"]),
532
533
  rpc_provider=str(rpc_config["provider"]),
533
534
  rpc_transport=str(rpc_config["transport"]),
@@ -554,6 +555,7 @@ def create_openclaw_solana_backend(
554
555
  signer=None,
555
556
  address=wallet_info["address"] or None,
556
557
  sign_only=effective_sign_only,
558
+ read_only=read_only,
557
559
  rpc_provider_mode=str(rpc_config["mode"]),
558
560
  rpc_provider=str(rpc_config["provider"]),
559
561
  rpc_transport=str(rpc_config["transport"]),
@@ -349,6 +349,24 @@ class AgentWalletBackend(ABC):
349
349
  ) -> dict[str, Any]:
350
350
  raise WalletBackendError(f"{self.name} does not support Uniswap swaps.")
351
351
 
352
+ async def preview_uniswap_liquidity(
353
+ self,
354
+ *,
355
+ action: str,
356
+ protocol: str,
357
+ request: dict[str, Any],
358
+ ) -> dict[str, Any]:
359
+ raise WalletBackendError(f"{self.name} does not support Uniswap liquidity previews.")
360
+
361
+ async def send_uniswap_liquidity(
362
+ self,
363
+ *,
364
+ action: str,
365
+ protocol: str,
366
+ request: dict[str, Any],
367
+ ) -> dict[str, Any]:
368
+ raise WalletBackendError(f"{self.name} does not support Uniswap liquidity operations.")
369
+
352
370
  async def preview_evm_native_transfer(
353
371
  self,
354
372
  *,
@@ -261,6 +261,7 @@ class SolanaWalletBackend(AgentWalletBackend):
261
261
  signer: SolanaLocalKeypairSigner | None = None,
262
262
  address: str | None = None,
263
263
  sign_only: bool = True,
264
+ read_only: bool = False,
264
265
  rpc_provider_mode: str | None = None,
265
266
  rpc_provider: str | None = None,
266
267
  rpc_transport: str | None = None,
@@ -281,6 +282,7 @@ class SolanaWalletBackend(AgentWalletBackend):
281
282
  self.commitment = commitment
282
283
  self.network = normalize_solana_network(network)
283
284
  self.signer = signer
285
+ self.read_only = read_only
284
286
  self.address = final_address
285
287
  self.sign_only = sign_only
286
288
  self.rpc_provider_mode = rpc_provider_mode
@@ -2028,6 +2028,103 @@ class WdkEvmLocalWalletBackend(AgentWalletBackend):
2028
2028
  "source": str(data.get("source") or "wdk-evm-wallet"),
2029
2029
  }
2030
2030
 
2031
+ def _normalize_uniswap_liquidity_payload(
2032
+ self,
2033
+ data: dict[str, Any],
2034
+ *,
2035
+ action: str,
2036
+ protocol: str,
2037
+ ) -> dict[str, Any]:
2038
+ transaction = dict(data.get("transaction") or {})
2039
+ result = dict(data.get("result") or {})
2040
+ request = dict(data.get("request") or {})
2041
+ return {
2042
+ "chain": self.chain,
2043
+ "network": self.network,
2044
+ "asset_type": "evm-uniswap-liquidity",
2045
+ "protocol": str(data.get("protocol") or "uniswap"),
2046
+ "liquidity_action": str(data.get("liquidityAction") or action),
2047
+ "liquidity_protocol": str(data.get("liquidityProtocol") or protocol).upper(),
2048
+ "from_address": str(data.get("address") or "").strip() or None,
2049
+ "request": request,
2050
+ "request_id": str(data.get("requestId") or "").strip() or None,
2051
+ "token0": data.get("token0"),
2052
+ "token1": data.get("token1"),
2053
+ "tick_lower": data.get("tickLower"),
2054
+ "tick_upper": data.get("tickUpper"),
2055
+ "adjusted_min_price": data.get("adjustedMinPrice"),
2056
+ "adjusted_max_price": data.get("adjustedMaxPrice"),
2057
+ "position_token_id": str(data.get("positionTokenId") or "").strip() or None,
2058
+ "position_manager": str(data.get("positionManager") or "").strip() or None,
2059
+ "gas_fee": str(data.get("gasFee")) if data.get("gasFee") is not None else None,
2060
+ "approvals": list(data.get("approvals") or []),
2061
+ "approval_results": list(data.get("approvalResults") or []),
2062
+ "simulation": _normalize_swap_simulation(data.get("simulation")),
2063
+ "transaction": {
2064
+ "to": str(transaction.get("to") or "").strip() or None,
2065
+ "value": str(transaction.get("value") or "0"),
2066
+ "data_hash": str(transaction.get("dataHash") or "").strip() or None,
2067
+ },
2068
+ "hash": result.get("hash"),
2069
+ "result": result,
2070
+ "chain_id": int(data.get("chainId") or 0),
2071
+ "broadcasted": bool(result.get("hash")),
2072
+ "confirmed": bool(data.get("confirmed")),
2073
+ "source": str(data.get("source") or "wdk-evm-wallet"),
2074
+ }
2075
+
2076
+ async def preview_uniswap_liquidity(
2077
+ self,
2078
+ *,
2079
+ action: str,
2080
+ protocol: str,
2081
+ request: dict[str, Any],
2082
+ ) -> dict[str, Any]:
2083
+ if not isinstance(request, dict):
2084
+ raise WalletBackendError("Uniswap liquidity request must be an object.")
2085
+ data = await self.client.post(
2086
+ "/v1/evm/uniswap/liquidity/quote",
2087
+ {
2088
+ "walletId": self.wallet_id,
2089
+ "address": await self.get_address(),
2090
+ "accountIndex": self.account_index,
2091
+ "network": self.network,
2092
+ "action": action,
2093
+ "protocol": protocol,
2094
+ "request": request,
2095
+ },
2096
+ )
2097
+ normalized = self._normalize_uniswap_liquidity_payload(data, action=action, protocol=protocol)
2098
+ normalized["from_address"] = await self.get_address()
2099
+ normalized["execution_supported"] = not self.sign_only
2100
+ return normalized
2101
+
2102
+ async def send_uniswap_liquidity(
2103
+ self,
2104
+ *,
2105
+ action: str,
2106
+ protocol: str,
2107
+ request: dict[str, Any],
2108
+ ) -> dict[str, Any]:
2109
+ if self.sign_only:
2110
+ raise WalletBackendError("wdk_evm_local is configured as sign_only.")
2111
+ if not isinstance(request, dict):
2112
+ raise WalletBackendError("Uniswap liquidity request must be an object.")
2113
+ data = await self.client.post(
2114
+ "/v1/evm/uniswap/liquidity/send",
2115
+ {
2116
+ "walletId": self.wallet_id,
2117
+ "accountIndex": self.account_index,
2118
+ "network": self.network,
2119
+ "action": action,
2120
+ "protocol": protocol,
2121
+ "request": request,
2122
+ },
2123
+ )
2124
+ normalized = self._normalize_uniswap_liquidity_payload(data, action=action, protocol=protocol)
2125
+ normalized["from_address"] = await self.get_address()
2126
+ return normalized
2127
+
2031
2128
  async def preview_evm_lifi_cross_chain_swap(
2032
2129
  self,
2033
2130
  *,
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Plugin-friendly wallet backend for OpenClaw agents with safe wallet tools and runtime instructions across Solana, local BTC, and local EVM.",
5
- "version": "0.1.92",
5
+ "version": "0.1.94",
6
6
  "skills": ["skills/wallet-operator"],
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openclaw-agent-wallet"
7
- version = "0.1.92"
7
+ version = "0.1.94"
8
8
  description = "Plugin-friendly wallet backend for OpenClaw agents"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-wallet",
3
3
  "displayName": "Agent Wallet",
4
- "version": "0.1.92",
4
+ "version": "0.1.94",
5
5
  "description": "Claude Code bridge for the existing AgentLayer wallet runtime. Connects to Solana, Bitcoin, and EVM wallets without creating a new one.",
6
6
  "author": {
7
7
  "name": "AgentLayer"
@@ -58,6 +58,8 @@ no-op once the backend is healthy.
58
58
  switch the session's active wallet backend to Base so follow-up wallet
59
59
  requests default to it.
60
60
  - `/wallet-ethereum` — print the Ethereum EVM wallet overview directly in chat.
61
+ - `/cards` -- issue a Laso Finance prepaid card (US or international), paid
62
+ via x402 from the connected wallet.
61
63
  - `/agentlayer-autonomous-approve` — enable high-trust autonomous Base swaps
62
64
  (`swap_evm_tokens` / `swap_evm_uniswap_tokens` on Base only) without
63
65
  per-transaction approvals. In Claude Code this command now asks for an