x402z-facilitator 0.0.4 → 0.0.5

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.
package/README.md CHANGED
@@ -17,6 +17,8 @@ Set env vars:
17
17
  - `FACILITATOR_EVM_CHAIN_ID` (default 11155111)
18
18
  - `FACILITATOR_NETWORKS` (default `eip155:11155111`)
19
19
  - `FACILITATOR_PORT` (default 8040)
20
+ - `FACILITATOR_BATCHER_ADDRESS` (optional FHETokenBatcher address)
21
+ - `FACILITATOR_GAS_MULTIPLIER` (optional, e.g. `2` to double estimated gas)
20
22
 
21
23
  Then run:
22
24
 
@@ -29,3 +31,4 @@ node packages/x402z-facilitator/dist/bootstrap.js
29
31
 
30
32
  - This service receives `/verify` and `/settle` HTTP calls from the server.
31
33
  - It submits `confidentialTransferWithAuthorization` transactions on-chain.
34
+ - When `FACILITATOR_BATCHER_ADDRESS` is set, it uses the batcher contract and validates the per-item result from batch events.
package/dist/bootstrap.js CHANGED
@@ -83,6 +83,63 @@ function createFacilitatorService(config) {
83
83
  // src/scheme.ts
84
84
  var import_viem = require("viem");
85
85
  var import_x402z_shared = require("x402z-shared");
86
+ var batcherAbi = [
87
+ {
88
+ inputs: [
89
+ { internalType: "address", name: "token", type: "address" },
90
+ {
91
+ components: [
92
+ {
93
+ components: [
94
+ { internalType: "address", name: "holder", type: "address" },
95
+ { internalType: "address", name: "payee", type: "address" },
96
+ { internalType: "uint256", name: "maxClearAmount", type: "uint256" },
97
+ { internalType: "bytes32", name: "resourceHash", type: "bytes32" },
98
+ { internalType: "uint48", name: "validAfter", type: "uint48" },
99
+ { internalType: "uint48", name: "validBefore", type: "uint48" },
100
+ { internalType: "bytes32", name: "nonce", type: "bytes32" },
101
+ { internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
102
+ ],
103
+ internalType: "struct IFHEToken.ConfidentialPayment",
104
+ name: "p",
105
+ type: "tuple"
106
+ },
107
+ { internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
108
+ { internalType: "bytes", name: "inputProof", type: "bytes" },
109
+ { internalType: "bytes", name: "sig", type: "bytes" }
110
+ ],
111
+ internalType: "struct FHETokenBatcher.Request[]",
112
+ name: "requests",
113
+ type: "tuple[]"
114
+ }
115
+ ],
116
+ name: "batchConfidentialTransferWithAuthorization",
117
+ outputs: [
118
+ { internalType: "bool[]", name: "successes", type: "bool[]" },
119
+ { internalType: "bytes32[]", name: "transferredHandles", type: "bytes32[]" }
120
+ ],
121
+ stateMutability: "nonpayable",
122
+ type: "function"
123
+ },
124
+ {
125
+ anonymous: false,
126
+ inputs: [
127
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
128
+ { indexed: false, internalType: "bytes32", name: "transferredHandle", type: "bytes32" }
129
+ ],
130
+ name: "BatchItemSuccess",
131
+ type: "event"
132
+ },
133
+ {
134
+ anonymous: false,
135
+ inputs: [
136
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
137
+ { indexed: false, internalType: "bytes", name: "reason", type: "bytes" }
138
+ ],
139
+ name: "BatchItemFailure",
140
+ type: "event"
141
+ }
142
+ ];
86
143
  var ConfidentialEvmFacilitator = class {
87
144
  constructor(config) {
88
145
  this.config = config;
@@ -219,8 +276,25 @@ var ConfidentialEvmFacilitator = class {
219
276
  network: requirements.network
220
277
  };
221
278
  }
222
- const txHash = await this.config.signer.writeContract({
223
- address: (0, import_viem.getAddress)(requirements.asset),
279
+ const tokenAddress = (0, import_viem.getAddress)(requirements.asset);
280
+ const batcherAddress = this.config.batcherAddress ? (0, import_viem.getAddress)(this.config.batcherAddress) : void 0;
281
+ const txRequest = batcherAddress ? {
282
+ address: batcherAddress,
283
+ abi: batcherAbi,
284
+ functionName: "batchConfidentialTransferWithAuthorization",
285
+ args: [
286
+ tokenAddress,
287
+ [
288
+ {
289
+ p: confidentialPayload.authorization,
290
+ encryptedAmountInput: confidentialPayload.encryptedAmountInput,
291
+ inputProof: confidentialPayload.inputProof,
292
+ sig: confidentialPayload.signature
293
+ }
294
+ ]
295
+ ]
296
+ } : {
297
+ address: tokenAddress,
224
298
  abi: import_x402z_shared.confidentialTokenAbi,
225
299
  functionName: "confidentialTransferWithAuthorization",
226
300
  args: [
@@ -229,10 +303,20 @@ var ConfidentialEvmFacilitator = class {
229
303
  confidentialPayload.inputProof,
230
304
  confidentialPayload.signature
231
305
  ]
232
- });
306
+ };
307
+ if (process.env.X402Z_DEBUG === "1") {
308
+ console.debug("[x402z-facilitator] settle tx", {
309
+ batcherAddress,
310
+ tokenAddress,
311
+ functionName: txRequest.functionName,
312
+ to: txRequest.address
313
+ });
314
+ }
315
+ const txHash = await this.config.signer.writeContract(txRequest);
233
316
  if (process.env.X402Z_DEBUG === "1") {
234
317
  console.debug("[x402z-facilitator] tx submitted", txHash);
235
318
  }
319
+ let batchResult;
236
320
  if (this.waitForReceipt) {
237
321
  const receipt = await this.config.signer.waitForTransactionReceipt({
238
322
  hash: txHash
@@ -249,12 +333,90 @@ var ConfidentialEvmFacilitator = class {
249
333
  network: requirements.network
250
334
  };
251
335
  }
336
+ if (batcherAddress) {
337
+ let batchSucceeded = false;
338
+ const logs = "logs" in receipt ? receipt.logs ?? [] : [];
339
+ for (const log of logs) {
340
+ if (!log || !("address" in log) || !log.address) {
341
+ continue;
342
+ }
343
+ if (!(0, import_viem.isAddressEqual)((0, import_viem.getAddress)(log.address), batcherAddress)) {
344
+ continue;
345
+ }
346
+ const decoded = (0, import_viem.decodeEventLog)({
347
+ abi: batcherAbi,
348
+ data: log.data,
349
+ topics: log.topics
350
+ });
351
+ if (process.env.X402Z_DEBUG === "1") {
352
+ console.debug("[x402z-facilitator] batch log", decoded);
353
+ }
354
+ if (decoded.eventName === "BatchItemSuccess") {
355
+ const args = decoded.args;
356
+ if (Number(args.index) === 0) {
357
+ batchSucceeded = true;
358
+ batchResult = {
359
+ index: Number(args.index),
360
+ success: true,
361
+ transferredHandle: args.transferredHandle
362
+ };
363
+ break;
364
+ }
365
+ }
366
+ if (decoded.eventName === "BatchItemFailure") {
367
+ const args = decoded.args;
368
+ if (Number(args.index) === 0) {
369
+ batchResult = {
370
+ index: Number(args.index),
371
+ success: false,
372
+ failureReason: args.reason
373
+ };
374
+ if (process.env.X402Z_DEBUG === "1") {
375
+ try {
376
+ await this.config.signer.readContract({
377
+ address: tokenAddress,
378
+ abi: import_x402z_shared.confidentialTokenAbi,
379
+ functionName: "confidentialTransferWithAuthorization",
380
+ args: [
381
+ confidentialPayload.authorization,
382
+ confidentialPayload.encryptedAmountInput,
383
+ confidentialPayload.inputProof,
384
+ confidentialPayload.signature
385
+ ]
386
+ });
387
+ } catch (innerError) {
388
+ console.debug("[x402z-facilitator] batch fallback call failed", innerError);
389
+ }
390
+ }
391
+ return {
392
+ success: false,
393
+ errorReason: "settlement_failed",
394
+ payer: confidentialPayload.authorization.holder,
395
+ transaction: txHash,
396
+ network: requirements.network,
397
+ ...batchResult ? { batch: batchResult } : {}
398
+ };
399
+ }
400
+ }
401
+ }
402
+ if (!batchSucceeded) {
403
+ return {
404
+ success: false,
405
+ errorReason: "settlement_failed",
406
+ payer: confidentialPayload.authorization.holder,
407
+ transaction: txHash,
408
+ network: requirements.network,
409
+ ...batchResult ? { batch: batchResult } : {}
410
+ };
411
+ }
412
+ }
252
413
  }
253
414
  return {
254
415
  success: true,
255
416
  payer: confidentialPayload.authorization.holder,
256
417
  transaction: txHash,
257
- network: requirements.network
418
+ network: requirements.network,
419
+ ...batchResult ? { batch: batchResult } : {}
258
420
  };
259
421
  }
260
422
  };
@@ -273,9 +435,11 @@ function createConfidentialFacilitatorFromEnv() {
273
435
  const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
274
436
  const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
275
437
  const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
438
+ const batcherAddress = process.env.FACILITATOR_BATCHER_ADDRESS;
276
439
  const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
277
440
  const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
278
441
  const receiptPollingIntervalMs = process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS ? Number(process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS) : void 0;
442
+ const gasMultiplier = process.env.FACILITATOR_GAS_MULTIPLIER ? Number(process.env.FACILITATOR_GAS_MULTIPLIER) : void 0;
279
443
  const debugEnabled = process.env.X402Z_DEBUG === "1";
280
444
  const account = (0, import_accounts.privateKeyToAccount)(privateKey);
281
445
  if (debugEnabled) {
@@ -284,6 +448,8 @@ function createConfidentialFacilitatorFromEnv() {
284
448
  networks,
285
449
  rpcUrl,
286
450
  waitForReceipt,
451
+ batcherAddress,
452
+ gasMultiplier,
287
453
  receipt: {
288
454
  confirmations: receiptConfirmations,
289
455
  timeoutMs: receiptTimeoutMs,
@@ -310,11 +476,32 @@ function createConfidentialFacilitatorFromEnv() {
310
476
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
311
477
  }),
312
478
  verifyTypedData: (args) => client.verifyTypedData(args),
313
- writeContract: (args) => client.writeContract({
314
- ...args,
315
- args: args.args || []
316
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
317
- }),
479
+ writeContract: async (args) => {
480
+ let gas;
481
+ if (gasMultiplier && gasMultiplier > 0) {
482
+ try {
483
+ const estimated = await client.estimateContractGas({
484
+ ...args,
485
+ args: args.args || [],
486
+ account
487
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
488
+ });
489
+ const scale = BigInt(Math.round(gasMultiplier * 1e3));
490
+ const scaled = estimated * scale / 1000n;
491
+ gas = scaled > estimated ? scaled : estimated;
492
+ } catch (error) {
493
+ if (debugEnabled) {
494
+ console.debug("[x402z-facilitator] gas estimate failed", error);
495
+ }
496
+ }
497
+ }
498
+ return client.writeContract({
499
+ ...args,
500
+ args: args.args || [],
501
+ ...gas ? { gas } : {}
502
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
503
+ });
504
+ },
318
505
  sendTransaction: (args) => (
319
506
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
320
507
  client.sendTransaction({ to: args.to, data: args.data })
@@ -329,6 +516,7 @@ function createConfidentialFacilitatorFromEnv() {
329
516
  new ConfidentialEvmFacilitator({
330
517
  signer,
331
518
  waitForReceipt,
519
+ batcherAddress,
332
520
  receipt: {
333
521
  confirmations: receiptConfirmations,
334
522
  timeoutMs: receiptTimeoutMs,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createConfidentialFacilitatorFromEnv,
3
3
  startConfidentialFacilitator
4
- } from "./chunk-H6QEA2EB.mjs";
4
+ } from "./chunk-4UDK7NYX.mjs";
5
5
  export {
6
6
  createConfidentialFacilitatorFromEnv,
7
7
  startConfidentialFacilitator
@@ -0,0 +1,540 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/bootstrap.ts
9
+ import { x402Facilitator } from "@x402/core/facilitator";
10
+ import { toFacilitatorEvmSigner } from "@x402/evm";
11
+ import { createWalletClient, http, publicActions } from "viem";
12
+ import { privateKeyToAccount } from "viem/accounts";
13
+
14
+ // src/service.ts
15
+ import { createServer } from "http";
16
+ async function readJson(req) {
17
+ const chunks = [];
18
+ for await (const chunk of req) {
19
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
20
+ }
21
+ const body = Buffer.concat(chunks).toString("utf8");
22
+ return JSON.parse(body);
23
+ }
24
+ function sendJson(res, status, payload) {
25
+ res.writeHead(status, { "content-type": "application/json" });
26
+ res.end(JSON.stringify(payload));
27
+ }
28
+ function createFacilitatorService(config) {
29
+ const server = createServer(async (req, res) => {
30
+ try {
31
+ const method = req.method ?? "GET";
32
+ const url = req.url ?? "/";
33
+ if (process.env.X402Z_DEBUG === "1") {
34
+ console.debug(`[x402z-facilitator] ${method} ${url}`);
35
+ }
36
+ if (!req.url) {
37
+ sendJson(res, 404, { error: "not_found" });
38
+ return;
39
+ }
40
+ if (req.method === "GET" && req.url === "/supported") {
41
+ sendJson(res, 200, config.facilitator.getSupported());
42
+ return;
43
+ }
44
+ if (req.method === "POST" && req.url === "/verify") {
45
+ const body = await readJson(req);
46
+ const result = await config.facilitator.verify(body.paymentPayload, body.paymentRequirements);
47
+ sendJson(res, 200, result);
48
+ return;
49
+ }
50
+ if (req.method === "POST" && req.url === "/settle") {
51
+ const body = await readJson(req);
52
+ const result = await config.facilitator.settle(body.paymentPayload, body.paymentRequirements);
53
+ sendJson(res, 200, result);
54
+ return;
55
+ }
56
+ sendJson(res, 404, { error: "not_found" });
57
+ } catch (error) {
58
+ const message = error instanceof Error ? error.message : "internal_error";
59
+ sendJson(res, 500, { error: message });
60
+ }
61
+ });
62
+ return server;
63
+ }
64
+ function startFacilitatorService(config) {
65
+ const port = config.port ?? 8040;
66
+ const server = createFacilitatorService(config);
67
+ server.listen(port);
68
+ return { port };
69
+ }
70
+
71
+ // src/scheme.ts
72
+ import { decodeEventLog, getAddress, isAddressEqual } from "viem";
73
+ import {
74
+ confidentialPaymentTypes,
75
+ confidentialTokenAbi,
76
+ hashEncryptedAmountInput
77
+ } from "x402z-shared";
78
+ var batcherAbi = [
79
+ {
80
+ inputs: [
81
+ { internalType: "address", name: "token", type: "address" },
82
+ {
83
+ components: [
84
+ {
85
+ components: [
86
+ { internalType: "address", name: "holder", type: "address" },
87
+ { internalType: "address", name: "payee", type: "address" },
88
+ { internalType: "uint256", name: "maxClearAmount", type: "uint256" },
89
+ { internalType: "bytes32", name: "resourceHash", type: "bytes32" },
90
+ { internalType: "uint48", name: "validAfter", type: "uint48" },
91
+ { internalType: "uint48", name: "validBefore", type: "uint48" },
92
+ { internalType: "bytes32", name: "nonce", type: "bytes32" },
93
+ { internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
94
+ ],
95
+ internalType: "struct IFHEToken.ConfidentialPayment",
96
+ name: "p",
97
+ type: "tuple"
98
+ },
99
+ { internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
100
+ { internalType: "bytes", name: "inputProof", type: "bytes" },
101
+ { internalType: "bytes", name: "sig", type: "bytes" }
102
+ ],
103
+ internalType: "struct FHETokenBatcher.Request[]",
104
+ name: "requests",
105
+ type: "tuple[]"
106
+ }
107
+ ],
108
+ name: "batchConfidentialTransferWithAuthorization",
109
+ outputs: [
110
+ { internalType: "bool[]", name: "successes", type: "bool[]" },
111
+ { internalType: "bytes32[]", name: "transferredHandles", type: "bytes32[]" }
112
+ ],
113
+ stateMutability: "nonpayable",
114
+ type: "function"
115
+ },
116
+ {
117
+ anonymous: false,
118
+ inputs: [
119
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
120
+ { indexed: false, internalType: "bytes32", name: "transferredHandle", type: "bytes32" }
121
+ ],
122
+ name: "BatchItemSuccess",
123
+ type: "event"
124
+ },
125
+ {
126
+ anonymous: false,
127
+ inputs: [
128
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
129
+ { indexed: false, internalType: "bytes", name: "reason", type: "bytes" }
130
+ ],
131
+ name: "BatchItemFailure",
132
+ type: "event"
133
+ }
134
+ ];
135
+ var ConfidentialEvmFacilitator = class {
136
+ constructor(config) {
137
+ this.config = config;
138
+ this.scheme = "erc7984-mind-v1";
139
+ this.caipFamily = "eip155:*";
140
+ this.hashFn = config.hashEncryptedAmountInput ?? hashEncryptedAmountInput;
141
+ this.clock = config.clock ?? (() => Math.floor(Date.now() / 1e3));
142
+ this.checkUsedNonces = config.checkUsedNonces ?? true;
143
+ this.waitForReceipt = config.waitForReceipt ?? true;
144
+ this.receiptOptions = config.receipt;
145
+ }
146
+ getExtra(_) {
147
+ return void 0;
148
+ }
149
+ getSigners(_) {
150
+ return [...this.config.signer.getAddresses()];
151
+ }
152
+ async verify(payload, requirements) {
153
+ const confidentialPayload = payload.payload;
154
+ if (payload.accepted.scheme !== this.scheme || requirements.scheme !== this.scheme) {
155
+ return {
156
+ isValid: false,
157
+ invalidReason: "unsupported_scheme",
158
+ payer: confidentialPayload?.authorization?.holder
159
+ };
160
+ }
161
+ if (payload.accepted.network !== requirements.network) {
162
+ return {
163
+ isValid: false,
164
+ invalidReason: "network_mismatch",
165
+ payer: confidentialPayload.authorization.holder
166
+ };
167
+ }
168
+ const extra = requirements.extra;
169
+ const eip712 = extra?.eip712;
170
+ if (!eip712?.name || !eip712?.version) {
171
+ return {
172
+ isValid: false,
173
+ invalidReason: "missing_eip712_domain",
174
+ payer: confidentialPayload.authorization.holder
175
+ };
176
+ }
177
+ const now = this.clock();
178
+ const validAfter = Number(confidentialPayload.authorization.validAfter);
179
+ const validBefore = Number(confidentialPayload.authorization.validBefore);
180
+ if (Number.isNaN(validAfter) || Number.isNaN(validBefore)) {
181
+ return {
182
+ isValid: false,
183
+ invalidReason: "invalid_validity_window",
184
+ payer: confidentialPayload.authorization.holder
185
+ };
186
+ }
187
+ if (now < validAfter || now > validBefore) {
188
+ return {
189
+ isValid: false,
190
+ invalidReason: "authorization_expired",
191
+ payer: confidentialPayload.authorization.holder
192
+ };
193
+ }
194
+ if (!isAddressEqual(getAddress(confidentialPayload.authorization.payee), getAddress(requirements.payTo))) {
195
+ return {
196
+ isValid: false,
197
+ invalidReason: "recipient_mismatch",
198
+ payer: confidentialPayload.authorization.holder
199
+ };
200
+ }
201
+ const computedHash = this.hashFn(confidentialPayload.encryptedAmountInput);
202
+ if (computedHash !== confidentialPayload.authorization.encryptedAmountHash) {
203
+ return {
204
+ isValid: false,
205
+ invalidReason: "encrypted_amount_mismatch",
206
+ payer: confidentialPayload.authorization.holder
207
+ };
208
+ }
209
+ const chainId = parseInt(requirements.network.split(":")[1]);
210
+ const isValidSignature = await this.config.signer.verifyTypedData({
211
+ address: confidentialPayload.authorization.holder,
212
+ domain: {
213
+ name: eip712.name,
214
+ version: eip712.version,
215
+ chainId,
216
+ verifyingContract: getAddress(requirements.asset)
217
+ },
218
+ types: confidentialPaymentTypes,
219
+ primaryType: "ConfidentialPayment",
220
+ message: {
221
+ holder: getAddress(confidentialPayload.authorization.holder),
222
+ payee: getAddress(confidentialPayload.authorization.payee),
223
+ maxClearAmount: BigInt(confidentialPayload.authorization.maxClearAmount),
224
+ resourceHash: confidentialPayload.authorization.resourceHash,
225
+ validAfter: BigInt(confidentialPayload.authorization.validAfter),
226
+ validBefore: BigInt(confidentialPayload.authorization.validBefore),
227
+ nonce: confidentialPayload.authorization.nonce,
228
+ encryptedAmountHash: confidentialPayload.authorization.encryptedAmountHash
229
+ },
230
+ signature: confidentialPayload.signature
231
+ });
232
+ if (!isValidSignature) {
233
+ return {
234
+ isValid: false,
235
+ invalidReason: "invalid_signature",
236
+ payer: confidentialPayload.authorization.holder
237
+ };
238
+ }
239
+ if (this.checkUsedNonces) {
240
+ const used = await this.config.signer.readContract({
241
+ address: getAddress(requirements.asset),
242
+ abi: confidentialTokenAbi,
243
+ functionName: "usedNonces",
244
+ args: [confidentialPayload.authorization.holder, confidentialPayload.authorization.nonce]
245
+ });
246
+ if (used) {
247
+ return {
248
+ isValid: false,
249
+ invalidReason: "nonce_already_used",
250
+ payer: confidentialPayload.authorization.holder
251
+ };
252
+ }
253
+ }
254
+ return {
255
+ isValid: true,
256
+ payer: confidentialPayload.authorization.holder
257
+ };
258
+ }
259
+ async settle(payload, requirements) {
260
+ const valid = await this.verify(payload, requirements);
261
+ const confidentialPayload = payload.payload;
262
+ if (!valid.isValid) {
263
+ return {
264
+ success: false,
265
+ errorReason: valid.invalidReason ?? "invalid_payment",
266
+ payer: confidentialPayload.authorization.holder,
267
+ transaction: "",
268
+ network: requirements.network
269
+ };
270
+ }
271
+ const tokenAddress = getAddress(requirements.asset);
272
+ const batcherAddress = this.config.batcherAddress ? getAddress(this.config.batcherAddress) : void 0;
273
+ const txRequest = batcherAddress ? {
274
+ address: batcherAddress,
275
+ abi: batcherAbi,
276
+ functionName: "batchConfidentialTransferWithAuthorization",
277
+ args: [
278
+ tokenAddress,
279
+ [
280
+ {
281
+ p: confidentialPayload.authorization,
282
+ encryptedAmountInput: confidentialPayload.encryptedAmountInput,
283
+ inputProof: confidentialPayload.inputProof,
284
+ sig: confidentialPayload.signature
285
+ }
286
+ ]
287
+ ]
288
+ } : {
289
+ address: tokenAddress,
290
+ abi: confidentialTokenAbi,
291
+ functionName: "confidentialTransferWithAuthorization",
292
+ args: [
293
+ confidentialPayload.authorization,
294
+ confidentialPayload.encryptedAmountInput,
295
+ confidentialPayload.inputProof,
296
+ confidentialPayload.signature
297
+ ]
298
+ };
299
+ if (process.env.X402Z_DEBUG === "1") {
300
+ console.debug("[x402z-facilitator] settle tx", {
301
+ batcherAddress,
302
+ tokenAddress,
303
+ functionName: txRequest.functionName,
304
+ to: txRequest.address
305
+ });
306
+ }
307
+ const txHash = await this.config.signer.writeContract(txRequest);
308
+ if (process.env.X402Z_DEBUG === "1") {
309
+ console.debug("[x402z-facilitator] tx submitted", txHash);
310
+ }
311
+ let batchResult;
312
+ if (this.waitForReceipt) {
313
+ const receipt = await this.config.signer.waitForTransactionReceipt({
314
+ hash: txHash
315
+ });
316
+ if (process.env.X402Z_DEBUG === "1") {
317
+ console.debug("[x402z-facilitator] tx receipt", receipt);
318
+ }
319
+ if (receipt.status !== "success") {
320
+ return {
321
+ success: false,
322
+ errorReason: "settlement_failed",
323
+ payer: confidentialPayload.authorization.holder,
324
+ transaction: txHash,
325
+ network: requirements.network
326
+ };
327
+ }
328
+ if (batcherAddress) {
329
+ let batchSucceeded = false;
330
+ const logs = "logs" in receipt ? receipt.logs ?? [] : [];
331
+ for (const log of logs) {
332
+ if (!log || !("address" in log) || !log.address) {
333
+ continue;
334
+ }
335
+ if (!isAddressEqual(getAddress(log.address), batcherAddress)) {
336
+ continue;
337
+ }
338
+ const decoded = decodeEventLog({
339
+ abi: batcherAbi,
340
+ data: log.data,
341
+ topics: log.topics
342
+ });
343
+ if (process.env.X402Z_DEBUG === "1") {
344
+ console.debug("[x402z-facilitator] batch log", decoded);
345
+ }
346
+ if (decoded.eventName === "BatchItemSuccess") {
347
+ const args = decoded.args;
348
+ if (Number(args.index) === 0) {
349
+ batchSucceeded = true;
350
+ batchResult = {
351
+ index: Number(args.index),
352
+ success: true,
353
+ transferredHandle: args.transferredHandle
354
+ };
355
+ break;
356
+ }
357
+ }
358
+ if (decoded.eventName === "BatchItemFailure") {
359
+ const args = decoded.args;
360
+ if (Number(args.index) === 0) {
361
+ batchResult = {
362
+ index: Number(args.index),
363
+ success: false,
364
+ failureReason: args.reason
365
+ };
366
+ if (process.env.X402Z_DEBUG === "1") {
367
+ try {
368
+ await this.config.signer.readContract({
369
+ address: tokenAddress,
370
+ abi: confidentialTokenAbi,
371
+ functionName: "confidentialTransferWithAuthorization",
372
+ args: [
373
+ confidentialPayload.authorization,
374
+ confidentialPayload.encryptedAmountInput,
375
+ confidentialPayload.inputProof,
376
+ confidentialPayload.signature
377
+ ]
378
+ });
379
+ } catch (innerError) {
380
+ console.debug("[x402z-facilitator] batch fallback call failed", innerError);
381
+ }
382
+ }
383
+ return {
384
+ success: false,
385
+ errorReason: "settlement_failed",
386
+ payer: confidentialPayload.authorization.holder,
387
+ transaction: txHash,
388
+ network: requirements.network,
389
+ ...batchResult ? { batch: batchResult } : {}
390
+ };
391
+ }
392
+ }
393
+ }
394
+ if (!batchSucceeded) {
395
+ return {
396
+ success: false,
397
+ errorReason: "settlement_failed",
398
+ payer: confidentialPayload.authorization.holder,
399
+ transaction: txHash,
400
+ network: requirements.network,
401
+ ...batchResult ? { batch: batchResult } : {}
402
+ };
403
+ }
404
+ }
405
+ }
406
+ return {
407
+ success: true,
408
+ payer: confidentialPayload.authorization.holder,
409
+ transaction: txHash,
410
+ network: requirements.network,
411
+ ...batchResult ? { batch: batchResult } : {}
412
+ };
413
+ }
414
+ };
415
+
416
+ // src/bootstrap.ts
417
+ function requireEnv(key) {
418
+ const value = process.env[key];
419
+ if (!value) {
420
+ throw new Error(`Missing required env var: ${key}`);
421
+ }
422
+ return value;
423
+ }
424
+ function createConfidentialFacilitatorFromEnv() {
425
+ const privateKey = requireEnv("FACILITATOR_EVM_PRIVATE_KEY");
426
+ const chainId = Number(process.env.FACILITATOR_EVM_CHAIN_ID ?? "11155111");
427
+ const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
428
+ const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
429
+ const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
430
+ const batcherAddress = process.env.FACILITATOR_BATCHER_ADDRESS;
431
+ const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
432
+ const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
433
+ const receiptPollingIntervalMs = process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS ? Number(process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS) : void 0;
434
+ const gasMultiplier = process.env.FACILITATOR_GAS_MULTIPLIER ? Number(process.env.FACILITATOR_GAS_MULTIPLIER) : void 0;
435
+ const debugEnabled = process.env.X402Z_DEBUG === "1";
436
+ const account = privateKeyToAccount(privateKey);
437
+ if (debugEnabled) {
438
+ console.debug("[x402z-facilitator] config", {
439
+ chainId,
440
+ networks,
441
+ rpcUrl,
442
+ waitForReceipt,
443
+ batcherAddress,
444
+ gasMultiplier,
445
+ receipt: {
446
+ confirmations: receiptConfirmations,
447
+ timeoutMs: receiptTimeoutMs,
448
+ pollingIntervalMs: receiptPollingIntervalMs
449
+ },
450
+ address: account.address
451
+ });
452
+ }
453
+ const client = createWalletClient({
454
+ account,
455
+ chain: {
456
+ id: chainId,
457
+ name: "custom",
458
+ nativeCurrency: { name: "native", symbol: "NATIVE", decimals: 18 },
459
+ rpcUrls: { default: { http: [rpcUrl] } }
460
+ },
461
+ transport: http(rpcUrl)
462
+ }).extend(publicActions);
463
+ const signer = toFacilitatorEvmSigner({
464
+ address: account.address,
465
+ readContract: (args) => client.readContract({
466
+ ...args,
467
+ args: args.args || []
468
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
469
+ }),
470
+ verifyTypedData: (args) => client.verifyTypedData(args),
471
+ writeContract: async (args) => {
472
+ let gas;
473
+ if (gasMultiplier && gasMultiplier > 0) {
474
+ try {
475
+ const estimated = await client.estimateContractGas({
476
+ ...args,
477
+ args: args.args || [],
478
+ account
479
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
480
+ });
481
+ const scale = BigInt(Math.round(gasMultiplier * 1e3));
482
+ const scaled = estimated * scale / 1000n;
483
+ gas = scaled > estimated ? scaled : estimated;
484
+ } catch (error) {
485
+ if (debugEnabled) {
486
+ console.debug("[x402z-facilitator] gas estimate failed", error);
487
+ }
488
+ }
489
+ }
490
+ return client.writeContract({
491
+ ...args,
492
+ args: args.args || [],
493
+ ...gas ? { gas } : {}
494
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
495
+ });
496
+ },
497
+ sendTransaction: (args) => (
498
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
499
+ client.sendTransaction({ to: args.to, data: args.data })
500
+ ),
501
+ waitForTransactionReceipt: (args) => client.waitForTransactionReceipt(args),
502
+ getCode: (args) => client.getCode(args)
503
+ });
504
+ const facilitator = new x402Facilitator();
505
+ for (const network of networks) {
506
+ facilitator.register(
507
+ network,
508
+ new ConfidentialEvmFacilitator({
509
+ signer,
510
+ waitForReceipt,
511
+ batcherAddress,
512
+ receipt: {
513
+ confirmations: receiptConfirmations,
514
+ timeoutMs: receiptTimeoutMs,
515
+ pollingIntervalMs: receiptPollingIntervalMs
516
+ }
517
+ })
518
+ );
519
+ }
520
+ return facilitator;
521
+ }
522
+ function startConfidentialFacilitator() {
523
+ const facilitator = createConfidentialFacilitatorFromEnv();
524
+ const port = Number(process.env.FACILITATOR_PORT ?? "8040");
525
+ const server = createFacilitatorService({ facilitator, port });
526
+ server.listen(port);
527
+ return { port };
528
+ }
529
+ if (__require.main === module) {
530
+ const { port } = startConfidentialFacilitator();
531
+ console.log(`Confidential facilitator listening on :${port}`);
532
+ }
533
+
534
+ export {
535
+ createFacilitatorService,
536
+ startFacilitatorService,
537
+ ConfidentialEvmFacilitator,
538
+ createConfidentialFacilitatorFromEnv,
539
+ startConfidentialFacilitator
540
+ };
package/dist/index.d.mts CHANGED
@@ -7,6 +7,7 @@ export { startConfidentialFacilitator } from './bootstrap.mjs';
7
7
 
8
8
  type ConfidentialFacilitatorConfig = {
9
9
  signer: FacilitatorEvmSigner;
10
+ batcherAddress?: `0x${string}`;
10
11
  hashEncryptedAmountInput?: (encryptedAmountInput: `0x${string}`) => `0x${string}`;
11
12
  checkUsedNonces?: boolean;
12
13
  clock?: () => number;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { startConfidentialFacilitator } from './bootstrap.js';
7
7
 
8
8
  type ConfidentialFacilitatorConfig = {
9
9
  signer: FacilitatorEvmSigner;
10
+ batcherAddress?: `0x${string}`;
10
11
  hashEncryptedAmountInput?: (encryptedAmountInput: `0x${string}`) => `0x${string}`;
11
12
  checkUsedNonces?: boolean;
12
13
  clock?: () => number;
package/dist/index.js CHANGED
@@ -31,6 +31,63 @@ module.exports = __toCommonJS(index_exports);
31
31
  // src/scheme.ts
32
32
  var import_viem = require("viem");
33
33
  var import_x402z_shared = require("x402z-shared");
34
+ var batcherAbi = [
35
+ {
36
+ inputs: [
37
+ { internalType: "address", name: "token", type: "address" },
38
+ {
39
+ components: [
40
+ {
41
+ components: [
42
+ { internalType: "address", name: "holder", type: "address" },
43
+ { internalType: "address", name: "payee", type: "address" },
44
+ { internalType: "uint256", name: "maxClearAmount", type: "uint256" },
45
+ { internalType: "bytes32", name: "resourceHash", type: "bytes32" },
46
+ { internalType: "uint48", name: "validAfter", type: "uint48" },
47
+ { internalType: "uint48", name: "validBefore", type: "uint48" },
48
+ { internalType: "bytes32", name: "nonce", type: "bytes32" },
49
+ { internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
50
+ ],
51
+ internalType: "struct IFHEToken.ConfidentialPayment",
52
+ name: "p",
53
+ type: "tuple"
54
+ },
55
+ { internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
56
+ { internalType: "bytes", name: "inputProof", type: "bytes" },
57
+ { internalType: "bytes", name: "sig", type: "bytes" }
58
+ ],
59
+ internalType: "struct FHETokenBatcher.Request[]",
60
+ name: "requests",
61
+ type: "tuple[]"
62
+ }
63
+ ],
64
+ name: "batchConfidentialTransferWithAuthorization",
65
+ outputs: [
66
+ { internalType: "bool[]", name: "successes", type: "bool[]" },
67
+ { internalType: "bytes32[]", name: "transferredHandles", type: "bytes32[]" }
68
+ ],
69
+ stateMutability: "nonpayable",
70
+ type: "function"
71
+ },
72
+ {
73
+ anonymous: false,
74
+ inputs: [
75
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
76
+ { indexed: false, internalType: "bytes32", name: "transferredHandle", type: "bytes32" }
77
+ ],
78
+ name: "BatchItemSuccess",
79
+ type: "event"
80
+ },
81
+ {
82
+ anonymous: false,
83
+ inputs: [
84
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
85
+ { indexed: false, internalType: "bytes", name: "reason", type: "bytes" }
86
+ ],
87
+ name: "BatchItemFailure",
88
+ type: "event"
89
+ }
90
+ ];
34
91
  var ConfidentialEvmFacilitator = class {
35
92
  constructor(config) {
36
93
  this.config = config;
@@ -167,8 +224,25 @@ var ConfidentialEvmFacilitator = class {
167
224
  network: requirements.network
168
225
  };
169
226
  }
170
- const txHash = await this.config.signer.writeContract({
171
- address: (0, import_viem.getAddress)(requirements.asset),
227
+ const tokenAddress = (0, import_viem.getAddress)(requirements.asset);
228
+ const batcherAddress = this.config.batcherAddress ? (0, import_viem.getAddress)(this.config.batcherAddress) : void 0;
229
+ const txRequest = batcherAddress ? {
230
+ address: batcherAddress,
231
+ abi: batcherAbi,
232
+ functionName: "batchConfidentialTransferWithAuthorization",
233
+ args: [
234
+ tokenAddress,
235
+ [
236
+ {
237
+ p: confidentialPayload.authorization,
238
+ encryptedAmountInput: confidentialPayload.encryptedAmountInput,
239
+ inputProof: confidentialPayload.inputProof,
240
+ sig: confidentialPayload.signature
241
+ }
242
+ ]
243
+ ]
244
+ } : {
245
+ address: tokenAddress,
172
246
  abi: import_x402z_shared.confidentialTokenAbi,
173
247
  functionName: "confidentialTransferWithAuthorization",
174
248
  args: [
@@ -177,10 +251,20 @@ var ConfidentialEvmFacilitator = class {
177
251
  confidentialPayload.inputProof,
178
252
  confidentialPayload.signature
179
253
  ]
180
- });
254
+ };
255
+ if (process.env.X402Z_DEBUG === "1") {
256
+ console.debug("[x402z-facilitator] settle tx", {
257
+ batcherAddress,
258
+ tokenAddress,
259
+ functionName: txRequest.functionName,
260
+ to: txRequest.address
261
+ });
262
+ }
263
+ const txHash = await this.config.signer.writeContract(txRequest);
181
264
  if (process.env.X402Z_DEBUG === "1") {
182
265
  console.debug("[x402z-facilitator] tx submitted", txHash);
183
266
  }
267
+ let batchResult;
184
268
  if (this.waitForReceipt) {
185
269
  const receipt = await this.config.signer.waitForTransactionReceipt({
186
270
  hash: txHash
@@ -197,12 +281,90 @@ var ConfidentialEvmFacilitator = class {
197
281
  network: requirements.network
198
282
  };
199
283
  }
284
+ if (batcherAddress) {
285
+ let batchSucceeded = false;
286
+ const logs = "logs" in receipt ? receipt.logs ?? [] : [];
287
+ for (const log of logs) {
288
+ if (!log || !("address" in log) || !log.address) {
289
+ continue;
290
+ }
291
+ if (!(0, import_viem.isAddressEqual)((0, import_viem.getAddress)(log.address), batcherAddress)) {
292
+ continue;
293
+ }
294
+ const decoded = (0, import_viem.decodeEventLog)({
295
+ abi: batcherAbi,
296
+ data: log.data,
297
+ topics: log.topics
298
+ });
299
+ if (process.env.X402Z_DEBUG === "1") {
300
+ console.debug("[x402z-facilitator] batch log", decoded);
301
+ }
302
+ if (decoded.eventName === "BatchItemSuccess") {
303
+ const args = decoded.args;
304
+ if (Number(args.index) === 0) {
305
+ batchSucceeded = true;
306
+ batchResult = {
307
+ index: Number(args.index),
308
+ success: true,
309
+ transferredHandle: args.transferredHandle
310
+ };
311
+ break;
312
+ }
313
+ }
314
+ if (decoded.eventName === "BatchItemFailure") {
315
+ const args = decoded.args;
316
+ if (Number(args.index) === 0) {
317
+ batchResult = {
318
+ index: Number(args.index),
319
+ success: false,
320
+ failureReason: args.reason
321
+ };
322
+ if (process.env.X402Z_DEBUG === "1") {
323
+ try {
324
+ await this.config.signer.readContract({
325
+ address: tokenAddress,
326
+ abi: import_x402z_shared.confidentialTokenAbi,
327
+ functionName: "confidentialTransferWithAuthorization",
328
+ args: [
329
+ confidentialPayload.authorization,
330
+ confidentialPayload.encryptedAmountInput,
331
+ confidentialPayload.inputProof,
332
+ confidentialPayload.signature
333
+ ]
334
+ });
335
+ } catch (innerError) {
336
+ console.debug("[x402z-facilitator] batch fallback call failed", innerError);
337
+ }
338
+ }
339
+ return {
340
+ success: false,
341
+ errorReason: "settlement_failed",
342
+ payer: confidentialPayload.authorization.holder,
343
+ transaction: txHash,
344
+ network: requirements.network,
345
+ ...batchResult ? { batch: batchResult } : {}
346
+ };
347
+ }
348
+ }
349
+ }
350
+ if (!batchSucceeded) {
351
+ return {
352
+ success: false,
353
+ errorReason: "settlement_failed",
354
+ payer: confidentialPayload.authorization.holder,
355
+ transaction: txHash,
356
+ network: requirements.network,
357
+ ...batchResult ? { batch: batchResult } : {}
358
+ };
359
+ }
360
+ }
200
361
  }
201
362
  return {
202
363
  success: true,
203
364
  payer: confidentialPayload.authorization.holder,
204
365
  transaction: txHash,
205
- network: requirements.network
366
+ network: requirements.network,
367
+ ...batchResult ? { batch: batchResult } : {}
206
368
  };
207
369
  }
208
370
  };
@@ -292,9 +454,11 @@ function createConfidentialFacilitatorFromEnv() {
292
454
  const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
293
455
  const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
294
456
  const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
457
+ const batcherAddress = process.env.FACILITATOR_BATCHER_ADDRESS;
295
458
  const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
296
459
  const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
297
460
  const receiptPollingIntervalMs = process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS ? Number(process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS) : void 0;
461
+ const gasMultiplier = process.env.FACILITATOR_GAS_MULTIPLIER ? Number(process.env.FACILITATOR_GAS_MULTIPLIER) : void 0;
298
462
  const debugEnabled = process.env.X402Z_DEBUG === "1";
299
463
  const account = (0, import_accounts.privateKeyToAccount)(privateKey);
300
464
  if (debugEnabled) {
@@ -303,6 +467,8 @@ function createConfidentialFacilitatorFromEnv() {
303
467
  networks,
304
468
  rpcUrl,
305
469
  waitForReceipt,
470
+ batcherAddress,
471
+ gasMultiplier,
306
472
  receipt: {
307
473
  confirmations: receiptConfirmations,
308
474
  timeoutMs: receiptTimeoutMs,
@@ -329,11 +495,32 @@ function createConfidentialFacilitatorFromEnv() {
329
495
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
330
496
  }),
331
497
  verifyTypedData: (args) => client.verifyTypedData(args),
332
- writeContract: (args) => client.writeContract({
333
- ...args,
334
- args: args.args || []
335
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
336
- }),
498
+ writeContract: async (args) => {
499
+ let gas;
500
+ if (gasMultiplier && gasMultiplier > 0) {
501
+ try {
502
+ const estimated = await client.estimateContractGas({
503
+ ...args,
504
+ args: args.args || [],
505
+ account
506
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
507
+ });
508
+ const scale = BigInt(Math.round(gasMultiplier * 1e3));
509
+ const scaled = estimated * scale / 1000n;
510
+ gas = scaled > estimated ? scaled : estimated;
511
+ } catch (error) {
512
+ if (debugEnabled) {
513
+ console.debug("[x402z-facilitator] gas estimate failed", error);
514
+ }
515
+ }
516
+ }
517
+ return client.writeContract({
518
+ ...args,
519
+ args: args.args || [],
520
+ ...gas ? { gas } : {}
521
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
522
+ });
523
+ },
337
524
  sendTransaction: (args) => (
338
525
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
339
526
  client.sendTransaction({ to: args.to, data: args.data })
@@ -348,6 +535,7 @@ function createConfidentialFacilitatorFromEnv() {
348
535
  new ConfidentialEvmFacilitator({
349
536
  signer,
350
537
  waitForReceipt,
538
+ batcherAddress,
351
539
  receipt: {
352
540
  confirmations: receiptConfirmations,
353
541
  timeoutMs: receiptTimeoutMs,
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createFacilitatorService,
4
4
  startConfidentialFacilitator,
5
5
  startFacilitatorService
6
- } from "./chunk-H6QEA2EB.mjs";
6
+ } from "./chunk-4UDK7NYX.mjs";
7
7
 
8
8
  // src/register.ts
9
9
  function registerConfidentialEvmScheme(facilitator, config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402z-facilitator",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  "@x402/core": "^2.0.0",
12
12
  "@x402/evm": "^2.0.0",
13
13
  "viem": "^2.39.3",
14
- "x402z-shared": "0.0.3"
14
+ "x402z-shared": "0.0.4"
15
15
  },
16
16
  "devDependencies": {
17
17
  "jest": "^29.7.0",