@agentlayer.tech/wallet 0.1.27 → 0.1.28

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.
@@ -956,7 +956,7 @@ const walletSessionToolDefinitions = [
956
956
  {
957
957
  name: "x402_pay_request",
958
958
  description:
959
- `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. ${OPENCLAW_EXECUTE_APPROVAL_GUIDANCE}`,
959
+ "Pay for and call an x402 endpoint using the active wallet backend. The tool probes the endpoint, validates compatibility, signs the payment, and returns the service response in one call.",
960
960
  parameters: {
961
961
  type: "object",
962
962
  properties: {
@@ -966,18 +966,9 @@ const walletSessionToolDefinitions = [
966
966
  query: { type: "object", additionalProperties: true },
967
967
  json_body: {},
968
968
  text_body: { type: "string" },
969
- mode: {
970
- type: "string",
971
- enum: ["prepare", "execute"],
972
- description: "prepare validates the payment plan; execute sends the paid retry.",
973
- },
974
969
  purpose: { type: "string" },
975
- user_intent: {
976
- type: "boolean",
977
- description: "Must be true for prepare mode.",
978
- },
979
970
  },
980
- required: ["url", "mode", "purpose"],
971
+ required: ["url", "purpose"],
981
972
  additionalProperties: false,
982
973
  },
983
974
  },
@@ -956,7 +956,7 @@ const walletSessionToolDefinitions = [
956
956
  {
957
957
  name: "x402_pay_request",
958
958
  description:
959
- `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. ${OPENCLAW_EXECUTE_APPROVAL_GUIDANCE}`,
959
+ "Pay for and call an x402 endpoint using the active wallet backend. The tool probes the endpoint, validates compatibility, signs the payment, and returns the service response in one call.",
960
960
  parameters: {
961
961
  type: "object",
962
962
  properties: {
@@ -966,18 +966,9 @@ const walletSessionToolDefinitions = [
966
966
  query: { type: "object", additionalProperties: true },
967
967
  json_body: {},
968
968
  text_body: { type: "string" },
969
- mode: {
970
- type: "string",
971
- enum: ["prepare", "execute"],
972
- description: "prepare validates the payment plan; execute sends the paid retry.",
973
- },
974
969
  purpose: { type: "string" },
975
- user_intent: {
976
- type: "boolean",
977
- description: "Must be true for prepare mode.",
978
- },
979
970
  },
980
- required: ["url", "mode", "purpose"],
971
+ required: ["url", "purpose"],
981
972
  additionalProperties: false,
982
973
  },
983
974
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
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,20 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.1.28 - 2026-05-28
6
+
7
+ - Simplified `x402_pay_request` into a single-shot paid execution flow while
8
+ keeping `x402_preview_request` as an optional research tool.
9
+ - Hardened x402 execution with explicit payment requirement validation, longer
10
+ paid-request timeouts, structured settlement logging, and safer settlement
11
+ header parsing.
12
+ - Fixed Base x402 EVM signing by normalizing typed-data byte fields before
13
+ sending them through the local WDK signer bridge.
14
+ - Reduced x402 preview confusion in OpenClaw by exposing a payment summary
15
+ without approval-token style confirmation semantics.
16
+ - Added an early safety guard for `x402.alchemy.com` so unsupported wallet-auth
17
+ flows fail before spending funds.
18
+
5
19
  ## v0.1.27 - 2026-05-27
6
20
 
7
21
  - Improved Solana swap fallback landing by enabling Jupiter dynamic slippage
@@ -245,8 +245,9 @@ class OpenClawWalletAdapter:
245
245
  AgentToolSpec(
246
246
  name="x402_pay_request",
247
247
  description=(
248
- "Prepare or execute an x402 paid request using the active wallet backend. "
249
- "This milestone executes the Solana exact buyer flow and keeps EVM as prepare-only."
248
+ "Pay for and call an x402 endpoint using the active wallet backend. "
249
+ "The tool probes the endpoint, validates compatibility, signs the payment, "
250
+ "and returns the service response in one call."
250
251
  ),
251
252
  input_schema={
252
253
  "type": "object",
@@ -257,26 +258,13 @@ class OpenClawWalletAdapter:
257
258
  "query": {"type": "object", "additionalProperties": True},
258
259
  "json_body": {},
259
260
  "text_body": {"type": "string"},
260
- "mode": {
261
- "type": "string",
262
- "enum": ["prepare", "execute"],
263
- "description": "prepare validates the payment plan; execute sends the paid retry.",
264
- },
265
261
  "purpose": {"type": "string"},
266
- "user_intent": {
267
- "type": "boolean",
268
- "description": "Must be true for prepare mode.",
269
- },
270
- "approval_token": {
271
- "type": "string",
272
- "description": "Required for execute mode and must be issued against the exact x402 payment summary.",
273
- },
274
262
  },
275
- "required": ["url", "mode", "purpose"],
263
+ "required": ["url", "purpose"],
276
264
  "additionalProperties": False,
277
265
  },
278
266
  read_only=False,
279
- requires_explicit_user_intent=True,
267
+ requires_explicit_user_intent=False,
280
268
  risk_level="high",
281
269
  ),
282
270
  ]
@@ -872,6 +860,42 @@ class OpenClawWalletAdapter:
872
860
  )
873
861
  return annotated
874
862
 
863
+ def _annotate_x402_payload(
864
+ self,
865
+ payload: dict[str, Any],
866
+ *,
867
+ mode: str,
868
+ ) -> dict[str, Any]:
869
+ if not payload.get("payment_required"):
870
+ return dict(payload)
871
+ annotated = self._annotate_sensitive_payload(
872
+ payload,
873
+ action_label="x402 paid request",
874
+ mode=mode,
875
+ )
876
+ summary = dict(annotated.get("confirmation_summary") or {})
877
+ if summary:
878
+ annotated["payment_summary"] = summary
879
+ requirements = dict(annotated.get("confirmation_requirements") or {})
880
+ requirements["prepare_requires_user_intent"] = False
881
+ requirements["execute_requires_approval_token"] = False
882
+ requirements["execute_requires_mainnet_confirmed_in_token"] = False
883
+ annotated.pop("approval_hint", None)
884
+ if mode == "preview":
885
+ annotated.pop("confirmation_summary", None)
886
+ annotated.pop("confirmation_requirements", None)
887
+ if annotated.get("is_mainnet"):
888
+ annotated["preview_note"] = (
889
+ "This is a paid mainnet endpoint preview only. Review the service URL, network, asset, amount, and payment destination before calling x402_pay_request."
890
+ )
891
+ return annotated
892
+ annotated["confirmation_requirements"] = requirements
893
+ if annotated.get("is_mainnet"):
894
+ annotated["mainnet_warning"] = (
895
+ "Mainnet x402 payment. Confirm the service URL, network, asset, amount, and payment destination before paying."
896
+ )
897
+ return annotated
898
+
875
899
  def list_tools(self) -> list[AgentToolSpec]:
876
900
  """Return wallet tools suitable for agent registration."""
877
901
  capabilities = self.backend.get_capabilities()
@@ -3309,14 +3333,7 @@ class OpenClawWalletAdapter:
3309
3333
  text_body=text_body,
3310
3334
  )
3311
3335
  if data.get("payment_required"):
3312
- data = self._annotate_sensitive_payload(
3313
- data,
3314
- action_label="x402 paid request",
3315
- mode="preview",
3316
- )
3317
- approval_hint = dict(data.get("approval_hint") or {})
3318
- approval_hint["tool_name"] = "x402_pay_request"
3319
- data["approval_hint"] = approval_hint
3336
+ data = self._annotate_x402_payload(data, mode="preview")
3320
3337
  return AgentToolResult(tool=tool_name, ok=True, data=data)
3321
3338
 
3322
3339
  if tool_name == "x402_pay_request":
@@ -3326,10 +3343,7 @@ class OpenClawWalletAdapter:
3326
3343
  query = args.get("query")
3327
3344
  json_body = args.get("json_body")
3328
3345
  text_body = args.get("text_body")
3329
- mode = str(args.get("mode") or "").strip().lower()
3330
3346
  purpose = args.get("purpose")
3331
- user_intent = args.get("user_intent")
3332
- approval_token = args.get("approval_token")
3333
3347
  if not isinstance(url, str) or not url.strip():
3334
3348
  raise WalletBackendError("url is required.")
3335
3349
  if method is not None and not isinstance(method, str):
@@ -3340,51 +3354,9 @@ class OpenClawWalletAdapter:
3340
3354
  raise WalletBackendError("query must be an object when provided.")
3341
3355
  if text_body is not None and not isinstance(text_body, str):
3342
3356
  raise WalletBackendError("text_body must be a string when provided.")
3343
- if mode not in {"prepare", "execute"}:
3344
- raise WalletBackendError("mode must be 'prepare' or 'execute'.")
3345
3357
  if not isinstance(purpose, str) or not purpose.strip():
3346
3358
  raise WalletBackendError("purpose is required.")
3347
- if mode == "prepare":
3348
- self._require_prepare_intent(user_intent)
3349
- data = await x402.prepare_request(
3350
- backend=active_backend,
3351
- url=url.strip(),
3352
- method=method,
3353
- headers=headers,
3354
- query=query,
3355
- json_body=json_body,
3356
- text_body=text_body,
3357
- )
3358
- data["purpose"] = purpose.strip()
3359
- data = self._annotate_sensitive_payload(
3360
- data,
3361
- action_label="x402 paid request",
3362
- mode="prepare",
3363
- )
3364
- return AgentToolResult(tool=tool_name, ok=True, data=data)
3365
- preview = await x402.prepare_request(
3366
- backend=active_backend,
3367
- url=url.strip(),
3368
- method=method,
3369
- headers=headers,
3370
- query=query,
3371
- json_body=json_body,
3372
- text_body=text_body,
3373
- )
3374
- preview["purpose"] = purpose.strip()
3375
- preview = self._annotate_sensitive_payload(
3376
- preview,
3377
- action_label="x402 paid request",
3378
- mode="execute",
3379
- )
3380
- self._require_execute_approval(
3381
- approval_token=approval_token,
3382
- tool_name=tool_name,
3383
- summary=preview["confirmation_summary"],
3384
- action_label="x402 paid request",
3385
- backend=active_backend,
3386
- )
3387
- data = await x402.execute_request(
3359
+ data = await x402.pay_and_fetch(
3388
3360
  backend=active_backend,
3389
3361
  url=url.strip(),
3390
3362
  method=method,
@@ -3394,11 +3366,7 @@ class OpenClawWalletAdapter:
3394
3366
  text_body=text_body,
3395
3367
  )
3396
3368
  data["purpose"] = purpose.strip()
3397
- data = self._annotate_sensitive_payload(
3398
- data,
3399
- action_label="x402 paid request",
3400
- mode="execute",
3401
- )
3369
+ data = self._annotate_x402_payload(data, mode="execute")
3402
3370
  return AgentToolResult(tool=tool_name, ok=True, data=data)
3403
3371
 
3404
3372
  if tool_name == "get_wallet_capabilities":
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import base64
6
6
  import hashlib
7
7
  import json
8
+ import logging
8
9
  from typing import Any
9
10
  from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
10
11
 
@@ -15,6 +16,7 @@ from agent_wallet.wallet_layer.base import AgentWalletBackend
15
16
 
16
17
  CDP_BAZAAR_DISCOVERY_BASE_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery"
17
18
  AGENTIC_MARKET_API_BASE_URL = "https://api.agentic.market/v1"
19
+ X402_EXECUTE_TIMEOUT_SECONDS = 45.0
18
20
  SOLANA_CAIP_BY_NETWORK = {
19
21
  "mainnet": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
20
22
  "devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
@@ -32,6 +34,7 @@ _USDC_IDENTIFIERS = {
32
34
  "0x036cbd53842c5426634e7929541ec2318f3dcf7e",
33
35
  "epjfwdd5aufqssqem2qn1xzybapc8g4wegkgkzwytdt1v",
34
36
  }
37
+ log = logging.getLogger("agent_wallet.x402")
35
38
 
36
39
 
37
40
  def _backend_chain(backend: AgentWalletBackend) -> str:
@@ -137,6 +140,13 @@ def _append_query(url: str, query: dict[str, str]) -> str:
137
140
  )
138
141
 
139
142
 
143
+ def _request_host(url: str) -> str:
144
+ try:
145
+ return _trim(urlsplit(url).netloc).lower()
146
+ except Exception:
147
+ return ""
148
+
149
+
140
150
  def _response_text(response: Any) -> str:
141
151
  try:
142
152
  text = response.text
@@ -513,6 +523,7 @@ def _build_request_metadata(
513
523
  )
514
524
  return {
515
525
  "url": final_url,
526
+ "host": _request_host(final_url),
516
527
  "method": http_method,
517
528
  "headers": normalized_headers,
518
529
  "query": normalized_query,
@@ -529,6 +540,7 @@ async def _send_request(
529
540
  client: Any,
530
541
  request: dict[str, Any],
531
542
  extra_headers: dict[str, str] | None = None,
543
+ timeout: float | None = None,
532
544
  ) -> Any:
533
545
  headers = dict(request["headers"])
534
546
  if extra_headers:
@@ -539,6 +551,7 @@ async def _send_request(
539
551
  headers=headers,
540
552
  json=request["json_body"] if request["json_body"] is not None else None,
541
553
  content=request["text_body"] if request["text_body"] is not None else None,
554
+ timeout=timeout,
542
555
  )
543
556
 
544
557
 
@@ -671,6 +684,96 @@ def _require_executable_payment(
671
684
  return selected
672
685
 
673
686
 
687
+ def _validate_payment_requirement(
688
+ selected: dict[str, Any] | None,
689
+ *,
690
+ backend: AgentWalletBackend,
691
+ request_url: str,
692
+ ) -> dict[str, Any]:
693
+ if not isinstance(selected, dict):
694
+ raise ProviderError(
695
+ "x402-validate",
696
+ "This endpoint returned HTTP 402 but no compatible payment option was found for the active wallet.",
697
+ details={
698
+ "request_url": request_url,
699
+ "wallet_chain": _backend_chain(backend),
700
+ "wallet_network": _backend_network(backend),
701
+ },
702
+ )
703
+
704
+ scheme = _trim(selected.get("scheme")).lower()
705
+ if scheme != "exact":
706
+ raise ProviderError(
707
+ "x402-validate",
708
+ f"Unsupported x402 payment scheme '{scheme or 'unknown'}'. Only 'exact' is supported.",
709
+ details={"request_url": request_url, "selected_payment": selected},
710
+ )
711
+
712
+ if not _trim(selected.get("pay_to")):
713
+ raise ProviderError(
714
+ "x402-validate",
715
+ "Payment destination (payTo) is missing from the x402 requirement.",
716
+ details={"request_url": request_url, "selected_payment": selected},
717
+ )
718
+
719
+ compatibility = _requirement_compatibility(selected, backend)
720
+ if compatibility["currently_executable"]:
721
+ return selected
722
+
723
+ chain = _backend_chain(backend) or "unknown"
724
+ network = _backend_network(backend) or "unknown"
725
+ requirement_network = _trim(selected.get("network")) or "unknown"
726
+ if chain == "solana" and requirement_network not in SOLANA_CAIP_BY_NETWORK.values():
727
+ message = (
728
+ f"This endpoint requires payment on {requirement_network}, but the active wallet is Solana ({network})."
729
+ )
730
+ elif chain == "evm" and requirement_network not in EVM_CAIP_BY_NETWORK.values():
731
+ message = (
732
+ f"This endpoint requires payment on {requirement_network}, but the active wallet is EVM ({network})."
733
+ )
734
+ else:
735
+ message = str(compatibility["reason"])
736
+
737
+ raise ProviderError(
738
+ "x402-validate",
739
+ message,
740
+ details={
741
+ "request_url": request_url,
742
+ "selected_payment": selected,
743
+ "compatibility": compatibility,
744
+ },
745
+ )
746
+
747
+
748
+ def _validate_request_execution_policy(
749
+ *,
750
+ request: dict[str, Any],
751
+ backend: AgentWalletBackend,
752
+ ) -> None:
753
+ host = _trim(request.get("host")).lower()
754
+ if host == "x402.alchemy.com":
755
+ headers = request.get("headers")
756
+ has_auth = isinstance(headers, dict) and any(
757
+ str(key).strip().lower() == "authorization" and str(value).strip()
758
+ for key, value in headers.items()
759
+ )
760
+ if not has_auth:
761
+ raise ProviderError(
762
+ "x402-validate",
763
+ (
764
+ "Alchemy's x402 gateway needs wallet-auth headers in addition to the payment challenge. "
765
+ "The generic x402 tool does not mint Alchemy SIWE/SIWS auth tokens yet, so this endpoint "
766
+ "is not safe to execute through the generic flow."
767
+ ),
768
+ details={
769
+ "request_url": request.get("url"),
770
+ "host": host,
771
+ "wallet_chain": _backend_chain(backend),
772
+ "wallet_network": _backend_network(backend),
773
+ "hint": "Use a dedicated Alchemy agent gateway integration or authenticated CLI flow.",
774
+ },
775
+ )
776
+
674
777
  def _select_sdk_payment_requirement(
675
778
  payment_required: Any,
676
779
  *,
@@ -940,15 +1043,57 @@ async def _create_payment_headers(
940
1043
  )
941
1044
 
942
1045
 
943
- def _extract_settlement_header(response: Any) -> dict[str, Any] | None:
1046
+ def _extract_settlement_header(response: Any) -> dict[str, Any]:
944
1047
  sdk = _load_x402_sdk()
1048
+ settle = sdk["x402HTTPClientBase"]().get_payment_settle_response(
1049
+ lambda name: response.headers.get(name)
1050
+ )
1051
+ return settle.model_dump(by_alias=True, exclude_none=True)
1052
+
1053
+
1054
+ def _extract_settlement_header_safe(response: Any) -> dict[str, Any] | None:
945
1055
  try:
946
- settle = sdk["x402HTTPClientBase"]().get_payment_settle_response(
947
- lambda name: response.headers.get(name)
1056
+ return _extract_settlement_header(response)
1057
+ except Exception as exc:
1058
+ log.warning(
1059
+ "x402 settlement header parse failed",
1060
+ extra={
1061
+ "status_code": getattr(response, "status_code", None),
1062
+ "payment_response": response.headers.get("PAYMENT-RESPONSE")
1063
+ if hasattr(response, "headers")
1064
+ else None,
1065
+ "x_payment_response": response.headers.get("X-PAYMENT-RESPONSE")
1066
+ if hasattr(response, "headers")
1067
+ else None,
1068
+ "error_type": type(exc).__name__,
1069
+ "error": str(exc) or None,
1070
+ },
948
1071
  )
949
- except Exception:
950
1072
  return None
951
- return settle.model_dump(by_alias=True, exclude_none=True)
1073
+
1074
+
1075
+ def _log_x402_execute(
1076
+ *,
1077
+ request: dict[str, Any],
1078
+ selected_payment: dict[str, Any] | None,
1079
+ response: Any,
1080
+ settlement: dict[str, Any] | None,
1081
+ ) -> None:
1082
+ log.info(
1083
+ "x402 execute completed",
1084
+ extra={
1085
+ "url": request.get("url"),
1086
+ "method": request.get("method"),
1087
+ "request_fingerprint": request.get("request_fingerprint"),
1088
+ "x402_network": selected_payment.get("network") if isinstance(selected_payment, dict) else None,
1089
+ "x402_asset": selected_payment.get("asset") if isinstance(selected_payment, dict) else None,
1090
+ "x402_amount": selected_payment.get("amount") if isinstance(selected_payment, dict) else None,
1091
+ "x402_pay_to": selected_payment.get("pay_to") if isinstance(selected_payment, dict) else None,
1092
+ "status_code": getattr(response, "status_code", None),
1093
+ "transaction": settlement.get("transaction") if isinstance(settlement, dict) else None,
1094
+ "confirmed": bool(settlement and settlement.get("success")),
1095
+ },
1096
+ )
952
1097
 
953
1098
 
954
1099
  async def search_services(
@@ -1250,6 +1395,29 @@ async def execute_request(
1250
1395
  query: dict[str, Any] | None = None,
1251
1396
  json_body: Any | None = None,
1252
1397
  text_body: str | None = None,
1398
+ ) -> dict[str, Any]:
1399
+ executed = await pay_and_fetch(
1400
+ backend=backend,
1401
+ url=url,
1402
+ method=method,
1403
+ headers=headers,
1404
+ query=query,
1405
+ json_body=json_body,
1406
+ text_body=text_body,
1407
+ )
1408
+ executed["mode"] = "execute"
1409
+ return executed
1410
+
1411
+
1412
+ async def pay_and_fetch(
1413
+ *,
1414
+ backend: AgentWalletBackend,
1415
+ url: str,
1416
+ method: str = "GET",
1417
+ headers: dict[str, Any] | None = None,
1418
+ query: dict[str, Any] | None = None,
1419
+ json_body: Any | None = None,
1420
+ text_body: str | None = None,
1253
1421
  ) -> dict[str, Any]:
1254
1422
  preview = await preview_request(
1255
1423
  backend=backend,
@@ -1268,7 +1436,13 @@ async def execute_request(
1268
1436
  executed["confirmed"] = False
1269
1437
  return executed
1270
1438
 
1271
- selected_payment = _require_executable_payment(preview=preview, backend=backend)
1439
+ selected_payment = _validate_payment_requirement(
1440
+ preview.get("selected_payment")
1441
+ if isinstance(preview.get("selected_payment"), dict)
1442
+ else None,
1443
+ backend=backend,
1444
+ request_url=str(preview.get("request_url") or url),
1445
+ )
1272
1446
  payment_required_header = (
1273
1447
  dict(preview.get("response_headers") or {}).get("payment-required")
1274
1448
  )
@@ -1283,15 +1457,26 @@ async def execute_request(
1283
1457
  json_body=json_body,
1284
1458
  text_body=text_body,
1285
1459
  )
1460
+ _validate_request_execution_policy(request=request, backend=backend)
1286
1461
  payment_headers = await _create_payment_headers(
1287
1462
  backend=backend,
1288
1463
  payment_required_header=payment_required_header,
1289
1464
  selected_payment=selected_payment,
1290
1465
  )
1291
- payment_headers["Access-Control-Expose-Headers"] = "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE"
1292
1466
  client = get_client()
1293
- response = await _send_request(client=client, request=request, extra_headers=payment_headers)
1294
- settlement = _extract_settlement_header(response)
1467
+ response = await _send_request(
1468
+ client=client,
1469
+ request=request,
1470
+ extra_headers=payment_headers,
1471
+ timeout=X402_EXECUTE_TIMEOUT_SECONDS,
1472
+ )
1473
+ settlement = _extract_settlement_header_safe(response)
1474
+ _log_x402_execute(
1475
+ request=request,
1476
+ selected_payment=selected_payment,
1477
+ response=response,
1478
+ settlement=settlement,
1479
+ )
1295
1480
 
1296
1481
  executed = dict(preview)
1297
1482
  executed.update(
@@ -33,6 +33,16 @@ def _lifi_chain_id_for_evm_network(network: str) -> str:
33
33
  return "1"
34
34
 
35
35
 
36
+ def _normalize_x402_typed_data_value(value: Any) -> Any:
37
+ if isinstance(value, (bytes, bytearray)):
38
+ return "0x" + bytes(value).hex()
39
+ if isinstance(value, list):
40
+ return [_normalize_x402_typed_data_value(item) for item in value]
41
+ if isinstance(value, dict):
42
+ return {str(key): _normalize_x402_typed_data_value(item) for key, item in value.items()}
43
+ return value
44
+
45
+
36
46
  def _extract_fee_wei(payload: dict[str, Any]) -> str | None:
37
47
  for key in ("fee", "maxFee", "totalFee", "gasCost", "cost"):
38
48
  value = payload.get(key)
@@ -457,7 +467,7 @@ class WdkEvmLocalWalletBackend(AgentWalletBackend):
457
467
  "domain": domain,
458
468
  "types": types,
459
469
  "primaryType": primary_type,
460
- "message": message,
470
+ "message": _normalize_x402_typed_data_value(message),
461
471
  },
462
472
  )
463
473
  signature = str(data.get("signature") or "").strip()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openclaw-agent-wallet"
7
- version = "0.1.27"
7
+ version = "0.1.28"
8
8
  description = "Plugin-friendly wallet backend for OpenClaw agents"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayer.tech/wallet",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "NPM installer for the OpenClaw Agent Wallet local runtime.",
5
5
  "type": "module",
6
6
  "repository": {