@puga-labs/x402-mantle-sdk 0.2.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/chunk-23QNUJIB.js +136 -0
- package/dist/chunk-6GLR5EBK.js +96 -0
- package/dist/chunk-BRGW36P7.js +211 -0
- package/dist/chunk-CTI5CRDY.js +274 -0
- package/dist/chunk-DA6ZBXNO.js +275 -0
- package/dist/chunk-E46A7I6B.js +274 -0
- package/dist/chunk-FD4HG7KR.js +135 -0
- package/dist/chunk-FHU6CFHF.js +0 -0
- package/dist/chunk-GHUWTX7J.js +66 -0
- package/dist/chunk-GWVWPS3R.js +277 -0
- package/dist/chunk-HEZZ74SI.js +62 -0
- package/dist/chunk-HTZ3QFY4.js +135 -0
- package/dist/chunk-MQALBRGV.js +135 -0
- package/dist/chunk-NQWSCY44.js +70 -0
- package/dist/chunk-PCJEJYP6.js +68 -0
- package/dist/chunk-PPVS3X5Z.js +99 -0
- package/dist/chunk-PYIYE3HI.js +135 -0
- package/dist/chunk-Q6SPMEIW.js +235 -0
- package/dist/chunk-RNKXSBT7.js +135 -0
- package/dist/chunk-SPCXFN7C.js +284 -0
- package/dist/chunk-T5DRYLNB.js +135 -0
- package/dist/chunk-TSEE5NSJ.js +297 -0
- package/dist/chunk-U73CZU3X.js +237 -0
- package/dist/chunk-WAKJRVUP.js +135 -0
- package/dist/chunk-WELDWRDX.js +307 -0
- package/dist/chunk-WFUDGBKK.js +68 -0
- package/dist/chunk-WO2MYZXT.js +0 -0
- package/dist/chunk-XAQGMFSR.js +56 -0
- package/dist/client.cjs +328 -0
- package/dist/client.d.cts +17 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.js +12 -0
- package/dist/constants-0ncqvV_O.d.ts +17 -0
- package/dist/constants-C7aY8u5b.d.cts +77 -0
- package/dist/constants-C7aY8u5b.d.ts +77 -0
- package/dist/constants-CVFF0ray.d.ts +17 -0
- package/dist/constants-CsIL25uQ.d.cts +17 -0
- package/dist/constants-DzCGK0Q3.d.cts +17 -0
- package/dist/createMantleClient-CO0uWPb-.d.cts +87 -0
- package/dist/createMantleClient-CuiPsTa6.d.ts +87 -0
- package/dist/createMantleClient-DS1Ghqrz.d.cts +51 -0
- package/dist/createMantleClient-DS1Ghqrz.d.ts +51 -0
- package/dist/createMantleClient-DVFkbBfS.d.ts +87 -0
- package/dist/createMantleClient-NN0Nitp9.d.cts +87 -0
- package/dist/express-Ck7eryef.d.cts +66 -0
- package/dist/express-CmEg5hR3.d.ts +66 -0
- package/dist/express-D8EwEcOL.d.ts +66 -0
- package/dist/express-eQOPxfnI.d.cts +66 -0
- package/dist/index.cjs +342 -155
- package/dist/index.d.cts +10 -290
- package/dist/index.d.ts +10 -290
- package/dist/index.js +18 -567
- package/dist/nextjs-Bp8DxYDN.d.ts +45 -0
- package/dist/nextjs-CliiaTPe.d.cts +45 -0
- package/dist/nextjs-D7t-BC4N.d.ts +45 -0
- package/dist/nextjs-Duecps0q.d.cts +45 -0
- package/dist/nextjs-TFhFiQuL.d.ts +45 -0
- package/dist/nextjs-ZO2J9mdo.d.cts +45 -0
- package/dist/react.cjs +454 -0
- package/dist/react.d.cts +93 -0
- package/dist/react.d.ts +93 -0
- package/dist/react.js +10 -0
- package/dist/server-express.cjs +368 -0
- package/dist/server-express.d.cts +5 -0
- package/dist/server-express.d.ts +5 -0
- package/dist/server-express.js +13 -0
- package/dist/server-nextjs.cjs +339 -0
- package/dist/server-nextjs.d.cts +5 -0
- package/dist/server-nextjs.d.ts +5 -0
- package/dist/server-nextjs.js +11 -0
- package/dist/server-web.cjs +339 -0
- package/dist/server-web.d.cts +4 -0
- package/dist/server-web.d.ts +4 -0
- package/dist/server-web.js +11 -0
- package/dist/server.cjs +497 -0
- package/dist/server.d.cts +79 -0
- package/dist/server.d.ts +79 -0
- package/dist/server.js +36 -0
- package/dist/types-2zqbJvcz.d.cts +63 -0
- package/dist/types-2zqbJvcz.d.ts +63 -0
- package/dist/types-BFUqKBBO.d.cts +63 -0
- package/dist/types-BFUqKBBO.d.ts +63 -0
- package/dist/types-C7EPJ6Hd.d.ts +85 -0
- package/dist/types-CEttmr1U.d.cts +97 -0
- package/dist/types-CoOdbZSp.d.cts +97 -0
- package/dist/types-CqQ6OgRi.d.ts +85 -0
- package/dist/types-CrOsOHcX.d.cts +85 -0
- package/dist/types-D20K36pc.d.ts +97 -0
- package/dist/types-DTzov_EE.d.ts +97 -0
- package/dist/types-xkNm0uzE.d.cts +85 -0
- package/dist/web-standards-BNQyWzBC.d.cts +77 -0
- package/dist/web-standards-C3D2vdTg.d.ts +77 -0
- package/dist/web-standards-D8j1kZxd.d.ts +77 -0
- package/dist/web-standards-DOYp0UDT.d.cts +77 -0
- package/package.json +80 -8
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -25,6 +35,7 @@ __export(index_exports, {
|
|
|
25
35
|
createPaymentClient: () => createPaymentClient,
|
|
26
36
|
createPaymentMiddleware: () => createPaymentMiddleware,
|
|
27
37
|
mantlePaywall: () => mantlePaywall,
|
|
38
|
+
useEthersWallet: () => useEthersWallet,
|
|
28
39
|
useMantleX402: () => useMantleX402
|
|
29
40
|
});
|
|
30
41
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -71,6 +82,54 @@ function usdCentsToAtomic(cents, decimals) {
|
|
|
71
82
|
return BigInt(cents) * base;
|
|
72
83
|
}
|
|
73
84
|
|
|
85
|
+
// src/server/core/utils.ts
|
|
86
|
+
function validateAddress(address, paramName = "address") {
|
|
87
|
+
if (!address) {
|
|
88
|
+
throw new Error(`${paramName} is required`);
|
|
89
|
+
}
|
|
90
|
+
if (typeof address !== "string") {
|
|
91
|
+
throw new Error(`${paramName} must be a string, got ${typeof address}`);
|
|
92
|
+
}
|
|
93
|
+
if (!address.startsWith("0x")) {
|
|
94
|
+
const preview = address.length > 10 ? `${address.substring(0, 10)}...` : address;
|
|
95
|
+
throw new Error(
|
|
96
|
+
`${paramName} must start with "0x", got: ${preview}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (address.length !== 42) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`${paramName} must be 42 characters (0x + 40 hex), got ${address.length} characters`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const hexPart = address.slice(2);
|
|
105
|
+
if (!/^[0-9a-fA-F]{40}$/.test(hexPart)) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`${paramName} must contain only hexadecimal characters (0-9, a-f, A-F) after "0x"`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function decodePaymentHeader(paymentHeaderBase64) {
|
|
112
|
+
try {
|
|
113
|
+
if (typeof Buffer !== "undefined") {
|
|
114
|
+
const json = Buffer.from(paymentHeaderBase64, "base64").toString("utf8");
|
|
115
|
+
return JSON.parse(json);
|
|
116
|
+
}
|
|
117
|
+
if (typeof atob === "function") {
|
|
118
|
+
const json = atob(paymentHeaderBase64);
|
|
119
|
+
return JSON.parse(json);
|
|
120
|
+
}
|
|
121
|
+
throw new Error("No base64 decoding available in this environment");
|
|
122
|
+
} catch (err) {
|
|
123
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
124
|
+
throw new Error(`Failed to decode paymentHeader: ${msg}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function buildRouteKey(method, path) {
|
|
128
|
+
const normalizedMethod = (method || "GET").toUpperCase();
|
|
129
|
+
const normalizedPath = path || "/";
|
|
130
|
+
return `${normalizedMethod} ${normalizedPath}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
74
133
|
// src/server/constants.ts
|
|
75
134
|
var DEFAULT_TELEMETRY_ENDPOINT = void 0;
|
|
76
135
|
|
|
@@ -124,28 +183,130 @@ async function sendTelemetry(event, endpoint) {
|
|
|
124
183
|
}
|
|
125
184
|
}
|
|
126
185
|
|
|
127
|
-
// src/server/
|
|
128
|
-
function
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
186
|
+
// src/server/core/verifyPayment.ts
|
|
187
|
+
async function checkPayment(input) {
|
|
188
|
+
const {
|
|
189
|
+
paymentHeader,
|
|
190
|
+
paymentRequirements,
|
|
191
|
+
facilitatorUrl,
|
|
192
|
+
routeKey,
|
|
193
|
+
network,
|
|
194
|
+
asset,
|
|
195
|
+
telemetry,
|
|
196
|
+
onPaymentSettled
|
|
197
|
+
} = input;
|
|
198
|
+
if (!paymentHeader) {
|
|
199
|
+
return {
|
|
200
|
+
status: "require_payment",
|
|
201
|
+
statusCode: 402,
|
|
202
|
+
responseBody: {
|
|
203
|
+
error: "Payment Required",
|
|
204
|
+
paymentRequirements,
|
|
205
|
+
paymentHeader: null
|
|
206
|
+
},
|
|
207
|
+
isValid: false
|
|
208
|
+
};
|
|
209
|
+
}
|
|
134
210
|
try {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
211
|
+
const verifyUrl = `${facilitatorUrl.replace(/\/+$/, "")}/verify`;
|
|
212
|
+
const verifyRes = await fetch(verifyUrl, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers: {
|
|
215
|
+
"Content-Type": "application/json"
|
|
216
|
+
},
|
|
217
|
+
body: JSON.stringify({
|
|
218
|
+
x402Version: 1,
|
|
219
|
+
paymentHeader,
|
|
220
|
+
paymentRequirements
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
if (!verifyRes.ok) {
|
|
224
|
+
const text = await verifyRes.text().catch(() => "");
|
|
225
|
+
console.error(
|
|
226
|
+
"[x402-mantle-sdk] Facilitator /verify returned non-OK:",
|
|
227
|
+
verifyRes.status,
|
|
228
|
+
text
|
|
229
|
+
);
|
|
230
|
+
return {
|
|
231
|
+
status: "verification_error",
|
|
232
|
+
statusCode: 500,
|
|
233
|
+
responseBody: {
|
|
234
|
+
error: "Payment verification error",
|
|
235
|
+
details: `Facilitator responded with HTTP ${verifyRes.status}`
|
|
236
|
+
},
|
|
237
|
+
isValid: false
|
|
238
|
+
};
|
|
138
239
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return
|
|
240
|
+
const verifyJson = await verifyRes.json();
|
|
241
|
+
if (!verifyJson.isValid) {
|
|
242
|
+
return {
|
|
243
|
+
status: "invalid_payment",
|
|
244
|
+
statusCode: 402,
|
|
245
|
+
responseBody: {
|
|
246
|
+
error: "Payment verification failed",
|
|
247
|
+
invalidReason: verifyJson.invalidReason ?? null,
|
|
248
|
+
paymentRequirements,
|
|
249
|
+
paymentHeader: null
|
|
250
|
+
},
|
|
251
|
+
isValid: false
|
|
252
|
+
};
|
|
142
253
|
}
|
|
143
|
-
|
|
254
|
+
if (onPaymentSettled) {
|
|
255
|
+
try {
|
|
256
|
+
const headerObj = decodePaymentHeader(paymentHeader);
|
|
257
|
+
const { authorization } = headerObj.payload;
|
|
258
|
+
const assetConfig = getDefaultAssetForNetwork(network);
|
|
259
|
+
const logEntry = {
|
|
260
|
+
id: authorization.nonce,
|
|
261
|
+
from: authorization.from,
|
|
262
|
+
to: authorization.to,
|
|
263
|
+
valueAtomic: authorization.value,
|
|
264
|
+
network,
|
|
265
|
+
asset,
|
|
266
|
+
route: routeKey,
|
|
267
|
+
timestamp: Date.now(),
|
|
268
|
+
facilitatorUrl,
|
|
269
|
+
paymentRequirements
|
|
270
|
+
};
|
|
271
|
+
onPaymentSettled(logEntry);
|
|
272
|
+
if (telemetry) {
|
|
273
|
+
const event = createTelemetryEvent(logEntry, telemetry);
|
|
274
|
+
sendTelemetry(event, telemetry.endpoint).catch(
|
|
275
|
+
(err) => console.error("[x402-telemetry] Async send failed:", err)
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error(
|
|
280
|
+
"[x402-mantle-sdk] Error calling onPaymentSettled hook:",
|
|
281
|
+
err
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
status: "verified",
|
|
287
|
+
statusCode: 200,
|
|
288
|
+
responseBody: null,
|
|
289
|
+
isValid: true
|
|
290
|
+
};
|
|
144
291
|
} catch (err) {
|
|
145
|
-
|
|
146
|
-
|
|
292
|
+
console.error(
|
|
293
|
+
"[x402-mantle-sdk] Error while calling facilitator /verify:",
|
|
294
|
+
err
|
|
295
|
+
);
|
|
296
|
+
const message = err instanceof Error ? err.message : "Unknown verification error";
|
|
297
|
+
return {
|
|
298
|
+
status: "verification_error",
|
|
299
|
+
statusCode: 500,
|
|
300
|
+
responseBody: {
|
|
301
|
+
error: "Payment verification error",
|
|
302
|
+
details: message
|
|
303
|
+
},
|
|
304
|
+
isValid: false
|
|
305
|
+
};
|
|
147
306
|
}
|
|
148
307
|
}
|
|
308
|
+
|
|
309
|
+
// src/server/adapters/express.ts
|
|
149
310
|
function createPaymentMiddleware(config) {
|
|
150
311
|
const { facilitatorUrl, receiverAddress, routes, onPaymentSettled, telemetry } = config;
|
|
151
312
|
if (!facilitatorUrl) {
|
|
@@ -154,11 +315,12 @@ function createPaymentMiddleware(config) {
|
|
|
154
315
|
if (!receiverAddress) {
|
|
155
316
|
throw new Error("receiverAddress is required");
|
|
156
317
|
}
|
|
318
|
+
validateAddress(receiverAddress, "receiverAddress");
|
|
157
319
|
if (!routes || Object.keys(routes).length === 0) {
|
|
158
320
|
throw new Error("routes config must not be empty");
|
|
159
321
|
}
|
|
160
322
|
return async function paymentMiddleware(req, res, next) {
|
|
161
|
-
const routeKey =
|
|
323
|
+
const routeKey = buildRouteKey(req.method, req.path);
|
|
162
324
|
const routeConfig = routes[routeKey];
|
|
163
325
|
if (!routeConfig) {
|
|
164
326
|
next();
|
|
@@ -179,104 +341,29 @@ function createPaymentMiddleware(config) {
|
|
|
179
341
|
price: `$${(priceUsdCents / 100).toFixed(2)}`,
|
|
180
342
|
currency: "USD"
|
|
181
343
|
};
|
|
182
|
-
const paymentHeader = req.header("X-PAYMENT")
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
headers: {
|
|
196
|
-
"Content-Type": "application/json"
|
|
197
|
-
},
|
|
198
|
-
body: JSON.stringify({
|
|
199
|
-
x402Version: 1,
|
|
200
|
-
paymentHeader,
|
|
201
|
-
paymentRequirements
|
|
202
|
-
})
|
|
203
|
-
});
|
|
204
|
-
if (!verifyRes.ok) {
|
|
205
|
-
const text = await verifyRes.text().catch(() => "");
|
|
206
|
-
console.error(
|
|
207
|
-
"[x402-mantle-sdk] Facilitator /verify returned non-OK:",
|
|
208
|
-
verifyRes.status,
|
|
209
|
-
text
|
|
210
|
-
);
|
|
211
|
-
res.status(500).json({
|
|
212
|
-
error: "Payment verification error",
|
|
213
|
-
details: `Facilitator responded with HTTP ${verifyRes.status}`
|
|
214
|
-
});
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
const verifyJson = await verifyRes.json();
|
|
218
|
-
if (!verifyJson.isValid) {
|
|
219
|
-
res.status(402).json({
|
|
220
|
-
error: "Payment verification failed",
|
|
221
|
-
invalidReason: verifyJson.invalidReason ?? null,
|
|
222
|
-
paymentRequirements,
|
|
223
|
-
paymentHeader: null
|
|
224
|
-
});
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (onPaymentSettled) {
|
|
228
|
-
try {
|
|
229
|
-
const headerObj = decodePaymentHeader(paymentHeader);
|
|
230
|
-
const { authorization } = headerObj.payload;
|
|
231
|
-
const logEntry = {
|
|
232
|
-
id: authorization.nonce,
|
|
233
|
-
from: authorization.from,
|
|
234
|
-
to: authorization.to,
|
|
235
|
-
valueAtomic: authorization.value,
|
|
236
|
-
network,
|
|
237
|
-
asset: assetConfig.address,
|
|
238
|
-
route: routeKey,
|
|
239
|
-
timestamp: Date.now(),
|
|
240
|
-
facilitatorUrl,
|
|
241
|
-
// Pass from config closure
|
|
242
|
-
paymentRequirements
|
|
243
|
-
};
|
|
244
|
-
onPaymentSettled(logEntry);
|
|
245
|
-
if (telemetry) {
|
|
246
|
-
const event = createTelemetryEvent(logEntry, telemetry);
|
|
247
|
-
sendTelemetry(event, telemetry.endpoint).catch(
|
|
248
|
-
(err) => console.error("[x402-telemetry] Async send failed:", err)
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
} catch (err) {
|
|
252
|
-
console.error(
|
|
253
|
-
"[x402-mantle-sdk] Error calling onPaymentSettled hook:",
|
|
254
|
-
err
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
next();
|
|
259
|
-
return;
|
|
260
|
-
} catch (err) {
|
|
261
|
-
console.error(
|
|
262
|
-
"[x402-mantle-sdk] Error while calling facilitator /verify:",
|
|
263
|
-
err
|
|
264
|
-
);
|
|
265
|
-
const message = err instanceof Error ? err.message : "Unknown verification error";
|
|
266
|
-
res.status(500).json({
|
|
267
|
-
error: "Payment verification error",
|
|
268
|
-
details: message
|
|
269
|
-
});
|
|
344
|
+
const paymentHeader = req.header("X-PAYMENT") || req.header("x-payment") || null;
|
|
345
|
+
const result = await checkPayment({
|
|
346
|
+
paymentHeader,
|
|
347
|
+
paymentRequirements,
|
|
348
|
+
facilitatorUrl,
|
|
349
|
+
routeKey,
|
|
350
|
+
network,
|
|
351
|
+
asset: assetConfig.address,
|
|
352
|
+
telemetry,
|
|
353
|
+
onPaymentSettled
|
|
354
|
+
});
|
|
355
|
+
if (!result.isValid) {
|
|
356
|
+
res.status(result.statusCode).json(result.responseBody);
|
|
270
357
|
return;
|
|
271
358
|
}
|
|
359
|
+
next();
|
|
272
360
|
};
|
|
273
361
|
}
|
|
274
|
-
|
|
275
|
-
// src/server/mantlePaywall.ts
|
|
276
362
|
function mantlePaywall(opts) {
|
|
277
363
|
const { priceUsd, payTo, facilitatorUrl, telemetry, onPaymentSettled } = opts;
|
|
364
|
+
validateAddress(payTo, "payTo");
|
|
278
365
|
const priceUsdCents = Math.round(priceUsd * 100);
|
|
279
|
-
return (req, res, next) => {
|
|
366
|
+
return async (req, res, next) => {
|
|
280
367
|
const method = (req.method || "GET").toUpperCase();
|
|
281
368
|
const path = req.path || "/";
|
|
282
369
|
const routeKey = `${method} ${path}`;
|
|
@@ -335,19 +422,6 @@ function joinUrl(base, path) {
|
|
|
335
422
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
336
423
|
return `${normalizedBase}${normalizedPath}`;
|
|
337
424
|
}
|
|
338
|
-
async function getUserAddressFromProvider(provider) {
|
|
339
|
-
const p = provider;
|
|
340
|
-
if (!p || typeof p.request !== "function") {
|
|
341
|
-
throw new Error("provider must implement EIP-1193 request()");
|
|
342
|
-
}
|
|
343
|
-
const accounts = await p.request({
|
|
344
|
-
method: "eth_requestAccounts"
|
|
345
|
-
});
|
|
346
|
-
if (!accounts || accounts.length === 0) {
|
|
347
|
-
throw new Error("No accounts returned from provider");
|
|
348
|
-
}
|
|
349
|
-
return accounts[0];
|
|
350
|
-
}
|
|
351
425
|
function buildTypedDataForAuthorization(authorization, paymentRequirements) {
|
|
352
426
|
const chainId = getChainIdForNetwork(paymentRequirements.network);
|
|
353
427
|
const verifyingContract = paymentRequirements.asset;
|
|
@@ -374,24 +448,26 @@ function buildTypedDataForAuthorization(authorization, paymentRequirements) {
|
|
|
374
448
|
message: authorization
|
|
375
449
|
};
|
|
376
450
|
}
|
|
377
|
-
async function signAuthorizationWithProvider(provider,
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
451
|
+
async function signAuthorizationWithProvider(provider, authorization, paymentRequirements) {
|
|
452
|
+
const { BrowserProvider } = await import("ethers");
|
|
453
|
+
const chainId = getChainIdForNetwork(paymentRequirements.network);
|
|
454
|
+
const browserProvider = new BrowserProvider(provider, chainId);
|
|
455
|
+
const signer = await browserProvider.getSigner();
|
|
456
|
+
const from = await signer.getAddress();
|
|
457
|
+
const authWithFrom = {
|
|
458
|
+
...authorization,
|
|
459
|
+
from
|
|
460
|
+
};
|
|
382
461
|
const typedData = buildTypedDataForAuthorization(
|
|
383
|
-
|
|
462
|
+
authWithFrom,
|
|
384
463
|
paymentRequirements
|
|
385
464
|
);
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
throw new Error("Invalid signature returned from provider");
|
|
393
|
-
}
|
|
394
|
-
return signature;
|
|
465
|
+
const signature = await signer.signTypedData(
|
|
466
|
+
typedData.domain,
|
|
467
|
+
typedData.types,
|
|
468
|
+
typedData.message
|
|
469
|
+
);
|
|
470
|
+
return { signature, from };
|
|
395
471
|
}
|
|
396
472
|
function createPaymentClient(config) {
|
|
397
473
|
const {
|
|
@@ -434,14 +510,6 @@ function createPaymentClient(config) {
|
|
|
434
510
|
});
|
|
435
511
|
return {
|
|
436
512
|
response: json,
|
|
437
|
-
paymentHeader: "",
|
|
438
|
-
paymentRequirements: {
|
|
439
|
-
scheme: "exact",
|
|
440
|
-
network: "mantle-mainnet",
|
|
441
|
-
asset: "",
|
|
442
|
-
maxAmountRequired: "0",
|
|
443
|
-
payTo: ""
|
|
444
|
-
},
|
|
445
513
|
txHash: void 0
|
|
446
514
|
};
|
|
447
515
|
}
|
|
@@ -452,26 +520,34 @@ function createPaymentClient(config) {
|
|
|
452
520
|
"402 response did not include paymentRequirements field"
|
|
453
521
|
);
|
|
454
522
|
}
|
|
455
|
-
const fromAddress = userAddressOverride ?? await getUserAddressFromProvider(provider);
|
|
456
523
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
457
524
|
const validAfter = "0";
|
|
458
525
|
const validBefore = String(nowSec + 10 * 60);
|
|
459
526
|
const nonce = randomBytes32Hex();
|
|
460
527
|
const valueAtomic = options?.valueOverrideAtomic ?? paymentRequirements.maxAmountRequired;
|
|
461
|
-
|
|
462
|
-
from:
|
|
528
|
+
let authorization = {
|
|
529
|
+
from: "0x0000000000000000000000000000000000000000",
|
|
463
530
|
to: paymentRequirements.payTo,
|
|
464
531
|
value: valueAtomic,
|
|
465
532
|
validAfter,
|
|
466
533
|
validBefore,
|
|
467
534
|
nonce
|
|
468
535
|
};
|
|
469
|
-
const signature = await signAuthorizationWithProvider(
|
|
536
|
+
const { signature, from } = await signAuthorizationWithProvider(
|
|
470
537
|
provider,
|
|
471
|
-
fromAddress,
|
|
472
538
|
authorization,
|
|
473
539
|
paymentRequirements
|
|
474
540
|
);
|
|
541
|
+
authorization = {
|
|
542
|
+
...authorization,
|
|
543
|
+
from
|
|
544
|
+
};
|
|
545
|
+
if (userAddressOverride && userAddressOverride.toLowerCase() !== from.toLowerCase()) {
|
|
546
|
+
console.warn(
|
|
547
|
+
"[SDK WARNING] userAddress override differs from signer address",
|
|
548
|
+
{ override: userAddressOverride, signer: from }
|
|
549
|
+
);
|
|
550
|
+
}
|
|
475
551
|
const paymentHeaderObject = {
|
|
476
552
|
x402Version: 1,
|
|
477
553
|
scheme: paymentRequirements.scheme,
|
|
@@ -545,7 +621,7 @@ function createMantleClient(config) {
|
|
|
545
621
|
const resourceUrl = config?.resourceUrl ?? (typeof window !== "undefined" ? window.location.origin : "");
|
|
546
622
|
const facilitatorUrl = config?.facilitatorUrl ?? (typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_FACILITATOR_URL : void 0) ?? "http://localhost:8080";
|
|
547
623
|
return {
|
|
548
|
-
async
|
|
624
|
+
async postWithPayment(url, body) {
|
|
549
625
|
const account = await config?.getAccount?.();
|
|
550
626
|
if (!account) {
|
|
551
627
|
throw new Error(
|
|
@@ -567,16 +643,121 @@ function createMantleClient(config) {
|
|
|
567
643
|
method: "POST",
|
|
568
644
|
body
|
|
569
645
|
});
|
|
570
|
-
return result
|
|
646
|
+
return result;
|
|
571
647
|
}
|
|
572
648
|
};
|
|
573
649
|
}
|
|
574
650
|
|
|
651
|
+
// src/client/react/useEthersWallet.ts
|
|
652
|
+
var import_react = require("react");
|
|
653
|
+
var import_ethers = require("ethers");
|
|
654
|
+
function useEthersWallet(options) {
|
|
655
|
+
const [address, setAddress] = (0, import_react.useState)(void 0);
|
|
656
|
+
const [isConnected, setIsConnected] = (0, import_react.useState)(false);
|
|
657
|
+
const [provider, setProvider] = (0, import_react.useState)(
|
|
658
|
+
void 0
|
|
659
|
+
);
|
|
660
|
+
const [chainId, setChainId] = (0, import_react.useState)(void 0);
|
|
661
|
+
const [error, setError] = (0, import_react.useState)(void 0);
|
|
662
|
+
const connect = (0, import_react.useCallback)(async () => {
|
|
663
|
+
try {
|
|
664
|
+
setError(void 0);
|
|
665
|
+
if (typeof window === "undefined" || !window.ethereum) {
|
|
666
|
+
throw new Error(
|
|
667
|
+
"No Ethereum wallet detected. Please install MetaMask or another wallet."
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
const browserProvider = new import_ethers.ethers.BrowserProvider(
|
|
671
|
+
window.ethereum
|
|
672
|
+
);
|
|
673
|
+
setProvider(browserProvider);
|
|
674
|
+
const accounts = await window.ethereum.request({
|
|
675
|
+
method: "eth_requestAccounts"
|
|
676
|
+
});
|
|
677
|
+
if (!accounts || accounts.length === 0) {
|
|
678
|
+
throw new Error("No accounts returned from wallet");
|
|
679
|
+
}
|
|
680
|
+
const userAddress = accounts[0];
|
|
681
|
+
setAddress(userAddress);
|
|
682
|
+
setIsConnected(true);
|
|
683
|
+
const network = await browserProvider.getNetwork();
|
|
684
|
+
setChainId(Number(network.chainId));
|
|
685
|
+
} catch (err) {
|
|
686
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
687
|
+
setError(errorObj);
|
|
688
|
+
setIsConnected(false);
|
|
689
|
+
setAddress(void 0);
|
|
690
|
+
setChainId(void 0);
|
|
691
|
+
throw errorObj;
|
|
692
|
+
}
|
|
693
|
+
}, []);
|
|
694
|
+
const disconnect = (0, import_react.useCallback)(() => {
|
|
695
|
+
setAddress(void 0);
|
|
696
|
+
setIsConnected(false);
|
|
697
|
+
setChainId(void 0);
|
|
698
|
+
setError(void 0);
|
|
699
|
+
}, []);
|
|
700
|
+
(0, import_react.useEffect)(() => {
|
|
701
|
+
if (typeof window === "undefined" || !window.ethereum) return;
|
|
702
|
+
const ethereum = window.ethereum;
|
|
703
|
+
const handleAccountsChanged = (accounts) => {
|
|
704
|
+
const accountsArray = accounts;
|
|
705
|
+
if (!accountsArray || accountsArray.length === 0) {
|
|
706
|
+
disconnect();
|
|
707
|
+
} else {
|
|
708
|
+
setAddress(accountsArray[0]);
|
|
709
|
+
setIsConnected(true);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
if (ethereum.on) {
|
|
713
|
+
ethereum.on("accountsChanged", handleAccountsChanged);
|
|
714
|
+
}
|
|
715
|
+
return () => {
|
|
716
|
+
if (ethereum.removeListener) {
|
|
717
|
+
ethereum.removeListener("accountsChanged", handleAccountsChanged);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
}, [disconnect]);
|
|
721
|
+
(0, import_react.useEffect)(() => {
|
|
722
|
+
if (typeof window === "undefined" || !window.ethereum) return;
|
|
723
|
+
const ethereum = window.ethereum;
|
|
724
|
+
const handleChainChanged = (chainIdHex) => {
|
|
725
|
+
const newChainId = parseInt(chainIdHex, 16);
|
|
726
|
+
setChainId(newChainId);
|
|
727
|
+
};
|
|
728
|
+
if (ethereum.on) {
|
|
729
|
+
ethereum.on("chainChanged", handleChainChanged);
|
|
730
|
+
}
|
|
731
|
+
return () => {
|
|
732
|
+
if (ethereum.removeListener) {
|
|
733
|
+
ethereum.removeListener("chainChanged", handleChainChanged);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
}, []);
|
|
737
|
+
const shouldAutoConnect = options?.autoConnect !== false;
|
|
738
|
+
(0, import_react.useEffect)(() => {
|
|
739
|
+
if (shouldAutoConnect) {
|
|
740
|
+
connect().catch((err) => {
|
|
741
|
+
console.warn("[useEthersWallet] Auto-connect failed:", err);
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}, [shouldAutoConnect, connect]);
|
|
745
|
+
return {
|
|
746
|
+
address,
|
|
747
|
+
isConnected,
|
|
748
|
+
provider,
|
|
749
|
+
chainId,
|
|
750
|
+
connect,
|
|
751
|
+
disconnect,
|
|
752
|
+
error
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
|
|
575
756
|
// src/client/react/useMantleX402.ts
|
|
576
|
-
var import_wagmi = require("wagmi");
|
|
577
757
|
function useMantleX402(opts) {
|
|
578
|
-
const { address, isConnected } = (
|
|
579
|
-
|
|
758
|
+
const { address, isConnected } = useEthersWallet({
|
|
759
|
+
autoConnect: opts?.autoConnect ?? false
|
|
760
|
+
});
|
|
580
761
|
const client = createMantleClient({
|
|
581
762
|
facilitatorUrl: opts?.facilitatorUrl,
|
|
582
763
|
resourceUrl: opts?.resourceUrl,
|
|
@@ -585,7 +766,12 @@ function useMantleX402(opts) {
|
|
|
585
766
|
if (!isConnected || !address) return void 0;
|
|
586
767
|
return address;
|
|
587
768
|
},
|
|
588
|
-
getProvider: () =>
|
|
769
|
+
getProvider: () => {
|
|
770
|
+
if (typeof window !== "undefined" && window.ethereum) {
|
|
771
|
+
return window.ethereum;
|
|
772
|
+
}
|
|
773
|
+
return void 0;
|
|
774
|
+
}
|
|
589
775
|
});
|
|
590
776
|
return client;
|
|
591
777
|
}
|
|
@@ -596,5 +782,6 @@ function useMantleX402(opts) {
|
|
|
596
782
|
createPaymentClient,
|
|
597
783
|
createPaymentMiddleware,
|
|
598
784
|
mantlePaywall,
|
|
785
|
+
useEthersWallet,
|
|
599
786
|
useMantleX402
|
|
600
787
|
});
|