@devlab.group/agent-commerce 2.4.0 → 2.5.0

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 (108) hide show
  1. package/README.md +115 -15
  2. package/dist/ap2.d.ts +24 -12
  3. package/dist/ap2.js +31 -13
  4. package/dist/ap2.js.map +1 -1
  5. package/dist/{chunk-AITMDXKW.js → chunk-3OTCFFFT.js} +37 -4
  6. package/dist/chunk-3OTCFFFT.js.map +1 -0
  7. package/dist/{chunk-4OEXK3YG.js → chunk-4K7FIBJM.js} +25 -4
  8. package/dist/chunk-4K7FIBJM.js.map +1 -0
  9. package/dist/{chunk-WUIAUAA7.js → chunk-FKQK5XZA.js} +652 -68
  10. package/dist/chunk-FKQK5XZA.js.map +1 -0
  11. package/dist/chunk-GA3O2A7R.js +92 -0
  12. package/dist/chunk-GA3O2A7R.js.map +1 -0
  13. package/dist/{chunk-6WACRJVT.js → chunk-VUCMBGUR.js} +3 -3
  14. package/dist/{chunk-6WACRJVT.js.map → chunk-VUCMBGUR.js.map} +1 -1
  15. package/dist/cli/{ap2-QDHPRSTF.js → ap2-YAPLERSC.js} +34 -15
  16. package/dist/cli/ap2-YAPLERSC.js.map +1 -0
  17. package/dist/cli/{chunk-G2JEY7MB.js → chunk-2J2IQQ4X.js} +8 -7
  18. package/dist/cli/chunk-2J2IQQ4X.js.map +1 -0
  19. package/dist/cli/chunk-2UPPX3FJ.js +311 -0
  20. package/dist/cli/chunk-2UPPX3FJ.js.map +1 -0
  21. package/dist/cli/{chunk-WYOGIANL.js → chunk-4H2QLHQI.js} +4 -4
  22. package/dist/cli/{chunk-WYOGIANL.js.map → chunk-4H2QLHQI.js.map} +1 -1
  23. package/dist/cli/{chunk-OZ4LAWBK.js → chunk-5R7DM5LM.js} +25 -4
  24. package/dist/cli/chunk-5R7DM5LM.js.map +1 -0
  25. package/dist/cli/chunk-663ALDZA.js +92 -0
  26. package/dist/cli/chunk-663ALDZA.js.map +1 -0
  27. package/dist/cli/{chunk-QQ3WY5L3.js → chunk-IDY2735M.js} +36 -104
  28. package/dist/cli/chunk-IDY2735M.js.map +1 -0
  29. package/dist/cli/chunk-JFVRG2HH.js +107 -0
  30. package/dist/cli/chunk-JFVRG2HH.js.map +1 -0
  31. package/dist/cli/chunk-M7NXVRU5.js +8 -0
  32. package/dist/cli/{chunk-UXB65XCS.js.map → chunk-M7NXVRU5.js.map} +1 -1
  33. package/dist/cli/chunk-NIU5EMSB.js +119 -0
  34. package/dist/cli/chunk-NIU5EMSB.js.map +1 -0
  35. package/dist/cli/{chunk-AZDWFVDW.js → chunk-QA2OPHBF.js} +655 -70
  36. package/dist/cli/chunk-QA2OPHBF.js.map +1 -0
  37. package/dist/cli/{chunk-DCMW67JM.js → chunk-QLUCNPRT.js} +404 -161
  38. package/dist/cli/chunk-QLUCNPRT.js.map +1 -0
  39. package/dist/cli/chunk-SYQLJXIU.js +105 -0
  40. package/dist/cli/chunk-SYQLJXIU.js.map +1 -0
  41. package/dist/cli/{chunk-3MGAJ5FX.js → chunk-VJ4EO4LE.js} +3 -3
  42. package/dist/cli/{chunk-3MGAJ5FX.js.map → chunk-VJ4EO4LE.js.map} +1 -1
  43. package/dist/cli/{chunk-PIMFPCNZ.js → chunk-Z34UMZBB.js} +234 -85
  44. package/dist/cli/chunk-Z34UMZBB.js.map +1 -0
  45. package/dist/cli/config-BWFMN2ZB.js +12 -0
  46. package/dist/cli/{config-UI4EDG4L.js.map → config-BWFMN2ZB.js.map} +1 -1
  47. package/dist/cli/index.js +258 -11
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/{mcp-26LJMN4N.js → mcp-KZEMXLHR.js} +5 -4
  50. package/dist/cli/mcp-KZEMXLHR.js.map +1 -0
  51. package/dist/cli/{near-5AY3HWYF.js → near-U6365VFX.js} +15 -4
  52. package/dist/cli/near-U6365VFX.js.map +1 -0
  53. package/dist/cli/payment-providers-SZL36H3Y.js +6 -0
  54. package/dist/cli/payment-providers-SZL36H3Y.js.map +1 -0
  55. package/dist/cli/{provider-Z4OJNAYI.js → provider-6TKB5ADJ.js} +30 -16
  56. package/dist/cli/provider-6TKB5ADJ.js.map +1 -0
  57. package/dist/cli/receipts-ZGLJWMQG.js +8 -0
  58. package/dist/cli/receipts-ZGLJWMQG.js.map +1 -0
  59. package/dist/cli/reconcile-IC22MJD5.js +4 -0
  60. package/dist/cli/reconcile-IC22MJD5.js.map +1 -0
  61. package/dist/cli/{run-TEPYJUHG.js → run-ZTYPQI4D.js} +151 -115
  62. package/dist/cli/run-ZTYPQI4D.js.map +1 -0
  63. package/dist/cli/svm-KDSPDFJG.js +48 -0
  64. package/dist/cli/svm-KDSPDFJG.js.map +1 -0
  65. package/dist/cli/{x402-BMVONZKA.js → x402-WLYBLODI.js} +10 -9
  66. package/dist/cli/x402-WLYBLODI.js.map +1 -0
  67. package/dist/index.d.ts +112 -12
  68. package/dist/index.js +948 -157
  69. package/dist/index.js.map +1 -1
  70. package/dist/mcp.d.ts +1 -2
  71. package/dist/mcp.js +1 -1
  72. package/dist/mpp.js +24 -11
  73. package/dist/mpp.js.map +1 -1
  74. package/dist/{near-D6C42VPE.js → near-FH7HPZV3.js} +15 -4
  75. package/dist/near-FH7HPZV3.js.map +1 -0
  76. package/dist/{protocol-adapter-C9odYl6l.d.ts → protocol-adapter-DEXpdp8m.d.ts} +102 -48
  77. package/dist/{runtime-Cl_BLVZV.d.ts → runtime-Dz2fSO-P.d.ts} +220 -2
  78. package/dist/svm-KNC3PHMS.js +48 -0
  79. package/dist/svm-KNC3PHMS.js.map +1 -0
  80. package/dist/x402.js +5 -5
  81. package/package.json +1 -1
  82. package/dist/authorization-DjAecwuW.d.ts +0 -115
  83. package/dist/chunk-4OEXK3YG.js.map +0 -1
  84. package/dist/chunk-AITMDXKW.js.map +0 -1
  85. package/dist/chunk-KA2AX5FH.js +0 -44
  86. package/dist/chunk-KA2AX5FH.js.map +0 -1
  87. package/dist/chunk-WUIAUAA7.js.map +0 -1
  88. package/dist/cli/ap2-QDHPRSTF.js.map +0 -1
  89. package/dist/cli/chunk-AZDWFVDW.js.map +0 -1
  90. package/dist/cli/chunk-DCMW67JM.js.map +0 -1
  91. package/dist/cli/chunk-G2JEY7MB.js.map +0 -1
  92. package/dist/cli/chunk-OSTCU6ZK.js +0 -44
  93. package/dist/cli/chunk-OSTCU6ZK.js.map +0 -1
  94. package/dist/cli/chunk-OZ4LAWBK.js.map +0 -1
  95. package/dist/cli/chunk-PIMFPCNZ.js.map +0 -1
  96. package/dist/cli/chunk-QQ3WY5L3.js.map +0 -1
  97. package/dist/cli/chunk-UXB65XCS.js +0 -8
  98. package/dist/cli/config-UI4EDG4L.js +0 -11
  99. package/dist/cli/mcp-26LJMN4N.js.map +0 -1
  100. package/dist/cli/near-5AY3HWYF.js.map +0 -1
  101. package/dist/cli/provider-Z4OJNAYI.js.map +0 -1
  102. package/dist/cli/run-TEPYJUHG.js.map +0 -1
  103. package/dist/cli/svm-3MMYFPC7.js +0 -33
  104. package/dist/cli/svm-3MMYFPC7.js.map +0 -1
  105. package/dist/cli/x402-BMVONZKA.js.map +0 -1
  106. package/dist/near-D6C42VPE.js.map +0 -1
  107. package/dist/svm-QEUAUNPQ.js +0 -33
  108. package/dist/svm-QEUAUNPQ.js.map +0 -1
@@ -1,9 +1,9 @@
1
- import { isWellKnownDevKey, findX402Network, normalizeAddress, assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeRpc, X402_DEFAULT_PAYMENT_FLOW, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY, SETTLE_AFTER_BACKEND_METADATA_KEY, sameAddress, LOCAL_CHAIN_ID, isTransactionReference, x402OfferName, isEvmAddress, describeDeploymentMode } from './chunk-4OEXK3YG.js';
2
- import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, redactedErrorText } from './chunk-AITMDXKW.js';
3
- import { computeReplayKey, computePermit2ReplayKey } from './chunk-KA2AX5FH.js';
1
+ import { isWellKnownDevKey, findX402Network, normalizeAddress, assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeRpc, canonicalJson, X402_DEFAULT_PAYMENT_FLOW, REUSE_REJECTED_AUTHORIZATION_METADATA_KEY, SETTLE_AFTER_BACKEND_METADATA_KEY, sameAddress, LOCAL_CHAIN_ID, isTransactionReference, x402OfferName, isEvmAddress, describeDeploymentMode } from './chunk-4K7FIBJM.js';
2
+ import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION, redactedErrorText, RECONCILIATION_METADATA_KEY, isCommerceError } from './chunk-3OTCFFFT.js';
3
+ import { LOCATOR_VERSION, eip3009Locator, computeReplayKey, permit2Locator, computePermit2ReplayKey, isoFromSeconds } from './chunk-GA3O2A7R.js';
4
4
  import { isRecord } from './chunk-2CJNA7MS.js';
5
- import { x402ExactPermit2ProxyAddress, toFacilitatorEvmSigner, PERMIT2_ADDRESS } from '@x402/evm';
6
- import { isAddress, keccak256, stringToBytes, getAddress, formatUnits, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, BaseError, ContractFunctionRevertedError, erc20Abi } from 'viem';
5
+ import { x402ExactPermit2ProxyAddress, toFacilitatorEvmSigner, PERMIT2_ADDRESS, eip3009ABI, x402ExactPermit2ProxyABI } from '@x402/evm';
6
+ import { parseAbi, isAddress, keccak256, stringToBytes, isHash, getAddress, formatUnits, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, BaseError, ContractFunctionRevertedError, erc20Abi, parseEventLogs, isAddressEqual, TransactionReceiptNotFoundError, decodeFunctionData } from 'viem';
7
7
  import { privateKeyToAccount } from 'viem/accounts';
8
8
  import { HTTPFacilitatorClient } from '@x402/core/http';
9
9
  import { SettleError, VerifyError } from '@x402/core/types';
@@ -24,10 +24,9 @@ var DEFAULT_IDS = {
24
24
 
25
25
  // src/payments/x402/provider/fee-payer.ts
26
26
  var SUPPORTED_TTL_MS = 6e4;
27
- function createSvmFeePayerSource(ctx) {
27
+ function createSupportedSource(ctx) {
28
28
  const { clock, remoteBinding } = ctx;
29
29
  let supportedSnapshot;
30
- const feePayers = /* @__PURE__ */ new Map();
31
30
  function currentSupported() {
32
31
  const now = clock.monotonicMs();
33
32
  if (supportedSnapshot && now - supportedSnapshot.at < SUPPORTED_TTL_MS) {
@@ -42,6 +41,10 @@ function createSvmFeePayerSource(ctx) {
42
41
  });
43
42
  return response;
44
43
  }
44
+ return currentSupported;
45
+ }
46
+ function createSvmFeePayerSource(currentSupported) {
47
+ const feePayers = /* @__PURE__ */ new Map();
45
48
  async function svmFeePayer(offer) {
46
49
  let supported;
47
50
  try {
@@ -70,6 +73,43 @@ function createSvmFeePayerSource(ctx) {
70
73
  }
71
74
  return svmFeePayer;
72
75
  }
76
+ function createNearRelayerSource(currentSupported, logger) {
77
+ return async (offer) => {
78
+ let supported;
79
+ try {
80
+ supported = await currentSupported();
81
+ } catch (err) {
82
+ logger.warn(
83
+ { err: redactedErrorText(err) },
84
+ `x402 verify(): facilitator ${offer.binding.describe} did not answer /supported; the NEAR locator names no relayer`
85
+ );
86
+ return [];
87
+ }
88
+ const { signers } = supported;
89
+ return [.../* @__PURE__ */ new Set([...signers[offer.network] ?? [], ...signers["near:*"] ?? []])];
90
+ };
91
+ }
92
+
93
+ // src/payments/x402/json-rpc.ts
94
+ async function jsonRpc(rpcUrl, method, params, timeoutMs) {
95
+ const response = await fetch(rpcUrl, {
96
+ method: "POST",
97
+ headers: { "content-type": "application/json" },
98
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
99
+ signal: AbortSignal.timeout(timeoutMs)
100
+ });
101
+ const body = await response.json();
102
+ if (body.error !== void 0) {
103
+ throw new CommerceError(
104
+ "PAYMENT_PROVIDER_UNAVAILABLE",
105
+ `RPC ${method} failed: ${JSON.stringify(body.error)}`,
106
+ { details: { rpcError: body.error } }
107
+ );
108
+ }
109
+ return body.result;
110
+ }
111
+
112
+ // src/payments/x402/provider/health.ts
73
113
  function createHealthCheck(ctx) {
74
114
  const { offers, clock, deploymentMode, remoteBinding, svm, near } = ctx;
75
115
  async function offerHealth(offer, kinds) {
@@ -143,7 +183,7 @@ function createHealthCheck(ctx) {
143
183
  async function svmOfferHealth(offer, kinds) {
144
184
  const { profile, rpcOrigin, binding } = offer;
145
185
  const svmModule = await svm();
146
- const genesis = await jsonRpc(offer.rpcUrl, "getGenesisHash", []);
186
+ const genesis = await rpc(offer.rpcUrl, "getGenesisHash", []);
147
187
  const cluster = typeof genesis === "string" ? `solana:${genesis.slice(0, 32)}` : void 0;
148
188
  if (cluster !== offer.network) {
149
189
  return {
@@ -151,10 +191,7 @@ function createHealthCheck(ctx) {
151
191
  detail: `RPC at ${rpcOrigin} serves ${cluster ?? "an unknown cluster"}, expected ${offer.network} (${profile.displayName})`
152
192
  };
153
193
  }
154
- const mint = await jsonRpc(offer.rpcUrl, "getAccountInfo", [
155
- offer.asset,
156
- { encoding: "base64" }
157
- ]);
194
+ const mint = await rpc(offer.rpcUrl, "getAccountInfo", [offer.asset, { encoding: "base64" }]);
158
195
  const mintInfo = readMint(mint);
159
196
  if (mintInfo === void 0) {
160
197
  return {
@@ -174,7 +211,7 @@ function createHealthCheck(ctx) {
174
211
  offer.asset,
175
212
  tokenProgram
176
213
  );
177
- const account = await jsonRpc(offer.rpcUrl, "getAccountInfo", [
214
+ const account = await rpc(offer.rpcUrl, "getAccountInfo", [
178
215
  payeeAccount,
179
216
  { encoding: "base64" }
180
217
  ]);
@@ -202,7 +239,7 @@ function createHealthCheck(ctx) {
202
239
  async function nearOfferHealth(offer, kinds) {
203
240
  const { profile, rpcOrigin, binding, rpcUrl } = offer;
204
241
  await near();
205
- const status = await jsonRpc(rpcUrl, "status", []);
242
+ const status = await rpc(rpcUrl, "status", []);
206
243
  const chainId = isRecord(status) ? status["chain_id"] : void 0;
207
244
  const expected = offer.network.slice("near:".length);
208
245
  if (chainId !== expected) {
@@ -211,7 +248,7 @@ function createHealthCheck(ctx) {
211
248
  detail: `RPC at ${rpcOrigin} serves chain ${String(chainId ?? "unknown")}, expected ${expected} (${profile.displayName})`
212
249
  };
213
250
  }
214
- const token = await jsonRpc(rpcUrl, "query", {
251
+ const token = await rpc(rpcUrl, "query", {
215
252
  request_type: "view_account",
216
253
  finality: "final",
217
254
  account_id: offer.asset
@@ -329,24 +366,9 @@ function readMint(result) {
329
366
  const decimals = bytes[44];
330
367
  return bytes.length >= 82 && bytes[45] === 1 && decimals !== void 0 ? { decimals, tokenProgram: owner } : void 0;
331
368
  }
332
- async function jsonRpc(rpcUrl, method, params) {
333
- const response = await fetch(rpcUrl, {
334
- method: "POST",
335
- headers: { "content-type": "application/json" },
336
- body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
337
- signal: AbortSignal.timeout(HEALTH_TIMEOUT_MS)
338
- });
339
- const body = await response.json();
340
- if (body.error !== void 0) {
341
- throw new CommerceError(
342
- "PAYMENT_PROVIDER_UNAVAILABLE",
343
- `RPC ${method} failed: ${JSON.stringify(body.error)}`
344
- );
345
- }
346
- return body.result;
347
- }
369
+ var rpc = (rpcUrl, method, params) => jsonRpc(rpcUrl, method, params, HEALTH_TIMEOUT_MS);
348
370
  async function nearView(rpcUrl, accountId, method, args) {
349
- const result = await jsonRpc(rpcUrl, "query", {
371
+ const result = await rpc(rpcUrl, "query", {
350
372
  request_type: "call_function",
351
373
  finality: "final",
352
374
  account_id: accountId,
@@ -391,7 +413,7 @@ function buildLocalChain(rpcUrl, chainId = LOCAL_CHAIN_ID) {
391
413
  function createLocalPublicClient(rpcUrl, timeoutMs, chainId) {
392
414
  return createPublicClient({
393
415
  chain: buildLocalChain(rpcUrl, chainId),
394
- transport: http(rpcUrl, { timeout: timeoutMs } )
416
+ transport: http(rpcUrl, timeoutMs !== void 0 ? { timeout: timeoutMs } : void 0)
395
417
  });
396
418
  }
397
419
  function createLocalFacilitatorClient(rpcUrl, signerPrivateKey, chainId) {
@@ -770,29 +792,6 @@ function offerCurrency(offer, quoted) {
770
792
  const canonical = offer.profile.canonicalAsset;
771
793
  return canonical !== void 0 && sameAddress(offer.profile, offer.asset, canonical.address) ? canonical.symbol : quoted;
772
794
  }
773
-
774
- // src/core/canonical-json.ts
775
- var LONE_SURROGATE = new RegExp("\\p{Cs}", "u");
776
- function canonicalJson(value) {
777
- if (typeof value === "string")
778
- return LONE_SURROGATE.test(value) ? void 0 : JSON.stringify(value);
779
- if (typeof value === "number") return Number.isFinite(value) ? JSON.stringify(value) : void 0;
780
- if (value === null || typeof value === "boolean") return JSON.stringify(value);
781
- if (Array.isArray(value)) {
782
- const items = value.map(canonicalJson);
783
- return items.includes(void 0) ? void 0 : `[${items.join(",")}]`;
784
- }
785
- if (typeof value !== "object") return void 0;
786
- const members = [];
787
- for (const key of Object.keys(value).sort()) {
788
- const member = canonicalJson(value[key]);
789
- if (member === void 0 || LONE_SURROGATE.test(key)) return void 0;
790
- members.push(`${JSON.stringify(key)}:${member}`);
791
- }
792
- return `{${members.join(",")}}`;
793
- }
794
-
795
- // src/payments/x402/provider/quote.ts
796
795
  var QUOTE_EXTENSION = "erc-8409";
797
796
  var QUOTE_REQUEST_SCHEME = "agent-commerce/request/v1";
798
797
  var QUOTE_DOMAIN = { name: "Signed Service Payment Quotes", version: "1" };
@@ -936,6 +935,553 @@ function quoteRequestHash(resourceId, input) {
936
935
  const canonical = canonicalJson({ input, resource: resourceId });
937
936
  return canonical === void 0 ? void 0 : keccak256(stringToBytes(canonical));
938
937
  }
938
+ var EVENTS = parseAbi([
939
+ "event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce)",
940
+ "event Transfer(address indexed from, address indexed to, uint256 value)"
941
+ ]);
942
+ var NONCE_BITMAP_ABI = parseAbi([
943
+ "function nonceBitmap(address owner, uint256 wordPosition) view returns (uint256)"
944
+ ]);
945
+ var CLOCK_MARGIN_SECONDS = 900n;
946
+ var LOG_CHUNK_BLOCKS = 10000n;
947
+ var MAX_WINDOW_BLOCKS = 200000n;
948
+ var UINT = /^\d{1,78}$/;
949
+ function parseEvmLocator(locator) {
950
+ const address = (key) => {
951
+ const value = locator[key];
952
+ return typeof value === "string" && isAddress(value) ? value : void 0;
953
+ };
954
+ const uint = (key) => {
955
+ const value = locator[key];
956
+ return typeof value === "string" && UINT.test(value) ? BigInt(value) : void 0;
957
+ };
958
+ const expiresAt = typeof locator["expiresAt"] === "string" ? locator["expiresAt"] : void 0;
959
+ if (locator["method"] === "eip3009") {
960
+ const [asset, from, to] = [address("asset"), address("from"), address("to")];
961
+ const [value, validAfter, validBefore] = [
962
+ uint("value"),
963
+ uint("validAfter"),
964
+ uint("validBefore")
965
+ ];
966
+ const nonce = locator["nonce"];
967
+ if (!asset || !from || !to || value === void 0 || validAfter === void 0) return void 0;
968
+ if (validBefore === void 0 || typeof nonce !== "string" || !isHash(nonce)) return void 0;
969
+ return { method: "eip3009", asset, from, to, value, nonce, validAfter, validBefore, expiresAt };
970
+ }
971
+ if (locator["method"] === "permit2") {
972
+ const [asset, owner, to, proxy] = [
973
+ address("asset"),
974
+ address("owner"),
975
+ address("to"),
976
+ address("proxy")
977
+ ];
978
+ const [amount, nonce, deadline, validAfter] = [
979
+ uint("amount"),
980
+ uint("nonce"),
981
+ uint("deadline"),
982
+ uint("validAfter")
983
+ ];
984
+ if (!asset || !owner || !to || !proxy || amount === void 0 || nonce === void 0) {
985
+ return void 0;
986
+ }
987
+ if (deadline === void 0 || validAfter === void 0) return void 0;
988
+ return {
989
+ method: "permit2",
990
+ asset,
991
+ owner,
992
+ to,
993
+ amount,
994
+ nonce,
995
+ deadline,
996
+ validAfter,
997
+ proxy,
998
+ expiresAt
999
+ };
1000
+ }
1001
+ return void 0;
1002
+ }
1003
+ async function readEvmEvidence(input) {
1004
+ const { client, chainId, locator, attempt } = input;
1005
+ const reported = await client.getChainId();
1006
+ if (reported !== chainId) {
1007
+ return unknown("chain_mismatch", { chainId: reported, expectedChainId: chainId });
1008
+ }
1009
+ const finalized = await client.getBlock({ blockTag: "finalized" });
1010
+ const finalizedAt = isoFromSeconds(String(finalized.timestamp));
1011
+ const finality = {
1012
+ finalizedBlock: String(finalized.number),
1013
+ ...finalizedAt !== void 0 ? { finalizedAt } : {}
1014
+ };
1015
+ const method = locator.method === "eip3009" ? eip3009(client, locator) : permit2(client, locator);
1016
+ const settled = (hash, block) => block <= finalized.number ? {
1017
+ outcome: "settled",
1018
+ reason: "transfer_final",
1019
+ externalReference: hash,
1020
+ evidence: { transactionHash: hash, blockNumber: String(block), ...finality }
1021
+ } : unknown("not_final", { transactionHash: hash, blockNumber: String(block), ...finality });
1022
+ const reference = attempt.externalReference;
1023
+ if (reference !== void 0 && isHash(reference)) {
1024
+ const block = await method.carries(reference);
1025
+ if (block !== void 0) return settled(reference, block);
1026
+ }
1027
+ if (!await method.used(finalized.number)) {
1028
+ if (finalized.timestamp >= method.endsAt) {
1029
+ return {
1030
+ outcome: "not-settled",
1031
+ reason: "expired_unused",
1032
+ evidence: { nonceUsed: false, ...finality }
1033
+ };
1034
+ }
1035
+ if (await method.used()) return unknown("not_final", finality);
1036
+ return {
1037
+ ...unknown("not_expired", finality),
1038
+ ...locator.expiresAt !== void 0 ? { retryAfter: locator.expiresAt } : {}
1039
+ };
1040
+ }
1041
+ const createdAt = BigInt(Math.floor(Date.parse(attempt.createdAt) / 1e3));
1042
+ const fromSeconds = max(method.validAfter, createdAt - CLOCK_MARGIN_SECONDS);
1043
+ const fromBlock = await firstBlockAt(client, fromSeconds, finalized);
1044
+ const endBlock = await firstBlockAt(client, method.endsAt, finalized) - 1n;
1045
+ const toBlock = min(endBlock, fromBlock + MAX_WINDOW_BLOCKS - 1n);
1046
+ const window = { fromBlock: String(fromBlock), toBlock: String(toBlock), ...finality };
1047
+ for (const [start, end] of logRanges(fromBlock, toBlock)) {
1048
+ for (const hash of await method.candidates(start, end)) {
1049
+ const block = await method.carries(hash);
1050
+ if (block !== void 0) return settled(hash, block);
1051
+ }
1052
+ }
1053
+ if (toBlock < endBlock) {
1054
+ return unknown("search_window_too_wide", { ...window, endBlock: String(endBlock) });
1055
+ }
1056
+ return unknown("used_without_record", { nonceUsed: true, ...window });
1057
+ }
1058
+ function eip3009(client, locator) {
1059
+ const { asset, from, to, value, nonce } = locator;
1060
+ return {
1061
+ endsAt: locator.validBefore,
1062
+ validAfter: locator.validAfter,
1063
+ used: (blockNumber) => client.readContract({
1064
+ address: asset,
1065
+ abi: eip3009ABI,
1066
+ functionName: "authorizationState",
1067
+ args: [from, nonce],
1068
+ ...blockNumber !== void 0 ? { blockNumber } : {}
1069
+ }),
1070
+ async candidates(fromBlock, toBlock) {
1071
+ const logs = await client.getLogs({
1072
+ address: asset,
1073
+ event: EVENTS[0],
1074
+ args: { authorizer: from, nonce },
1075
+ fromBlock,
1076
+ toBlock
1077
+ });
1078
+ return logs.map((log) => log.transactionHash);
1079
+ },
1080
+ async carries(hash) {
1081
+ const receipt = await receiptOf(client, hash);
1082
+ if (receipt?.status !== "success") return void 0;
1083
+ const logs = parseEventLogs({ abi: EVENTS, logs: receipt.logs }).filter(
1084
+ (log) => isAddressEqual(log.address, asset)
1085
+ );
1086
+ const used = logs.some(
1087
+ (log) => log.eventName === "AuthorizationUsed" && isAddressEqual(log.args.authorizer, from) && log.args.nonce.toLowerCase() === nonce.toLowerCase()
1088
+ );
1089
+ return used && logs.some((log) => isTransfer(log, from, to, value)) ? receipt.blockNumber : void 0;
1090
+ }
1091
+ };
1092
+ }
1093
+ function permit2(client, locator) {
1094
+ const { asset, owner, to, amount, nonce, proxy } = locator;
1095
+ return {
1096
+ // Permit2 accepts a transfer while the timestamp is at most the deadline
1097
+ endsAt: locator.deadline + 1n,
1098
+ validAfter: locator.validAfter,
1099
+ async used(blockNumber) {
1100
+ const bitmap = await client.readContract({
1101
+ address: PERMIT2_ADDRESS,
1102
+ abi: NONCE_BITMAP_ABI,
1103
+ functionName: "nonceBitmap",
1104
+ args: [owner, nonce >> 8n],
1105
+ ...blockNumber !== void 0 ? { blockNumber } : {}
1106
+ });
1107
+ return (bitmap >> (nonce & 0xffn) & 1n) === 1n;
1108
+ },
1109
+ // Match the nonce in proxy calldata to distinguish transfers with the
1110
+ // same owner, recipient and amount
1111
+ async candidates(fromBlock, toBlock) {
1112
+ const logs = await client.getLogs({
1113
+ address: asset,
1114
+ event: EVENTS[1],
1115
+ args: { from: owner, to },
1116
+ fromBlock,
1117
+ toBlock
1118
+ });
1119
+ return [...new Set(logs.map((log) => log.transactionHash))];
1120
+ },
1121
+ async carries(hash) {
1122
+ const receipt = await receiptOf(client, hash);
1123
+ if (receipt?.status !== "success" || !receipt.to || !isAddressEqual(receipt.to, proxy)) {
1124
+ return void 0;
1125
+ }
1126
+ const call = proxyCall((await client.getTransaction({ hash })).input);
1127
+ const named = call !== void 0 && isAddressEqual(call.owner, owner) && call.nonce === nonce && isAddressEqual(call.asset, asset) && isAddressEqual(call.to, to);
1128
+ const transferred = parseEventLogs({ abi: EVENTS, logs: receipt.logs }).some(
1129
+ (log) => isAddressEqual(log.address, asset) && isTransfer(log, owner, to, amount)
1130
+ );
1131
+ return named && transferred ? receipt.blockNumber : void 0;
1132
+ }
1133
+ };
1134
+ }
1135
+ function proxyCall(input) {
1136
+ let call;
1137
+ try {
1138
+ call = decodeProxyInput(input);
1139
+ } catch {
1140
+ return void 0;
1141
+ }
1142
+ const parts = call.functionName === "settle" ? call.args : call.functionName === "settleWithPermit" ? [call.args[1], call.args[2], call.args[3]] : void 0;
1143
+ if (parts === void 0) return void 0;
1144
+ const [permit, owner, witness] = parts;
1145
+ return { owner, nonce: permit.nonce, asset: permit.permitted.token, to: witness.to };
1146
+ }
1147
+ var decodeProxyInput = (data) => decodeFunctionData({ abi: x402ExactPermit2ProxyABI, data });
1148
+ function isTransfer(log, from, to, value) {
1149
+ return log.eventName === "Transfer" && isAddressEqual(log.args.from, from) && isAddressEqual(log.args.to, to) && log.args.value === value;
1150
+ }
1151
+ async function receiptOf(client, hash) {
1152
+ try {
1153
+ return await client.getTransactionReceipt({ hash });
1154
+ } catch (err) {
1155
+ if (err instanceof TransactionReceiptNotFoundError) return void 0;
1156
+ throw err;
1157
+ }
1158
+ }
1159
+ function logRanges(fromBlock, toBlock) {
1160
+ const ranges = [];
1161
+ for (let start = fromBlock; start <= toBlock; start += LOG_CHUNK_BLOCKS) {
1162
+ ranges.push([start, min(start + LOG_CHUNK_BLOCKS - 1n, toBlock)]);
1163
+ }
1164
+ return ranges;
1165
+ }
1166
+ async function firstBlockAt(client, seconds, finalized) {
1167
+ if (seconds > finalized.timestamp) return finalized.number + 1n;
1168
+ const timestampOf = async (blockNumber) => (await client.getBlock({ blockNumber })).timestamp;
1169
+ let low = 0n;
1170
+ let lowTime = await timestampOf(low);
1171
+ if (lowTime >= seconds) return 0n;
1172
+ let high = finalized.number;
1173
+ let highTime = finalized.timestamp;
1174
+ for (let step = 0; high - low > 1n; step++) {
1175
+ let middle = (low + high) / 2n;
1176
+ if (step % 2 === 0 && highTime > lowTime) {
1177
+ const guess = low + (seconds - lowTime) * (high - low) / (highTime - lowTime);
1178
+ middle = min(max(guess, low + 1n), high - 1n);
1179
+ }
1180
+ const timestamp = await timestampOf(middle);
1181
+ if (timestamp >= seconds) [high, highTime] = [middle, timestamp];
1182
+ else [low, lowTime] = [middle, timestamp];
1183
+ }
1184
+ return high;
1185
+ }
1186
+ function unknown(reason, evidence) {
1187
+ return { outcome: "unknown", reason, ...evidence !== void 0 ? { evidence } : {} };
1188
+ }
1189
+ var max = (a, b) => a > b ? a : b;
1190
+ var min = (a, b) => a < b ? a : b;
1191
+
1192
+ // src/payments/x402/reconcile/near.ts
1193
+ var UINT2 = /^\d{1,20}$/;
1194
+ var TX_HASH = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
1195
+ function parseNearLocator(locator) {
1196
+ const text = (key) => {
1197
+ const value = locator[key];
1198
+ return typeof value === "string" && value !== "" ? value : void 0;
1199
+ };
1200
+ const uint = (key) => {
1201
+ const value = text(key);
1202
+ return value !== void 0 && UINT2.test(value) ? value : void 0;
1203
+ };
1204
+ const [senderId, publicKey, asset, receiver] = [
1205
+ text("senderId"),
1206
+ text("publicKey"),
1207
+ text("asset"),
1208
+ text("receiver")
1209
+ ];
1210
+ const [nonce, maxBlockHeight, amount] = [uint("nonce"), uint("maxBlockHeight"), uint("amount")];
1211
+ const relayers = locator["relayers"] ?? [];
1212
+ if (!senderId || !publicKey || !asset || !receiver || !nonce || !maxBlockHeight || !amount) {
1213
+ return void 0;
1214
+ }
1215
+ if (!Array.isArray(relayers) || !relayers.every((id) => typeof id === "string")) {
1216
+ return void 0;
1217
+ }
1218
+ return {
1219
+ senderId,
1220
+ publicKey,
1221
+ nonce: BigInt(nonce),
1222
+ maxBlockHeight: BigInt(maxBlockHeight),
1223
+ asset,
1224
+ receiver,
1225
+ amount,
1226
+ relayers
1227
+ };
1228
+ }
1229
+ async function readNearEvidence(input) {
1230
+ const { rpc: rpc2, network, locator, attempt } = input;
1231
+ const status = await rpc2("status", []);
1232
+ const chainId = isRecord(status) ? status["chain_id"] : void 0;
1233
+ const expected = network.slice("near:".length);
1234
+ if (chainId !== expected) {
1235
+ return unknown("chain_mismatch", { chainId, expectedChainId: expected });
1236
+ }
1237
+ const reference = attempt.externalReference;
1238
+ if (reference !== void 0 && TX_HASH.test(reference)) {
1239
+ for (const relayer of locator.relayers) {
1240
+ const outcome = await txStatus(rpc2, reference, relayer);
1241
+ if (outcome === void 0) continue;
1242
+ if (outcome.final_execution_status !== "FINAL") {
1243
+ return unknown("not_final", { transactionHash: reference });
1244
+ }
1245
+ if (carries(outcome, locator)) {
1246
+ return {
1247
+ outcome: "settled",
1248
+ reason: "transfer_final",
1249
+ externalReference: reference,
1250
+ evidence: { transactionHash: reference, relayer }
1251
+ };
1252
+ }
1253
+ break;
1254
+ }
1255
+ }
1256
+ const block = await rpc2("block", { finality: "final" });
1257
+ const height = block.header?.height;
1258
+ if (typeof height !== "number" || !Number.isSafeInteger(height)) {
1259
+ throw new CommerceError("PAYMENT_PROVIDER_UNAVAILABLE", "block returned no height");
1260
+ }
1261
+ const finality = { finalBlock: String(height) };
1262
+ let key;
1263
+ try {
1264
+ key = await rpc2("query", {
1265
+ request_type: "view_access_key",
1266
+ block_id: height,
1267
+ account_id: locator.senderId,
1268
+ public_key: locator.publicKey
1269
+ });
1270
+ } catch (err) {
1271
+ if (rpcErrorName(err) === "UNKNOWN_ACCESS_KEY") return unknown("access_key_missing", finality);
1272
+ throw err;
1273
+ }
1274
+ if (typeof key.error === "string") return unknown("access_key_missing", finality);
1275
+ if (typeof key.nonce !== "number" || !Number.isSafeInteger(key.nonce)) {
1276
+ throw new CommerceError("PAYMENT_PROVIDER_UNAVAILABLE", "view_access_key returned no nonce");
1277
+ }
1278
+ const evidence = { keyNonce: String(key.nonce), ...finality };
1279
+ if (BigInt(key.nonce) >= locator.nonce) return unknown("used_without_record", evidence);
1280
+ if (BigInt(height) > locator.maxBlockHeight) {
1281
+ return { outcome: "not-settled", reason: "expired_unused", evidence };
1282
+ }
1283
+ return unknown("not_expired", { maxBlockHeight: String(locator.maxBlockHeight), ...evidence });
1284
+ }
1285
+ async function txStatus(rpc2, hash, sender) {
1286
+ try {
1287
+ return await rpc2("EXPERIMENTAL_tx_status", {
1288
+ tx_hash: hash,
1289
+ sender_account_id: sender,
1290
+ wait_until: "NONE"
1291
+ });
1292
+ } catch (err) {
1293
+ if (rpcErrorName(err) === "UNKNOWN_TRANSACTION") return void 0;
1294
+ throw err;
1295
+ }
1296
+ }
1297
+ function carries(outcome, locator) {
1298
+ const delegated = (outcome.transaction?.actions ?? []).some((action) => {
1299
+ const delegate = action.Delegate?.delegate_action;
1300
+ return delegate?.sender_id === locator.senderId && delegate.public_key === locator.publicKey && String(delegate.nonce) === String(locator.nonce);
1301
+ });
1302
+ const succeeded = new Set(
1303
+ (outcome.receipts_outcome ?? []).filter((entry) => isRecord(entry.outcome?.status) && "SuccessValue" in entry.outcome.status).map((entry) => entry.id)
1304
+ );
1305
+ const transferred = (outcome.receipts ?? []).some(
1306
+ (receipt) => receipt.receiver_id === locator.asset && receipt.predecessor_id === locator.senderId && succeeded.has(receipt.receipt_id) && (receipt.receipt?.Action?.actions ?? []).some((action) => {
1307
+ const call = action.FunctionCall;
1308
+ if (call?.method_name !== "ft_transfer" || typeof call.args !== "string") return false;
1309
+ const args = parseArgs(call.args);
1310
+ return args?.["receiver_id"] === locator.receiver && args["amount"] === locator.amount;
1311
+ })
1312
+ );
1313
+ return delegated && transferred;
1314
+ }
1315
+ function parseArgs(base64) {
1316
+ try {
1317
+ const args = JSON.parse(Buffer.from(base64, "base64").toString("utf8"));
1318
+ return isRecord(args) ? args : void 0;
1319
+ } catch {
1320
+ return void 0;
1321
+ }
1322
+ }
1323
+ function rpcErrorName(err) {
1324
+ const rpcError = isCommerceError(err) ? err.details?.["rpcError"] : void 0;
1325
+ return isRecord(rpcError) && isRecord(rpcError["cause"]) ? rpcError["cause"]["name"] : void 0;
1326
+ }
1327
+
1328
+ // src/payments/x402/reconcile/svm.ts
1329
+ var CLOCK_MARGIN_SECONDS2 = 900;
1330
+ var HISTORY_PAGE = 1e3;
1331
+ var MAX_HISTORY_PAGES = 5;
1332
+ var BASE58 = /^[1-9A-HJ-NP-Za-km-z]+$/;
1333
+ var MESSAGE_HASH = /^[A-Za-z0-9+/]{43}=$/;
1334
+ function parseSvmLocator(locator) {
1335
+ const { messageHash, recentBlockhash, payer } = locator;
1336
+ if (typeof messageHash !== "string" || !MESSAGE_HASH.test(messageHash)) return void 0;
1337
+ if (!isBase58(recentBlockhash, 32, 44)) return void 0;
1338
+ if (payer !== void 0 && !isBase58(payer, 32, 44)) return void 0;
1339
+ return { messageHash, recentBlockhash, payer };
1340
+ }
1341
+ async function readSvmEvidence(input) {
1342
+ const { rpc: rpc2, network, locator, attempt, messageHashOf } = input;
1343
+ const genesis = await rpc2("getGenesisHash", []);
1344
+ const served = `solana:${String(genesis).slice(0, 32)}`;
1345
+ if (served !== network) {
1346
+ return unknown("chain_mismatch", { network: served, expectedNetwork: network });
1347
+ }
1348
+ const carries2 = async (id) => {
1349
+ const landed = await rpc2("getTransaction", [
1350
+ id,
1351
+ { encoding: "base64", commitment: "finalized", maxSupportedTransactionVersion: 0 }
1352
+ ]);
1353
+ if (landed?.meta?.err !== null || typeof landed.slot !== "number") return void 0;
1354
+ const [wire] = Array.isArray(landed.transaction) ? landed.transaction : [];
1355
+ return typeof wire === "string" && messageHashOf(wire) === locator.messageHash ? landed.slot : void 0;
1356
+ };
1357
+ const settled = (id, slot) => ({
1358
+ outcome: "settled",
1359
+ reason: "transfer_final",
1360
+ externalReference: id,
1361
+ evidence: { transactionId: id, slot: String(slot) }
1362
+ });
1363
+ const reference = attempt.externalReference;
1364
+ if (reference !== void 0 && isBase58(reference, 64, 88)) {
1365
+ const slot = await carries2(reference);
1366
+ if (slot !== void 0) return settled(reference, slot);
1367
+ }
1368
+ if (locator.payer !== void 0) {
1369
+ const createdAt = Math.floor(Date.parse(attempt.createdAt) / 1e3);
1370
+ const from = createdAt - CLOCK_MARGIN_SECONDS2;
1371
+ const to = createdAt + CLOCK_MARGIN_SECONDS2;
1372
+ let before;
1373
+ search: for (let page = 0; ; page += 1) {
1374
+ if (page === MAX_HISTORY_PAGES) return unknown("history_too_long", { payer: locator.payer });
1375
+ const entries = await rpc2("getSignaturesForAddress", [
1376
+ locator.payer,
1377
+ {
1378
+ commitment: "finalized",
1379
+ limit: HISTORY_PAGE,
1380
+ ...before !== void 0 ? { before } : {}
1381
+ }
1382
+ ]);
1383
+ if (!Array.isArray(entries)) {
1384
+ throw new CommerceError(
1385
+ "PAYMENT_PROVIDER_UNAVAILABLE",
1386
+ "getSignaturesForAddress returned no list"
1387
+ );
1388
+ }
1389
+ for (const entry of entries) {
1390
+ if (typeof entry.signature !== "string") continue;
1391
+ before = entry.signature;
1392
+ const time = typeof entry.blockTime === "number" ? entry.blockTime : void 0;
1393
+ if (time !== void 0 && time < from) break search;
1394
+ if (entry.err !== null || time !== void 0 && time > to) continue;
1395
+ const slot = await carries2(entry.signature);
1396
+ if (slot !== void 0) return settled(entry.signature, slot);
1397
+ }
1398
+ if (entries.length < HISTORY_PAGE) break;
1399
+ }
1400
+ }
1401
+ const validity = await rpc2("isBlockhashValid", [
1402
+ locator.recentBlockhash,
1403
+ { commitment: "confirmed" }
1404
+ ]);
1405
+ const valid = isRecord(validity) ? validity["value"] : void 0;
1406
+ if (typeof valid !== "boolean") {
1407
+ throw new CommerceError("PAYMENT_PROVIDER_UNAVAILABLE", "isBlockhashValid returned no value");
1408
+ }
1409
+ return unknown(valid ? "not_expired" : "blockhash_expired", {
1410
+ payerSearched: locator.payer !== void 0
1411
+ });
1412
+ }
1413
+ function isBase58(value, minLength, maxLength) {
1414
+ return typeof value === "string" && value.length >= minLength && value.length <= maxLength && BASE58.test(value);
1415
+ }
1416
+
1417
+ // src/payments/x402/provider/reconcile.ts
1418
+ var RECONCILE_TIMEOUT_MS = 3e4;
1419
+ function createReconcile(ctx) {
1420
+ const clients = /* @__PURE__ */ new Map();
1421
+ const evmClient = (offer) => {
1422
+ let client = clients.get(offer);
1423
+ if (client === void 0) {
1424
+ client = createLocalPublicClient(offer.rpcUrl, RECONCILE_TIMEOUT_MS, offer.profile.chainId);
1425
+ clients.set(offer, client);
1426
+ }
1427
+ return client;
1428
+ };
1429
+ const rpc2 = (offer) => (method, params) => jsonRpc(offer.rpcUrl, method, params, RECONCILE_TIMEOUT_MS);
1430
+ const read = async (offer, evidence) => {
1431
+ try {
1432
+ return await evidence();
1433
+ } catch (err) {
1434
+ return unknown("rpc_error", { rpc: offer.rpcOrigin, error: redactedErrorText(err) });
1435
+ }
1436
+ };
1437
+ return async ({ attempt, locator }) => {
1438
+ if (locator === void 0) return unknown("no_locator");
1439
+ if (locator["v"] !== LOCATOR_VERSION) return unknown("unsupported_locator_version");
1440
+ const network = locator["network"];
1441
+ if (typeof network !== "string") return unknown("unsupported_family");
1442
+ const offerFor = (family) => ctx.offers.find(
1443
+ (candidate) => candidate.family === family && candidate.network === network
1444
+ );
1445
+ const notConfigured = unknown("network_not_configured", { network });
1446
+ if (network.startsWith("eip155:")) {
1447
+ const parsed = parseEvmLocator(locator);
1448
+ if (parsed === void 0) return unknown("invalid_locator");
1449
+ const offer = offerFor("evm");
1450
+ if (offer === void 0) return notConfigured;
1451
+ return read(
1452
+ offer,
1453
+ () => readEvmEvidence({
1454
+ client: evmClient(offer),
1455
+ chainId: offer.profile.chainId,
1456
+ locator: parsed,
1457
+ attempt
1458
+ })
1459
+ );
1460
+ }
1461
+ if (network.startsWith("solana:")) {
1462
+ const parsed = parseSvmLocator(locator);
1463
+ if (parsed === void 0) return unknown("invalid_locator");
1464
+ const offer = offerFor("svm");
1465
+ if (offer === void 0) return notConfigured;
1466
+ const { messageHashOf } = await ctx.svm();
1467
+ return read(
1468
+ offer,
1469
+ () => readSvmEvidence({ rpc: rpc2(offer), network, locator: parsed, attempt, messageHashOf })
1470
+ );
1471
+ }
1472
+ if (network.startsWith("near:")) {
1473
+ const parsed = parseNearLocator(locator);
1474
+ if (parsed === void 0) return unknown("invalid_locator");
1475
+ const offer = offerFor("near");
1476
+ if (offer === void 0) return notConfigured;
1477
+ return read(
1478
+ offer,
1479
+ () => readNearEvidence({ rpc: rpc2(offer), network, locator: parsed, attempt })
1480
+ );
1481
+ }
1482
+ return unknown("unsupported_family");
1483
+ };
1484
+ }
939
1485
 
940
1486
  // src/payments/x402/amount.ts
941
1487
  var DECIMAL_STRING_PATTERN = /^\d+(?:\.\d+)?$/;
@@ -1138,12 +1684,13 @@ function readTransfer(payload, offer) {
1138
1684
  from: getAddress(from2),
1139
1685
  nonce: nonce2
1140
1686
  }),
1687
+ locator: eip3009Locator(offer.network, offer.asset, authorization),
1141
1688
  recipientMismatch: "invalid_exact_evm_payload_recipient_mismatch",
1142
1689
  amountMismatch: "invalid_exact_evm_payload_authorization_value_mismatch"
1143
1690
  };
1144
1691
  }
1145
1692
  if (!isExactPermit2Payload(payload)) return "unsupported_scheme";
1146
- const { from, spender, permitted, witness, nonce } = payload.payload.permit2Authorization;
1693
+ const { from, spender, permitted, witness, nonce, deadline } = payload.payload.permit2Authorization;
1147
1694
  if (getAddress(spender) !== getAddress(x402ExactPermit2ProxyAddress)) {
1148
1695
  return "invalid_permit2_spender";
1149
1696
  }
@@ -1153,6 +1700,16 @@ function readTransfer(payload, offer) {
1153
1700
  to: getAddress(witness.to),
1154
1701
  value: permitted.amount,
1155
1702
  replayKey: computePermit2ReplayKey({ chainId, owner: getAddress(from), nonce }),
1703
+ locator: permit2Locator(offer.network, {
1704
+ asset: permitted.token,
1705
+ owner: from,
1706
+ to: witness.to,
1707
+ amount: permitted.amount,
1708
+ nonce,
1709
+ deadline,
1710
+ validAfter: witness.validAfter,
1711
+ proxy: spender
1712
+ }),
1156
1713
  recipientMismatch: "invalid_permit2_recipient_mismatch",
1157
1714
  amountMismatch: "permit2_amount_mismatch"
1158
1715
  };
@@ -1327,7 +1884,8 @@ function createSettle(ctx) {
1327
1884
  }
1328
1885
  return settle;
1329
1886
  }
1330
- function createVerify(ctx) {
1887
+ var RELAYER_GRACE_MS = 1e3;
1888
+ function createVerify(ctx, nearRelayers) {
1331
1889
  const { offersFor, clock, logger, svm, near } = ctx;
1332
1890
  async function verify(context) {
1333
1891
  const { requirement, submission } = context;
@@ -1370,11 +1928,13 @@ function createVerify(ctx) {
1370
1928
  }
1371
1929
  let transfer;
1372
1930
  let replayKey;
1931
+ let locator;
1373
1932
  let derivedPayer;
1374
1933
  if (offer.family === "svm") {
1375
- const identity = (await svm()).svmReplayKey(payload.payload, offer.network);
1376
- if (typeof identity === "string") return rejected(identity);
1377
- replayKey = identity.replayKey;
1934
+ const inspected = (await svm()).inspectSvmPayload(payload.payload, offer.network);
1935
+ if (typeof inspected === "string") return rejected(inspected);
1936
+ replayKey = inspected.replayKey;
1937
+ locator = inspected.locator;
1378
1938
  } else if (offer.family === "near") {
1379
1939
  const inspected = (await near()).inspectNearPayload(payload.payload, {
1380
1940
  network: offer.network,
@@ -1384,12 +1944,14 @@ function createVerify(ctx) {
1384
1944
  });
1385
1945
  if (typeof inspected === "string") return rejected(inspected);
1386
1946
  replayKey = inspected.replayKey;
1947
+ locator = inspected.locator;
1387
1948
  derivedPayer = inspected.payer;
1388
1949
  } else {
1389
1950
  const read = readTransfer(payload, offer);
1390
1951
  if (typeof read === "string") return rejected(read);
1391
1952
  transfer = read;
1392
1953
  replayKey = read.replayKey;
1954
+ locator = read.locator;
1393
1955
  derivedPayer = read.from;
1394
1956
  }
1395
1957
  if (payload.accepted.network !== offer.network) {
@@ -1419,6 +1981,7 @@ function createVerify(ctx) {
1419
1981
  return rejected(transfer.amountMismatch);
1420
1982
  }
1421
1983
  }
1984
+ const relayers = offer.family === "near" ? nearRelayers(offer) : void 0;
1422
1985
  const scope = offer.binding.open();
1423
1986
  let sdkResult;
1424
1987
  try {
@@ -1455,6 +2018,9 @@ function createVerify(ctx) {
1455
2018
  return rejected(sanitizeReason(sdkResult.invalidReason, "invalid_payment"));
1456
2019
  }
1457
2020
  const payer = derivedPayer ?? (sdkResult.payer !== void 0 && normalizeAddress(offer.profile, sdkResult.payer) ? sdkResult.payer : void 0);
2021
+ if (offer.family === "svm" && payer !== void 0) locator = { ...locator, payer };
2022
+ const relayerIds = relayers !== void 0 ? await withinGrace(relayers) : [];
2023
+ if (relayerIds.length > 0) locator = { ...locator, relayers: relayerIds };
1458
2024
  return {
1459
2025
  status: "verified",
1460
2026
  provider: "x402",
@@ -1464,10 +2030,26 @@ function createVerify(ctx) {
1464
2030
  currency: offerCurrency(offer, requirement.currency),
1465
2031
  network: payload.accepted.network,
1466
2032
  asset: offer.family === "evm" ? getAddress(requirements.asset) : offer.asset,
1467
- replayKey
2033
+ replayKey,
2034
+ metadata: { [RECONCILIATION_METADATA_KEY]: locator }
1468
2035
  };
1469
2036
  }
1470
2037
  return verify;
2038
+ async function withinGrace(relayers) {
2039
+ let timer;
2040
+ const late = new Promise((resolve) => {
2041
+ timer = setTimeout(() => resolve(void 0), RELAYER_GRACE_MS);
2042
+ timer.unref();
2043
+ });
2044
+ const ids = await Promise.race([relayers, late]).finally(() => clearTimeout(timer));
2045
+ if (ids === void 0) {
2046
+ logger.warn(
2047
+ { graceMs: RELAYER_GRACE_MS },
2048
+ "x402 verify(): /supported is slow; the NEAR locator names no relayer"
2049
+ );
2050
+ }
2051
+ return ids ?? [];
2052
+ }
1471
2053
  }
1472
2054
 
1473
2055
  // src/payments/x402/provider/index.ts
@@ -1536,8 +2118,8 @@ function createX402PaymentProvider(options) {
1536
2118
  "auth-capture scheme"
1537
2119
  ]
1538
2120
  };
1539
- const svmModule = hasSvm ? loadOptionalModule(() => import('./svm-QEUAUNPQ.js'), "Solana offers need @x402/svm and @solana/kit") : void 0;
1540
- const nearModule = hasNear ? loadOptionalModule(() => import('./near-D6C42VPE.js'), "NEAR offers need @x402/near") : void 0;
2121
+ const svmModule = hasSvm ? loadOptionalModule(() => import('./svm-KNC3PHMS.js'), "Solana offers need @x402/svm and @solana/kit") : void 0;
2122
+ const nearModule = hasNear ? loadOptionalModule(() => import('./near-FH7HPZV3.js'), "NEAR offers need @x402/near") : void 0;
1541
2123
  const svm = async () => {
1542
2124
  if (!svmModule)
1543
2125
  throw new CommerceError("INTERNAL_ERROR", "x402 provider: no Solana offer is configured");
@@ -1562,11 +2144,12 @@ function createX402PaymentProvider(options) {
1562
2144
  svm,
1563
2145
  near
1564
2146
  };
2147
+ const supported = createSupportedSource(ctx);
1565
2148
  const { createRequirement, selectRequirement } = createRequirementBuilders(
1566
2149
  ctx,
1567
- createSvmFeePayerSource(ctx)
2150
+ createSvmFeePayerSource(supported)
1568
2151
  );
1569
- const verify = createVerify(ctx);
2152
+ const verify = createVerify(ctx, createNearRelayerSource(supported, logger));
1570
2153
  const settle = createSettle(ctx);
1571
2154
  const health = createHealthCheck(ctx);
1572
2155
  return {
@@ -1577,6 +2160,7 @@ function createX402PaymentProvider(options) {
1577
2160
  ...severalOffers ? { selectRequirement } : {},
1578
2161
  verify,
1579
2162
  settle,
2163
+ reconcile: createReconcile(ctx),
1580
2164
  health,
1581
2165
  ...quotes ? {
1582
2166
  quote: {
@@ -1599,5 +2183,5 @@ function loadOptionalModule(load, missing) {
1599
2183
  }
1600
2184
 
1601
2185
  export { DEFAULT_IDS, chainIdFromCaip2, createX402PaymentProvider, parseCanonicalAmount };
1602
- //# sourceMappingURL=chunk-WUIAUAA7.js.map
1603
- //# sourceMappingURL=chunk-WUIAUAA7.js.map
2186
+ //# sourceMappingURL=chunk-FKQK5XZA.js.map
2187
+ //# sourceMappingURL=chunk-FKQK5XZA.js.map