@tanakayuto/intmax402-express 0.3.1 → 0.3.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/dist/middleware.js +13 -3
- package/dist/verify-payment.js +32 -3
- package/package.json +1 -1
package/dist/middleware.js
CHANGED
|
@@ -18,9 +18,19 @@ function intmax402(config) {
|
|
|
18
18
|
return async (req, res, next) => {
|
|
19
19
|
try {
|
|
20
20
|
// Wait for payment verifier initialization if in progress
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
try {
|
|
22
|
+
if (initPromise) {
|
|
23
|
+
await initPromise;
|
|
24
|
+
initPromise = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
res.status(503).json({
|
|
29
|
+
error: 'Payment verifier temporarily unavailable',
|
|
30
|
+
hint: 'INTMAX network may be experiencing issues. Please try again later.',
|
|
31
|
+
protocol: 'INTMAX402',
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
24
34
|
}
|
|
25
35
|
const authHeader = req.headers.authorization;
|
|
26
36
|
if (!authHeader) {
|
package/dist/verify-payment.js
CHANGED
|
@@ -40,8 +40,16 @@ async function initPaymentVerifier(config) {
|
|
|
40
40
|
l1_rpc_url: config.l1_rpc_url,
|
|
41
41
|
loggerLevel: "warn",
|
|
42
42
|
});
|
|
43
|
-
loginPromise = client
|
|
43
|
+
loginPromise = client
|
|
44
|
+
.login()
|
|
45
|
+
.then(() => {
|
|
44
46
|
loginPromise = null;
|
|
47
|
+
})
|
|
48
|
+
.catch((err) => {
|
|
49
|
+
console.warn("[intmax402] INTMAX network login failed — payment verifier unavailable:", err instanceof Error ? err.message : String(err));
|
|
50
|
+
client = null;
|
|
51
|
+
loginPromise = null;
|
|
52
|
+
throw err;
|
|
45
53
|
});
|
|
46
54
|
await loginPromise;
|
|
47
55
|
}
|
|
@@ -52,7 +60,10 @@ function getPaymentVerifierAddress() {
|
|
|
52
60
|
}
|
|
53
61
|
async function verifyPayment(txHash, expectedAmount, serverAddress, tokenIndex) {
|
|
54
62
|
if (!client || !client.isLoggedIn) {
|
|
55
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
valid: false,
|
|
65
|
+
error: "Payment verifier temporarily unavailable. INTMAX network may be down.",
|
|
66
|
+
};
|
|
56
67
|
}
|
|
57
68
|
// Replay prevention: check if txHash was already used (or pending)
|
|
58
69
|
cleanupExpiredHashes();
|
|
@@ -71,7 +82,25 @@ async function verifyPayment(txHash, expectedAmount, serverAddress, tokenIndex)
|
|
|
71
82
|
transfers = transfers.concat(response2.items);
|
|
72
83
|
}
|
|
73
84
|
// Find matching transaction by digest
|
|
74
|
-
|
|
85
|
+
let match = transfers.find((tx) => tx.digest === txHash);
|
|
86
|
+
// Polling retry: if not found, retry up to 3 times with 5s delay
|
|
87
|
+
// (transfer may not be reflected immediately after submission)
|
|
88
|
+
if (!match) {
|
|
89
|
+
for (let retry = 0; retry < 3; retry++) {
|
|
90
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
91
|
+
const retryResponse = await client.fetchTransfers({ cursor: null, limit: 100 });
|
|
92
|
+
match = retryResponse.items.find((tx) => tx.digest === txHash);
|
|
93
|
+
if (match)
|
|
94
|
+
break;
|
|
95
|
+
// Also check next page on retry if needed
|
|
96
|
+
if (!match && retryResponse.pagination?.has_more && retryResponse.pagination?.next_cursor != null) {
|
|
97
|
+
const retryResponse2 = await client.fetchTransfers({ cursor: retryResponse.pagination.next_cursor, limit: 100 });
|
|
98
|
+
match = retryResponse2.items.find((tx) => tx.digest === txHash);
|
|
99
|
+
if (match)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
75
104
|
if (!match) {
|
|
76
105
|
// Fix 1: Rollback on validation failure
|
|
77
106
|
usedTxHashes.delete(txHash);
|