x402z-facilitator 0.0.3 → 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 +3 -0
- package/dist/bootstrap.js +197 -9
- package/dist/bootstrap.mjs +3 -100
- package/dist/chunk-4UDK7NYX.mjs +540 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +290 -4
- package/dist/index.mjs +3 -1
- package/package.json +2 -2
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
|
|
223
|
-
|
|
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) =>
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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,
|
package/dist/bootstrap.mjs
CHANGED
|
@@ -1,104 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./chunk-4LCQ4MN3.mjs";
|
|
6
|
-
|
|
7
|
-
// src/bootstrap.ts
|
|
8
|
-
import { x402Facilitator } from "@x402/core/facilitator";
|
|
9
|
-
import { toFacilitatorEvmSigner } from "@x402/evm";
|
|
10
|
-
import { createWalletClient, http, publicActions } from "viem";
|
|
11
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
12
|
-
function requireEnv(key) {
|
|
13
|
-
const value = process.env[key];
|
|
14
|
-
if (!value) {
|
|
15
|
-
throw new Error(`Missing required env var: ${key}`);
|
|
16
|
-
}
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
function createConfidentialFacilitatorFromEnv() {
|
|
20
|
-
const privateKey = requireEnv("FACILITATOR_EVM_PRIVATE_KEY");
|
|
21
|
-
const chainId = Number(process.env.FACILITATOR_EVM_CHAIN_ID ?? "11155111");
|
|
22
|
-
const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
|
|
23
|
-
const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
|
|
24
|
-
const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
|
|
25
|
-
const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
|
|
26
|
-
const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
|
|
27
|
-
const receiptPollingIntervalMs = process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS ? Number(process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS) : void 0;
|
|
28
|
-
const debugEnabled = process.env.X402Z_DEBUG === "1";
|
|
29
|
-
const account = privateKeyToAccount(privateKey);
|
|
30
|
-
if (debugEnabled) {
|
|
31
|
-
console.debug("[x402z-facilitator] config", {
|
|
32
|
-
chainId,
|
|
33
|
-
networks,
|
|
34
|
-
rpcUrl,
|
|
35
|
-
waitForReceipt,
|
|
36
|
-
receipt: {
|
|
37
|
-
confirmations: receiptConfirmations,
|
|
38
|
-
timeoutMs: receiptTimeoutMs,
|
|
39
|
-
pollingIntervalMs: receiptPollingIntervalMs
|
|
40
|
-
},
|
|
41
|
-
address: account.address
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
const client = createWalletClient({
|
|
45
|
-
account,
|
|
46
|
-
chain: {
|
|
47
|
-
id: chainId,
|
|
48
|
-
name: "custom",
|
|
49
|
-
nativeCurrency: { name: "native", symbol: "NATIVE", decimals: 18 },
|
|
50
|
-
rpcUrls: { default: { http: [rpcUrl] } }
|
|
51
|
-
},
|
|
52
|
-
transport: http(rpcUrl)
|
|
53
|
-
}).extend(publicActions);
|
|
54
|
-
const signer = toFacilitatorEvmSigner({
|
|
55
|
-
address: account.address,
|
|
56
|
-
readContract: (args) => client.readContract({
|
|
57
|
-
...args,
|
|
58
|
-
args: args.args || []
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
-
}),
|
|
61
|
-
verifyTypedData: (args) => client.verifyTypedData(args),
|
|
62
|
-
writeContract: (args) => client.writeContract({
|
|
63
|
-
...args,
|
|
64
|
-
args: args.args || []
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
-
}),
|
|
67
|
-
sendTransaction: (args) => (
|
|
68
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
|
-
client.sendTransaction({ to: args.to, data: args.data })
|
|
70
|
-
),
|
|
71
|
-
waitForTransactionReceipt: (args) => client.waitForTransactionReceipt(args),
|
|
72
|
-
getCode: (args) => client.getCode(args)
|
|
73
|
-
});
|
|
74
|
-
const facilitator = new x402Facilitator();
|
|
75
|
-
for (const network of networks) {
|
|
76
|
-
facilitator.register(
|
|
77
|
-
network,
|
|
78
|
-
new ConfidentialEvmFacilitator({
|
|
79
|
-
signer,
|
|
80
|
-
waitForReceipt,
|
|
81
|
-
receipt: {
|
|
82
|
-
confirmations: receiptConfirmations,
|
|
83
|
-
timeoutMs: receiptTimeoutMs,
|
|
84
|
-
pollingIntervalMs: receiptPollingIntervalMs
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
return facilitator;
|
|
90
|
-
}
|
|
91
|
-
function startConfidentialFacilitator() {
|
|
92
|
-
const facilitator = createConfidentialFacilitatorFromEnv();
|
|
93
|
-
const port = Number(process.env.FACILITATOR_PORT ?? "8040");
|
|
94
|
-
const server = createFacilitatorService({ facilitator, port });
|
|
95
|
-
server.listen(port);
|
|
96
|
-
return { port };
|
|
97
|
-
}
|
|
98
|
-
if (__require.main === module) {
|
|
99
|
-
const { port } = startConfidentialFacilitator();
|
|
100
|
-
console.log(`Confidential facilitator listening on :${port}`);
|
|
101
|
-
}
|
|
2
|
+
createConfidentialFacilitatorFromEnv,
|
|
3
|
+
startConfidentialFacilitator
|
|
4
|
+
} from "./chunk-4UDK7NYX.mjs";
|
|
102
5
|
export {
|
|
103
6
|
createConfidentialFacilitatorFromEnv,
|
|
104
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
|
@@ -3,9 +3,11 @@ import { FacilitatorEvmSigner } from '@x402/evm';
|
|
|
3
3
|
import { x402Facilitator } from '@x402/core/facilitator';
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
|
+
export { startConfidentialFacilitator } from './bootstrap.mjs';
|
|
6
7
|
|
|
7
8
|
type ConfidentialFacilitatorConfig = {
|
|
8
9
|
signer: FacilitatorEvmSigner;
|
|
10
|
+
batcherAddress?: `0x${string}`;
|
|
9
11
|
hashEncryptedAmountInput?: (encryptedAmountInput: `0x${string}`) => `0x${string}`;
|
|
10
12
|
checkUsedNonces?: boolean;
|
|
11
13
|
clock?: () => number;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,11 @@ import { FacilitatorEvmSigner } from '@x402/evm';
|
|
|
3
3
|
import { x402Facilitator } from '@x402/core/facilitator';
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
|
+
export { startConfidentialFacilitator } from './bootstrap.js';
|
|
6
7
|
|
|
7
8
|
type ConfidentialFacilitatorConfig = {
|
|
8
9
|
signer: FacilitatorEvmSigner;
|
|
10
|
+
batcherAddress?: `0x${string}`;
|
|
9
11
|
hashEncryptedAmountInput?: (encryptedAmountInput: `0x${string}`) => `0x${string}`;
|
|
10
12
|
checkUsedNonces?: boolean;
|
|
11
13
|
clock?: () => number;
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
ConfidentialEvmFacilitator: () => ConfidentialEvmFacilitator,
|
|
24
24
|
createFacilitatorService: () => createFacilitatorService,
|
|
25
25
|
registerConfidentialEvmScheme: () => registerConfidentialEvmScheme,
|
|
26
|
+
startConfidentialFacilitator: () => startConfidentialFacilitator,
|
|
26
27
|
startFacilitatorService: () => startFacilitatorService
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -30,6 +31,63 @@ module.exports = __toCommonJS(index_exports);
|
|
|
30
31
|
// src/scheme.ts
|
|
31
32
|
var import_viem = require("viem");
|
|
32
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
|
+
];
|
|
33
91
|
var ConfidentialEvmFacilitator = class {
|
|
34
92
|
constructor(config) {
|
|
35
93
|
this.config = config;
|
|
@@ -166,8 +224,25 @@ var ConfidentialEvmFacilitator = class {
|
|
|
166
224
|
network: requirements.network
|
|
167
225
|
};
|
|
168
226
|
}
|
|
169
|
-
const
|
|
170
|
-
|
|
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,
|
|
171
246
|
abi: import_x402z_shared.confidentialTokenAbi,
|
|
172
247
|
functionName: "confidentialTransferWithAuthorization",
|
|
173
248
|
args: [
|
|
@@ -176,10 +251,20 @@ var ConfidentialEvmFacilitator = class {
|
|
|
176
251
|
confidentialPayload.inputProof,
|
|
177
252
|
confidentialPayload.signature
|
|
178
253
|
]
|
|
179
|
-
}
|
|
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);
|
|
180
264
|
if (process.env.X402Z_DEBUG === "1") {
|
|
181
265
|
console.debug("[x402z-facilitator] tx submitted", txHash);
|
|
182
266
|
}
|
|
267
|
+
let batchResult;
|
|
183
268
|
if (this.waitForReceipt) {
|
|
184
269
|
const receipt = await this.config.signer.waitForTransactionReceipt({
|
|
185
270
|
hash: txHash
|
|
@@ -196,12 +281,90 @@ var ConfidentialEvmFacilitator = class {
|
|
|
196
281
|
network: requirements.network
|
|
197
282
|
};
|
|
198
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
|
+
}
|
|
199
361
|
}
|
|
200
362
|
return {
|
|
201
363
|
success: true,
|
|
202
364
|
payer: confidentialPayload.authorization.holder,
|
|
203
365
|
transaction: txHash,
|
|
204
|
-
network: requirements.network
|
|
366
|
+
network: requirements.network,
|
|
367
|
+
...batchResult ? { batch: batchResult } : {}
|
|
205
368
|
};
|
|
206
369
|
}
|
|
207
370
|
};
|
|
@@ -272,10 +435,133 @@ function startFacilitatorService(config) {
|
|
|
272
435
|
server.listen(port);
|
|
273
436
|
return { port };
|
|
274
437
|
}
|
|
438
|
+
|
|
439
|
+
// src/bootstrap.ts
|
|
440
|
+
var import_facilitator = require("@x402/core/facilitator");
|
|
441
|
+
var import_evm = require("@x402/evm");
|
|
442
|
+
var import_viem2 = require("viem");
|
|
443
|
+
var import_accounts = require("viem/accounts");
|
|
444
|
+
function requireEnv(key) {
|
|
445
|
+
const value = process.env[key];
|
|
446
|
+
if (!value) {
|
|
447
|
+
throw new Error(`Missing required env var: ${key}`);
|
|
448
|
+
}
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
function createConfidentialFacilitatorFromEnv() {
|
|
452
|
+
const privateKey = requireEnv("FACILITATOR_EVM_PRIVATE_KEY");
|
|
453
|
+
const chainId = Number(process.env.FACILITATOR_EVM_CHAIN_ID ?? "11155111");
|
|
454
|
+
const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
|
|
455
|
+
const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
|
|
456
|
+
const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
|
|
457
|
+
const batcherAddress = process.env.FACILITATOR_BATCHER_ADDRESS;
|
|
458
|
+
const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
|
|
459
|
+
const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
|
|
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;
|
|
462
|
+
const debugEnabled = process.env.X402Z_DEBUG === "1";
|
|
463
|
+
const account = (0, import_accounts.privateKeyToAccount)(privateKey);
|
|
464
|
+
if (debugEnabled) {
|
|
465
|
+
console.debug("[x402z-facilitator] config", {
|
|
466
|
+
chainId,
|
|
467
|
+
networks,
|
|
468
|
+
rpcUrl,
|
|
469
|
+
waitForReceipt,
|
|
470
|
+
batcherAddress,
|
|
471
|
+
gasMultiplier,
|
|
472
|
+
receipt: {
|
|
473
|
+
confirmations: receiptConfirmations,
|
|
474
|
+
timeoutMs: receiptTimeoutMs,
|
|
475
|
+
pollingIntervalMs: receiptPollingIntervalMs
|
|
476
|
+
},
|
|
477
|
+
address: account.address
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const client = (0, import_viem2.createWalletClient)({
|
|
481
|
+
account,
|
|
482
|
+
chain: {
|
|
483
|
+
id: chainId,
|
|
484
|
+
name: "custom",
|
|
485
|
+
nativeCurrency: { name: "native", symbol: "NATIVE", decimals: 18 },
|
|
486
|
+
rpcUrls: { default: { http: [rpcUrl] } }
|
|
487
|
+
},
|
|
488
|
+
transport: (0, import_viem2.http)(rpcUrl)
|
|
489
|
+
}).extend(import_viem2.publicActions);
|
|
490
|
+
const signer = (0, import_evm.toFacilitatorEvmSigner)({
|
|
491
|
+
address: account.address,
|
|
492
|
+
readContract: (args) => client.readContract({
|
|
493
|
+
...args,
|
|
494
|
+
args: args.args || []
|
|
495
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
496
|
+
}),
|
|
497
|
+
verifyTypedData: (args) => client.verifyTypedData(args),
|
|
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
|
+
},
|
|
524
|
+
sendTransaction: (args) => (
|
|
525
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
526
|
+
client.sendTransaction({ to: args.to, data: args.data })
|
|
527
|
+
),
|
|
528
|
+
waitForTransactionReceipt: (args) => client.waitForTransactionReceipt(args),
|
|
529
|
+
getCode: (args) => client.getCode(args)
|
|
530
|
+
});
|
|
531
|
+
const facilitator = new import_facilitator.x402Facilitator();
|
|
532
|
+
for (const network of networks) {
|
|
533
|
+
facilitator.register(
|
|
534
|
+
network,
|
|
535
|
+
new ConfidentialEvmFacilitator({
|
|
536
|
+
signer,
|
|
537
|
+
waitForReceipt,
|
|
538
|
+
batcherAddress,
|
|
539
|
+
receipt: {
|
|
540
|
+
confirmations: receiptConfirmations,
|
|
541
|
+
timeoutMs: receiptTimeoutMs,
|
|
542
|
+
pollingIntervalMs: receiptPollingIntervalMs
|
|
543
|
+
}
|
|
544
|
+
})
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
return facilitator;
|
|
548
|
+
}
|
|
549
|
+
function startConfidentialFacilitator() {
|
|
550
|
+
const facilitator = createConfidentialFacilitatorFromEnv();
|
|
551
|
+
const port = Number(process.env.FACILITATOR_PORT ?? "8040");
|
|
552
|
+
const server = createFacilitatorService({ facilitator, port });
|
|
553
|
+
server.listen(port);
|
|
554
|
+
return { port };
|
|
555
|
+
}
|
|
556
|
+
if (require.main === module) {
|
|
557
|
+
const { port } = startConfidentialFacilitator();
|
|
558
|
+
console.log(`Confidential facilitator listening on :${port}`);
|
|
559
|
+
}
|
|
275
560
|
// Annotate the CommonJS export names for ESM import in node:
|
|
276
561
|
0 && (module.exports = {
|
|
277
562
|
ConfidentialEvmFacilitator,
|
|
278
563
|
createFacilitatorService,
|
|
279
564
|
registerConfidentialEvmScheme,
|
|
565
|
+
startConfidentialFacilitator,
|
|
280
566
|
startFacilitatorService
|
|
281
567
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConfidentialEvmFacilitator,
|
|
3
3
|
createFacilitatorService,
|
|
4
|
+
startConfidentialFacilitator,
|
|
4
5
|
startFacilitatorService
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4UDK7NYX.mjs";
|
|
6
7
|
|
|
7
8
|
// src/register.ts
|
|
8
9
|
function registerConfidentialEvmScheme(facilitator, config) {
|
|
@@ -17,5 +18,6 @@ export {
|
|
|
17
18
|
ConfidentialEvmFacilitator,
|
|
18
19
|
createFacilitatorService,
|
|
19
20
|
registerConfidentialEvmScheme,
|
|
21
|
+
startConfidentialFacilitator,
|
|
20
22
|
startFacilitatorService
|
|
21
23
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x402z-facilitator",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
14
|
+
"x402z-shared": "0.0.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"jest": "^29.7.0",
|