moltspay 0.8.14 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +156 -504
- package/dist/cli/index.js +553 -171
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +555 -173
- package/dist/cli/index.mjs.map +1 -1
- package/dist/facilitators/index.d.mts +61 -0
- package/dist/facilitators/index.d.ts +61 -0
- package/dist/facilitators/index.js +502 -0
- package/dist/facilitators/index.js.map +1 -0
- package/dist/facilitators/index.mjs +461 -0
- package/dist/facilitators/index.mjs.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +583 -190
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +580 -192
- package/dist/index.mjs.map +1 -1
- package/dist/registry-OsEO2dOu.d.mts +233 -0
- package/dist/registry-OsEO2dOu.d.ts +233 -0
- package/dist/server/index.d.mts +19 -15
- package/dist/server/index.d.ts +19 -15
- package/dist/server/index.js +514 -145
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +514 -145
- package/dist/server/index.mjs.map +1 -1
- package/package.json +7 -2
- package/schemas/moltspay.services.schema.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2891,7 +2891,7 @@ function alphabet(letters) {
|
|
|
2891
2891
|
};
|
|
2892
2892
|
}
|
|
2893
2893
|
// @__NO_SIDE_EFFECTS__
|
|
2894
|
-
function
|
|
2894
|
+
function join5(separator = "") {
|
|
2895
2895
|
astr("join", separator);
|
|
2896
2896
|
return {
|
|
2897
2897
|
encode: (from) => {
|
|
@@ -3098,10 +3098,10 @@ var init_esm = __esm({
|
|
|
3098
3098
|
convertRadix2,
|
|
3099
3099
|
radix,
|
|
3100
3100
|
radix2,
|
|
3101
|
-
join:
|
|
3101
|
+
join: join5,
|
|
3102
3102
|
padding
|
|
3103
3103
|
};
|
|
3104
|
-
genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain(/* @__PURE__ */ radix(58), /* @__PURE__ */ alphabet(abc), /* @__PURE__ */
|
|
3104
|
+
genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain(/* @__PURE__ */ radix(58), /* @__PURE__ */ alphabet(abc), /* @__PURE__ */ join5(""));
|
|
3105
3105
|
base58 = /* @__PURE__ */ genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
|
3106
3106
|
createBase58check = (sha2566) => /* @__PURE__ */ chain(checksum(4, (data) => sha2566(sha2566(data))), base58);
|
|
3107
3107
|
}
|
|
@@ -3249,14 +3249,14 @@ var init_esm2 = __esm({
|
|
|
3249
3249
|
}
|
|
3250
3250
|
this.pubHash = hash160(this.pubKey);
|
|
3251
3251
|
}
|
|
3252
|
-
derive(
|
|
3253
|
-
if (!/^[mM]'?/.test(
|
|
3252
|
+
derive(path5) {
|
|
3253
|
+
if (!/^[mM]'?/.test(path5)) {
|
|
3254
3254
|
throw new Error('Path must start with "m" or "M"');
|
|
3255
3255
|
}
|
|
3256
|
-
if (/^[mM]'?$/.test(
|
|
3256
|
+
if (/^[mM]'?$/.test(path5)) {
|
|
3257
3257
|
return this;
|
|
3258
3258
|
}
|
|
3259
|
-
const parts =
|
|
3259
|
+
const parts = path5.replace(/^[mM]'?\//, "").split("/");
|
|
3260
3260
|
let child = this;
|
|
3261
3261
|
for (const c of parts) {
|
|
3262
3262
|
const m = /^(\d+)('?)$/.exec(c);
|
|
@@ -9617,8 +9617,8 @@ var init_privateKeyToAccount = __esm({
|
|
|
9617
9617
|
});
|
|
9618
9618
|
|
|
9619
9619
|
// node_modules/viem/_esm/accounts/hdKeyToAccount.js
|
|
9620
|
-
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path:
|
|
9621
|
-
const hdKey = hdKey_.derive(
|
|
9620
|
+
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path: path5, ...options } = {}) {
|
|
9621
|
+
const hdKey = hdKey_.derive(path5 || `m/44'/60'/${accountIndex}'/${changeIndex}/${addressIndex}`);
|
|
9622
9622
|
const account = privateKeyToAccount(toHex(hdKey.privateKey), options);
|
|
9623
9623
|
return {
|
|
9624
9624
|
...account,
|
|
@@ -30330,20 +30330,478 @@ init_esm_shims();
|
|
|
30330
30330
|
|
|
30331
30331
|
// src/server/index.ts
|
|
30332
30332
|
init_esm_shims();
|
|
30333
|
-
import { readFileSync, existsSync } from "fs";
|
|
30333
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
30334
30334
|
import { createServer } from "http";
|
|
30335
|
+
import * as path3 from "path";
|
|
30336
|
+
|
|
30337
|
+
// src/facilitators/index.ts
|
|
30338
|
+
init_esm_shims();
|
|
30339
|
+
|
|
30340
|
+
// src/facilitators/interface.ts
|
|
30341
|
+
init_esm_shims();
|
|
30342
|
+
var BaseFacilitator = class {
|
|
30343
|
+
supportsNetwork(network) {
|
|
30344
|
+
return this.supportedNetworks.includes(network);
|
|
30345
|
+
}
|
|
30346
|
+
};
|
|
30347
|
+
|
|
30348
|
+
// src/facilitators/cdp.ts
|
|
30349
|
+
init_esm_shims();
|
|
30350
|
+
import { readFileSync, existsSync } from "fs";
|
|
30335
30351
|
import * as path2 from "path";
|
|
30352
|
+
var X402_VERSION = 2;
|
|
30353
|
+
var CDP_MAINNET_URL = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
30354
|
+
var CDP_TESTNET_URL = "https://www.x402.org/facilitator";
|
|
30355
|
+
function loadEnvFile() {
|
|
30356
|
+
const envPaths = [
|
|
30357
|
+
path2.join(process.cwd(), ".env"),
|
|
30358
|
+
path2.join(process.env.HOME || "", ".moltspay", ".env")
|
|
30359
|
+
];
|
|
30360
|
+
for (const envPath of envPaths) {
|
|
30361
|
+
if (existsSync(envPath)) {
|
|
30362
|
+
try {
|
|
30363
|
+
const content = readFileSync(envPath, "utf-8");
|
|
30364
|
+
for (const line of content.split("\n")) {
|
|
30365
|
+
const trimmed = line.trim();
|
|
30366
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
30367
|
+
const eqIndex = trimmed.indexOf("=");
|
|
30368
|
+
if (eqIndex === -1) continue;
|
|
30369
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
30370
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
30371
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
30372
|
+
value = value.slice(1, -1);
|
|
30373
|
+
}
|
|
30374
|
+
if (!process.env[key]) {
|
|
30375
|
+
process.env[key] = value;
|
|
30376
|
+
}
|
|
30377
|
+
}
|
|
30378
|
+
break;
|
|
30379
|
+
} catch {
|
|
30380
|
+
}
|
|
30381
|
+
}
|
|
30382
|
+
}
|
|
30383
|
+
}
|
|
30384
|
+
var CDPFacilitator = class extends BaseFacilitator {
|
|
30385
|
+
name = "cdp";
|
|
30386
|
+
displayName = "Coinbase CDP";
|
|
30387
|
+
supportedNetworks;
|
|
30388
|
+
endpoint;
|
|
30389
|
+
useMainnet;
|
|
30390
|
+
apiKeyId;
|
|
30391
|
+
apiKeySecret;
|
|
30392
|
+
constructor(config = {}) {
|
|
30393
|
+
super();
|
|
30394
|
+
loadEnvFile();
|
|
30395
|
+
this.useMainnet = config.useMainnet ?? process.env.USE_MAINNET?.toLowerCase() === "true";
|
|
30396
|
+
this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
|
|
30397
|
+
this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
|
|
30398
|
+
this.endpoint = this.useMainnet ? CDP_MAINNET_URL : CDP_TESTNET_URL;
|
|
30399
|
+
this.supportedNetworks = this.useMainnet ? ["eip155:8453"] : ["eip155:8453", "eip155:84532"];
|
|
30400
|
+
if (this.useMainnet && (!this.apiKeyId || !this.apiKeySecret)) {
|
|
30401
|
+
console.warn("[CDPFacilitator] WARNING: Mainnet mode but missing CDP credentials!");
|
|
30402
|
+
console.warn("[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET");
|
|
30403
|
+
}
|
|
30404
|
+
}
|
|
30405
|
+
/**
|
|
30406
|
+
* Get auth headers for CDP API requests
|
|
30407
|
+
*/
|
|
30408
|
+
async getAuthHeaders(method, urlPath, body) {
|
|
30409
|
+
if (!this.useMainnet) {
|
|
30410
|
+
return {};
|
|
30411
|
+
}
|
|
30412
|
+
if (!this.apiKeyId || !this.apiKeySecret) {
|
|
30413
|
+
throw new Error("CDP credentials required for mainnet");
|
|
30414
|
+
}
|
|
30415
|
+
try {
|
|
30416
|
+
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
30417
|
+
return await getAuthHeaders({
|
|
30418
|
+
apiKeyId: this.apiKeyId,
|
|
30419
|
+
apiKeySecret: this.apiKeySecret,
|
|
30420
|
+
requestMethod: method,
|
|
30421
|
+
requestHost: "api.cdp.coinbase.com",
|
|
30422
|
+
requestPath: urlPath,
|
|
30423
|
+
requestBody: body
|
|
30424
|
+
});
|
|
30425
|
+
} catch (err) {
|
|
30426
|
+
throw new Error(`Failed to generate CDP auth: ${err.message}`);
|
|
30427
|
+
}
|
|
30428
|
+
}
|
|
30429
|
+
/**
|
|
30430
|
+
* Health check - verify facilitator is reachable
|
|
30431
|
+
*/
|
|
30432
|
+
async healthCheck() {
|
|
30433
|
+
const start = Date.now();
|
|
30434
|
+
try {
|
|
30435
|
+
const controller = new AbortController();
|
|
30436
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
30437
|
+
const response = await fetch(this.endpoint.replace("/x402", ""), {
|
|
30438
|
+
method: "HEAD",
|
|
30439
|
+
signal: controller.signal
|
|
30440
|
+
}).catch(() => null);
|
|
30441
|
+
clearTimeout(timeout);
|
|
30442
|
+
const latencyMs = Date.now() - start;
|
|
30443
|
+
return {
|
|
30444
|
+
healthy: response !== null,
|
|
30445
|
+
latencyMs
|
|
30446
|
+
};
|
|
30447
|
+
} catch (err) {
|
|
30448
|
+
return {
|
|
30449
|
+
healthy: false,
|
|
30450
|
+
error: err.message,
|
|
30451
|
+
latencyMs: Date.now() - start
|
|
30452
|
+
};
|
|
30453
|
+
}
|
|
30454
|
+
}
|
|
30455
|
+
/**
|
|
30456
|
+
* Verify payment signature with facilitator
|
|
30457
|
+
*/
|
|
30458
|
+
async verify(paymentPayload, requirements) {
|
|
30459
|
+
try {
|
|
30460
|
+
const requestBody = {
|
|
30461
|
+
x402Version: X402_VERSION,
|
|
30462
|
+
paymentPayload,
|
|
30463
|
+
paymentRequirements: requirements
|
|
30464
|
+
};
|
|
30465
|
+
const headers = {
|
|
30466
|
+
"Content-Type": "application/json"
|
|
30467
|
+
};
|
|
30468
|
+
if (this.useMainnet) {
|
|
30469
|
+
const authHeaders = await this.getAuthHeaders(
|
|
30470
|
+
"POST",
|
|
30471
|
+
"/platform/v2/x402/verify",
|
|
30472
|
+
requestBody
|
|
30473
|
+
);
|
|
30474
|
+
Object.assign(headers, authHeaders);
|
|
30475
|
+
}
|
|
30476
|
+
const response = await fetch(`${this.endpoint}/verify`, {
|
|
30477
|
+
method: "POST",
|
|
30478
|
+
headers,
|
|
30479
|
+
body: JSON.stringify(requestBody)
|
|
30480
|
+
});
|
|
30481
|
+
const result = await response.json();
|
|
30482
|
+
if (!response.ok || !result.isValid) {
|
|
30483
|
+
return {
|
|
30484
|
+
valid: false,
|
|
30485
|
+
error: result.invalidReason || result.error || "Verification failed",
|
|
30486
|
+
details: result
|
|
30487
|
+
};
|
|
30488
|
+
}
|
|
30489
|
+
return { valid: true, details: result };
|
|
30490
|
+
} catch (err) {
|
|
30491
|
+
return {
|
|
30492
|
+
valid: false,
|
|
30493
|
+
error: `Facilitator error: ${err.message}`
|
|
30494
|
+
};
|
|
30495
|
+
}
|
|
30496
|
+
}
|
|
30497
|
+
/**
|
|
30498
|
+
* Settle payment on-chain via facilitator
|
|
30499
|
+
*/
|
|
30500
|
+
async settle(paymentPayload, requirements) {
|
|
30501
|
+
try {
|
|
30502
|
+
const requestBody = {
|
|
30503
|
+
x402Version: X402_VERSION,
|
|
30504
|
+
paymentPayload,
|
|
30505
|
+
paymentRequirements: requirements
|
|
30506
|
+
};
|
|
30507
|
+
const headers = {
|
|
30508
|
+
"Content-Type": "application/json"
|
|
30509
|
+
};
|
|
30510
|
+
if (this.useMainnet) {
|
|
30511
|
+
const authHeaders = await this.getAuthHeaders(
|
|
30512
|
+
"POST",
|
|
30513
|
+
"/platform/v2/x402/settle",
|
|
30514
|
+
requestBody
|
|
30515
|
+
);
|
|
30516
|
+
Object.assign(headers, authHeaders);
|
|
30517
|
+
}
|
|
30518
|
+
const response = await fetch(`${this.endpoint}/settle`, {
|
|
30519
|
+
method: "POST",
|
|
30520
|
+
headers,
|
|
30521
|
+
body: JSON.stringify(requestBody)
|
|
30522
|
+
});
|
|
30523
|
+
const result = await response.json();
|
|
30524
|
+
if (!response.ok || !result.success) {
|
|
30525
|
+
return {
|
|
30526
|
+
success: false,
|
|
30527
|
+
error: result.error || result.errorReason || "Settlement failed"
|
|
30528
|
+
};
|
|
30529
|
+
}
|
|
30530
|
+
return {
|
|
30531
|
+
success: true,
|
|
30532
|
+
transaction: result.transaction,
|
|
30533
|
+
status: result.status || "settled"
|
|
30534
|
+
};
|
|
30535
|
+
} catch (err) {
|
|
30536
|
+
return {
|
|
30537
|
+
success: false,
|
|
30538
|
+
error: `Settlement error: ${err.message}`
|
|
30539
|
+
};
|
|
30540
|
+
}
|
|
30541
|
+
}
|
|
30542
|
+
/**
|
|
30543
|
+
* Get CDP fee information
|
|
30544
|
+
*/
|
|
30545
|
+
async getFee() {
|
|
30546
|
+
return {
|
|
30547
|
+
perTx: 1e-3,
|
|
30548
|
+
currency: "USD",
|
|
30549
|
+
freeQuota: 1e3
|
|
30550
|
+
};
|
|
30551
|
+
}
|
|
30552
|
+
/**
|
|
30553
|
+
* Get configuration summary (for logging)
|
|
30554
|
+
*/
|
|
30555
|
+
getConfigSummary() {
|
|
30556
|
+
const mode = this.useMainnet ? "mainnet" : "testnet";
|
|
30557
|
+
const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);
|
|
30558
|
+
return `CDP Facilitator (${mode}, credentials: ${hasCredentials ? "yes" : "no"})`;
|
|
30559
|
+
}
|
|
30560
|
+
};
|
|
30561
|
+
|
|
30562
|
+
// src/facilitators/registry.ts
|
|
30563
|
+
init_esm_shims();
|
|
30564
|
+
var FacilitatorRegistry = class {
|
|
30565
|
+
factories = /* @__PURE__ */ new Map();
|
|
30566
|
+
instances = /* @__PURE__ */ new Map();
|
|
30567
|
+
selection;
|
|
30568
|
+
roundRobinIndex = 0;
|
|
30569
|
+
constructor(selection) {
|
|
30570
|
+
this.registerFactory("cdp", (config) => new CDPFacilitator(config));
|
|
30571
|
+
this.selection = selection || { primary: "cdp", strategy: "failover" };
|
|
30572
|
+
}
|
|
30573
|
+
/**
|
|
30574
|
+
* Register a new facilitator factory
|
|
30575
|
+
*/
|
|
30576
|
+
registerFactory(name, factory) {
|
|
30577
|
+
this.factories.set(name, factory);
|
|
30578
|
+
}
|
|
30579
|
+
/**
|
|
30580
|
+
* Get or create a facilitator instance
|
|
30581
|
+
*/
|
|
30582
|
+
get(name, config) {
|
|
30583
|
+
if (this.instances.has(name)) {
|
|
30584
|
+
return this.instances.get(name);
|
|
30585
|
+
}
|
|
30586
|
+
const factory = this.factories.get(name);
|
|
30587
|
+
if (!factory) {
|
|
30588
|
+
throw new Error(`Unknown facilitator: ${name}. Available: ${Array.from(this.factories.keys()).join(", ")}`);
|
|
30589
|
+
}
|
|
30590
|
+
const mergedConfig = {
|
|
30591
|
+
...this.selection.config?.[name],
|
|
30592
|
+
...config
|
|
30593
|
+
};
|
|
30594
|
+
const instance = factory(mergedConfig);
|
|
30595
|
+
this.instances.set(name, instance);
|
|
30596
|
+
return instance;
|
|
30597
|
+
}
|
|
30598
|
+
/**
|
|
30599
|
+
* Get all configured facilitator names
|
|
30600
|
+
*/
|
|
30601
|
+
getConfiguredNames() {
|
|
30602
|
+
const names = [this.selection.primary];
|
|
30603
|
+
if (this.selection.fallback) {
|
|
30604
|
+
names.push(...this.selection.fallback);
|
|
30605
|
+
}
|
|
30606
|
+
return names;
|
|
30607
|
+
}
|
|
30608
|
+
/**
|
|
30609
|
+
* Get list of facilitators based on selection strategy
|
|
30610
|
+
*/
|
|
30611
|
+
async getOrderedFacilitators(network) {
|
|
30612
|
+
const names = this.getConfiguredNames();
|
|
30613
|
+
const facilitators = [];
|
|
30614
|
+
for (const name of names) {
|
|
30615
|
+
try {
|
|
30616
|
+
const f = this.get(name);
|
|
30617
|
+
if (f.supportsNetwork(network)) {
|
|
30618
|
+
facilitators.push(f);
|
|
30619
|
+
}
|
|
30620
|
+
} catch (err) {
|
|
30621
|
+
console.warn(`[Registry] Failed to get facilitator ${name}:`, err);
|
|
30622
|
+
}
|
|
30623
|
+
}
|
|
30624
|
+
if (facilitators.length === 0) {
|
|
30625
|
+
throw new Error(`No facilitators available for network: ${network}`);
|
|
30626
|
+
}
|
|
30627
|
+
switch (this.selection.strategy) {
|
|
30628
|
+
case "random":
|
|
30629
|
+
return this.shuffle(facilitators);
|
|
30630
|
+
case "roundrobin":
|
|
30631
|
+
this.roundRobinIndex = (this.roundRobinIndex + 1) % facilitators.length;
|
|
30632
|
+
return [
|
|
30633
|
+
...facilitators.slice(this.roundRobinIndex),
|
|
30634
|
+
...facilitators.slice(0, this.roundRobinIndex)
|
|
30635
|
+
];
|
|
30636
|
+
case "cheapest":
|
|
30637
|
+
return this.sortByCheapest(facilitators);
|
|
30638
|
+
case "fastest":
|
|
30639
|
+
return this.sortByFastest(facilitators);
|
|
30640
|
+
case "failover":
|
|
30641
|
+
default:
|
|
30642
|
+
return facilitators;
|
|
30643
|
+
}
|
|
30644
|
+
}
|
|
30645
|
+
shuffle(array) {
|
|
30646
|
+
const result = [...array];
|
|
30647
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
30648
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
30649
|
+
[result[i], result[j]] = [result[j], result[i]];
|
|
30650
|
+
}
|
|
30651
|
+
return result;
|
|
30652
|
+
}
|
|
30653
|
+
async sortByCheapest(facilitators) {
|
|
30654
|
+
const withFees = await Promise.all(
|
|
30655
|
+
facilitators.map(async (f) => {
|
|
30656
|
+
try {
|
|
30657
|
+
const fee = await f.getFee?.();
|
|
30658
|
+
return { facilitator: f, perTx: fee?.perTx ?? Infinity };
|
|
30659
|
+
} catch {
|
|
30660
|
+
return { facilitator: f, perTx: Infinity };
|
|
30661
|
+
}
|
|
30662
|
+
})
|
|
30663
|
+
);
|
|
30664
|
+
withFees.sort((a, b) => a.perTx - b.perTx);
|
|
30665
|
+
return withFees.map((w) => w.facilitator);
|
|
30666
|
+
}
|
|
30667
|
+
async sortByFastest(facilitators) {
|
|
30668
|
+
const withLatency = await Promise.all(
|
|
30669
|
+
facilitators.map(async (f) => {
|
|
30670
|
+
try {
|
|
30671
|
+
const health = await f.healthCheck();
|
|
30672
|
+
return { facilitator: f, latency: health.latencyMs ?? Infinity };
|
|
30673
|
+
} catch {
|
|
30674
|
+
return { facilitator: f, latency: Infinity };
|
|
30675
|
+
}
|
|
30676
|
+
})
|
|
30677
|
+
);
|
|
30678
|
+
withLatency.sort((a, b) => a.latency - b.latency);
|
|
30679
|
+
return withLatency.map((w) => w.facilitator);
|
|
30680
|
+
}
|
|
30681
|
+
/**
|
|
30682
|
+
* Verify payment using configured facilitators
|
|
30683
|
+
*/
|
|
30684
|
+
async verify(paymentPayload, requirements) {
|
|
30685
|
+
const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;
|
|
30686
|
+
const facilitators = await this.getOrderedFacilitators(network);
|
|
30687
|
+
let lastError;
|
|
30688
|
+
for (const f of facilitators) {
|
|
30689
|
+
try {
|
|
30690
|
+
console.log(`[Registry] Trying ${f.name} for verify...`);
|
|
30691
|
+
const result = await f.verify(paymentPayload, requirements);
|
|
30692
|
+
if (result.valid) {
|
|
30693
|
+
console.log(`[Registry] ${f.name} verify succeeded`);
|
|
30694
|
+
return { ...result, facilitator: f.name };
|
|
30695
|
+
}
|
|
30696
|
+
lastError = result.error;
|
|
30697
|
+
console.log(`[Registry] ${f.name} verify failed: ${result.error}`);
|
|
30698
|
+
if (this.selection.strategy === "failover" && !this.isTransientError(result.error)) {
|
|
30699
|
+
break;
|
|
30700
|
+
}
|
|
30701
|
+
} catch (err) {
|
|
30702
|
+
lastError = err.message;
|
|
30703
|
+
console.error(`[Registry] ${f.name} error:`, err.message);
|
|
30704
|
+
}
|
|
30705
|
+
}
|
|
30706
|
+
return {
|
|
30707
|
+
valid: false,
|
|
30708
|
+
error: lastError || "All facilitators failed",
|
|
30709
|
+
facilitator: "none"
|
|
30710
|
+
};
|
|
30711
|
+
}
|
|
30712
|
+
/**
|
|
30713
|
+
* Settle payment using configured facilitators
|
|
30714
|
+
*/
|
|
30715
|
+
async settle(paymentPayload, requirements) {
|
|
30716
|
+
const network = paymentPayload.accepted?.network || paymentPayload.network || requirements.network;
|
|
30717
|
+
const facilitators = await this.getOrderedFacilitators(network);
|
|
30718
|
+
let lastError;
|
|
30719
|
+
for (const f of facilitators) {
|
|
30720
|
+
try {
|
|
30721
|
+
console.log(`[Registry] Trying ${f.name} for settle...`);
|
|
30722
|
+
const result = await f.settle(paymentPayload, requirements);
|
|
30723
|
+
if (result.success) {
|
|
30724
|
+
console.log(`[Registry] ${f.name} settle succeeded: ${result.transaction}`);
|
|
30725
|
+
return { ...result, facilitator: f.name };
|
|
30726
|
+
}
|
|
30727
|
+
lastError = result.error;
|
|
30728
|
+
console.log(`[Registry] ${f.name} settle failed: ${result.error}`);
|
|
30729
|
+
} catch (err) {
|
|
30730
|
+
lastError = err.message;
|
|
30731
|
+
console.error(`[Registry] ${f.name} error:`, err.message);
|
|
30732
|
+
}
|
|
30733
|
+
}
|
|
30734
|
+
return {
|
|
30735
|
+
success: false,
|
|
30736
|
+
error: lastError || "All facilitators failed",
|
|
30737
|
+
facilitator: "none"
|
|
30738
|
+
};
|
|
30739
|
+
}
|
|
30740
|
+
/**
|
|
30741
|
+
* Check health of all configured facilitators
|
|
30742
|
+
*/
|
|
30743
|
+
async healthCheckAll() {
|
|
30744
|
+
const results = {};
|
|
30745
|
+
for (const name of this.getConfiguredNames()) {
|
|
30746
|
+
try {
|
|
30747
|
+
const f = this.get(name);
|
|
30748
|
+
results[name] = await f.healthCheck();
|
|
30749
|
+
} catch (err) {
|
|
30750
|
+
results[name] = { healthy: false, error: err.message };
|
|
30751
|
+
}
|
|
30752
|
+
}
|
|
30753
|
+
return results;
|
|
30754
|
+
}
|
|
30755
|
+
/**
|
|
30756
|
+
* Check if an error is transient (network/server issue) vs permanent (bad request)
|
|
30757
|
+
*/
|
|
30758
|
+
isTransientError(error) {
|
|
30759
|
+
if (!error) return true;
|
|
30760
|
+
const transientPatterns = [
|
|
30761
|
+
/timeout/i,
|
|
30762
|
+
/network/i,
|
|
30763
|
+
/connection/i,
|
|
30764
|
+
/ECONNREFUSED/i,
|
|
30765
|
+
/ETIMEDOUT/i,
|
|
30766
|
+
/503/,
|
|
30767
|
+
/502/,
|
|
30768
|
+
/500/
|
|
30769
|
+
];
|
|
30770
|
+
return transientPatterns.some((p) => p.test(error));
|
|
30771
|
+
}
|
|
30772
|
+
/**
|
|
30773
|
+
* Update selection configuration
|
|
30774
|
+
*/
|
|
30775
|
+
setSelection(selection) {
|
|
30776
|
+
this.selection = selection;
|
|
30777
|
+
this.instances.clear();
|
|
30778
|
+
}
|
|
30779
|
+
/**
|
|
30780
|
+
* Get current selection configuration
|
|
30781
|
+
*/
|
|
30782
|
+
getSelection() {
|
|
30783
|
+
return { ...this.selection };
|
|
30784
|
+
}
|
|
30785
|
+
};
|
|
30786
|
+
var defaultRegistry = null;
|
|
30787
|
+
function getDefaultRegistry() {
|
|
30788
|
+
if (!defaultRegistry) {
|
|
30789
|
+
defaultRegistry = new FacilitatorRegistry();
|
|
30790
|
+
}
|
|
30791
|
+
return defaultRegistry;
|
|
30792
|
+
}
|
|
30793
|
+
function createRegistry(selection) {
|
|
30794
|
+
return new FacilitatorRegistry(selection);
|
|
30795
|
+
}
|
|
30336
30796
|
|
|
30337
30797
|
// src/server/types.ts
|
|
30338
30798
|
init_esm_shims();
|
|
30339
30799
|
|
|
30340
30800
|
// src/server/index.ts
|
|
30341
|
-
var
|
|
30801
|
+
var X402_VERSION2 = 2;
|
|
30342
30802
|
var PAYMENT_REQUIRED_HEADER = "x-payment-required";
|
|
30343
30803
|
var PAYMENT_HEADER = "x-payment";
|
|
30344
30804
|
var PAYMENT_RESPONSE_HEADER = "x-payment-response";
|
|
30345
|
-
var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
|
|
30346
|
-
var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
30347
30805
|
var USDC_ADDRESSES = {
|
|
30348
30806
|
"eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
30349
30807
|
// Base mainnet
|
|
@@ -30354,15 +30812,15 @@ var USDC_DOMAIN = {
|
|
|
30354
30812
|
name: "USD Coin",
|
|
30355
30813
|
version: "2"
|
|
30356
30814
|
};
|
|
30357
|
-
function
|
|
30815
|
+
function loadEnvFile2() {
|
|
30358
30816
|
const envPaths = [
|
|
30359
|
-
|
|
30360
|
-
|
|
30817
|
+
path3.join(process.cwd(), ".env"),
|
|
30818
|
+
path3.join(process.env.HOME || "", ".moltspay", ".env")
|
|
30361
30819
|
];
|
|
30362
30820
|
for (const envPath of envPaths) {
|
|
30363
|
-
if (
|
|
30821
|
+
if (existsSync2(envPath)) {
|
|
30364
30822
|
try {
|
|
30365
|
-
const content =
|
|
30823
|
+
const content = readFileSync2(envPath, "utf-8");
|
|
30366
30824
|
for (const line of content.split("\n")) {
|
|
30367
30825
|
const trimmed = line.trim();
|
|
30368
30826
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -30379,77 +30837,44 @@ function loadEnvFiles() {
|
|
|
30379
30837
|
}
|
|
30380
30838
|
console.log(`[MoltsPay] Loaded config from ${envPath}`);
|
|
30381
30839
|
break;
|
|
30382
|
-
} catch
|
|
30383
|
-
console.warn(`[MoltsPay] Failed to load ${envPath}:`, err);
|
|
30840
|
+
} catch {
|
|
30384
30841
|
}
|
|
30385
30842
|
}
|
|
30386
30843
|
}
|
|
30387
30844
|
}
|
|
30388
|
-
function getCDPConfig() {
|
|
30389
|
-
loadEnvFiles();
|
|
30390
|
-
return {
|
|
30391
|
-
useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
|
|
30392
|
-
apiKeyId: process.env.CDP_API_KEY_ID,
|
|
30393
|
-
apiKeySecret: process.env.CDP_API_KEY_SECRET
|
|
30394
|
-
};
|
|
30395
|
-
}
|
|
30396
|
-
async function getCDPAuthHeaders(method, urlPath, body) {
|
|
30397
|
-
const config = getCDPConfig();
|
|
30398
|
-
if (!config.apiKeyId || !config.apiKeySecret) {
|
|
30399
|
-
throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
|
|
30400
|
-
}
|
|
30401
|
-
try {
|
|
30402
|
-
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
30403
|
-
const headers = await getAuthHeaders({
|
|
30404
|
-
apiKeyId: config.apiKeyId,
|
|
30405
|
-
apiKeySecret: config.apiKeySecret,
|
|
30406
|
-
requestMethod: method,
|
|
30407
|
-
requestHost: "api.cdp.coinbase.com",
|
|
30408
|
-
requestPath: urlPath,
|
|
30409
|
-
requestBody: body
|
|
30410
|
-
});
|
|
30411
|
-
return headers;
|
|
30412
|
-
} catch (err) {
|
|
30413
|
-
console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
|
|
30414
|
-
throw err;
|
|
30415
|
-
}
|
|
30416
|
-
}
|
|
30417
30845
|
var MoltsPayServer = class {
|
|
30418
30846
|
manifest;
|
|
30419
30847
|
skills = /* @__PURE__ */ new Map();
|
|
30420
30848
|
options;
|
|
30421
|
-
|
|
30422
|
-
facilitatorUrl;
|
|
30849
|
+
registry;
|
|
30423
30850
|
networkId;
|
|
30851
|
+
useMainnet;
|
|
30424
30852
|
constructor(servicesPath, options = {}) {
|
|
30425
|
-
|
|
30426
|
-
const content =
|
|
30853
|
+
loadEnvFile2();
|
|
30854
|
+
const content = readFileSync2(servicesPath, "utf-8");
|
|
30427
30855
|
this.manifest = JSON.parse(content);
|
|
30428
30856
|
this.options = {
|
|
30429
30857
|
port: options.port || 3e3,
|
|
30430
|
-
host: options.host || "0.0.0.0"
|
|
30858
|
+
host: options.host || "0.0.0.0",
|
|
30859
|
+
...options
|
|
30431
30860
|
};
|
|
30432
|
-
|
|
30433
|
-
|
|
30434
|
-
|
|
30435
|
-
|
|
30861
|
+
this.useMainnet = process.env.USE_MAINNET?.toLowerCase() === "true";
|
|
30862
|
+
this.networkId = this.useMainnet ? "eip155:8453" : "eip155:84532";
|
|
30863
|
+
const facilitatorConfig = options.facilitators || {
|
|
30864
|
+
primary: "cdp",
|
|
30865
|
+
strategy: "failover",
|
|
30866
|
+
config: {
|
|
30867
|
+
cdp: { useMainnet: this.useMainnet }
|
|
30436
30868
|
}
|
|
30437
|
-
|
|
30438
|
-
|
|
30439
|
-
|
|
30440
|
-
|
|
30441
|
-
this.networkId = "eip155:84532";
|
|
30442
|
-
}
|
|
30443
|
-
const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
|
|
30444
|
-
const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
|
|
30869
|
+
};
|
|
30870
|
+
this.registry = new FacilitatorRegistry(facilitatorConfig);
|
|
30871
|
+
const primaryFacilitator = this.registry.get(facilitatorConfig.primary);
|
|
30872
|
+
const networkName = this.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
|
|
30445
30873
|
console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
|
|
30446
30874
|
console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
|
|
30447
30875
|
console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
|
|
30448
30876
|
console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
|
|
30449
|
-
console.log(`[MoltsPay] Facilitator: ${
|
|
30450
|
-
if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
|
|
30451
|
-
console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
|
|
30452
|
-
}
|
|
30877
|
+
console.log(`[MoltsPay] Facilitator: ${primaryFacilitator.displayName} (${facilitatorConfig.strategy || "failover"})`);
|
|
30453
30878
|
console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
|
|
30454
30879
|
}
|
|
30455
30880
|
/**
|
|
@@ -30475,6 +30900,7 @@ var MoltsPayServer = class {
|
|
|
30475
30900
|
console.log(`[MoltsPay] Endpoints:`);
|
|
30476
30901
|
console.log(` GET /services - List available services`);
|
|
30477
30902
|
console.log(` POST /execute - Execute service (x402 payment)`);
|
|
30903
|
+
console.log(` GET /health - Health check (incl. facilitators)`);
|
|
30478
30904
|
});
|
|
30479
30905
|
}
|
|
30480
30906
|
/**
|
|
@@ -30495,6 +30921,9 @@ var MoltsPayServer = class {
|
|
|
30495
30921
|
if (url.pathname === "/services" && req.method === "GET") {
|
|
30496
30922
|
return this.handleGetServices(res);
|
|
30497
30923
|
}
|
|
30924
|
+
if (url.pathname === "/health" && req.method === "GET") {
|
|
30925
|
+
return await this.handleHealthCheck(res);
|
|
30926
|
+
}
|
|
30498
30927
|
if (url.pathname === "/execute" && req.method === "POST") {
|
|
30499
30928
|
const body = await this.readBody(req);
|
|
30500
30929
|
const paymentHeader = req.headers[PAYMENT_HEADER];
|
|
@@ -30520,18 +30949,37 @@ var MoltsPayServer = class {
|
|
|
30520
30949
|
output: s.output,
|
|
30521
30950
|
available: this.skills.has(s.id)
|
|
30522
30951
|
}));
|
|
30952
|
+
const selection = this.registry.getSelection();
|
|
30523
30953
|
this.sendJson(res, 200, {
|
|
30524
30954
|
provider: this.manifest.provider,
|
|
30525
30955
|
services,
|
|
30526
30956
|
x402: {
|
|
30527
|
-
version:
|
|
30957
|
+
version: X402_VERSION2,
|
|
30528
30958
|
network: this.networkId,
|
|
30529
30959
|
schemes: ["exact"],
|
|
30530
|
-
|
|
30531
|
-
|
|
30960
|
+
facilitators: {
|
|
30961
|
+
primary: selection.primary,
|
|
30962
|
+
fallback: selection.fallback,
|
|
30963
|
+
strategy: selection.strategy
|
|
30964
|
+
},
|
|
30965
|
+
mainnet: this.useMainnet
|
|
30532
30966
|
}
|
|
30533
30967
|
});
|
|
30534
30968
|
}
|
|
30969
|
+
/**
|
|
30970
|
+
* GET /health - Health check endpoint
|
|
30971
|
+
*/
|
|
30972
|
+
async handleHealthCheck(res) {
|
|
30973
|
+
const facilitatorHealth = await this.registry.healthCheckAll();
|
|
30974
|
+
const allHealthy = Object.values(facilitatorHealth).every((h) => h.healthy);
|
|
30975
|
+
this.sendJson(res, allHealthy ? 200 : 503, {
|
|
30976
|
+
status: allHealthy ? "healthy" : "degraded",
|
|
30977
|
+
network: this.networkId,
|
|
30978
|
+
facilitators: facilitatorHealth,
|
|
30979
|
+
services: this.manifest.services.length,
|
|
30980
|
+
registered: this.skills.size
|
|
30981
|
+
});
|
|
30982
|
+
}
|
|
30535
30983
|
/**
|
|
30536
30984
|
* POST /execute - Execute service with x402 payment
|
|
30537
30985
|
*/
|
|
@@ -30563,11 +31011,16 @@ var MoltsPayServer = class {
|
|
|
30563
31011
|
if (!validation.valid) {
|
|
30564
31012
|
return this.sendJson(res, 402, { error: validation.error });
|
|
30565
31013
|
}
|
|
30566
|
-
|
|
30567
|
-
|
|
31014
|
+
const requirements = this.buildPaymentRequirements(skill.config);
|
|
31015
|
+
console.log(`[MoltsPay] Verifying payment...`);
|
|
31016
|
+
const verifyResult = await this.registry.verify(payment, requirements);
|
|
30568
31017
|
if (!verifyResult.valid) {
|
|
30569
|
-
return this.sendJson(res, 402, {
|
|
31018
|
+
return this.sendJson(res, 402, {
|
|
31019
|
+
error: `Payment verification failed: ${verifyResult.error}`,
|
|
31020
|
+
facilitator: verifyResult.facilitator
|
|
31021
|
+
});
|
|
30570
31022
|
}
|
|
31023
|
+
console.log(`[MoltsPay] Verified by ${verifyResult.facilitator}`);
|
|
30571
31024
|
console.log(`[MoltsPay] Executing skill: ${service}`);
|
|
30572
31025
|
let result;
|
|
30573
31026
|
try {
|
|
@@ -30582,17 +31035,18 @@ var MoltsPayServer = class {
|
|
|
30582
31035
|
console.log(`[MoltsPay] Skill succeeded, settling payment...`);
|
|
30583
31036
|
let settlement = null;
|
|
30584
31037
|
try {
|
|
30585
|
-
settlement = await this.
|
|
30586
|
-
console.log(`[MoltsPay] Payment settled: ${settlement.transaction || "pending"}`);
|
|
31038
|
+
settlement = await this.registry.settle(payment, requirements);
|
|
31039
|
+
console.log(`[MoltsPay] Payment settled by ${settlement.facilitator}: ${settlement.transaction || "pending"}`);
|
|
30587
31040
|
} catch (err) {
|
|
30588
31041
|
console.error("[MoltsPay] Settlement failed:", err.message);
|
|
30589
31042
|
}
|
|
30590
31043
|
const responseHeaders = {};
|
|
30591
|
-
if (settlement) {
|
|
31044
|
+
if (settlement?.success) {
|
|
30592
31045
|
const responsePayload = {
|
|
30593
31046
|
success: true,
|
|
30594
31047
|
transaction: settlement.transaction,
|
|
30595
|
-
network: payment.network
|
|
31048
|
+
network: payment.network || payment.accepted?.network,
|
|
31049
|
+
facilitator: settlement.facilitator
|
|
30596
31050
|
};
|
|
30597
31051
|
responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(
|
|
30598
31052
|
JSON.stringify(responsePayload)
|
|
@@ -30601,7 +31055,7 @@ var MoltsPayServer = class {
|
|
|
30601
31055
|
this.sendJson(res, 200, {
|
|
30602
31056
|
success: true,
|
|
30603
31057
|
result,
|
|
30604
|
-
payment: settlement ? { transaction: settlement.transaction, status: "settled" } : { status: "pending" }
|
|
31058
|
+
payment: settlement?.success ? { transaction: settlement.transaction, status: "settled", facilitator: settlement.facilitator } : { status: "pending" }
|
|
30605
31059
|
}, responseHeaders);
|
|
30606
31060
|
}
|
|
30607
31061
|
/**
|
|
@@ -30610,7 +31064,7 @@ var MoltsPayServer = class {
|
|
|
30610
31064
|
sendPaymentRequired(config, res) {
|
|
30611
31065
|
const requirements = this.buildPaymentRequirements(config);
|
|
30612
31066
|
const paymentRequired = {
|
|
30613
|
-
x402Version:
|
|
31067
|
+
x402Version: X402_VERSION2,
|
|
30614
31068
|
accepts: [requirements],
|
|
30615
31069
|
resource: {
|
|
30616
31070
|
url: `/execute?service=${config.id}`,
|
|
@@ -30633,7 +31087,7 @@ var MoltsPayServer = class {
|
|
|
30633
31087
|
* Basic payment validation
|
|
30634
31088
|
*/
|
|
30635
31089
|
validatePayment(payment, config) {
|
|
30636
|
-
if (payment.x402Version !==
|
|
31090
|
+
if (payment.x402Version !== X402_VERSION2) {
|
|
30637
31091
|
return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };
|
|
30638
31092
|
}
|
|
30639
31093
|
const scheme = payment.accepted?.scheme || payment.scheme;
|
|
@@ -30647,7 +31101,7 @@ var MoltsPayServer = class {
|
|
|
30647
31101
|
return { valid: true };
|
|
30648
31102
|
}
|
|
30649
31103
|
/**
|
|
30650
|
-
* Build
|
|
31104
|
+
* Build payment requirements for facilitator
|
|
30651
31105
|
*/
|
|
30652
31106
|
buildPaymentRequirements(config) {
|
|
30653
31107
|
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
@@ -30662,77 +31116,6 @@ var MoltsPayServer = class {
|
|
|
30662
31116
|
extra: USDC_DOMAIN
|
|
30663
31117
|
};
|
|
30664
31118
|
}
|
|
30665
|
-
/**
|
|
30666
|
-
* Verify payment with facilitator (testnet or CDP)
|
|
30667
|
-
*/
|
|
30668
|
-
async verifyWithFacilitator(payment, config) {
|
|
30669
|
-
try {
|
|
30670
|
-
const requirements = this.buildPaymentRequirements(config);
|
|
30671
|
-
const requestBody = {
|
|
30672
|
-
x402Version: X402_VERSION,
|
|
30673
|
-
// Required at top level for CDP
|
|
30674
|
-
paymentPayload: payment,
|
|
30675
|
-
paymentRequirements: requirements
|
|
30676
|
-
};
|
|
30677
|
-
console.log("[MoltsPay] Verify request:", JSON.stringify(requestBody, null, 2));
|
|
30678
|
-
let headers = { "Content-Type": "application/json" };
|
|
30679
|
-
if (this.cdpConfig.useMainnet) {
|
|
30680
|
-
const authHeaders = await getCDPAuthHeaders(
|
|
30681
|
-
"POST",
|
|
30682
|
-
"/platform/v2/x402/verify",
|
|
30683
|
-
requestBody
|
|
30684
|
-
);
|
|
30685
|
-
headers = { ...headers, ...authHeaders };
|
|
30686
|
-
}
|
|
30687
|
-
const response = await fetch(`${this.facilitatorUrl}/verify`, {
|
|
30688
|
-
method: "POST",
|
|
30689
|
-
headers,
|
|
30690
|
-
body: JSON.stringify(requestBody)
|
|
30691
|
-
});
|
|
30692
|
-
const result = await response.json();
|
|
30693
|
-
console.log("[MoltsPay] Verify response:", JSON.stringify(result, null, 2));
|
|
30694
|
-
if (!response.ok || !result.isValid) {
|
|
30695
|
-
return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
|
|
30696
|
-
}
|
|
30697
|
-
return { valid: true };
|
|
30698
|
-
} catch (err) {
|
|
30699
|
-
return { valid: false, error: `Facilitator error: ${err.message}` };
|
|
30700
|
-
}
|
|
30701
|
-
}
|
|
30702
|
-
/**
|
|
30703
|
-
* Settle payment with facilitator (execute on-chain transfer)
|
|
30704
|
-
*/
|
|
30705
|
-
async settleWithFacilitator(payment, config) {
|
|
30706
|
-
const requirements = this.buildPaymentRequirements(config);
|
|
30707
|
-
const requestBody = {
|
|
30708
|
-
x402Version: X402_VERSION,
|
|
30709
|
-
// Required at top level for CDP
|
|
30710
|
-
paymentPayload: payment,
|
|
30711
|
-
paymentRequirements: requirements
|
|
30712
|
-
};
|
|
30713
|
-
let headers = { "Content-Type": "application/json" };
|
|
30714
|
-
if (this.cdpConfig.useMainnet) {
|
|
30715
|
-
const authHeaders = await getCDPAuthHeaders(
|
|
30716
|
-
"POST",
|
|
30717
|
-
"/platform/v2/x402/settle",
|
|
30718
|
-
requestBody
|
|
30719
|
-
);
|
|
30720
|
-
headers = { ...headers, ...authHeaders };
|
|
30721
|
-
}
|
|
30722
|
-
const response = await fetch(`${this.facilitatorUrl}/settle`, {
|
|
30723
|
-
method: "POST",
|
|
30724
|
-
headers,
|
|
30725
|
-
body: JSON.stringify(requestBody)
|
|
30726
|
-
});
|
|
30727
|
-
const result = await response.json();
|
|
30728
|
-
if (!response.ok || !result.success) {
|
|
30729
|
-
throw new Error(result.error || result.errorReason || "Settlement failed");
|
|
30730
|
-
}
|
|
30731
|
-
return {
|
|
30732
|
-
transaction: result.transaction,
|
|
30733
|
-
status: result.status || "settled"
|
|
30734
|
-
};
|
|
30735
|
-
}
|
|
30736
31119
|
async readBody(req) {
|
|
30737
31120
|
return new Promise((resolve, reject) => {
|
|
30738
31121
|
let body = "";
|
|
@@ -30759,9 +31142,9 @@ var MoltsPayServer = class {
|
|
|
30759
31142
|
|
|
30760
31143
|
// src/client/index.ts
|
|
30761
31144
|
init_esm_shims();
|
|
30762
|
-
import { existsSync as
|
|
31145
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync, mkdirSync, statSync, chmodSync } from "fs";
|
|
30763
31146
|
import { homedir } from "os";
|
|
30764
|
-
import { join as
|
|
31147
|
+
import { join as join3 } from "path";
|
|
30765
31148
|
import { Wallet, ethers } from "ethers";
|
|
30766
31149
|
|
|
30767
31150
|
// src/chains/index.ts
|
|
@@ -30846,7 +31229,7 @@ var ERC20_ABI = [
|
|
|
30846
31229
|
init_esm_shims();
|
|
30847
31230
|
|
|
30848
31231
|
// src/client/index.ts
|
|
30849
|
-
var
|
|
31232
|
+
var X402_VERSION3 = 2;
|
|
30850
31233
|
var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
|
|
30851
31234
|
var PAYMENT_HEADER2 = "x-payment";
|
|
30852
31235
|
var DEFAULT_CONFIG = {
|
|
@@ -30864,7 +31247,7 @@ var MoltsPayClient = class {
|
|
|
30864
31247
|
todaySpending = 0;
|
|
30865
31248
|
lastSpendingReset = 0;
|
|
30866
31249
|
constructor(options = {}) {
|
|
30867
|
-
this.configDir = options.configDir ||
|
|
31250
|
+
this.configDir = options.configDir || join3(homedir(), ".moltspay");
|
|
30868
31251
|
this.config = this.loadConfig();
|
|
30869
31252
|
this.walletData = this.loadWallet();
|
|
30870
31253
|
this.loadSpending();
|
|
@@ -30972,7 +31355,7 @@ var MoltsPayClient = class {
|
|
|
30972
31355
|
}
|
|
30973
31356
|
const authorization = await this.signEIP3009(payTo, amount, chain2);
|
|
30974
31357
|
const payload = {
|
|
30975
|
-
x402Version:
|
|
31358
|
+
x402Version: X402_VERSION3,
|
|
30976
31359
|
payload: authorization,
|
|
30977
31360
|
// v2 requires 'accepted' field with the requirements being fulfilled
|
|
30978
31361
|
accepted: {
|
|
@@ -31069,26 +31452,26 @@ var MoltsPayClient = class {
|
|
|
31069
31452
|
}
|
|
31070
31453
|
// --- Config & Wallet Management ---
|
|
31071
31454
|
loadConfig() {
|
|
31072
|
-
const configPath =
|
|
31073
|
-
if (
|
|
31074
|
-
const content =
|
|
31455
|
+
const configPath = join3(this.configDir, "config.json");
|
|
31456
|
+
if (existsSync3(configPath)) {
|
|
31457
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
31075
31458
|
return { ...DEFAULT_CONFIG, ...JSON.parse(content) };
|
|
31076
31459
|
}
|
|
31077
31460
|
return { ...DEFAULT_CONFIG };
|
|
31078
31461
|
}
|
|
31079
31462
|
saveConfig() {
|
|
31080
31463
|
mkdirSync(this.configDir, { recursive: true });
|
|
31081
|
-
const configPath =
|
|
31464
|
+
const configPath = join3(this.configDir, "config.json");
|
|
31082
31465
|
writeFileSync(configPath, JSON.stringify(this.config, null, 2));
|
|
31083
31466
|
}
|
|
31084
31467
|
/**
|
|
31085
31468
|
* Load spending data from disk
|
|
31086
31469
|
*/
|
|
31087
31470
|
loadSpending() {
|
|
31088
|
-
const spendingPath =
|
|
31089
|
-
if (
|
|
31471
|
+
const spendingPath = join3(this.configDir, "spending.json");
|
|
31472
|
+
if (existsSync3(spendingPath)) {
|
|
31090
31473
|
try {
|
|
31091
|
-
const data = JSON.parse(
|
|
31474
|
+
const data = JSON.parse(readFileSync3(spendingPath, "utf-8"));
|
|
31092
31475
|
const today = (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0);
|
|
31093
31476
|
if (data.date && data.date === today) {
|
|
31094
31477
|
this.todaySpending = data.amount || 0;
|
|
@@ -31108,7 +31491,7 @@ var MoltsPayClient = class {
|
|
|
31108
31491
|
*/
|
|
31109
31492
|
saveSpending() {
|
|
31110
31493
|
mkdirSync(this.configDir, { recursive: true });
|
|
31111
|
-
const spendingPath =
|
|
31494
|
+
const spendingPath = join3(this.configDir, "spending.json");
|
|
31112
31495
|
const data = {
|
|
31113
31496
|
date: this.lastSpendingReset || (/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0),
|
|
31114
31497
|
amount: this.todaySpending,
|
|
@@ -31117,8 +31500,8 @@ var MoltsPayClient = class {
|
|
|
31117
31500
|
writeFileSync(spendingPath, JSON.stringify(data, null, 2));
|
|
31118
31501
|
}
|
|
31119
31502
|
loadWallet() {
|
|
31120
|
-
const walletPath =
|
|
31121
|
-
if (
|
|
31503
|
+
const walletPath = join3(this.configDir, "wallet.json");
|
|
31504
|
+
if (existsSync3(walletPath)) {
|
|
31122
31505
|
try {
|
|
31123
31506
|
const stats = statSync(walletPath);
|
|
31124
31507
|
const mode = stats.mode & 511;
|
|
@@ -31129,7 +31512,7 @@ var MoltsPayClient = class {
|
|
|
31129
31512
|
}
|
|
31130
31513
|
} catch (err) {
|
|
31131
31514
|
}
|
|
31132
|
-
const content =
|
|
31515
|
+
const content = readFileSync3(walletPath, "utf-8");
|
|
31133
31516
|
return JSON.parse(content);
|
|
31134
31517
|
}
|
|
31135
31518
|
return null;
|
|
@@ -31145,7 +31528,7 @@ var MoltsPayClient = class {
|
|
|
31145
31528
|
privateKey: wallet.privateKey,
|
|
31146
31529
|
createdAt: Date.now()
|
|
31147
31530
|
};
|
|
31148
|
-
const walletPath =
|
|
31531
|
+
const walletPath = join3(configDir, "wallet.json");
|
|
31149
31532
|
writeFileSync(walletPath, JSON.stringify(walletData, null, 2), { mode: 384 });
|
|
31150
31533
|
const config = {
|
|
31151
31534
|
chain: options.chain,
|
|
@@ -31154,7 +31537,7 @@ var MoltsPayClient = class {
|
|
|
31154
31537
|
maxPerDay: options.maxPerDay
|
|
31155
31538
|
}
|
|
31156
31539
|
};
|
|
31157
|
-
const configPath =
|
|
31540
|
+
const configPath = join3(configDir, "config.json");
|
|
31158
31541
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
31159
31542
|
return { address: wallet.address, configDir };
|
|
31160
31543
|
}
|
|
@@ -31193,10 +31576,10 @@ import { ethers as ethers2 } from "ethers";
|
|
|
31193
31576
|
// src/wallet/createWallet.ts
|
|
31194
31577
|
init_esm_shims();
|
|
31195
31578
|
import { ethers as ethers3 } from "ethers";
|
|
31196
|
-
import { writeFileSync as writeFileSync2, readFileSync as
|
|
31197
|
-
import { join as
|
|
31579
|
+
import { writeFileSync as writeFileSync2, readFileSync as readFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
31580
|
+
import { join as join4, dirname } from "path";
|
|
31198
31581
|
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
|
|
31199
|
-
var DEFAULT_STORAGE_DIR =
|
|
31582
|
+
var DEFAULT_STORAGE_DIR = join4(process.env.HOME || "~", ".moltspay");
|
|
31200
31583
|
var DEFAULT_STORAGE_FILE = "wallet.json";
|
|
31201
31584
|
function encryptPrivateKey(privateKey, password) {
|
|
31202
31585
|
const salt = randomBytes(16);
|
|
@@ -31219,10 +31602,10 @@ function decryptPrivateKey(encrypted, password, iv, salt) {
|
|
|
31219
31602
|
return decrypted;
|
|
31220
31603
|
}
|
|
31221
31604
|
function createWallet(options = {}) {
|
|
31222
|
-
const storagePath = options.storagePath ||
|
|
31223
|
-
if (
|
|
31605
|
+
const storagePath = options.storagePath || join4(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
31606
|
+
if (existsSync4(storagePath) && !options.overwrite) {
|
|
31224
31607
|
try {
|
|
31225
|
-
const existing = JSON.parse(
|
|
31608
|
+
const existing = JSON.parse(readFileSync4(storagePath, "utf8"));
|
|
31226
31609
|
return {
|
|
31227
31610
|
success: true,
|
|
31228
31611
|
address: existing.address,
|
|
@@ -31254,7 +31637,7 @@ function createWallet(options = {}) {
|
|
|
31254
31637
|
walletData.privateKey = wallet.privateKey;
|
|
31255
31638
|
}
|
|
31256
31639
|
const dir = dirname(storagePath);
|
|
31257
|
-
if (!
|
|
31640
|
+
if (!existsSync4(dir)) {
|
|
31258
31641
|
mkdirSync2(dir, { recursive: true });
|
|
31259
31642
|
}
|
|
31260
31643
|
writeFileSync2(storagePath, JSON.stringify(walletData, null, 2), { mode: 384 });
|
|
@@ -31272,12 +31655,12 @@ function createWallet(options = {}) {
|
|
|
31272
31655
|
}
|
|
31273
31656
|
}
|
|
31274
31657
|
function loadWallet(options = {}) {
|
|
31275
|
-
const storagePath = options.storagePath ||
|
|
31276
|
-
if (!
|
|
31658
|
+
const storagePath = options.storagePath || join4(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
31659
|
+
if (!existsSync4(storagePath)) {
|
|
31277
31660
|
return { success: false, error: "Wallet not found. Run createWallet() first." };
|
|
31278
31661
|
}
|
|
31279
31662
|
try {
|
|
31280
|
-
const data = JSON.parse(
|
|
31663
|
+
const data = JSON.parse(readFileSync4(storagePath, "utf8"));
|
|
31281
31664
|
if (data.encrypted) {
|
|
31282
31665
|
if (!options.password) {
|
|
31283
31666
|
return { success: false, error: "Wallet is encrypted. Password required." };
|
|
@@ -31292,20 +31675,20 @@ function loadWallet(options = {}) {
|
|
|
31292
31675
|
}
|
|
31293
31676
|
}
|
|
31294
31677
|
function getWalletAddress(storagePath) {
|
|
31295
|
-
const
|
|
31296
|
-
if (!
|
|
31678
|
+
const path5 = storagePath || join4(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
31679
|
+
if (!existsSync4(path5)) {
|
|
31297
31680
|
return null;
|
|
31298
31681
|
}
|
|
31299
31682
|
try {
|
|
31300
|
-
const data = JSON.parse(
|
|
31683
|
+
const data = JSON.parse(readFileSync4(path5, "utf8"));
|
|
31301
31684
|
return data.address;
|
|
31302
31685
|
} catch {
|
|
31303
31686
|
return null;
|
|
31304
31687
|
}
|
|
31305
31688
|
}
|
|
31306
31689
|
function walletExists(storagePath) {
|
|
31307
|
-
const
|
|
31308
|
-
return
|
|
31690
|
+
const path5 = storagePath || join4(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
31691
|
+
return existsSync4(path5);
|
|
31309
31692
|
}
|
|
31310
31693
|
|
|
31311
31694
|
// src/verify/index.ts
|
|
@@ -31448,8 +31831,8 @@ async function waitForTransaction(txHash, chain2 = "base", confirmations = 1, ti
|
|
|
31448
31831
|
// src/cdp/index.ts
|
|
31449
31832
|
init_esm_shims();
|
|
31450
31833
|
import * as fs from "fs";
|
|
31451
|
-
import * as
|
|
31452
|
-
var DEFAULT_STORAGE_DIR2 =
|
|
31834
|
+
import * as path4 from "path";
|
|
31835
|
+
var DEFAULT_STORAGE_DIR2 = path4.join(process.env.HOME || ".", ".moltspay");
|
|
31453
31836
|
var CDP_CONFIG_FILE = "cdp-wallet.json";
|
|
31454
31837
|
function isCDPAvailable() {
|
|
31455
31838
|
try {
|
|
@@ -31471,7 +31854,7 @@ function getCDPCredentials(config) {
|
|
|
31471
31854
|
async function initCDPWallet(config = {}) {
|
|
31472
31855
|
const storageDir = config.storageDir || DEFAULT_STORAGE_DIR2;
|
|
31473
31856
|
const chain2 = config.chain || "base";
|
|
31474
|
-
const storagePath =
|
|
31857
|
+
const storagePath = path4.join(storageDir, CDP_CONFIG_FILE);
|
|
31475
31858
|
if (fs.existsSync(storagePath)) {
|
|
31476
31859
|
try {
|
|
31477
31860
|
const data = JSON.parse(fs.readFileSync(storagePath, "utf-8"));
|
|
@@ -31533,7 +31916,7 @@ async function initCDPWallet(config = {}) {
|
|
|
31533
31916
|
}
|
|
31534
31917
|
function loadCDPWallet(config = {}) {
|
|
31535
31918
|
const storageDir = config.storageDir || DEFAULT_STORAGE_DIR2;
|
|
31536
|
-
const storagePath =
|
|
31919
|
+
const storagePath = path4.join(storageDir, CDP_CONFIG_FILE);
|
|
31537
31920
|
if (!fs.existsSync(storagePath)) {
|
|
31538
31921
|
return null;
|
|
31539
31922
|
}
|
|
@@ -31651,15 +32034,20 @@ var CDPWallet = class {
|
|
|
31651
32034
|
}
|
|
31652
32035
|
};
|
|
31653
32036
|
export {
|
|
32037
|
+
BaseFacilitator,
|
|
32038
|
+
CDPFacilitator,
|
|
31654
32039
|
CDPWallet,
|
|
31655
32040
|
CHAINS,
|
|
31656
32041
|
ERC20_ABI,
|
|
32042
|
+
FacilitatorRegistry,
|
|
31657
32043
|
MoltsPayClient,
|
|
31658
32044
|
MoltsPayServer,
|
|
32045
|
+
createRegistry,
|
|
31659
32046
|
createWallet,
|
|
31660
32047
|
getCDPWalletAddress,
|
|
31661
32048
|
getChain,
|
|
31662
32049
|
getChainById,
|
|
32050
|
+
getDefaultRegistry,
|
|
31663
32051
|
getTransactionStatus,
|
|
31664
32052
|
getWalletAddress,
|
|
31665
32053
|
initCDPWallet,
|