@puga-labs/x402-mantle-sdk 0.3.10 → 0.4.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.
Files changed (66) hide show
  1. package/README.md +488 -0
  2. package/dist/chunk-2IGT3ZXX.js +179 -0
  3. package/dist/chunk-3YIQEQDT.js +96 -0
  4. package/dist/chunk-4BUJR6G5.js +100 -0
  5. package/dist/chunk-5WQRPHQL.js +108 -0
  6. package/dist/chunk-6IR4GUG7.js +326 -0
  7. package/dist/chunk-HUKLI4UV.js +318 -0
  8. package/dist/chunk-HVQ2RGMT.js +126 -0
  9. package/dist/chunk-IWRQEN5H.js +97 -0
  10. package/dist/chunk-KFLH22GF.js +179 -0
  11. package/dist/chunk-N2XBZWB6.js +111 -0
  12. package/dist/chunk-NC5OU47J.js +99 -0
  13. package/dist/chunk-NWWXJFJ4.js +293 -0
  14. package/dist/chunk-RVPI6FMV.js +307 -0
  15. package/dist/chunk-UGW2GEWW.js +303 -0
  16. package/dist/chunk-UOY3C2LF.js +128 -0
  17. package/dist/chunk-YCCM6HBF.js +149 -0
  18. package/dist/client.cjs +13 -7
  19. package/dist/client.d.cts +2 -2
  20. package/dist/client.d.ts +2 -2
  21. package/dist/client.js +1 -1
  22. package/dist/createMantleClient-CMwzWrtB.d.ts +103 -0
  23. package/dist/createMantleClient-DEqYPoMs.d.cts +103 -0
  24. package/dist/createMantleClient-DyOpGjHf.d.ts +103 -0
  25. package/dist/createMantleClient-MlVEklNy.d.cts +103 -0
  26. package/dist/express-BIIgsBDf.d.ts +73 -0
  27. package/dist/express-BrBmK46G.d.cts +73 -0
  28. package/dist/express-DVL-tJDp.d.ts +80 -0
  29. package/dist/express-DcopaNmZ.d.cts +80 -0
  30. package/dist/index.cjs +95 -34
  31. package/dist/index.d.cts +3 -3
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.js +4 -4
  34. package/dist/nextjs-BD0e-jPY.d.cts +89 -0
  35. package/dist/nextjs-C062eZ_O.d.ts +89 -0
  36. package/dist/nextjs-CvArUfyl.d.ts +89 -0
  37. package/dist/nextjs-Xr2VtN1D.d.cts +89 -0
  38. package/dist/react.cjs +13 -7
  39. package/dist/react.d.cts +10 -4
  40. package/dist/react.d.ts +10 -4
  41. package/dist/react.js +2 -2
  42. package/dist/server-express.cjs +92 -27
  43. package/dist/server-express.d.cts +2 -2
  44. package/dist/server-express.d.ts +2 -2
  45. package/dist/server-express.js +2 -2
  46. package/dist/server-nextjs.cjs +78 -24
  47. package/dist/server-nextjs.d.cts +2 -2
  48. package/dist/server-nextjs.d.ts +2 -2
  49. package/dist/server-nextjs.js +2 -2
  50. package/dist/server-web.cjs +78 -24
  51. package/dist/server-web.d.cts +2 -2
  52. package/dist/server-web.d.ts +2 -2
  53. package/dist/server-web.js +2 -2
  54. package/dist/server.cjs +138 -47
  55. package/dist/server.d.cts +35 -7
  56. package/dist/server.d.ts +35 -7
  57. package/dist/server.js +6 -4
  58. package/dist/types-AMVZT3Hf.d.ts +125 -0
  59. package/dist/types-CED_oMWa.d.cts +143 -0
  60. package/dist/types-D1mhWKmb.d.ts +143 -0
  61. package/dist/types-pF3IaKvC.d.cts +125 -0
  62. package/dist/web-standards-BxG0Rdwk.d.ts +77 -0
  63. package/dist/web-standards-C8EBfBLy.d.ts +77 -0
  64. package/dist/web-standards-CXf21iDH.d.cts +77 -0
  65. package/dist/web-standards-D-2Neqyr.d.cts +77 -0
  66. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,488 @@
1
+ # @puga-labs/x402-mantle-sdk
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@puga-labs/x402-mantle-sdk.svg)](https://www.npmjs.com/package/@puga-labs/x402-mantle-sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ SDK for x402 payments on Mantle blockchain. Protect your APIs with USDC payments using a simple middleware.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @puga-labs/x402-mantle-sdk
12
+ ```
13
+
14
+ ## Features
15
+
16
+ - React hooks (`useMantleX402`, `useEthersWallet`)
17
+ - Vanilla JS client (`createMantleClient`)
18
+ - Server middleware for Express, Next.js, Hono, Cloudflare Workers, Deno
19
+ - Full TypeScript support
20
+ - Automatic payment flow handling
21
+ - Analytics & telemetry integration
22
+
23
+ ---
24
+
25
+ ## Client-Side Usage
26
+
27
+ ### React (Recommended)
28
+
29
+ ```tsx
30
+ import { useMantleX402 } from '@puga-labs/x402-mantle-sdk/react';
31
+
32
+ function PaymentButton() {
33
+ const { postWithPayment } = useMantleX402({
34
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
35
+ });
36
+
37
+ const handlePay = async () => {
38
+ try {
39
+ const { response, txHash } = await postWithPayment('/api/generate', {
40
+ prompt: 'Hello world'
41
+ });
42
+
43
+ console.log('Result:', response);
44
+ console.log('Transaction:', txHash);
45
+ } catch (error) {
46
+ console.error('Payment failed:', error);
47
+ }
48
+ };
49
+
50
+ return <button onClick={handlePay}>Generate ($0.01)</button>;
51
+ }
52
+ ```
53
+
54
+ ### Wallet Hook
55
+
56
+ Separate hook for wallet management:
57
+
58
+ ```tsx
59
+ import { useEthersWallet } from '@puga-labs/x402-mantle-sdk/react';
60
+
61
+ function WalletConnect() {
62
+ const {
63
+ address,
64
+ isConnected,
65
+ chainId,
66
+ connect,
67
+ disconnect,
68
+ error
69
+ } = useEthersWallet({ autoConnect: false });
70
+
71
+ if (isConnected) {
72
+ return (
73
+ <div>
74
+ <p>Connected: {address}</p>
75
+ <p>Chain ID: {chainId}</p>
76
+ <button onClick={disconnect}>Disconnect</button>
77
+ </div>
78
+ );
79
+ }
80
+
81
+ return <button onClick={connect}>Connect Wallet</button>;
82
+ }
83
+ ```
84
+
85
+ ### Vanilla JavaScript
86
+
87
+ ```typescript
88
+ import { createMantleClient } from '@puga-labs/x402-mantle-sdk/client';
89
+
90
+ // Create client
91
+ const client = createMantleClient({
92
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz',
93
+ resourceUrl: 'https://your-api.com',
94
+ getProvider: () => window.ethereum,
95
+ getAccount: () => userAddress
96
+ });
97
+
98
+ // Make paid request
99
+ const { response, txHash } = await client.postWithPayment('/api/generate', {
100
+ prompt: 'Hello world'
101
+ });
102
+ ```
103
+
104
+ ### Low-Level Payment Client
105
+
106
+ For full control over the payment flow:
107
+
108
+ ```typescript
109
+ import { createPaymentClient } from '@puga-labs/x402-mantle-sdk/client';
110
+
111
+ const paymentClient = createPaymentClient({
112
+ resourceUrl: 'https://your-api.com',
113
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz',
114
+ provider: window.ethereum,
115
+ userAddress: '0x...' // Optional
116
+ });
117
+
118
+ const result = await paymentClient.callWithPayment('/api/endpoint', {
119
+ data: 'payload'
120
+ });
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Server-Side Usage
126
+
127
+ ### Express.js
128
+
129
+ ```typescript
130
+ import express from 'express';
131
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/express';
132
+
133
+ const app = express();
134
+ app.use(express.json());
135
+
136
+ // Create paywall middleware
137
+ const pay = mantlePaywall({
138
+ priceUsd: 0.01,
139
+ payTo: '0xYourWalletAddress',
140
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
141
+ });
142
+
143
+ // Protected route
144
+ app.post('/api/generate', pay, async (req, res) => {
145
+ const { prompt } = req.body;
146
+ // Your logic here - only runs after payment
147
+ res.json({ result: 'Generated content' });
148
+ });
149
+
150
+ // Unprotected route
151
+ app.get('/api/health', (req, res) => {
152
+ res.json({ status: 'ok' });
153
+ });
154
+
155
+ app.listen(3000);
156
+ ```
157
+
158
+ ### Next.js (App Router)
159
+
160
+ ```typescript
161
+ // app/api/generate/route.ts
162
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/nextjs';
163
+ import { NextRequest, NextResponse } from 'next/server';
164
+
165
+ const pay = mantlePaywall({
166
+ priceUsd: 0.01,
167
+ payTo: '0xYourWalletAddress',
168
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
169
+ });
170
+
171
+ export const POST = pay(async (req: NextRequest) => {
172
+ const { prompt } = await req.json();
173
+ // Your logic here
174
+ return NextResponse.json({ result: 'Generated content' });
175
+ });
176
+ ```
177
+
178
+ ### Hono
179
+
180
+ ```typescript
181
+ import { Hono } from 'hono';
182
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/web';
183
+
184
+ const app = new Hono();
185
+
186
+ const pay = mantlePaywall({
187
+ priceUsd: 0.01,
188
+ payTo: '0xYourWalletAddress',
189
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
190
+ });
191
+
192
+ app.post('/api/generate', pay(async (c) => {
193
+ const { prompt } = await c.req.json();
194
+ return c.json({ result: 'Generated content' });
195
+ }));
196
+
197
+ export default app;
198
+ ```
199
+
200
+ ### Cloudflare Workers
201
+
202
+ ```typescript
203
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/web';
204
+
205
+ const pay = mantlePaywall({
206
+ priceUsd: 0.01,
207
+ payTo: '0xYourWalletAddress',
208
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
209
+ });
210
+
211
+ export default {
212
+ async fetch(request: Request): Promise<Response> {
213
+ if (request.method === 'POST') {
214
+ return pay(async (req) => {
215
+ const body = await req.json();
216
+ return new Response(JSON.stringify({ result: 'success' }), {
217
+ headers: { 'Content-Type': 'application/json' }
218
+ });
219
+ })(request);
220
+ }
221
+ return new Response('Method not allowed', { status: 405 });
222
+ }
223
+ };
224
+ ```
225
+
226
+ ### Deno
227
+
228
+ ```typescript
229
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/web';
230
+
231
+ const pay = mantlePaywall({
232
+ priceUsd: 0.01,
233
+ payTo: '0xYourWalletAddress',
234
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz'
235
+ });
236
+
237
+ Deno.serve(pay(async (req) => {
238
+ const body = await req.json();
239
+ return new Response(JSON.stringify({ result: 'success' }), {
240
+ headers: { 'Content-Type': 'application/json' }
241
+ });
242
+ }));
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Configuration
248
+
249
+ ### Client Options
250
+
251
+ | Option | Type | Default | Description |
252
+ |--------|------|---------|-------------|
253
+ | `facilitatorUrl` | `string` | From 402 response | Facilitator service URL (auto-detected from backend) |
254
+ | `resourceUrl` | `string` | `window.location.origin` | Your API base URL |
255
+ | `projectKey` | `string` | From 402 response | Project key (auto-detected from backend) |
256
+ | `getProvider` | `() => EIP1193Provider` | - | Function returning wallet provider |
257
+ | `getAccount` | `() => string` | - | Function returning user address |
258
+
259
+ **Note:** Both `facilitatorUrl` and `projectKey` are automatically passed from your backend via 402 responses, so clients typically don't need to configure them.
260
+
261
+ ### Server Options (mantlePaywall)
262
+
263
+ | Option | Type | Required | Description |
264
+ |--------|------|----------|-------------|
265
+ | `priceUsd` | `number` | Yes | Price in USD (e.g., `0.01` for 1 cent) |
266
+ | `payTo` | `string` | Yes | Your wallet address to receive payments |
267
+ | `facilitatorUrl` | `string` | No | Facilitator URL (default: localhost:8080) |
268
+ | `projectKey` | `string` | No | Project key from dashboard (for hosted facilitator + analytics) |
269
+ | `facilitatorSecret` | `string` | For self-hosted | Shared secret with your facilitator (required for self-hosted) |
270
+ | `network` | `string` | No | Network ID (default: `mantle-mainnet`) |
271
+ | `onPaymentSettled` | `function` | No | Callback when payment is verified |
272
+ | `telemetry` | `object` | No | Analytics configuration (auto-uses projectKey if not set) |
273
+
274
+ ---
275
+
276
+ ## Hosted vs Self-Hosted Facilitator
277
+
278
+ ### Hosted Facilitator (Recommended)
279
+
280
+ Use our managed facilitator service:
281
+
282
+ ```typescript
283
+ const pay = mantlePaywall({
284
+ priceUsd: 0.01,
285
+ payTo: '0xYourWallet',
286
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz',
287
+ projectKey: 'pk_xxx' // Get from dashboard (used for billing + analytics)
288
+ });
289
+ ```
290
+
291
+ Get your project key from [Dashboard](https://x402mantlesdk.xyz/dashboard).
292
+
293
+ **Note:** `projectKey` is automatically passed to clients via 402 responses, so they don't need to configure it separately.
294
+
295
+ ### Self-Hosted Facilitator
296
+
297
+ Run your own facilitator for full control and cost savings:
298
+
299
+ ```typescript
300
+ const pay = mantlePaywall({
301
+ priceUsd: 0.01,
302
+ payTo: '0xYourWallet',
303
+ facilitatorUrl: 'https://your-facilitator.com',
304
+ // REQUIRED: Must match FACILITATOR_SECRET in your facilitator's .env
305
+ facilitatorSecret: process.env.FACILITATOR_SECRET
306
+ });
307
+ ```
308
+
309
+ The `facilitatorSecret` is **required** for self-hosted facilitators to prevent unauthorized usage of your facilitator by third parties.
310
+
311
+ Create a facilitator with:
312
+ ```bash
313
+ npx create-mantle-facilitator my-facilitator
314
+ ```
315
+
316
+ After setup, copy `FACILITATOR_SECRET` from the generated `.env` file to your backend's environment variables.
317
+
318
+ ---
319
+
320
+ ## Analytics & Telemetry
321
+
322
+ Track payments with built-in analytics:
323
+
324
+ ```typescript
325
+ const pay = mantlePaywall({
326
+ priceUsd: 0.01,
327
+ payTo: '0x...',
328
+ facilitatorUrl: 'https://facilitator.x402mantlesdk.xyz',
329
+ projectKey: 'pk_xxx', // Get from dashboard - used for both billing AND analytics
330
+
331
+ // Optional: Advanced telemetry config
332
+ telemetry: {
333
+ debug: true // Enable console logging (projectKey auto-derived from above)
334
+ },
335
+
336
+ // Callback on each successful payment
337
+ onPaymentSettled: (entry) => {
338
+ console.log('Payment received!');
339
+ console.log('Amount:', entry.valueAtomic);
340
+ console.log('From:', entry.from);
341
+ console.log('To:', entry.to);
342
+ console.log('TxHash:', entry.txHash);
343
+ console.log('Route:', entry.route);
344
+ }
345
+ });
346
+ ```
347
+
348
+ ### PaymentLogEntry Fields
349
+
350
+ | Field | Type | Description |
351
+ |-------|------|-------------|
352
+ | `id` | `string` | Unique payment identifier (nonce) |
353
+ | `from` | `string` | Payer's wallet address |
354
+ | `to` | `string` | Recipient's wallet address |
355
+ | `valueAtomic` | `string` | Amount in atomic units |
356
+ | `network` | `string` | Network ID |
357
+ | `asset` | `string` | Token contract address |
358
+ | `route` | `string` | API route (e.g., `POST /api/generate`) |
359
+ | `txHash` | `string` | Blockchain transaction hash |
360
+ | `timestamp` | `number` | Unix timestamp (ms) |
361
+
362
+ ---
363
+
364
+ ## TypeScript Types
365
+
366
+ ```typescript
367
+ import type {
368
+ // Shared types
369
+ PaymentRequirements,
370
+ Authorization,
371
+ PaymentHeaderObject,
372
+ NetworkId,
373
+
374
+ // Client types
375
+ MantleClient,
376
+ MantleClientConfig,
377
+ PaymentClient,
378
+ PaymentClientConfig,
379
+ CallWithPaymentResult,
380
+
381
+ // Server types
382
+ PaymentLogEntry,
383
+ TelemetryConfig,
384
+ MinimalPaywallOptions,
385
+
386
+ // React types
387
+ UseMantleX402Options,
388
+ UseEthersWalletOptions,
389
+ UseEthersWalletReturn
390
+ } from '@puga-labs/x402-mantle-sdk';
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Import Paths
396
+
397
+ ```typescript
398
+ // Main exports (types + constants)
399
+ import { MANTLE_DEFAULTS } from '@puga-labs/x402-mantle-sdk';
400
+
401
+ // Client
402
+ import { createMantleClient, createPaymentClient } from '@puga-labs/x402-mantle-sdk/client';
403
+
404
+ // React hooks
405
+ import { useMantleX402, useEthersWallet } from '@puga-labs/x402-mantle-sdk/react';
406
+
407
+ // Server - Express
408
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/express';
409
+
410
+ // Server - Next.js
411
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/nextjs';
412
+
413
+ // Server - Web Standards (Hono, CF Workers, Deno)
414
+ import { mantlePaywall } from '@puga-labs/x402-mantle-sdk/server/web';
415
+ ```
416
+
417
+ ---
418
+
419
+ ## Network Configuration
420
+
421
+ | Network | Chain ID | USDC Address | Decimals |
422
+ |---------|----------|--------------|----------|
423
+ | Mantle Mainnet | 5000 | `0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9` | 6 |
424
+
425
+ ### Price Conversion
426
+
427
+ - `priceUsd: 0.01` = 1 cent = 10,000 atomic units
428
+ - Formula: `atomicUnits = priceUsd * 10^6`
429
+
430
+ ---
431
+
432
+ ## Error Handling
433
+
434
+ ### Client-Side Errors
435
+
436
+ ```typescript
437
+ try {
438
+ const { response, txHash } = await postWithPayment('/api/generate', data);
439
+ } catch (error) {
440
+ if (error.code === 4001) {
441
+ // User rejected the transaction
442
+ console.log('User cancelled');
443
+ } else if (error.code === -32603) {
444
+ // Internal error (insufficient funds, etc.)
445
+ console.log('Transaction failed:', error.message);
446
+ } else {
447
+ // Network or facilitator error
448
+ console.log('Error:', error.message);
449
+ }
450
+ }
451
+ ```
452
+
453
+ ### Server-Side Error Responses
454
+
455
+ ```typescript
456
+ // 402 Payment Required
457
+ {
458
+ "error": "Payment Required",
459
+ "paymentRequirements": {
460
+ "scheme": "exact",
461
+ "network": "mantle-mainnet",
462
+ "asset": "0x09Bc4E0D...",
463
+ "maxAmountRequired": "10000",
464
+ "payTo": "0x...",
465
+ "price": "$0.01",
466
+ "currency": "USD"
467
+ }
468
+ }
469
+
470
+ // 400 Invalid Payment
471
+ {
472
+ "error": "Invalid payment",
473
+ "invalidReason": "Payment amount too low"
474
+ }
475
+ ```
476
+
477
+ ---
478
+
479
+ ## Links
480
+
481
+ - [Full Documentation](https://x402mantlesdk.xyz/docs)
482
+ - [Dashboard](https://x402mantlesdk.xyz/dashboard)
483
+ - [GitHub](https://github.com/puga-labs/x402-mantle-sdk)
484
+ - [Facilitator Kit](../create-mantle-facilitator)
485
+
486
+ ## License
487
+
488
+ MIT
@@ -0,0 +1,179 @@
1
+ import {
2
+ createMantleClient
3
+ } from "./chunk-RVPI6FMV.js";
4
+
5
+ // src/client/react/useEthersWallet.ts
6
+ import { useState, useEffect, useCallback } from "react";
7
+ import { ethers } from "ethers";
8
+ function useEthersWallet(options) {
9
+ const [address, setAddress] = useState(void 0);
10
+ const [isConnected, setIsConnected] = useState(false);
11
+ const [provider, setProvider] = useState(
12
+ void 0
13
+ );
14
+ const [chainId, setChainId] = useState(void 0);
15
+ const [error, setError] = useState(void 0);
16
+ const setProviderAndChain = useCallback(async () => {
17
+ if (typeof window === "undefined" || !window.ethereum) return;
18
+ const browserProvider = new ethers.BrowserProvider(
19
+ window.ethereum
20
+ );
21
+ setProvider(browserProvider);
22
+ const network = await browserProvider.getNetwork();
23
+ setChainId(Number(network.chainId));
24
+ }, []);
25
+ const hydrateFromPermissions = useCallback(async () => {
26
+ if (typeof window === "undefined" || !window.ethereum) return;
27
+ try {
28
+ const accounts = await window.ethereum.request({
29
+ method: "eth_accounts"
30
+ });
31
+ if (accounts && accounts.length > 0) {
32
+ const userAddress = accounts[0];
33
+ setAddress(userAddress);
34
+ setIsConnected(true);
35
+ await setProviderAndChain();
36
+ }
37
+ } catch (err) {
38
+ console.warn("[useEthersWallet] Failed to hydrate from permissions:", err);
39
+ }
40
+ }, [setProviderAndChain]);
41
+ const connect = useCallback(async () => {
42
+ try {
43
+ setError(void 0);
44
+ if (typeof window === "undefined" || !window.ethereum) {
45
+ throw new Error(
46
+ "No Ethereum wallet detected. Please install MetaMask or another wallet."
47
+ );
48
+ }
49
+ const browserProvider = new ethers.BrowserProvider(
50
+ window.ethereum
51
+ );
52
+ setProvider(browserProvider);
53
+ const accounts = await window.ethereum.request({
54
+ method: "eth_requestAccounts"
55
+ });
56
+ if (!accounts || accounts.length === 0) {
57
+ throw new Error("No accounts returned from wallet");
58
+ }
59
+ const userAddress = accounts[0];
60
+ setAddress(userAddress);
61
+ setIsConnected(true);
62
+ const network = await browserProvider.getNetwork();
63
+ setChainId(Number(network.chainId));
64
+ } catch (err) {
65
+ const errorObj = err instanceof Error ? err : new Error(String(err));
66
+ setError(errorObj);
67
+ setIsConnected(false);
68
+ setAddress(void 0);
69
+ setChainId(void 0);
70
+ throw errorObj;
71
+ }
72
+ }, []);
73
+ const disconnect = useCallback(() => {
74
+ setAddress(void 0);
75
+ setIsConnected(false);
76
+ setChainId(void 0);
77
+ setError(void 0);
78
+ }, []);
79
+ useEffect(() => {
80
+ if (typeof window === "undefined" || !window.ethereum) return;
81
+ const ethereum = window.ethereum;
82
+ const handleAccountsChanged = (accounts) => {
83
+ const accountsArray = accounts;
84
+ if (!accountsArray || accountsArray.length === 0) {
85
+ disconnect();
86
+ } else {
87
+ setAddress(accountsArray[0]);
88
+ setIsConnected(true);
89
+ void setProviderAndChain();
90
+ }
91
+ };
92
+ if (ethereum.on) {
93
+ ethereum.on("accountsChanged", handleAccountsChanged);
94
+ }
95
+ return () => {
96
+ if (ethereum.removeListener) {
97
+ ethereum.removeListener("accountsChanged", handleAccountsChanged);
98
+ }
99
+ };
100
+ }, [disconnect, setProviderAndChain]);
101
+ useEffect(() => {
102
+ if (typeof window === "undefined" || !window.ethereum) return;
103
+ const ethereum = window.ethereum;
104
+ const handleConnect = () => {
105
+ void hydrateFromPermissions();
106
+ };
107
+ if (ethereum.on) {
108
+ ethereum.on("connect", handleConnect);
109
+ }
110
+ return () => {
111
+ if (ethereum.removeListener) {
112
+ ethereum.removeListener("connect", handleConnect);
113
+ }
114
+ };
115
+ }, [hydrateFromPermissions]);
116
+ useEffect(() => {
117
+ if (typeof window === "undefined" || !window.ethereum) return;
118
+ const ethereum = window.ethereum;
119
+ const handleChainChanged = (chainIdHex) => {
120
+ const newChainId = parseInt(chainIdHex, 16);
121
+ setChainId(newChainId);
122
+ };
123
+ if (ethereum.on) {
124
+ ethereum.on("chainChanged", handleChainChanged);
125
+ }
126
+ return () => {
127
+ if (ethereum.removeListener) {
128
+ ethereum.removeListener("chainChanged", handleChainChanged);
129
+ }
130
+ };
131
+ }, []);
132
+ useEffect(() => {
133
+ void hydrateFromPermissions();
134
+ }, [hydrateFromPermissions]);
135
+ useEffect(() => {
136
+ if (options?.autoConnect) {
137
+ connect().catch((err) => {
138
+ console.warn("[useEthersWallet] Auto-connect failed:", err);
139
+ });
140
+ }
141
+ }, [options?.autoConnect, connect]);
142
+ return {
143
+ address,
144
+ isConnected,
145
+ provider,
146
+ chainId,
147
+ connect,
148
+ disconnect,
149
+ error
150
+ };
151
+ }
152
+
153
+ // src/client/react/useMantleX402.ts
154
+ function useMantleX402(opts) {
155
+ const { address, isConnected } = useEthersWallet({
156
+ autoConnect: opts?.autoConnect ?? false
157
+ });
158
+ const client = createMantleClient({
159
+ facilitatorUrl: opts?.facilitatorUrl,
160
+ resourceUrl: opts?.resourceUrl,
161
+ projectKey: opts?.projectKey,
162
+ getAccount: () => {
163
+ if (!isConnected || !address) return void 0;
164
+ return address;
165
+ },
166
+ getProvider: () => {
167
+ if (typeof window !== "undefined" && window.ethereum) {
168
+ return window.ethereum;
169
+ }
170
+ return void 0;
171
+ }
172
+ });
173
+ return client;
174
+ }
175
+
176
+ export {
177
+ useEthersWallet,
178
+ useMantleX402
179
+ };