moltspay 0.7.2 → 0.8.1
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/dist/cli/index.js +293 -274
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +294 -275
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +11 -5
- package/dist/client/index.d.ts +11 -5
- package/dist/client/index.js +99 -68
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +96 -55
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.js +435 -343
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +430 -338
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +25 -9
- package/dist/server/index.d.ts +25 -9
- package/dist/server/index.js +187 -210
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +187 -210
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -30333,10 +30333,6 @@ init_esm_shims();
|
|
|
30333
30333
|
import { readFileSync } from "fs";
|
|
30334
30334
|
import { createServer } from "http";
|
|
30335
30335
|
|
|
30336
|
-
// src/verify/index.ts
|
|
30337
|
-
init_esm_shims();
|
|
30338
|
-
import { ethers } from "ethers";
|
|
30339
|
-
|
|
30340
30336
|
// src/chains/index.ts
|
|
30341
30337
|
init_esm_shims();
|
|
30342
30338
|
var CHAINS = {
|
|
@@ -30415,165 +30411,33 @@ var ERC20_ABI = [
|
|
|
30415
30411
|
"event Approval(address indexed owner, address indexed spender, uint256 value)"
|
|
30416
30412
|
];
|
|
30417
30413
|
|
|
30418
|
-
// src/verify/index.ts
|
|
30419
|
-
var TRANSFER_EVENT_TOPIC = ethers.id("Transfer(address,address,uint256)");
|
|
30420
|
-
async function verifyPayment(params) {
|
|
30421
|
-
const { txHash, expectedAmount, expectedTo } = params;
|
|
30422
|
-
let chain2;
|
|
30423
|
-
try {
|
|
30424
|
-
if (typeof params.chain === "number") {
|
|
30425
|
-
chain2 = getChainById(params.chain);
|
|
30426
|
-
} else {
|
|
30427
|
-
chain2 = getChain(params.chain || "base");
|
|
30428
|
-
}
|
|
30429
|
-
if (!chain2) {
|
|
30430
|
-
return { verified: false, error: `Unsupported chain: ${params.chain}` };
|
|
30431
|
-
}
|
|
30432
|
-
} catch (e) {
|
|
30433
|
-
return { verified: false, error: `Unsupported chain: ${params.chain}` };
|
|
30434
|
-
}
|
|
30435
|
-
try {
|
|
30436
|
-
const provider = new ethers.JsonRpcProvider(chain2.rpc);
|
|
30437
|
-
const receipt = await provider.getTransactionReceipt(txHash);
|
|
30438
|
-
if (!receipt) {
|
|
30439
|
-
return { verified: false, error: "Transaction not found or not confirmed" };
|
|
30440
|
-
}
|
|
30441
|
-
if (receipt.status !== 1) {
|
|
30442
|
-
return { verified: false, error: "Transaction failed" };
|
|
30443
|
-
}
|
|
30444
|
-
const usdcAddress = chain2.usdc?.toLowerCase();
|
|
30445
|
-
if (!usdcAddress) {
|
|
30446
|
-
return { verified: false, error: `Chain ${chain2.name} USDC address not configured` };
|
|
30447
|
-
}
|
|
30448
|
-
for (const log of receipt.logs) {
|
|
30449
|
-
if (log.address.toLowerCase() !== usdcAddress) {
|
|
30450
|
-
continue;
|
|
30451
|
-
}
|
|
30452
|
-
if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {
|
|
30453
|
-
continue;
|
|
30454
|
-
}
|
|
30455
|
-
const from = "0x" + log.topics[1].slice(-40);
|
|
30456
|
-
const to = "0x" + log.topics[2].slice(-40);
|
|
30457
|
-
const amountRaw = BigInt(log.data);
|
|
30458
|
-
const amount = Number(amountRaw) / 1e6;
|
|
30459
|
-
if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {
|
|
30460
|
-
continue;
|
|
30461
|
-
}
|
|
30462
|
-
if (amount < expectedAmount) {
|
|
30463
|
-
return {
|
|
30464
|
-
verified: false,
|
|
30465
|
-
error: `Insufficient amount: received ${amount} USDC, expected ${expectedAmount} USDC`,
|
|
30466
|
-
amount,
|
|
30467
|
-
from,
|
|
30468
|
-
to,
|
|
30469
|
-
txHash,
|
|
30470
|
-
blockNumber: receipt.blockNumber
|
|
30471
|
-
};
|
|
30472
|
-
}
|
|
30473
|
-
return {
|
|
30474
|
-
verified: true,
|
|
30475
|
-
amount,
|
|
30476
|
-
from,
|
|
30477
|
-
to,
|
|
30478
|
-
txHash,
|
|
30479
|
-
blockNumber: receipt.blockNumber
|
|
30480
|
-
};
|
|
30481
|
-
}
|
|
30482
|
-
return { verified: false, error: "No USDC transfer found" };
|
|
30483
|
-
} catch (e) {
|
|
30484
|
-
return { verified: false, error: e.message || String(e) };
|
|
30485
|
-
}
|
|
30486
|
-
}
|
|
30487
|
-
async function getTransactionStatus(txHash, chain2 = "base") {
|
|
30488
|
-
let chainConfig;
|
|
30489
|
-
try {
|
|
30490
|
-
chainConfig = typeof chain2 === "number" ? getChainById(chain2) : getChain(chain2);
|
|
30491
|
-
if (!chainConfig) return { status: "not_found" };
|
|
30492
|
-
} catch {
|
|
30493
|
-
return { status: "not_found" };
|
|
30494
|
-
}
|
|
30495
|
-
try {
|
|
30496
|
-
const provider = new ethers.JsonRpcProvider(chainConfig.rpc);
|
|
30497
|
-
const receipt = await provider.getTransactionReceipt(txHash);
|
|
30498
|
-
if (!receipt) {
|
|
30499
|
-
const tx = await provider.getTransaction(txHash);
|
|
30500
|
-
if (tx) {
|
|
30501
|
-
return { status: "pending" };
|
|
30502
|
-
}
|
|
30503
|
-
return { status: "not_found" };
|
|
30504
|
-
}
|
|
30505
|
-
const currentBlock = await provider.getBlockNumber();
|
|
30506
|
-
const confirmations = currentBlock - receipt.blockNumber;
|
|
30507
|
-
if (receipt.status === 1) {
|
|
30508
|
-
return {
|
|
30509
|
-
status: "confirmed",
|
|
30510
|
-
blockNumber: receipt.blockNumber,
|
|
30511
|
-
confirmations
|
|
30512
|
-
};
|
|
30513
|
-
} else {
|
|
30514
|
-
return {
|
|
30515
|
-
status: "failed",
|
|
30516
|
-
blockNumber: receipt.blockNumber
|
|
30517
|
-
};
|
|
30518
|
-
}
|
|
30519
|
-
} catch {
|
|
30520
|
-
return { status: "not_found" };
|
|
30521
|
-
}
|
|
30522
|
-
}
|
|
30523
|
-
async function waitForTransaction(txHash, chain2 = "base", confirmations = 1, timeoutMs = 6e4) {
|
|
30524
|
-
let chainConfig;
|
|
30525
|
-
try {
|
|
30526
|
-
chainConfig = typeof chain2 === "number" ? getChainById(chain2) : getChain(chain2);
|
|
30527
|
-
if (!chainConfig) {
|
|
30528
|
-
return { verified: false, confirmed: false, error: `Unsupported chain: ${chain2}` };
|
|
30529
|
-
}
|
|
30530
|
-
} catch (e) {
|
|
30531
|
-
return { verified: false, confirmed: false, error: `Unsupported chain: ${chain2}` };
|
|
30532
|
-
}
|
|
30533
|
-
const provider = new ethers.JsonRpcProvider(chainConfig.rpc);
|
|
30534
|
-
try {
|
|
30535
|
-
const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
|
|
30536
|
-
if (!receipt) {
|
|
30537
|
-
return { verified: false, confirmed: false, error: "Timeout waiting" };
|
|
30538
|
-
}
|
|
30539
|
-
if (receipt.status !== 1) {
|
|
30540
|
-
return { verified: false, confirmed: true, error: "Transaction failed" };
|
|
30541
|
-
}
|
|
30542
|
-
return {
|
|
30543
|
-
verified: true,
|
|
30544
|
-
confirmed: true,
|
|
30545
|
-
txHash,
|
|
30546
|
-
blockNumber: receipt.blockNumber
|
|
30547
|
-
};
|
|
30548
|
-
} catch (e) {
|
|
30549
|
-
return { verified: false, confirmed: false, error: e.message || String(e) };
|
|
30550
|
-
}
|
|
30551
|
-
}
|
|
30552
|
-
|
|
30553
30414
|
// src/server/types.ts
|
|
30554
30415
|
init_esm_shims();
|
|
30555
30416
|
|
|
30556
30417
|
// src/server/index.ts
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
|
|
30418
|
+
var X402_VERSION = 2;
|
|
30419
|
+
var PAYMENT_REQUIRED_HEADER = "x-payment-required";
|
|
30420
|
+
var PAYMENT_HEADER = "x-payment";
|
|
30421
|
+
var PAYMENT_RESPONSE_HEADER = "x-payment-response";
|
|
30422
|
+
var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
|
|
30560
30423
|
var MoltsPayServer = class {
|
|
30561
30424
|
manifest;
|
|
30562
30425
|
skills = /* @__PURE__ */ new Map();
|
|
30563
|
-
charges = /* @__PURE__ */ new Map();
|
|
30564
30426
|
options;
|
|
30427
|
+
facilitatorUrl;
|
|
30565
30428
|
constructor(servicesPath, options = {}) {
|
|
30566
30429
|
const content = readFileSync(servicesPath, "utf-8");
|
|
30567
30430
|
this.manifest = JSON.parse(content);
|
|
30568
30431
|
this.options = {
|
|
30569
30432
|
port: options.port || 3e3,
|
|
30570
|
-
host: options.host || "0.0.0.0"
|
|
30571
|
-
chargeExpirySecs: options.chargeExpirySecs || 300
|
|
30572
|
-
// 5 minutes
|
|
30433
|
+
host: options.host || "0.0.0.0"
|
|
30573
30434
|
};
|
|
30435
|
+
this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
|
|
30574
30436
|
console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
|
|
30575
30437
|
console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
|
|
30576
|
-
console.log(`[MoltsPay]
|
|
30438
|
+
console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
|
|
30439
|
+
console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
|
|
30440
|
+
console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
|
|
30577
30441
|
}
|
|
30578
30442
|
/**
|
|
30579
30443
|
* Register a skill handler for a service
|
|
@@ -30583,56 +30447,45 @@ var MoltsPayServer = class {
|
|
|
30583
30447
|
if (!config) {
|
|
30584
30448
|
throw new Error(`Service '${serviceId}' not found in manifest`);
|
|
30585
30449
|
}
|
|
30586
|
-
this.skills.set(serviceId, {
|
|
30587
|
-
id: serviceId,
|
|
30588
|
-
config,
|
|
30589
|
-
handler
|
|
30590
|
-
});
|
|
30591
|
-
console.log(`[MoltsPay] Registered skill: ${serviceId} ($${config.price} ${config.currency})`);
|
|
30450
|
+
this.skills.set(serviceId, { id: serviceId, config, handler });
|
|
30592
30451
|
return this;
|
|
30593
30452
|
}
|
|
30594
30453
|
/**
|
|
30595
|
-
* Start
|
|
30454
|
+
* Start HTTP server
|
|
30596
30455
|
*/
|
|
30597
30456
|
listen(port) {
|
|
30598
|
-
const p = port || this.options.port;
|
|
30457
|
+
const p = port || this.options.port || 3e3;
|
|
30458
|
+
const host = this.options.host || "0.0.0.0";
|
|
30599
30459
|
const server = createServer((req, res) => this.handleRequest(req, res));
|
|
30600
|
-
server.listen(p,
|
|
30601
|
-
console.log(`[MoltsPay] Server listening on http://${
|
|
30460
|
+
server.listen(p, host, () => {
|
|
30461
|
+
console.log(`[MoltsPay] Server listening on http://${host}:${p}`);
|
|
30602
30462
|
console.log(`[MoltsPay] Endpoints:`);
|
|
30603
|
-
console.log(` GET /services
|
|
30604
|
-
console.log(` POST /
|
|
30605
|
-
console.log(` POST /verify - Verify payment & get result`);
|
|
30606
|
-
console.log(` GET /status/:id - Check charge status`);
|
|
30463
|
+
console.log(` GET /services - List available services`);
|
|
30464
|
+
console.log(` POST /execute - Execute service (x402 payment)`);
|
|
30607
30465
|
});
|
|
30608
30466
|
}
|
|
30467
|
+
/**
|
|
30468
|
+
* Handle incoming request
|
|
30469
|
+
*/
|
|
30609
30470
|
async handleRequest(req, res) {
|
|
30610
|
-
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
30611
|
-
const path3 = url.pathname;
|
|
30612
|
-
const method = req.method || "GET";
|
|
30613
30471
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
30614
30472
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
30615
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
30616
|
-
|
|
30473
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Payment");
|
|
30474
|
+
res.setHeader("Access-Control-Expose-Headers", "X-Payment-Required, X-Payment-Response");
|
|
30475
|
+
if (req.method === "OPTIONS") {
|
|
30617
30476
|
res.writeHead(204);
|
|
30618
30477
|
res.end();
|
|
30619
30478
|
return;
|
|
30620
30479
|
}
|
|
30621
30480
|
try {
|
|
30622
|
-
|
|
30481
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
30482
|
+
if (url.pathname === "/services" && req.method === "GET") {
|
|
30623
30483
|
return this.handleGetServices(res);
|
|
30624
30484
|
}
|
|
30625
|
-
if (
|
|
30626
|
-
const body = await this.readBody(req);
|
|
30627
|
-
return this.handlePay(body, res);
|
|
30628
|
-
}
|
|
30629
|
-
if (method === "POST" && path3 === "/verify") {
|
|
30485
|
+
if (url.pathname === "/execute" && req.method === "POST") {
|
|
30630
30486
|
const body = await this.readBody(req);
|
|
30631
|
-
|
|
30632
|
-
|
|
30633
|
-
if (method === "GET" && path3.startsWith("/status/")) {
|
|
30634
|
-
const chargeId = path3.replace("/status/", "");
|
|
30635
|
-
return this.handleStatus(chargeId, res);
|
|
30487
|
+
const paymentHeader = req.headers[PAYMENT_HEADER];
|
|
30488
|
+
return await this.handleExecute(body, paymentHeader, res);
|
|
30636
30489
|
}
|
|
30637
30490
|
this.sendJson(res, 404, { error: "Not found" });
|
|
30638
30491
|
} catch (err) {
|
|
@@ -30644,6 +30497,7 @@ var MoltsPayServer = class {
|
|
|
30644
30497
|
* GET /services - List available services
|
|
30645
30498
|
*/
|
|
30646
30499
|
handleGetServices(res) {
|
|
30500
|
+
const chain2 = getChain(this.manifest.provider.chain);
|
|
30647
30501
|
const services = this.manifest.services.map((s) => ({
|
|
30648
30502
|
id: s.id,
|
|
30649
30503
|
name: s.name,
|
|
@@ -30656,14 +30510,21 @@ var MoltsPayServer = class {
|
|
|
30656
30510
|
}));
|
|
30657
30511
|
this.sendJson(res, 200, {
|
|
30658
30512
|
provider: this.manifest.provider,
|
|
30659
|
-
services
|
|
30513
|
+
services,
|
|
30514
|
+
x402: {
|
|
30515
|
+
version: X402_VERSION,
|
|
30516
|
+
network: `eip155:${chain2.chainId}`,
|
|
30517
|
+
schemes: ["exact"],
|
|
30518
|
+
facilitator: this.facilitatorUrl
|
|
30519
|
+
}
|
|
30660
30520
|
});
|
|
30661
30521
|
}
|
|
30662
30522
|
/**
|
|
30663
|
-
* POST /
|
|
30523
|
+
* POST /execute - Execute service with x402 payment
|
|
30664
30524
|
* Body: { service: string, params: object }
|
|
30525
|
+
* Header: X-Payment (optional - if missing, returns 402)
|
|
30665
30526
|
*/
|
|
30666
|
-
|
|
30527
|
+
async handleExecute(body, paymentHeader, res) {
|
|
30667
30528
|
const { service, params } = body;
|
|
30668
30529
|
if (!service) {
|
|
30669
30530
|
return this.sendJson(res, 400, { error: "Missing service" });
|
|
@@ -30677,113 +30538,162 @@ var MoltsPayServer = class {
|
|
|
30677
30538
|
return this.sendJson(res, 400, { error: `Missing required param: ${key}` });
|
|
30678
30539
|
}
|
|
30679
30540
|
}
|
|
30680
|
-
|
|
30681
|
-
|
|
30682
|
-
|
|
30683
|
-
|
|
30684
|
-
|
|
30685
|
-
|
|
30686
|
-
|
|
30687
|
-
|
|
30688
|
-
|
|
30689
|
-
|
|
30690
|
-
|
|
30691
|
-
|
|
30692
|
-
|
|
30693
|
-
|
|
30694
|
-
|
|
30695
|
-
|
|
30696
|
-
|
|
30697
|
-
|
|
30698
|
-
|
|
30699
|
-
|
|
30700
|
-
|
|
30701
|
-
|
|
30702
|
-
|
|
30703
|
-
|
|
30704
|
-
|
|
30541
|
+
if (!paymentHeader) {
|
|
30542
|
+
return this.sendPaymentRequired(skill.config, res);
|
|
30543
|
+
}
|
|
30544
|
+
let payment;
|
|
30545
|
+
try {
|
|
30546
|
+
const decoded = Buffer.from(paymentHeader, "base64").toString("utf-8");
|
|
30547
|
+
payment = JSON.parse(decoded);
|
|
30548
|
+
} catch {
|
|
30549
|
+
return this.sendJson(res, 400, { error: "Invalid X-Payment header" });
|
|
30550
|
+
}
|
|
30551
|
+
const validation = this.validatePayment(payment, skill.config);
|
|
30552
|
+
if (!validation.valid) {
|
|
30553
|
+
return this.sendJson(res, 402, { error: validation.error });
|
|
30554
|
+
}
|
|
30555
|
+
console.log(`[MoltsPay] Verifying payment with facilitator...`);
|
|
30556
|
+
const verifyResult = await this.verifyWithFacilitator(payment, skill.config);
|
|
30557
|
+
if (!verifyResult.valid) {
|
|
30558
|
+
return this.sendJson(res, 402, { error: `Payment verification failed: ${verifyResult.error}` });
|
|
30559
|
+
}
|
|
30560
|
+
console.log(`[MoltsPay] Executing skill: ${service}`);
|
|
30561
|
+
let result;
|
|
30562
|
+
try {
|
|
30563
|
+
result = await skill.handler(params || {});
|
|
30564
|
+
} catch (err) {
|
|
30565
|
+
console.error("[MoltsPay] Skill execution failed:", err.message);
|
|
30566
|
+
return this.sendJson(res, 500, {
|
|
30567
|
+
error: "Service execution failed",
|
|
30568
|
+
message: err.message
|
|
30569
|
+
});
|
|
30570
|
+
}
|
|
30571
|
+
console.log(`[MoltsPay] Skill succeeded, settling payment...`);
|
|
30572
|
+
let settlement = null;
|
|
30573
|
+
try {
|
|
30574
|
+
settlement = await this.settleWithFacilitator(payment, skill.config);
|
|
30575
|
+
console.log(`[MoltsPay] Payment settled: ${settlement.transaction || "pending"}`);
|
|
30576
|
+
} catch (err) {
|
|
30577
|
+
console.error("[MoltsPay] Settlement failed:", err.message);
|
|
30578
|
+
}
|
|
30579
|
+
const responseHeaders = {};
|
|
30580
|
+
if (settlement) {
|
|
30581
|
+
const responsePayload = {
|
|
30582
|
+
success: true,
|
|
30583
|
+
transaction: settlement.transaction,
|
|
30584
|
+
network: payment.network
|
|
30585
|
+
};
|
|
30586
|
+
responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(
|
|
30587
|
+
JSON.stringify(responsePayload)
|
|
30588
|
+
).toString("base64");
|
|
30589
|
+
}
|
|
30590
|
+
this.sendJson(res, 200, {
|
|
30591
|
+
success: true,
|
|
30592
|
+
result,
|
|
30593
|
+
payment: settlement ? { transaction: settlement.transaction, status: "settled" } : { status: "pending" }
|
|
30594
|
+
}, responseHeaders);
|
|
30595
|
+
}
|
|
30596
|
+
/**
|
|
30597
|
+
* Return 402 with x402 payment requirements
|
|
30598
|
+
*/
|
|
30599
|
+
sendPaymentRequired(config, res) {
|
|
30600
|
+
const chain2 = getChain(this.manifest.provider.chain);
|
|
30601
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
30602
|
+
const requirements = [{
|
|
30603
|
+
scheme: "exact",
|
|
30604
|
+
network: `eip155:${chain2.chainId}`,
|
|
30605
|
+
maxAmountRequired: amountInUnits,
|
|
30606
|
+
resource: this.manifest.provider.wallet,
|
|
30607
|
+
description: `${config.name} - $${config.price} ${config.currency}`,
|
|
30608
|
+
// Include facilitator info for client
|
|
30609
|
+
extra: JSON.stringify({ facilitator: this.facilitatorUrl })
|
|
30610
|
+
}];
|
|
30611
|
+
const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
|
|
30612
|
+
res.writeHead(402, {
|
|
30613
|
+
"Content-Type": "application/json",
|
|
30614
|
+
[PAYMENT_REQUIRED_HEADER]: encoded
|
|
30705
30615
|
});
|
|
30616
|
+
res.end(JSON.stringify({
|
|
30617
|
+
error: "Payment required",
|
|
30618
|
+
message: `Service requires $${config.price} ${config.currency}`,
|
|
30619
|
+
x402: requirements[0]
|
|
30620
|
+
}, null, 2));
|
|
30706
30621
|
}
|
|
30707
30622
|
/**
|
|
30708
|
-
*
|
|
30709
|
-
* Body: { chargeId: string, txHash: string }
|
|
30623
|
+
* Basic payment validation (before calling facilitator)
|
|
30710
30624
|
*/
|
|
30711
|
-
|
|
30712
|
-
|
|
30713
|
-
|
|
30714
|
-
return this.sendJson(res, 400, { error: "Missing chargeId or txHash" });
|
|
30625
|
+
validatePayment(payment, config) {
|
|
30626
|
+
if (payment.x402Version !== X402_VERSION) {
|
|
30627
|
+
return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };
|
|
30715
30628
|
}
|
|
30716
|
-
|
|
30717
|
-
|
|
30718
|
-
return this.sendJson(res, 404, { error: "Charge not found" });
|
|
30629
|
+
if (payment.scheme !== "exact") {
|
|
30630
|
+
return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
|
|
30719
30631
|
}
|
|
30720
|
-
|
|
30721
|
-
|
|
30722
|
-
|
|
30723
|
-
|
|
30724
|
-
if (charge.status === "completed") {
|
|
30725
|
-
return this.sendJson(res, 200, {
|
|
30726
|
-
status: "completed",
|
|
30727
|
-
result: charge.result
|
|
30728
|
-
});
|
|
30632
|
+
const chain2 = getChain(this.manifest.provider.chain);
|
|
30633
|
+
const expectedNetwork = `eip155:${chain2.chainId}`;
|
|
30634
|
+
if (payment.network !== expectedNetwork) {
|
|
30635
|
+
return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
|
|
30729
30636
|
}
|
|
30637
|
+
return { valid: true };
|
|
30638
|
+
}
|
|
30639
|
+
/**
|
|
30640
|
+
* Verify payment with facilitator
|
|
30641
|
+
*/
|
|
30642
|
+
async verifyWithFacilitator(payment, config) {
|
|
30730
30643
|
try {
|
|
30731
|
-
const
|
|
30732
|
-
|
|
30733
|
-
|
|
30734
|
-
|
|
30735
|
-
|
|
30644
|
+
const chain2 = getChain(this.manifest.provider.chain);
|
|
30645
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
30646
|
+
const requirements = {
|
|
30647
|
+
scheme: "exact",
|
|
30648
|
+
network: `eip155:${chain2.chainId}`,
|
|
30649
|
+
maxAmountRequired: amountInUnits,
|
|
30650
|
+
resource: this.manifest.provider.wallet
|
|
30651
|
+
};
|
|
30652
|
+
const response = await fetch(`${this.facilitatorUrl}/verify`, {
|
|
30653
|
+
method: "POST",
|
|
30654
|
+
headers: { "Content-Type": "application/json" },
|
|
30655
|
+
body: JSON.stringify({
|
|
30656
|
+
paymentPayload: payment,
|
|
30657
|
+
paymentRequirements: requirements
|
|
30658
|
+
})
|
|
30736
30659
|
});
|
|
30737
|
-
|
|
30738
|
-
|
|
30739
|
-
return
|
|
30740
|
-
error: "Payment verification failed",
|
|
30741
|
-
reason: verification.error
|
|
30742
|
-
});
|
|
30660
|
+
const result = await response.json();
|
|
30661
|
+
if (!response.ok || !result.isValid) {
|
|
30662
|
+
return { valid: false, error: result.invalidReason || "Verification failed" };
|
|
30743
30663
|
}
|
|
30744
|
-
|
|
30745
|
-
charge.txHash = txHash;
|
|
30746
|
-
charge.paidAt = Date.now();
|
|
30747
|
-
const skill = this.skills.get(charge.service);
|
|
30748
|
-
console.log(`[MoltsPay] Executing skill: ${charge.service}`);
|
|
30749
|
-
const result = await skill.handler(charge.params);
|
|
30750
|
-
charge.status = "completed";
|
|
30751
|
-
charge.result = result;
|
|
30752
|
-
charge.completedAt = Date.now();
|
|
30753
|
-
this.sendJson(res, 200, {
|
|
30754
|
-
status: "completed",
|
|
30755
|
-
chargeId,
|
|
30756
|
-
txHash,
|
|
30757
|
-
result
|
|
30758
|
-
});
|
|
30664
|
+
return { valid: true };
|
|
30759
30665
|
} catch (err) {
|
|
30760
|
-
|
|
30761
|
-
charge.status = "failed";
|
|
30762
|
-
this.sendJson(res, 500, {
|
|
30763
|
-
error: "Skill execution failed",
|
|
30764
|
-
message: err.message
|
|
30765
|
-
});
|
|
30666
|
+
return { valid: false, error: `Facilitator error: ${err.message}` };
|
|
30766
30667
|
}
|
|
30767
30668
|
}
|
|
30768
30669
|
/**
|
|
30769
|
-
*
|
|
30670
|
+
* Settle payment with facilitator (execute on-chain transfer)
|
|
30770
30671
|
*/
|
|
30771
|
-
|
|
30772
|
-
const
|
|
30773
|
-
|
|
30774
|
-
|
|
30775
|
-
|
|
30776
|
-
|
|
30777
|
-
|
|
30778
|
-
|
|
30779
|
-
|
|
30780
|
-
|
|
30781
|
-
|
|
30782
|
-
|
|
30783
|
-
|
|
30784
|
-
|
|
30785
|
-
|
|
30672
|
+
async settleWithFacilitator(payment, config) {
|
|
30673
|
+
const chain2 = getChain(this.manifest.provider.chain);
|
|
30674
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
30675
|
+
const requirements = {
|
|
30676
|
+
scheme: "exact",
|
|
30677
|
+
network: `eip155:${chain2.chainId}`,
|
|
30678
|
+
maxAmountRequired: amountInUnits,
|
|
30679
|
+
resource: this.manifest.provider.wallet
|
|
30680
|
+
};
|
|
30681
|
+
const response = await fetch(`${this.facilitatorUrl}/settle`, {
|
|
30682
|
+
method: "POST",
|
|
30683
|
+
headers: { "Content-Type": "application/json" },
|
|
30684
|
+
body: JSON.stringify({
|
|
30685
|
+
paymentPayload: payment,
|
|
30686
|
+
paymentRequirements: requirements
|
|
30687
|
+
})
|
|
30786
30688
|
});
|
|
30689
|
+
const result = await response.json();
|
|
30690
|
+
if (!response.ok) {
|
|
30691
|
+
throw new Error(result.error || "Settlement failed");
|
|
30692
|
+
}
|
|
30693
|
+
return {
|
|
30694
|
+
transaction: result.transaction,
|
|
30695
|
+
status: result.status || "settled"
|
|
30696
|
+
};
|
|
30787
30697
|
}
|
|
30788
30698
|
async readBody(req) {
|
|
30789
30699
|
return new Promise((resolve, reject) => {
|
|
@@ -30799,8 +30709,12 @@ var MoltsPayServer = class {
|
|
|
30799
30709
|
req.on("error", reject);
|
|
30800
30710
|
});
|
|
30801
30711
|
}
|
|
30802
|
-
sendJson(res, status, data) {
|
|
30803
|
-
|
|
30712
|
+
sendJson(res, status, data, extraHeaders) {
|
|
30713
|
+
const headers = { "Content-Type": "application/json" };
|
|
30714
|
+
if (extraHeaders) {
|
|
30715
|
+
Object.assign(headers, extraHeaders);
|
|
30716
|
+
}
|
|
30717
|
+
res.writeHead(status, headers);
|
|
30804
30718
|
res.end(JSON.stringify(data, null, 2));
|
|
30805
30719
|
}
|
|
30806
30720
|
};
|
|
@@ -30810,12 +30724,15 @@ init_esm_shims();
|
|
|
30810
30724
|
import { existsSync, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
30811
30725
|
import { homedir } from "os";
|
|
30812
30726
|
import { join } from "path";
|
|
30813
|
-
import { Wallet } from "ethers";
|
|
30727
|
+
import { Wallet, ethers } from "ethers";
|
|
30814
30728
|
|
|
30815
30729
|
// src/client/types.ts
|
|
30816
30730
|
init_esm_shims();
|
|
30817
30731
|
|
|
30818
30732
|
// src/client/index.ts
|
|
30733
|
+
var X402_VERSION2 = 2;
|
|
30734
|
+
var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
|
|
30735
|
+
var PAYMENT_HEADER2 = "x-payment";
|
|
30819
30736
|
var DEFAULT_CONFIG = {
|
|
30820
30737
|
chain: "base",
|
|
30821
30738
|
limits: {
|
|
@@ -30879,43 +30796,112 @@ var MoltsPayClient = class {
|
|
|
30879
30796
|
return res.json();
|
|
30880
30797
|
}
|
|
30881
30798
|
/**
|
|
30882
|
-
* Pay for a service and get the result
|
|
30799
|
+
* Pay for a service and get the result (x402 protocol)
|
|
30800
|
+
*
|
|
30801
|
+
* This is GASLESS for the client - server pays gas to claim payment.
|
|
30802
|
+
* This is PAY-FOR-SUCCESS - payment only claimed if service succeeds.
|
|
30883
30803
|
*/
|
|
30884
30804
|
async pay(serverUrl, service, params) {
|
|
30885
|
-
if (!this.wallet) {
|
|
30805
|
+
if (!this.wallet || !this.walletData) {
|
|
30886
30806
|
throw new Error("Client not initialized. Run: npx moltspay init");
|
|
30887
30807
|
}
|
|
30888
|
-
|
|
30808
|
+
console.log(`[MoltsPay] Requesting service: ${service}`);
|
|
30809
|
+
const initialRes = await fetch(`${serverUrl}/execute`, {
|
|
30889
30810
|
method: "POST",
|
|
30890
30811
|
headers: { "Content-Type": "application/json" },
|
|
30891
30812
|
body: JSON.stringify({ service, params })
|
|
30892
30813
|
});
|
|
30893
|
-
if (
|
|
30894
|
-
const
|
|
30895
|
-
|
|
30814
|
+
if (initialRes.status !== 402) {
|
|
30815
|
+
const data = await initialRes.json();
|
|
30816
|
+
if (initialRes.ok && data.result) {
|
|
30817
|
+
return data.result;
|
|
30818
|
+
}
|
|
30819
|
+
throw new Error(data.error || "Unexpected response");
|
|
30820
|
+
}
|
|
30821
|
+
const paymentRequiredHeader = initialRes.headers.get(PAYMENT_REQUIRED_HEADER2);
|
|
30822
|
+
if (!paymentRequiredHeader) {
|
|
30823
|
+
throw new Error("Missing x-payment-required header");
|
|
30824
|
+
}
|
|
30825
|
+
let requirements;
|
|
30826
|
+
try {
|
|
30827
|
+
const decoded = Buffer.from(paymentRequiredHeader, "base64").toString("utf-8");
|
|
30828
|
+
requirements = JSON.parse(decoded);
|
|
30829
|
+
if (!Array.isArray(requirements)) {
|
|
30830
|
+
requirements = [requirements];
|
|
30831
|
+
}
|
|
30832
|
+
} catch {
|
|
30833
|
+
throw new Error("Invalid x-payment-required header");
|
|
30896
30834
|
}
|
|
30897
|
-
const
|
|
30898
|
-
const
|
|
30899
|
-
|
|
30900
|
-
|
|
30901
|
-
|
|
30902
|
-
|
|
30903
|
-
const
|
|
30835
|
+
const chain2 = getChain(this.config.chain);
|
|
30836
|
+
const network = `eip155:${chain2.chainId}`;
|
|
30837
|
+
const req = requirements.find((r) => r.scheme === "exact" && r.network === network);
|
|
30838
|
+
if (!req) {
|
|
30839
|
+
throw new Error(`No matching payment option for ${network}`);
|
|
30840
|
+
}
|
|
30841
|
+
const amount = Number(req.maxAmountRequired) / 1e6;
|
|
30842
|
+
this.checkLimits(amount);
|
|
30843
|
+
console.log(`[MoltsPay] Signing payment: $${amount} USDC (gasless)`);
|
|
30844
|
+
const authorization = await this.signEIP3009(req.resource, amount, chain2);
|
|
30845
|
+
const payload = {
|
|
30846
|
+
x402Version: X402_VERSION2,
|
|
30847
|
+
scheme: "exact",
|
|
30848
|
+
network,
|
|
30849
|
+
payload: authorization
|
|
30850
|
+
};
|
|
30851
|
+
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
30852
|
+
console.log(`[MoltsPay] Sending request with payment...`);
|
|
30853
|
+
const paidRes = await fetch(`${serverUrl}/execute`, {
|
|
30904
30854
|
method: "POST",
|
|
30905
|
-
headers: {
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
})
|
|
30855
|
+
headers: {
|
|
30856
|
+
"Content-Type": "application/json",
|
|
30857
|
+
[PAYMENT_HEADER2]: paymentHeader
|
|
30858
|
+
},
|
|
30859
|
+
body: JSON.stringify({ service, params })
|
|
30910
30860
|
});
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
throw new Error(
|
|
30861
|
+
const result = await paidRes.json();
|
|
30862
|
+
if (!paidRes.ok) {
|
|
30863
|
+
throw new Error(result.error || "Service execution failed");
|
|
30914
30864
|
}
|
|
30915
|
-
|
|
30916
|
-
|
|
30865
|
+
this.recordSpending(amount);
|
|
30866
|
+
console.log(`[MoltsPay] Success! Payment: ${result.payment?.status || "claimed"}`);
|
|
30917
30867
|
return result.result;
|
|
30918
30868
|
}
|
|
30869
|
+
/**
|
|
30870
|
+
* Sign EIP-3009 transferWithAuthorization (GASLESS)
|
|
30871
|
+
* This only signs - no on-chain transaction, no gas needed.
|
|
30872
|
+
*/
|
|
30873
|
+
async signEIP3009(to, amount, chain2) {
|
|
30874
|
+
const validAfter = 0;
|
|
30875
|
+
const validBefore = Math.floor(Date.now() / 1e3) + 3600;
|
|
30876
|
+
const nonce = ethers.hexlify(ethers.randomBytes(32));
|
|
30877
|
+
const value = BigInt(Math.floor(amount * 1e6)).toString();
|
|
30878
|
+
const authorization = {
|
|
30879
|
+
from: this.wallet.address,
|
|
30880
|
+
to,
|
|
30881
|
+
value,
|
|
30882
|
+
validAfter: validAfter.toString(),
|
|
30883
|
+
validBefore: validBefore.toString(),
|
|
30884
|
+
nonce
|
|
30885
|
+
};
|
|
30886
|
+
const domain = {
|
|
30887
|
+
name: "USD Coin",
|
|
30888
|
+
version: "2",
|
|
30889
|
+
chainId: chain2.chainId,
|
|
30890
|
+
verifyingContract: chain2.usdc
|
|
30891
|
+
};
|
|
30892
|
+
const types = {
|
|
30893
|
+
TransferWithAuthorization: [
|
|
30894
|
+
{ name: "from", type: "address" },
|
|
30895
|
+
{ name: "to", type: "address" },
|
|
30896
|
+
{ name: "value", type: "uint256" },
|
|
30897
|
+
{ name: "validAfter", type: "uint256" },
|
|
30898
|
+
{ name: "validBefore", type: "uint256" },
|
|
30899
|
+
{ name: "nonce", type: "bytes32" }
|
|
30900
|
+
]
|
|
30901
|
+
};
|
|
30902
|
+
const signature = await this.wallet.signTypedData(domain, types, authorization);
|
|
30903
|
+
return { authorization, signature };
|
|
30904
|
+
}
|
|
30919
30905
|
/**
|
|
30920
30906
|
* Check spending limits
|
|
30921
30907
|
*/
|
|
@@ -30942,36 +30928,6 @@ var MoltsPayClient = class {
|
|
|
30942
30928
|
recordSpending(amount) {
|
|
30943
30929
|
this.todaySpending += amount;
|
|
30944
30930
|
}
|
|
30945
|
-
/**
|
|
30946
|
-
* Execute payment on-chain
|
|
30947
|
-
*/
|
|
30948
|
-
async executePayment(payment) {
|
|
30949
|
-
let chain2;
|
|
30950
|
-
try {
|
|
30951
|
-
chain2 = getChain(payment.chain);
|
|
30952
|
-
} catch {
|
|
30953
|
-
throw new Error(`Unknown chain: ${payment.chain}`);
|
|
30954
|
-
}
|
|
30955
|
-
const { ethers: ethers4 } = await import("ethers");
|
|
30956
|
-
const provider = new ethers4.JsonRpcProvider(chain2.rpc);
|
|
30957
|
-
const signer = new ethers4.Wallet(this.walletData.privateKey, provider);
|
|
30958
|
-
const usdcAddress = chain2.usdc;
|
|
30959
|
-
const usdcAbi = [
|
|
30960
|
-
"function transfer(address to, uint256 amount) returns (bool)",
|
|
30961
|
-
"function balanceOf(address account) view returns (uint256)"
|
|
30962
|
-
];
|
|
30963
|
-
const usdc = new ethers4.Contract(usdcAddress, usdcAbi, signer);
|
|
30964
|
-
const amountInUnits = ethers4.parseUnits(payment.amount.toString(), 6);
|
|
30965
|
-
const balance = await usdc.balanceOf(this.wallet.address);
|
|
30966
|
-
if (balance < amountInUnits) {
|
|
30967
|
-
throw new Error(
|
|
30968
|
-
`Insufficient USDC balance: ${ethers4.formatUnits(balance, 6)} < ${payment.amount}`
|
|
30969
|
-
);
|
|
30970
|
-
}
|
|
30971
|
-
const tx = await usdc.transfer(payment.wallet, amountInUnits);
|
|
30972
|
-
const receipt = await tx.wait();
|
|
30973
|
-
return receipt.hash;
|
|
30974
|
-
}
|
|
30975
30931
|
// --- Config & Wallet Management ---
|
|
30976
30932
|
loadConfig() {
|
|
30977
30933
|
const configPath = join(this.configDir, "config.json");
|
|
@@ -31031,15 +30987,14 @@ var MoltsPayClient = class {
|
|
|
31031
30987
|
} catch {
|
|
31032
30988
|
throw new Error(`Unknown chain: ${this.config.chain}`);
|
|
31033
30989
|
}
|
|
31034
|
-
const
|
|
31035
|
-
const provider = new ethers4.JsonRpcProvider(chain2.rpc);
|
|
30990
|
+
const provider = new ethers.JsonRpcProvider(chain2.rpc);
|
|
31036
30991
|
const nativeBalance = await provider.getBalance(this.wallet.address);
|
|
31037
30992
|
const usdcAbi = ["function balanceOf(address) view returns (uint256)"];
|
|
31038
|
-
const usdc = new
|
|
30993
|
+
const usdc = new ethers.Contract(chain2.usdc, usdcAbi, provider);
|
|
31039
30994
|
const usdcBalance = await usdc.balanceOf(this.wallet.address);
|
|
31040
30995
|
return {
|
|
31041
|
-
usdc: parseFloat(
|
|
31042
|
-
native: parseFloat(
|
|
30996
|
+
usdc: parseFloat(ethers.formatUnits(usdcBalance, 6)),
|
|
30997
|
+
native: parseFloat(ethers.formatEther(nativeBalance))
|
|
31043
30998
|
};
|
|
31044
30999
|
}
|
|
31045
31000
|
};
|
|
@@ -31169,6 +31124,143 @@ function walletExists(storagePath) {
|
|
|
31169
31124
|
return existsSync2(path3);
|
|
31170
31125
|
}
|
|
31171
31126
|
|
|
31127
|
+
// src/verify/index.ts
|
|
31128
|
+
init_esm_shims();
|
|
31129
|
+
import { ethers as ethers4 } from "ethers";
|
|
31130
|
+
var TRANSFER_EVENT_TOPIC = ethers4.id("Transfer(address,address,uint256)");
|
|
31131
|
+
async function verifyPayment(params) {
|
|
31132
|
+
const { txHash, expectedAmount, expectedTo } = params;
|
|
31133
|
+
let chain2;
|
|
31134
|
+
try {
|
|
31135
|
+
if (typeof params.chain === "number") {
|
|
31136
|
+
chain2 = getChainById(params.chain);
|
|
31137
|
+
} else {
|
|
31138
|
+
chain2 = getChain(params.chain || "base");
|
|
31139
|
+
}
|
|
31140
|
+
if (!chain2) {
|
|
31141
|
+
return { verified: false, error: `Unsupported chain: ${params.chain}` };
|
|
31142
|
+
}
|
|
31143
|
+
} catch (e) {
|
|
31144
|
+
return { verified: false, error: `Unsupported chain: ${params.chain}` };
|
|
31145
|
+
}
|
|
31146
|
+
try {
|
|
31147
|
+
const provider = new ethers4.JsonRpcProvider(chain2.rpc);
|
|
31148
|
+
const receipt = await provider.getTransactionReceipt(txHash);
|
|
31149
|
+
if (!receipt) {
|
|
31150
|
+
return { verified: false, error: "Transaction not found or not confirmed" };
|
|
31151
|
+
}
|
|
31152
|
+
if (receipt.status !== 1) {
|
|
31153
|
+
return { verified: false, error: "Transaction failed" };
|
|
31154
|
+
}
|
|
31155
|
+
const usdcAddress = chain2.usdc?.toLowerCase();
|
|
31156
|
+
if (!usdcAddress) {
|
|
31157
|
+
return { verified: false, error: `Chain ${chain2.name} USDC address not configured` };
|
|
31158
|
+
}
|
|
31159
|
+
for (const log of receipt.logs) {
|
|
31160
|
+
if (log.address.toLowerCase() !== usdcAddress) {
|
|
31161
|
+
continue;
|
|
31162
|
+
}
|
|
31163
|
+
if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {
|
|
31164
|
+
continue;
|
|
31165
|
+
}
|
|
31166
|
+
const from = "0x" + log.topics[1].slice(-40);
|
|
31167
|
+
const to = "0x" + log.topics[2].slice(-40);
|
|
31168
|
+
const amountRaw = BigInt(log.data);
|
|
31169
|
+
const amount = Number(amountRaw) / 1e6;
|
|
31170
|
+
if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {
|
|
31171
|
+
continue;
|
|
31172
|
+
}
|
|
31173
|
+
if (amount < expectedAmount) {
|
|
31174
|
+
return {
|
|
31175
|
+
verified: false,
|
|
31176
|
+
error: `Insufficient amount: received ${amount} USDC, expected ${expectedAmount} USDC`,
|
|
31177
|
+
amount,
|
|
31178
|
+
from,
|
|
31179
|
+
to,
|
|
31180
|
+
txHash,
|
|
31181
|
+
blockNumber: receipt.blockNumber
|
|
31182
|
+
};
|
|
31183
|
+
}
|
|
31184
|
+
return {
|
|
31185
|
+
verified: true,
|
|
31186
|
+
amount,
|
|
31187
|
+
from,
|
|
31188
|
+
to,
|
|
31189
|
+
txHash,
|
|
31190
|
+
blockNumber: receipt.blockNumber
|
|
31191
|
+
};
|
|
31192
|
+
}
|
|
31193
|
+
return { verified: false, error: "No USDC transfer found" };
|
|
31194
|
+
} catch (e) {
|
|
31195
|
+
return { verified: false, error: e.message || String(e) };
|
|
31196
|
+
}
|
|
31197
|
+
}
|
|
31198
|
+
async function getTransactionStatus(txHash, chain2 = "base") {
|
|
31199
|
+
let chainConfig;
|
|
31200
|
+
try {
|
|
31201
|
+
chainConfig = typeof chain2 === "number" ? getChainById(chain2) : getChain(chain2);
|
|
31202
|
+
if (!chainConfig) return { status: "not_found" };
|
|
31203
|
+
} catch {
|
|
31204
|
+
return { status: "not_found" };
|
|
31205
|
+
}
|
|
31206
|
+
try {
|
|
31207
|
+
const provider = new ethers4.JsonRpcProvider(chainConfig.rpc);
|
|
31208
|
+
const receipt = await provider.getTransactionReceipt(txHash);
|
|
31209
|
+
if (!receipt) {
|
|
31210
|
+
const tx = await provider.getTransaction(txHash);
|
|
31211
|
+
if (tx) {
|
|
31212
|
+
return { status: "pending" };
|
|
31213
|
+
}
|
|
31214
|
+
return { status: "not_found" };
|
|
31215
|
+
}
|
|
31216
|
+
const currentBlock = await provider.getBlockNumber();
|
|
31217
|
+
const confirmations = currentBlock - receipt.blockNumber;
|
|
31218
|
+
if (receipt.status === 1) {
|
|
31219
|
+
return {
|
|
31220
|
+
status: "confirmed",
|
|
31221
|
+
blockNumber: receipt.blockNumber,
|
|
31222
|
+
confirmations
|
|
31223
|
+
};
|
|
31224
|
+
} else {
|
|
31225
|
+
return {
|
|
31226
|
+
status: "failed",
|
|
31227
|
+
blockNumber: receipt.blockNumber
|
|
31228
|
+
};
|
|
31229
|
+
}
|
|
31230
|
+
} catch {
|
|
31231
|
+
return { status: "not_found" };
|
|
31232
|
+
}
|
|
31233
|
+
}
|
|
31234
|
+
async function waitForTransaction(txHash, chain2 = "base", confirmations = 1, timeoutMs = 6e4) {
|
|
31235
|
+
let chainConfig;
|
|
31236
|
+
try {
|
|
31237
|
+
chainConfig = typeof chain2 === "number" ? getChainById(chain2) : getChain(chain2);
|
|
31238
|
+
if (!chainConfig) {
|
|
31239
|
+
return { verified: false, confirmed: false, error: `Unsupported chain: ${chain2}` };
|
|
31240
|
+
}
|
|
31241
|
+
} catch (e) {
|
|
31242
|
+
return { verified: false, confirmed: false, error: `Unsupported chain: ${chain2}` };
|
|
31243
|
+
}
|
|
31244
|
+
const provider = new ethers4.JsonRpcProvider(chainConfig.rpc);
|
|
31245
|
+
try {
|
|
31246
|
+
const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
|
|
31247
|
+
if (!receipt) {
|
|
31248
|
+
return { verified: false, confirmed: false, error: "Timeout waiting" };
|
|
31249
|
+
}
|
|
31250
|
+
if (receipt.status !== 1) {
|
|
31251
|
+
return { verified: false, confirmed: true, error: "Transaction failed" };
|
|
31252
|
+
}
|
|
31253
|
+
return {
|
|
31254
|
+
verified: true,
|
|
31255
|
+
confirmed: true,
|
|
31256
|
+
txHash,
|
|
31257
|
+
blockNumber: receipt.blockNumber
|
|
31258
|
+
};
|
|
31259
|
+
} catch (e) {
|
|
31260
|
+
return { verified: false, confirmed: false, error: e.message || String(e) };
|
|
31261
|
+
}
|
|
31262
|
+
}
|
|
31263
|
+
|
|
31172
31264
|
// src/cdp/index.ts
|
|
31173
31265
|
init_esm_shims();
|
|
31174
31266
|
import * as fs from "fs";
|
|
@@ -31290,9 +31382,9 @@ var CDPWallet = class {
|
|
|
31290
31382
|
* Get USDC balance
|
|
31291
31383
|
*/
|
|
31292
31384
|
async getBalance() {
|
|
31293
|
-
const { ethers:
|
|
31294
|
-
const provider = new
|
|
31295
|
-
const usdcContract = new
|
|
31385
|
+
const { ethers: ethers5 } = await import("ethers");
|
|
31386
|
+
const provider = new ethers5.JsonRpcProvider(this.chainConfig.rpc);
|
|
31387
|
+
const usdcContract = new ethers5.Contract(
|
|
31296
31388
|
this.chainConfig.usdc,
|
|
31297
31389
|
["function balanceOf(address) view returns (uint256)"],
|
|
31298
31390
|
provider
|
|
@@ -31303,7 +31395,7 @@ var CDPWallet = class {
|
|
|
31303
31395
|
]);
|
|
31304
31396
|
return {
|
|
31305
31397
|
usdc: (Number(usdcBalance) / 1e6).toFixed(2),
|
|
31306
|
-
eth:
|
|
31398
|
+
eth: ethers5.formatEther(ethBalance)
|
|
31307
31399
|
};
|
|
31308
31400
|
}
|
|
31309
31401
|
/**
|
|
@@ -31321,7 +31413,7 @@ var CDPWallet = class {
|
|
|
31321
31413
|
}
|
|
31322
31414
|
try {
|
|
31323
31415
|
const { CdpClient } = await import("@coinbase/cdp-sdk");
|
|
31324
|
-
const { ethers:
|
|
31416
|
+
const { ethers: ethers5 } = await import("ethers");
|
|
31325
31417
|
const cdp = new CdpClient({
|
|
31326
31418
|
apiKeyId: creds.apiKeyId,
|
|
31327
31419
|
apiKeySecret: creds.apiKeySecret,
|
|
@@ -31329,7 +31421,7 @@ var CDPWallet = class {
|
|
|
31329
31421
|
});
|
|
31330
31422
|
const account = await cdp.evm.getAccount({ address: this.address });
|
|
31331
31423
|
const amountWei = BigInt(Math.floor(params.amount * 1e6));
|
|
31332
|
-
const iface = new
|
|
31424
|
+
const iface = new ethers5.Interface([
|
|
31333
31425
|
"function transfer(address to, uint256 amount) returns (bool)"
|
|
31334
31426
|
]);
|
|
31335
31427
|
const callData = iface.encodeFunctionData("transfer", [params.to, amountWei]);
|