@agentlayer.tech/wallet 0.1.17 → 0.1.19

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 (34) hide show
  1. package/.openclaw/AGENTS.md +0 -7
  2. package/.openclaw/extensions/agent-wallet/README.md +3 -2
  3. package/.openclaw/extensions/agent-wallet/dist/index.js +105 -7
  4. package/.openclaw/extensions/agent-wallet/index.ts +105 -7
  5. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +5 -1
  6. package/.openclaw/extensions/agent-wallet/package.json +1 -1
  7. package/CHANGELOG.md +24 -0
  8. package/README.md +1 -3
  9. package/RELEASING.md +5 -15
  10. package/agent-wallet/README.md +7 -0
  11. package/agent-wallet/agent_wallet/config.py +11 -0
  12. package/agent-wallet/agent_wallet/evm_user_wallets.py +310 -2
  13. package/agent-wallet/agent_wallet/openclaw_adapter.py +303 -1
  14. package/agent-wallet/agent_wallet/openclaw_runtime.py +10 -41
  15. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +52 -0
  16. package/agent-wallet/agent_wallet/providers/x402.py +1323 -0
  17. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +30 -0
  18. package/agent-wallet/pyproject.toml +2 -1
  19. package/agent-wallet/scripts/build_release_bundle.py +1 -0
  20. package/agent-wallet/scripts/install_agent_wallet.py +3 -0
  21. package/agent-wallet/scripts/install_openclaw_local_config.py +25 -49
  22. package/agent-wallet/scripts/install_openclaw_sealed_keys.py +9 -1
  23. package/package.json +1 -2
  24. package/wdk-evm-wallet/src/server.js +6 -0
  25. package/wdk-evm-wallet/src/wdk_evm_wallet.js +108 -0
  26. package/.openclaw/extensions/pay-bridge/README.md +0 -38
  27. package/.openclaw/extensions/pay-bridge/core.mjs +0 -287
  28. package/.openclaw/extensions/pay-bridge/dist/core.mjs +0 -287
  29. package/.openclaw/extensions/pay-bridge/dist/index.js +0 -196
  30. package/.openclaw/extensions/pay-bridge/index.ts +0 -196
  31. package/.openclaw/extensions/pay-bridge/openclaw.plugin.json +0 -34
  32. package/.openclaw/extensions/pay-bridge/package.json +0 -49
  33. package/.openclaw/extensions/pay-bridge/skills/pay-operator/SKILL.md +0 -20
  34. package/.openclaw/extensions/pay-bridge/smoke_pay_bridge.mjs +0 -38
@@ -7,22 +7,16 @@ These instructions apply to the entire `.openclaw/` tree.
7
7
  This tree contains local OpenClaw host-side workspace assets. In the current repo, its main responsibilities are:
8
8
 
9
9
  - the `agent-wallet` extension that bridges OpenClaw to the authoritative Python `agent-wallet` backend
10
- - the `pay-bridge` extension that bridges OpenClaw to the local `pay` CLI for paid API discovery and execution
11
10
 
12
11
  ## Current structure
13
12
  - `.openclaw/extensions/agent-wallet/index.ts` — TypeScript extension entrypoint registered by OpenClaw.
14
13
  - `.openclaw/extensions/agent-wallet/openclaw.plugin.json` — plugin manifest and config schema.
15
14
  - `.openclaw/extensions/agent-wallet/package.json` — extension package metadata.
16
15
  - `.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md` — user-facing operational wallet safety guidance.
17
- - `.openclaw/extensions/pay-bridge/index.ts` — TypeScript entrypoint for the local `pay` CLI bridge.
18
- - `.openclaw/extensions/pay-bridge/openclaw.plugin.json` — plugin manifest and config schema for pay tools.
19
- - `.openclaw/extensions/pay-bridge/core.mjs` — local `pay` command execution and output shaping.
20
- - `.openclaw/extensions/pay-bridge/skills/pay-operator/SKILL.md` — user-facing operational guidance for paid API usage.
21
16
 
22
17
  ## Design intent
23
18
  - Keep the TypeScript extension thin and host-oriented.
24
19
  - Let Python own wallet logic, policy, approvals, signing rules, and Solana implementation details.
25
- - Let `pay` remain the source of truth for paid API wallet/account behavior.
26
20
  - Let the extension focus on:
27
21
  - resolving config
28
22
  - locating the Python package
@@ -35,7 +29,6 @@ This tree contains local OpenClaw host-side workspace assets. In the current rep
35
29
 
36
30
  ### Keep bridge logic thin
37
31
  - Do not duplicate business logic from Python unless OpenClaw requires it at registration time.
38
- - Do not duplicate payment protocol logic from `pay`; prefer invoking the local CLI and shaping its output.
39
32
  - Do not reimplement approval validation, transaction policy, wallet derivation, or Solana-specific rules in TypeScript.
40
33
  - Prefer forwarding config into the CLI bridge and letting Python decide runtime behavior.
41
34
  - Treat this layer as a transport and schema bridge, not an execution authority.
@@ -77,7 +77,7 @@ The ClawHub plugin package only installs the native OpenClaw plugin. It expects
77
77
 
78
78
  If that runtime is not present, set `plugins.entries.agent-wallet.config.packageRoot` explicitly.
79
79
 
80
- That installs the Python backend, Node dependencies for the local BTC/EVM runtimes, and patches the OpenClaw plugin config. Wallet creation, unlock, and local service start stay as separate host-side steps.
80
+ That installs the Python backend, Node dependencies for the local BTC/EVM runtimes, and patches the OpenClaw plugin config. Solana stays ready immediately; EVM readiness can now be auto-healed during normal wallet switching when the runtime has sealed local vault credentials.
81
81
 
82
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`.
83
83
 
@@ -88,12 +88,13 @@ Important:
88
88
  - For a local official OpenClaw install, `userId` should represent the wallet owner for that agent install.
89
89
  - The public OpenClaw plugin docs do not document a per-request end-user identifier in `registerTool(...).execute(...)`, so dynamic multi-user wallet selection is intentionally kept in the Python/runtime layer, not inside the TypeScript plugin itself.
90
90
  - Helper scripts in `agent-wallet/scripts/` are generic patch/finalize utilities and no longer assume a specific local username, path, or temporary master key.
91
- - The OpenClaw plugin API in this repo exposes tool registration, not host password prompts, so BTC and EVM wallet create/unlock remain host-shell or CLI flows outside the agent tool surface.
91
+ - The OpenClaw plugin API in this repo exposes tool registration, not host password prompts. EVM wallet create/unlock still is not a public agent tool, but the runtime can now auto-create or auto-unlock the local EVM wallet during `set_wallet_backend` or EVM tool calls when `sealed_keys.json` contains the local EVM vault password.
92
92
  - For a one-command local BTC onboarding path, use `agent-wallet/scripts/bootstrap_openclaw_btc.py`, which both sets up the BTC wallet binding and patches local OpenClaw config for `backend=wdk_btc_local`.
93
93
  - The BTC flow now only supports local service URLs (`127.0.0.1` / `localhost` / `::1`).
94
94
  - The local BTC service is protected with a bearer token loaded from `~/.openclaw/wdk-btc-wallet/local-auth-token`, not from plugin config JSON.
95
95
  - When the BTC service URL is local, that bootstrap script can also auto-start `wdk-btc-wallet` before patching OpenClaw config.
96
96
  - The EVM flow also only supports local service URLs (`127.0.0.1` / `localhost` / `::1`) and uses a bearer token loaded from `~/.openclaw/wdk-evm-wallet/local-auth-token`.
97
+ - The installer now provisions a sealed local EVM vault password under `sealed_keys.json` by default, and host-side EVM setup helpers refresh that sealed value whenever the operator enters a new password.
97
98
  - The EVM tool surface is intentionally narrow: Velora swap quote/execute, Aave V3 account/reserve/position flows, native transfers, ERC-20 transfers, fee quotes, and receipt lookup only. No arbitrary calldata, standalone approvals, or generic contract execution are exposed to the agent.
98
99
  - Velora swap and Aave V3 support are currently limited to `ethereum` and `base`. Test carefully because the upstream WDK protocol packages are still beta.
99
100
  - Agents can call `set_wallet_backend` to switch the active wallet for the current OpenClaw plugin session between Solana, EVM, and Bitcoin. This does not edit `openclaw.json`; plugin config remains the startup default.
@@ -25,6 +25,9 @@ const approvalPreviewCache = new Map();
25
25
  const privateSwapOrderCache = new Map();
26
26
  const WALLET_TOOL_ONLY_GUIDANCE =
27
27
  "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
+ const APPROVAL_PREVIEW_TOOL_ALIASES = new Map([
29
+ ["x402_pay_request", "x402_preview_request"],
30
+ ]);
28
31
 
29
32
  function canonicalJsonText(payload) {
30
33
  const normalize = (value) => {
@@ -51,6 +54,11 @@ function approvalCacheKey(userId, toolName) {
51
54
  return `${userId}::${toolName}`;
52
55
  }
53
56
 
57
+ function approvalPreviewToolName(toolName) {
58
+ const normalized = typeof toolName === "string" ? toolName.trim() : "";
59
+ return APPROVAL_PREVIEW_TOOL_ALIASES.get(normalized) || normalized;
60
+ }
61
+
54
62
  function pruneApprovalPreviewCache() {
55
63
  const now = Date.now();
56
64
  for (const [key, value] of approvalPreviewCache.entries()) {
@@ -61,29 +69,30 @@ function pruneApprovalPreviewCache() {
61
69
  }
62
70
 
63
71
  function cachePreviewForApproval(userId, toolName, payload) {
72
+ const cacheToolName = approvalPreviewToolName(toolName);
64
73
  if (!payload || payload.ok !== true || !payload.data || typeof payload.data !== "object") return;
65
74
  const preview = payload.data;
66
75
  if (preview.mode !== "preview") return;
67
76
  if (!preview.confirmation_summary || typeof preview.confirmation_summary !== "object") return;
68
77
  pruneApprovalPreviewCache();
69
78
  const digest = previewDigest(preview);
70
- approvalPreviewCache.set(approvalCacheKey(userId, toolName), {
79
+ approvalPreviewCache.set(approvalCacheKey(userId, cacheToolName), {
71
80
  digest,
72
81
  expiresAt:
73
- toolName === "swap_solana_privately"
82
+ cacheToolName === "swap_solana_privately"
74
83
  ? Date.now() + PRIVATE_SWAP_CACHE_TTL_MS
75
84
  : Date.now() + PREVIEW_CACHE_TTL_MS,
76
85
  preview,
77
86
  summary: preview.confirmation_summary,
78
87
  });
79
- if (toolName === "swap_solana_privately") {
80
- privateSwapOrderCache.delete(approvalCacheKey(userId, toolName));
88
+ if (cacheToolName === "swap_solana_privately") {
89
+ privateSwapOrderCache.delete(approvalCacheKey(userId, cacheToolName));
81
90
  }
82
91
  }
83
92
 
84
93
  function latestCachedPreview(userId, toolName) {
85
94
  pruneApprovalPreviewCache();
86
- return approvalPreviewCache.get(approvalCacheKey(userId, toolName)) || null;
95
+ return approvalPreviewCache.get(approvalCacheKey(userId, approvalPreviewToolName(toolName))) || null;
87
96
  }
88
97
 
89
98
  function approvalTokenPreviewDigest(token) {
@@ -498,8 +507,9 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
498
507
  if (!summary || typeof summary !== "object") {
499
508
  throw new Error(`No confirmation_summary available for ${toolName}.`);
500
509
  }
501
- const digest = previewDigest(previewPayload);
502
- const summaryForToken = { ...summary, _preview_digest: digest };
510
+ const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName)
511
+ ? { ...summary, _preview_digest: previewDigest(previewPayload) }
512
+ : { ...summary };
503
513
  const extraArgs = [
504
514
  "--tool",
505
515
  toolName,
@@ -819,6 +829,94 @@ const walletSessionToolDefinitions = [
819
829
  additionalProperties: false,
820
830
  },
821
831
  },
832
+ {
833
+ name: "x402_search_services",
834
+ description:
835
+ "Search x402-paid services through CDP Bazaar or Agentic Market. This is read-only discovery and does not spend funds.",
836
+ parameters: {
837
+ type: "object",
838
+ properties: {
839
+ query: { type: "string" },
840
+ discovery_provider: {
841
+ type: "string",
842
+ enum: ["auto", "cdp_bazaar", "agentic_market"],
843
+ },
844
+ network: { type: "string" },
845
+ asset: { type: "string" },
846
+ scheme: { type: "string" },
847
+ max_usd_price: { type: "string" },
848
+ limit: { type: "integer" },
849
+ },
850
+ additionalProperties: false,
851
+ },
852
+ },
853
+ {
854
+ name: "x402_get_service_details",
855
+ description:
856
+ "Resolve one x402 service or resource into a normalized details payload. Use a resource URL for CDP Bazaar or a domain/service id for Agentic Market.",
857
+ parameters: {
858
+ type: "object",
859
+ properties: {
860
+ reference: { type: "string" },
861
+ discovery_provider: {
862
+ type: "string",
863
+ enum: ["auto", "cdp_bazaar", "agentic_market"],
864
+ },
865
+ },
866
+ required: ["reference"],
867
+ additionalProperties: false,
868
+ },
869
+ },
870
+ {
871
+ name: "x402_preview_request",
872
+ description:
873
+ "Make an unpaid HTTP request to an x402 endpoint, detect HTTP 402, parse PAYMENT-REQUIRED, and summarize the payment options. This does not pay or execute.",
874
+ parameters: {
875
+ type: "object",
876
+ properties: {
877
+ url: { type: "string" },
878
+ method: { type: "string" },
879
+ headers: { type: "object", additionalProperties: { type: "string" } },
880
+ query: { type: "object", additionalProperties: true },
881
+ json_body: {},
882
+ text_body: { type: "string" },
883
+ },
884
+ required: ["url"],
885
+ additionalProperties: false,
886
+ },
887
+ },
888
+ {
889
+ name: "x402_pay_request",
890
+ description:
891
+ "Prepare or execute an x402 paid request using the active wallet backend. This milestone executes the Solana exact buyer flow and keeps EVM as prepare-only.",
892
+ parameters: {
893
+ type: "object",
894
+ properties: {
895
+ url: { type: "string" },
896
+ method: { type: "string" },
897
+ headers: { type: "object", additionalProperties: { type: "string" } },
898
+ query: { type: "object", additionalProperties: true },
899
+ json_body: {},
900
+ text_body: { type: "string" },
901
+ mode: {
902
+ type: "string",
903
+ enum: ["prepare", "execute"],
904
+ description: "prepare validates the payment plan; execute sends the paid retry.",
905
+ },
906
+ purpose: { type: "string" },
907
+ user_intent: {
908
+ type: "boolean",
909
+ description: "Must be true for prepare mode.",
910
+ },
911
+ approval_token: {
912
+ type: "string",
913
+ description: "Required for execute mode and must be issued against the exact x402 payment summary.",
914
+ },
915
+ },
916
+ required: ["url", "mode", "purpose"],
917
+ additionalProperties: false,
918
+ },
919
+ },
822
920
  {
823
921
  name: "get_active_wallet_backend",
824
922
  description: "Show which wallet backend is active in this OpenClaw plugin session and whether it differs from the startup plugin config.",
@@ -25,6 +25,9 @@ const approvalPreviewCache = new Map();
25
25
  const privateSwapOrderCache = new Map();
26
26
  const WALLET_TOOL_ONLY_GUIDANCE =
27
27
  "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
+ const APPROVAL_PREVIEW_TOOL_ALIASES = new Map([
29
+ ["x402_pay_request", "x402_preview_request"],
30
+ ]);
28
31
 
29
32
  function canonicalJsonText(payload) {
30
33
  const normalize = (value) => {
@@ -51,6 +54,11 @@ function approvalCacheKey(userId, toolName) {
51
54
  return `${userId}::${toolName}`;
52
55
  }
53
56
 
57
+ function approvalPreviewToolName(toolName) {
58
+ const normalized = typeof toolName === "string" ? toolName.trim() : "";
59
+ return APPROVAL_PREVIEW_TOOL_ALIASES.get(normalized) || normalized;
60
+ }
61
+
54
62
  function pruneApprovalPreviewCache() {
55
63
  const now = Date.now();
56
64
  for (const [key, value] of approvalPreviewCache.entries()) {
@@ -61,29 +69,30 @@ function pruneApprovalPreviewCache() {
61
69
  }
62
70
 
63
71
  function cachePreviewForApproval(userId, toolName, payload) {
72
+ const cacheToolName = approvalPreviewToolName(toolName);
64
73
  if (!payload || payload.ok !== true || !payload.data || typeof payload.data !== "object") return;
65
74
  const preview = payload.data;
66
75
  if (preview.mode !== "preview") return;
67
76
  if (!preview.confirmation_summary || typeof preview.confirmation_summary !== "object") return;
68
77
  pruneApprovalPreviewCache();
69
78
  const digest = previewDigest(preview);
70
- approvalPreviewCache.set(approvalCacheKey(userId, toolName), {
79
+ approvalPreviewCache.set(approvalCacheKey(userId, cacheToolName), {
71
80
  digest,
72
81
  expiresAt:
73
- toolName === "swap_solana_privately"
82
+ cacheToolName === "swap_solana_privately"
74
83
  ? Date.now() + PRIVATE_SWAP_CACHE_TTL_MS
75
84
  : Date.now() + PREVIEW_CACHE_TTL_MS,
76
85
  preview,
77
86
  summary: preview.confirmation_summary,
78
87
  });
79
- if (toolName === "swap_solana_privately") {
80
- privateSwapOrderCache.delete(approvalCacheKey(userId, toolName));
88
+ if (cacheToolName === "swap_solana_privately") {
89
+ privateSwapOrderCache.delete(approvalCacheKey(userId, cacheToolName));
81
90
  }
82
91
  }
83
92
 
84
93
  function latestCachedPreview(userId, toolName) {
85
94
  pruneApprovalPreviewCache();
86
- return approvalPreviewCache.get(approvalCacheKey(userId, toolName)) || null;
95
+ return approvalPreviewCache.get(approvalCacheKey(userId, approvalPreviewToolName(toolName))) || null;
87
96
  }
88
97
 
89
98
  function approvalTokenPreviewDigest(token) {
@@ -498,8 +507,9 @@ async function issueApprovalToken(api, config, userId, toolName, previewPayload)
498
507
  if (!summary || typeof summary !== "object") {
499
508
  throw new Error(`No confirmation_summary available for ${toolName}.`);
500
509
  }
501
- const digest = previewDigest(previewPayload);
502
- const summaryForToken = { ...summary, _preview_digest: digest };
510
+ const summaryForToken = PREVIEW_BOUND_SWAP_TOOLS.has(toolName)
511
+ ? { ...summary, _preview_digest: previewDigest(previewPayload) }
512
+ : { ...summary };
503
513
  const extraArgs = [
504
514
  "--tool",
505
515
  toolName,
@@ -819,6 +829,94 @@ const walletSessionToolDefinitions = [
819
829
  additionalProperties: false,
820
830
  },
821
831
  },
832
+ {
833
+ name: "x402_search_services",
834
+ description:
835
+ "Search x402-paid services through CDP Bazaar or Agentic Market. This is read-only discovery and does not spend funds.",
836
+ parameters: {
837
+ type: "object",
838
+ properties: {
839
+ query: { type: "string" },
840
+ discovery_provider: {
841
+ type: "string",
842
+ enum: ["auto", "cdp_bazaar", "agentic_market"],
843
+ },
844
+ network: { type: "string" },
845
+ asset: { type: "string" },
846
+ scheme: { type: "string" },
847
+ max_usd_price: { type: "string" },
848
+ limit: { type: "integer" },
849
+ },
850
+ additionalProperties: false,
851
+ },
852
+ },
853
+ {
854
+ name: "x402_get_service_details",
855
+ description:
856
+ "Resolve one x402 service or resource into a normalized details payload. Use a resource URL for CDP Bazaar or a domain/service id for Agentic Market.",
857
+ parameters: {
858
+ type: "object",
859
+ properties: {
860
+ reference: { type: "string" },
861
+ discovery_provider: {
862
+ type: "string",
863
+ enum: ["auto", "cdp_bazaar", "agentic_market"],
864
+ },
865
+ },
866
+ required: ["reference"],
867
+ additionalProperties: false,
868
+ },
869
+ },
870
+ {
871
+ name: "x402_preview_request",
872
+ description:
873
+ "Make an unpaid HTTP request to an x402 endpoint, detect HTTP 402, parse PAYMENT-REQUIRED, and summarize the payment options. This does not pay or execute.",
874
+ parameters: {
875
+ type: "object",
876
+ properties: {
877
+ url: { type: "string" },
878
+ method: { type: "string" },
879
+ headers: { type: "object", additionalProperties: { type: "string" } },
880
+ query: { type: "object", additionalProperties: true },
881
+ json_body: {},
882
+ text_body: { type: "string" },
883
+ },
884
+ required: ["url"],
885
+ additionalProperties: false,
886
+ },
887
+ },
888
+ {
889
+ name: "x402_pay_request",
890
+ description:
891
+ "Prepare or execute an x402 paid request using the active wallet backend. This milestone executes the Solana exact buyer flow and keeps EVM as prepare-only.",
892
+ parameters: {
893
+ type: "object",
894
+ properties: {
895
+ url: { type: "string" },
896
+ method: { type: "string" },
897
+ headers: { type: "object", additionalProperties: { type: "string" } },
898
+ query: { type: "object", additionalProperties: true },
899
+ json_body: {},
900
+ text_body: { type: "string" },
901
+ mode: {
902
+ type: "string",
903
+ enum: ["prepare", "execute"],
904
+ description: "prepare validates the payment plan; execute sends the paid retry.",
905
+ },
906
+ purpose: { type: "string" },
907
+ user_intent: {
908
+ type: "boolean",
909
+ description: "Must be true for prepare mode.",
910
+ },
911
+ approval_token: {
912
+ type: "string",
913
+ description: "Required for execute mode and must be issued against the exact x402 payment summary.",
914
+ },
915
+ },
916
+ required: ["url", "mode", "purpose"],
917
+ additionalProperties: false,
918
+ },
919
+ },
822
920
  {
823
921
  name: "get_active_wallet_backend",
824
922
  description: "Show which wallet backend is active in this OpenClaw plugin session and whether it differs from the startup plugin config.",
@@ -70,7 +70,11 @@
70
70
  "transfer_evm_native",
71
71
  "transfer_evm_token",
72
72
  "transfer_sol",
73
- "transfer_spl_token"
73
+ "transfer_spl_token",
74
+ "x402_get_service_details",
75
+ "x402_pay_request",
76
+ "x402_preview_request",
77
+ "x402_search_services"
74
78
  ]
75
79
  },
76
80
  "skills": ["skills/wallet-operator"],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
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,30 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.1.18 - 2026-05-19
6
+
7
+ - Started the native x402 buyer integration inside `agent-wallet` instead of
8
+ the separate `pay-bridge` wallet path.
9
+ - Added read-only x402 discovery helpers for `CDP Bazaar` and
10
+ `Agentic Market`, including normalized service/resource search results.
11
+ - Added `x402_preview_request`, which performs an unpaid request, parses
12
+ `PAYMENT-REQUIRED`, and summarizes accepted payment options without spending
13
+ funds.
14
+ - Added `x402_pay_request` with `prepare` and `execute` flow for exact buyer
15
+ payments from the native wallet on Solana, Base, and Base Sepolia.
16
+ - Added buyer-side x402 signing support to the local EVM runtime so Base
17
+ payments execute without requiring a separate wallet product.
18
+ - Fixed x402 Solana execution against hosted RPC routing by deriving an
19
+ SDK-compatible direct Solana RPC URL for the x402 SVM client.
20
+ - Fixed x402 payment requirement selection so SDK model objects survive through
21
+ prepare and execute without crashing on plain dict access.
22
+ - Added automatic host approval-token issuance for `x402_pay_request` from the
23
+ cached `x402_preview_request` summary in the OpenClaw bridge.
24
+ - Fixed x402 approval-token binding so execute validates against the exact
25
+ `confirmation_summary` used by the Python wallet policy gate.
26
+ - Synced the OpenClaw coding profile allowlist and runtime bundle so the new
27
+ x402 tools are exposed correctly in packaged installs.
28
+
5
29
  ## v0.1.17 - 2026-05-17
6
30
 
7
31
  - Added Flash Trade collateral-aware perp opens so the Solana wallet flow can
package/README.md CHANGED
@@ -18,7 +18,7 @@ AgentLayer is a beta local-first wallet and finance stack for agents.
18
18
  The repository includes:
19
19
 
20
20
  - `agent-wallet/` - the main wallet backend for AgentLayer
21
- - `.openclaw/` - the local AgentLayer bridge layer, including the OpenClaw wallet bridge and the `pay.sh` API-payments bridge
21
+ - `.openclaw/` - the local AgentLayer bridge layer for the OpenClaw wallet integration
22
22
  - `hermes/` - optional Hermes Agent plugin bridge for the same wallet backend
23
23
  - `wdk-btc-wallet/` - the local Bitcoin wallet service
24
24
  - `wdk-evm-wallet/` - the local EVM wallet service
@@ -55,7 +55,6 @@ Install the native OpenClaw plugins from ClawHub:
55
55
 
56
56
  ```bash
57
57
  openclaw plugins install clawhub:@agentlayertech/agent-wallet-plugin
58
- openclaw plugins install clawhub:@agentlayertech/pay-bridge-plugin
59
58
  ```
60
59
 
61
60
  Those ClawHub packages do not replace the npm installer. Keep `npx @agentlayer.tech/wallet install --yes` for laying down the local wallet runtime, Python backend, and helper services. The ClawHub packages only install the OpenClaw plugin surfaces that point at that runtime.
@@ -92,7 +91,6 @@ Use ClawHub when you want the plugin itself to be installed through OpenClaw:
92
91
 
93
92
  ```bash
94
93
  openclaw plugins install clawhub:@agentlayertech/agent-wallet-plugin
95
- openclaw plugins install clawhub:@agentlayertech/pay-bridge-plugin
96
94
  ```
97
95
 
98
96
  Recommended order:
package/RELEASING.md CHANGED
@@ -12,11 +12,10 @@ The public install command is:
12
12
  npx @agentlayer.tech/wallet install --yes
13
13
  ```
14
14
 
15
- The repo also ships two native OpenClaw plugin packages for ClawHub:
15
+ The repo also ships a native OpenClaw plugin package for ClawHub:
16
16
 
17
17
  ```text
18
18
  @agentlayertech/agent-wallet-plugin
19
- @agentlayertech/pay-bridge-plugin
20
19
  ```
21
20
 
22
21
  ## When npm Publishes
@@ -200,7 +199,6 @@ Dry-run the package contents from each plugin directory:
200
199
 
201
200
  ```bash
202
201
  (cd .openclaw/extensions/agent-wallet && npm pack --dry-run)
203
- (cd .openclaw/extensions/pay-bridge && npm pack --dry-run)
204
202
  ```
205
203
 
206
204
  Publish to ClawHub with the package-specific command documented by OpenClaw:
@@ -208,16 +206,12 @@ Publish to ClawHub with the package-specific command documented by OpenClaw:
208
206
  ```bash
209
207
  clawhub package publish .openclaw/extensions/agent-wallet --dry-run
210
208
  clawhub package publish .openclaw/extensions/agent-wallet
211
-
212
- clawhub package publish .openclaw/extensions/pay-bridge --dry-run
213
- clawhub package publish .openclaw/extensions/pay-bridge
214
209
  ```
215
210
 
216
211
  Users then install them natively through OpenClaw:
217
212
 
218
213
  ```bash
219
214
  openclaw plugins install clawhub:@agentlayertech/agent-wallet-plugin
220
- openclaw plugins install clawhub:@agentlayertech/pay-bridge-plugin
221
215
  ```
222
216
 
223
217
  GitHub Actions can publish the same packages automatically from tags and manual
@@ -231,14 +225,13 @@ CLAWHUB_TOKEN
231
225
 
232
226
  Workflow behavior:
233
227
 
234
- - `pull_request`: packs both plugins and runs ClawHub `--dry-run`
228
+ - `pull_request`: packs the plugin and runs ClawHub `--dry-run`
235
229
  - `workflow_dispatch`: publishes or dry-runs based on the `dry_run` input
236
- - `push` on `v*` tags: publishes both plugins automatically
230
+ - `push` on `v*` tags: publishes the plugin automatically
237
231
 
238
232
  The workflow currently publishes:
239
233
 
240
234
  - `.openclaw/extensions/agent-wallet` as `bundle-plugin`
241
- - `.openclaw/extensions/pay-bridge` as `code-plugin`
242
235
 
243
236
  `agent-wallet` stays on `bundle-plugin` because that package name was first
244
237
  published to ClawHub with that family, and ClawHub does not allow family
@@ -298,17 +291,16 @@ It publishes these ClawHub packages:
298
291
 
299
292
  ```text
300
293
  @agentlayertech/agent-wallet-plugin
301
- @agentlayertech/pay-bridge-plugin
302
294
  ```
303
295
 
304
296
  ### Triggers
305
297
 
306
298
  - `pull_request`
307
- - runs ClawHub publish in `--dry-run` mode for both plugin packages
299
+ - runs ClawHub publish in `--dry-run` mode for the plugin package
308
300
  - `workflow_dispatch`
309
301
  - supports manual runs with a `dry_run` boolean input
310
302
  - `push` on git tags matching `v*`
311
- - publishes both plugin packages to ClawHub
303
+ - publishes the plugin package to ClawHub
312
304
 
313
305
  ### Required secret
314
306
 
@@ -330,7 +322,6 @@ publisher access to:
330
322
  The workflow currently publishes:
331
323
 
332
324
  - `.openclaw/extensions/agent-wallet` as `bundle-plugin`
333
- - `.openclaw/extensions/pay-bridge` as `code-plugin`
334
325
 
335
326
  `agent-wallet` remains on `bundle-plugin` because the package
336
327
  `@agentlayertech/agent-wallet-plugin` was first created in ClawHub with that
@@ -346,7 +337,6 @@ If you want one git tag to publish both npm and ClawHub surfaces together:
346
337
  package.json
347
338
  agent-wallet/pyproject.toml
348
339
  .openclaw/extensions/agent-wallet/package.json
349
- .openclaw/extensions/pay-bridge/package.json
350
340
  ```
351
341
 
352
342
  2. Commit the release version bump.
@@ -108,6 +108,10 @@ Current safe tools:
108
108
  - `deactivate_solana_stake`
109
109
  - `withdraw_solana_stake`
110
110
  - `request_devnet_airdrop`
111
+ - `x402_search_services`
112
+ - `x402_get_service_details`
113
+ - `x402_preview_request`
114
+ - `x402_pay_request`
111
115
 
112
116
  Temporarily disabled but kept in the codebase for later re-enable:
113
117
 
@@ -401,6 +405,7 @@ For the local EVM backend (`backend=wdk_evm_local`), the lifecycle mirrors the B
401
405
  - the EVM service is localhost-only and no longer accepts remote service URLs through the OpenClaw EVM flow
402
406
  - `agent-wallet` talks to it through a local bearer token loaded from `~/.openclaw/wdk-evm-wallet/local-auth-token`
403
407
  - `agent-wallet` stores only a per-user EVM wallet binding under `~/.openclaw/users/<normalized-user-id>/wallets/evm-<network>-agent.json`
408
+ - the runtime can auto-create missing EVM bindings or auto-unlock the local vault during ordinary OpenClaw switching/tool calls when `sealed_keys.json` contains `wdk_evm_wallet_password`
404
409
  - supported EVM networks are `ethereum`, `sepolia`, `base`, and `base-sepolia`
405
410
  - OpenClaw-facing EVM tools accept an optional per-call `network` override for `ethereum` or `base`, so the agent can switch between the two mainnet EVM paths without editing host config
406
411
  - EVM `get_wallet_balance` now returns an enriched portfolio-style payload with native balance, discovered ERC-20 balances, and USD values when token discovery and pricing are available
@@ -425,6 +430,7 @@ That wrapper:
425
430
  - can auto-start `wdk-evm-wallet/run-local.sh` if the local service is not already healthy
426
431
  - creates or unlocks the local EVM wallet binding
427
432
  - also binds the paired EVM network by default: `ethereum <-> base`, `sepolia <-> base-sepolia`
433
+ - stores the entered EVM vault password into `sealed_keys.json` when `AGENT_WALLET_BOOT_KEY` is available, so later OpenClaw wallet switching can auto-raise the EVM backend without another password prompt
428
434
  - patches OpenClaw config to `backend=wdk_evm_local`
429
435
 
430
436
  Example host-side EVM wallet creation:
@@ -449,6 +455,7 @@ Per-user wallets are now encrypted at rest in one hardened mode:
449
455
 
450
456
  Do not store `masterKey`, `privateKey`, or approval secrets in plugin config JSON or direct runtime environment variables.
451
457
  `AGENT_WALLET_MASTER_KEY`, `AGENT_WALLET_APPROVAL_SECRET`, and `SOLANA_AGENT_PRIVATE_KEY` are now provisioning-only inputs for installer/admin scripts and are rejected by the runtime.
458
+ The installer also provisions a sealed `wdk_evm_wallet_password` by default so greenfield EVM wallet setup can happen automatically on first switch.
452
459
  Create or update that sealed file with:
453
460
 
454
461
  ```bash
@@ -368,6 +368,17 @@ def resolve_solana_private_key() -> str:
368
368
  )
369
369
 
370
370
 
371
+ def resolve_evm_wallet_password() -> str:
372
+ """Resolve the local EVM vault password from env or the sealed secret store."""
373
+ direct = os.getenv("WDK_EVM_WALLET_PASSWORD", "").strip()
374
+ if direct:
375
+ return direct
376
+ return _resolve_sealed_secret(
377
+ "wdk_evm_wallet_password",
378
+ "evm_wallet_password",
379
+ )
380
+
381
+
371
382
  def use_encrypted_user_wallets() -> bool:
372
383
  """Per-user wallet files are always encrypted in the hardened runtime."""
373
384
  return True