moltspay 0.9.0 → 0.9.2
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/.env.example +48 -3
- package/dist/cli/index.js +163 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +163 -2
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.js +163 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -2
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +25 -0
- package/dist/server/index.d.ts +25 -0
- package/dist/server/index.js +163 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +163 -2
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -30861,8 +30861,9 @@ var MoltsPayServer = class {
|
|
|
30861
30861
|
this.useMainnet = process.env.USE_MAINNET?.toLowerCase() === "true";
|
|
30862
30862
|
this.networkId = this.useMainnet ? "eip155:8453" : "eip155:84532";
|
|
30863
30863
|
const facilitatorConfig = options.facilitators || {
|
|
30864
|
-
primary: "cdp",
|
|
30865
|
-
|
|
30864
|
+
primary: process.env.FACILITATOR_PRIMARY || "cdp",
|
|
30865
|
+
fallback: process.env.FACILITATOR_FALLBACK?.split(",").filter(Boolean),
|
|
30866
|
+
strategy: process.env.FACILITATOR_STRATEGY || "failover",
|
|
30866
30867
|
config: {
|
|
30867
30868
|
cdp: { useMainnet: this.useMainnet }
|
|
30868
30869
|
}
|
|
@@ -30900,6 +30901,7 @@ var MoltsPayServer = class {
|
|
|
30900
30901
|
console.log(`[MoltsPay] Endpoints:`);
|
|
30901
30902
|
console.log(` GET /services - List available services`);
|
|
30902
30903
|
console.log(` POST /execute - Execute service (x402 payment)`);
|
|
30904
|
+
console.log(` POST /proxy - Proxy payment for external services`);
|
|
30903
30905
|
console.log(` GET /health - Health check (incl. facilitators)`);
|
|
30904
30906
|
});
|
|
30905
30907
|
}
|
|
@@ -30929,6 +30931,15 @@ var MoltsPayServer = class {
|
|
|
30929
30931
|
const paymentHeader = req.headers[PAYMENT_HEADER];
|
|
30930
30932
|
return await this.handleExecute(body, paymentHeader, res);
|
|
30931
30933
|
}
|
|
30934
|
+
if (url.pathname === "/proxy" && req.method === "POST") {
|
|
30935
|
+
const clientIP = req.headers["x-real-ip"] || req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.socket.remoteAddress || "";
|
|
30936
|
+
if (!this.isProxyAllowed(clientIP)) {
|
|
30937
|
+
return this.sendJson(res, 403, { error: "Forbidden: IP not allowed" });
|
|
30938
|
+
}
|
|
30939
|
+
const body = await this.readBody(req);
|
|
30940
|
+
const paymentHeader = req.headers[PAYMENT_HEADER];
|
|
30941
|
+
return await this.handleProxy(body, paymentHeader, res);
|
|
30942
|
+
}
|
|
30932
30943
|
this.sendJson(res, 404, { error: "Not found" });
|
|
30933
30944
|
} catch (err) {
|
|
30934
30945
|
console.error("[MoltsPay] Error:", err);
|
|
@@ -31138,6 +31149,156 @@ var MoltsPayServer = class {
|
|
|
31138
31149
|
res.writeHead(status, headers);
|
|
31139
31150
|
res.end(JSON.stringify(data, null, 2));
|
|
31140
31151
|
}
|
|
31152
|
+
/**
|
|
31153
|
+
* Check if IP is allowed for /proxy endpoint
|
|
31154
|
+
*/
|
|
31155
|
+
isProxyAllowed(clientIP) {
|
|
31156
|
+
const allowedIPs = process.env.PROXY_ALLOWED_IPS?.split(",").map((ip) => ip.trim()) || [];
|
|
31157
|
+
if (allowedIPs.length === 0) {
|
|
31158
|
+
console.log(`[MoltsPay] /proxy denied: no PROXY_ALLOWED_IPS configured`);
|
|
31159
|
+
return false;
|
|
31160
|
+
}
|
|
31161
|
+
const normalizedIP = clientIP === "::1" ? "127.0.0.1" : clientIP.replace("::ffff:", "");
|
|
31162
|
+
const allowed = allowedIPs.includes(normalizedIP) || allowedIPs.includes(clientIP);
|
|
31163
|
+
if (!allowed) {
|
|
31164
|
+
console.log(`[MoltsPay] /proxy denied for IP: ${clientIP} (normalized: ${normalizedIP})`);
|
|
31165
|
+
}
|
|
31166
|
+
return allowed;
|
|
31167
|
+
}
|
|
31168
|
+
/**
|
|
31169
|
+
* POST /proxy - Handle payment for external services (moltspay-creators)
|
|
31170
|
+
*
|
|
31171
|
+
* This endpoint allows other services to delegate x402 payment handling.
|
|
31172
|
+
* It does NOT execute any skill - just handles payment verification/settlement.
|
|
31173
|
+
*
|
|
31174
|
+
* Request body:
|
|
31175
|
+
* { wallet, amount, currency, chain, memo, serviceId, description }
|
|
31176
|
+
*
|
|
31177
|
+
* Without X-Payment header: returns 402 with payment requirements
|
|
31178
|
+
* With X-Payment header: verifies payment and returns result
|
|
31179
|
+
*/
|
|
31180
|
+
async handleProxy(body, paymentHeader, res) {
|
|
31181
|
+
const { wallet, amount, currency, chain: chain2, memo, serviceId, description } = body;
|
|
31182
|
+
if (!wallet || !amount) {
|
|
31183
|
+
return this.sendJson(res, 400, { error: "Missing required fields: wallet, amount" });
|
|
31184
|
+
}
|
|
31185
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(wallet)) {
|
|
31186
|
+
return this.sendJson(res, 400, { error: "Invalid wallet address format" });
|
|
31187
|
+
}
|
|
31188
|
+
const amountNum = parseFloat(amount);
|
|
31189
|
+
if (isNaN(amountNum) || amountNum <= 0) {
|
|
31190
|
+
return this.sendJson(res, 400, { error: "Invalid amount" });
|
|
31191
|
+
}
|
|
31192
|
+
const proxyConfig = {
|
|
31193
|
+
id: serviceId || "proxy",
|
|
31194
|
+
name: description || "Proxy Payment",
|
|
31195
|
+
description: description || "",
|
|
31196
|
+
price: amountNum,
|
|
31197
|
+
currency: currency || "USDC",
|
|
31198
|
+
function: "",
|
|
31199
|
+
// Not used
|
|
31200
|
+
input: {},
|
|
31201
|
+
output: {}
|
|
31202
|
+
};
|
|
31203
|
+
const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet);
|
|
31204
|
+
if (!paymentHeader) {
|
|
31205
|
+
return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, res);
|
|
31206
|
+
}
|
|
31207
|
+
let payment;
|
|
31208
|
+
try {
|
|
31209
|
+
const decoded = Buffer.from(paymentHeader, "base64").toString("utf-8");
|
|
31210
|
+
payment = JSON.parse(decoded);
|
|
31211
|
+
} catch {
|
|
31212
|
+
return this.sendJson(res, 400, { error: "Invalid X-Payment header" });
|
|
31213
|
+
}
|
|
31214
|
+
if (payment.x402Version !== X402_VERSION2) {
|
|
31215
|
+
return this.sendJson(res, 402, { error: `Unsupported x402 version: ${payment.x402Version}` });
|
|
31216
|
+
}
|
|
31217
|
+
const scheme = payment.accepted?.scheme || payment.scheme;
|
|
31218
|
+
const network = payment.accepted?.network || payment.network;
|
|
31219
|
+
if (scheme !== "exact") {
|
|
31220
|
+
return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });
|
|
31221
|
+
}
|
|
31222
|
+
if (network !== this.networkId) {
|
|
31223
|
+
return this.sendJson(res, 402, { error: `Network mismatch: expected ${this.networkId}, got ${network}` });
|
|
31224
|
+
}
|
|
31225
|
+
console.log(`[MoltsPay] /proxy: Verifying payment for ${wallet}...`);
|
|
31226
|
+
const verifyResult = await this.registry.verify(payment, requirements);
|
|
31227
|
+
if (!verifyResult.valid) {
|
|
31228
|
+
return this.sendJson(res, 402, {
|
|
31229
|
+
success: false,
|
|
31230
|
+
error: `Payment verification failed: ${verifyResult.error}`,
|
|
31231
|
+
facilitator: verifyResult.facilitator
|
|
31232
|
+
});
|
|
31233
|
+
}
|
|
31234
|
+
console.log(`[MoltsPay] /proxy: Verified by ${verifyResult.facilitator}`);
|
|
31235
|
+
console.log(`[MoltsPay] /proxy: Settling payment...`);
|
|
31236
|
+
let settlement = null;
|
|
31237
|
+
try {
|
|
31238
|
+
settlement = await this.registry.settle(payment, requirements);
|
|
31239
|
+
console.log(`[MoltsPay] /proxy: Payment settled by ${settlement.facilitator}: ${settlement.transaction || "pending"}`);
|
|
31240
|
+
} catch (err) {
|
|
31241
|
+
console.error("[MoltsPay] /proxy: Settlement failed:", err.message);
|
|
31242
|
+
return this.sendJson(res, 500, {
|
|
31243
|
+
success: false,
|
|
31244
|
+
error: `Settlement failed: ${err.message}`
|
|
31245
|
+
});
|
|
31246
|
+
}
|
|
31247
|
+
this.sendJson(res, 200, {
|
|
31248
|
+
success: true,
|
|
31249
|
+
verified: true,
|
|
31250
|
+
settled: settlement?.success || false,
|
|
31251
|
+
txHash: settlement?.transaction,
|
|
31252
|
+
paidTo: wallet,
|
|
31253
|
+
amount: amountNum,
|
|
31254
|
+
currency: currency || "USDC",
|
|
31255
|
+
facilitator: settlement?.facilitator,
|
|
31256
|
+
memo
|
|
31257
|
+
});
|
|
31258
|
+
}
|
|
31259
|
+
/**
|
|
31260
|
+
* Build payment requirements for proxy endpoint (uses provided wallet)
|
|
31261
|
+
*/
|
|
31262
|
+
buildProxyPaymentRequirements(config, wallet) {
|
|
31263
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
31264
|
+
const usdcAddress = USDC_ADDRESSES[this.networkId];
|
|
31265
|
+
return {
|
|
31266
|
+
scheme: "exact",
|
|
31267
|
+
network: this.networkId,
|
|
31268
|
+
asset: usdcAddress,
|
|
31269
|
+
amount: amountInUnits,
|
|
31270
|
+
payTo: wallet,
|
|
31271
|
+
// Use provided wallet, not manifest
|
|
31272
|
+
maxTimeoutSeconds: 300,
|
|
31273
|
+
extra: USDC_DOMAIN
|
|
31274
|
+
};
|
|
31275
|
+
}
|
|
31276
|
+
/**
|
|
31277
|
+
* Return 402 with x402 payment requirements for proxy endpoint
|
|
31278
|
+
*/
|
|
31279
|
+
sendProxyPaymentRequired(config, wallet, memo, res) {
|
|
31280
|
+
const requirements = this.buildProxyPaymentRequirements(config, wallet);
|
|
31281
|
+
const paymentRequired = {
|
|
31282
|
+
x402Version: X402_VERSION2,
|
|
31283
|
+
accepts: [requirements],
|
|
31284
|
+
resource: {
|
|
31285
|
+
url: `/proxy`,
|
|
31286
|
+
description: `${config.name} - $${config.price} ${config.currency}`,
|
|
31287
|
+
mimeType: "application/json",
|
|
31288
|
+
memo
|
|
31289
|
+
}
|
|
31290
|
+
};
|
|
31291
|
+
const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString("base64");
|
|
31292
|
+
res.writeHead(402, {
|
|
31293
|
+
"Content-Type": "application/json",
|
|
31294
|
+
[PAYMENT_REQUIRED_HEADER]: encoded
|
|
31295
|
+
});
|
|
31296
|
+
res.end(JSON.stringify({
|
|
31297
|
+
error: "Payment required",
|
|
31298
|
+
message: `Payment requires $${config.price} ${config.currency}`,
|
|
31299
|
+
x402: paymentRequired
|
|
31300
|
+
}, null, 2));
|
|
31301
|
+
}
|
|
31141
31302
|
};
|
|
31142
31303
|
|
|
31143
31304
|
// src/client/index.ts
|