x402-mantle-sdk 0.1.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.
@@ -0,0 +1,793 @@
1
+ // src/client/constants.ts
2
+ var NETWORKS = {
3
+ mantle: {
4
+ chainId: 5e3,
5
+ rpcUrl: "https://rpc.mantle.xyz",
6
+ name: "Mantle",
7
+ environment: "mainnet",
8
+ nativeCurrency: { name: "Mantle", symbol: "MNT", decimals: 18 },
9
+ blockExplorer: "https://explorer.mantle.xyz"
10
+ },
11
+ "mantle-sepolia": {
12
+ chainId: 5003,
13
+ rpcUrl: "https://rpc.sepolia.mantle.xyz",
14
+ name: "Mantle Sepolia",
15
+ environment: "testnet",
16
+ nativeCurrency: { name: "Mantle", symbol: "MNT", decimals: 18 },
17
+ blockExplorer: "https://explorer.sepolia.mantle.xyz"
18
+ },
19
+ "mantle-testnet": {
20
+ chainId: 5003,
21
+ rpcUrl: "https://rpc.sepolia.mantle.xyz",
22
+ name: "Mantle Testnet",
23
+ environment: "testnet",
24
+ nativeCurrency: { name: "Mantle", symbol: "MNT", decimals: 18 },
25
+ blockExplorer: "https://explorer.sepolia.mantle.xyz"
26
+ }
27
+ };
28
+ var TOKENS = {
29
+ mantle: {
30
+ USDC: {
31
+ address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
32
+ decimals: 6,
33
+ symbol: "USDC"
34
+ },
35
+ USDT: {
36
+ address: "0x201EBa5CC46D216Ce6DC03F6a759e8E766e956aE",
37
+ decimals: 6,
38
+ symbol: "USDT"
39
+ },
40
+ mETH: {
41
+ address: "0xcDA86A272531e8640cD7F1a92c01839911B90bb0",
42
+ decimals: 18,
43
+ symbol: "mETH"
44
+ },
45
+ WMNT: {
46
+ address: "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
47
+ decimals: 18,
48
+ symbol: "WMNT"
49
+ }
50
+ },
51
+ "mantle-sepolia": {
52
+ USDC: {
53
+ address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
54
+ decimals: 6,
55
+ symbol: "USDC"
56
+ },
57
+ mETH: {
58
+ address: "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111",
59
+ decimals: 18,
60
+ symbol: "mETH"
61
+ },
62
+ WMNT: {
63
+ address: "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
64
+ decimals: 18,
65
+ symbol: "WMNT"
66
+ }
67
+ },
68
+ "mantle-testnet": {
69
+ USDC: {
70
+ address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9",
71
+ decimals: 6,
72
+ symbol: "USDC"
73
+ },
74
+ mETH: {
75
+ address: "0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111",
76
+ decimals: 18,
77
+ symbol: "mETH"
78
+ },
79
+ WMNT: {
80
+ address: "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
81
+ decimals: 18,
82
+ symbol: "WMNT"
83
+ }
84
+ }
85
+ };
86
+ var TREASURY_ADDRESS = "0xB27705342ACE73736AE490540Ea031cc06C3eF49";
87
+ var PLATFORM_FEE_BPS = 50n;
88
+ var BPS_DENOMINATOR = 10000n;
89
+ var TREASURY_ADMIN = "0xDacCF30F8BB2aEb8D76E68E03033629809ed08E1";
90
+ var customNetworks = /* @__PURE__ */ new Map();
91
+ var customTokens = /* @__PURE__ */ new Map();
92
+ function registerCustomNetwork(networkId, config) {
93
+ customNetworks.set(networkId.toLowerCase(), {
94
+ chainId: config.chainId,
95
+ rpcUrl: config.rpcUrl,
96
+ name: config.name || networkId,
97
+ environment: config.environment || "testnet",
98
+ nativeCurrency: { name: "Native", symbol: "ETH", decimals: 18 },
99
+ blockExplorer: config.blockExplorer || ""
100
+ });
101
+ }
102
+ function registerCustomTokens(networkId, tokens) {
103
+ const networkKey = networkId.toLowerCase();
104
+ if (!customTokens.has(networkKey)) {
105
+ customTokens.set(networkKey, /* @__PURE__ */ new Map());
106
+ }
107
+ const tokenMap = customTokens.get(networkKey);
108
+ for (const [symbol, config] of Object.entries(tokens)) {
109
+ tokenMap.set(symbol.toUpperCase(), {
110
+ address: config.address,
111
+ decimals: config.decimals,
112
+ symbol: symbol.toUpperCase()
113
+ });
114
+ }
115
+ }
116
+ function isTestnet(network) {
117
+ const config = getNetworkConfig(network);
118
+ return config.environment === "testnet";
119
+ }
120
+ function isMainnet(network) {
121
+ const config = getNetworkConfig(network);
122
+ return config.environment === "mainnet";
123
+ }
124
+ function getNetworkConfig(network) {
125
+ const networkKey = network.toLowerCase();
126
+ const custom = customNetworks.get(networkKey);
127
+ if (custom) {
128
+ return custom;
129
+ }
130
+ const preset = NETWORKS[networkKey];
131
+ if (preset) {
132
+ return preset;
133
+ }
134
+ return NETWORKS.mantle;
135
+ }
136
+ function getTokenConfig(token, network) {
137
+ const networkKey = network.toLowerCase();
138
+ const tokenKey = token.toUpperCase();
139
+ if (tokenKey === "MNT") {
140
+ return null;
141
+ }
142
+ const customMap = customTokens.get(networkKey);
143
+ if (customMap?.has(tokenKey)) {
144
+ return customMap.get(tokenKey);
145
+ }
146
+ return TOKENS[networkKey]?.[tokenKey] || null;
147
+ }
148
+ function getChainId(network) {
149
+ return getNetworkConfig(network).chainId;
150
+ }
151
+ function getAvailableNetworks() {
152
+ const preset = Object.keys(NETWORKS);
153
+ const custom = Array.from(customNetworks.keys());
154
+ return [.../* @__PURE__ */ new Set([...preset, ...custom])];
155
+ }
156
+ function getNetworksByEnvironment(env) {
157
+ return getAvailableNetworks().filter((network) => {
158
+ const config = getNetworkConfig(network);
159
+ return config.environment === env;
160
+ });
161
+ }
162
+
163
+ // src/client/wallet.ts
164
+ function getEthereumProvider() {
165
+ if (typeof window === "undefined") {
166
+ return null;
167
+ }
168
+ return window.ethereum || null;
169
+ }
170
+ var MetaMaskProvider = class {
171
+ constructor() {
172
+ this.ethereum = getEthereumProvider();
173
+ }
174
+ isAvailable() {
175
+ return this.ethereum !== null && this.ethereum.isMetaMask === true;
176
+ }
177
+ async connect() {
178
+ if (!this.ethereum) {
179
+ throw new Error("MetaMask is not available");
180
+ }
181
+ const accounts = await this.ethereum.request({
182
+ method: "eth_requestAccounts"
183
+ });
184
+ if (!accounts || accounts.length === 0) {
185
+ throw new Error("No accounts found");
186
+ }
187
+ return accounts[0];
188
+ }
189
+ async getAccount() {
190
+ if (!this.ethereum) {
191
+ return null;
192
+ }
193
+ try {
194
+ const accounts = await this.ethereum.request({
195
+ method: "eth_accounts"
196
+ });
197
+ return accounts && accounts.length > 0 ? accounts[0] : null;
198
+ } catch {
199
+ return null;
200
+ }
201
+ }
202
+ async getChainId() {
203
+ if (!this.ethereum) {
204
+ return null;
205
+ }
206
+ try {
207
+ const chainIdHex = await this.ethereum.request({
208
+ method: "eth_chainId"
209
+ });
210
+ return parseInt(chainIdHex, 16);
211
+ } catch {
212
+ return null;
213
+ }
214
+ }
215
+ async switchNetwork(chainId) {
216
+ if (!this.ethereum) {
217
+ throw new Error("MetaMask is not available");
218
+ }
219
+ const chainIdHex = `0x${chainId.toString(16)}`;
220
+ try {
221
+ await this.ethereum.request({
222
+ method: "wallet_switchEthereumChain",
223
+ params: [{ chainId: chainIdHex }]
224
+ });
225
+ } catch (error) {
226
+ const switchError = error;
227
+ if (switchError.code === 4902) {
228
+ throw new Error(`Network with chainId ${chainId} not found. Use addNetwork() first.`);
229
+ }
230
+ throw error;
231
+ }
232
+ }
233
+ async addNetwork(params) {
234
+ if (!this.ethereum) {
235
+ throw new Error("MetaMask is not available");
236
+ }
237
+ await this.ethereum.request({
238
+ method: "wallet_addEthereumChain",
239
+ params: [params]
240
+ });
241
+ }
242
+ async sendTransaction(tx) {
243
+ if (!this.ethereum) {
244
+ throw new Error("MetaMask is not available");
245
+ }
246
+ const txHash = await this.ethereum.request({
247
+ method: "eth_sendTransaction",
248
+ params: [tx]
249
+ });
250
+ return txHash;
251
+ }
252
+ async signMessage(message) {
253
+ if (!this.ethereum) {
254
+ throw new Error("MetaMask is not available");
255
+ }
256
+ const account = await this.getAccount();
257
+ if (!account) {
258
+ throw new Error("No account connected");
259
+ }
260
+ const signature = await this.ethereum.request({
261
+ method: "personal_sign",
262
+ params: [message, account]
263
+ });
264
+ return signature;
265
+ }
266
+ };
267
+ function detectWalletProvider() {
268
+ const metaMask = new MetaMaskProvider();
269
+ if (metaMask.isAvailable()) {
270
+ return metaMask;
271
+ }
272
+ return null;
273
+ }
274
+ async function connectWallet(provider) {
275
+ const wallet = provider || detectWalletProvider();
276
+ if (!wallet) {
277
+ throw new Error(
278
+ "No wallet provider found. Please install MetaMask or another compatible wallet."
279
+ );
280
+ }
281
+ return wallet.connect();
282
+ }
283
+ async function ensureNetwork(wallet, network, autoAdd = true) {
284
+ const config = getNetworkConfig(network);
285
+ const targetChainId = config.chainId;
286
+ const currentChainId = await wallet.getChainId();
287
+ if (currentChainId === targetChainId) {
288
+ return;
289
+ }
290
+ try {
291
+ await wallet.switchNetwork(targetChainId);
292
+ } catch (error) {
293
+ const switchError = error;
294
+ if (autoAdd && switchError.message?.includes("not found")) {
295
+ await wallet.addNetwork({
296
+ chainId: `0x${targetChainId.toString(16)}`,
297
+ chainName: config.name,
298
+ nativeCurrency: config.nativeCurrency,
299
+ rpcUrls: [config.rpcUrl],
300
+ blockExplorerUrls: config.blockExplorer ? [config.blockExplorer] : void 0
301
+ });
302
+ } else {
303
+ throw error;
304
+ }
305
+ }
306
+ }
307
+ function getAddNetworkParams(network) {
308
+ const config = getNetworkConfig(network);
309
+ return {
310
+ chainId: `0x${config.chainId.toString(16)}`,
311
+ chainName: config.name,
312
+ nativeCurrency: config.nativeCurrency,
313
+ rpcUrls: [config.rpcUrl],
314
+ blockExplorerUrls: config.blockExplorer ? [config.blockExplorer] : void 0
315
+ };
316
+ }
317
+
318
+ // src/client/payment.ts
319
+ var ERC20_TRANSFER_SIG = "0xa9059cbb";
320
+ function amountToWei(amount, decimals = 18) {
321
+ const parts = amount.split(".");
322
+ const whole = parts[0] || "0";
323
+ const fraction = (parts[1] || "").padEnd(decimals, "0").slice(0, decimals);
324
+ return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(fraction);
325
+ }
326
+ function calculateSplit(amount) {
327
+ const feeAmount = amount * PLATFORM_FEE_BPS / BPS_DENOMINATOR;
328
+ const merchantAmount = amount - feeAmount;
329
+ return { merchantAmount, feeAmount };
330
+ }
331
+ function encodeERC20Transfer(to, amount) {
332
+ const toHex = to.slice(2).toLowerCase().padStart(64, "0");
333
+ const amountHex = amount.toString(16).padStart(64, "0");
334
+ return ERC20_TRANSFER_SIG + toHex + amountHex;
335
+ }
336
+ async function processPayment(request, wallet) {
337
+ const tokenConfig = getTokenConfig(request.token, request.network);
338
+ const decimals = tokenConfig?.decimals ?? 18;
339
+ const totalAmount = amountToWei(request.amount, decimals);
340
+ const { merchantAmount, feeAmount } = calculateSplit(totalAmount);
341
+ let txHash;
342
+ if (tokenConfig) {
343
+ const transferData = encodeERC20Transfer(request.recipient, totalAmount);
344
+ const tx = {
345
+ to: tokenConfig.address,
346
+ data: transferData
347
+ };
348
+ txHash = await wallet.sendTransaction(tx);
349
+ } else {
350
+ const merchantTx = {
351
+ to: request.recipient,
352
+ value: `0x${merchantAmount.toString(16)}`
353
+ };
354
+ txHash = await wallet.sendTransaction(merchantTx);
355
+ if (feeAmount > 0n) {
356
+ const feeTx = {
357
+ to: TREASURY_ADDRESS,
358
+ value: `0x${feeAmount.toString(16)}`
359
+ };
360
+ await wallet.sendTransaction(feeTx);
361
+ }
362
+ }
363
+ return {
364
+ transactionHash: txHash,
365
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
366
+ };
367
+ }
368
+
369
+ // src/client/modal-vanilla.ts
370
+ var STYLES = {
371
+ overlay: `
372
+ position: fixed;
373
+ inset: 0;
374
+ z-index: 9999;
375
+ display: flex;
376
+ align-items: center;
377
+ justify-content: center;
378
+ background: rgba(0, 0, 0, 0.5);
379
+ backdrop-filter: blur(4px);
380
+ `,
381
+ modal: `
382
+ width: 100%;
383
+ max-width: 28rem;
384
+ border-radius: 0.75rem;
385
+ border: 1px solid rgba(255, 255, 255, 0.1);
386
+ background: rgba(24, 24, 27, 0.95);
387
+ padding: 1.5rem;
388
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);
389
+ backdrop-filter: blur(16px);
390
+ color: #fafafa;
391
+ `,
392
+ header: `
393
+ display: flex;
394
+ align-items: center;
395
+ justify-content: space-between;
396
+ margin-bottom: 1.5rem;
397
+ `,
398
+ logo: `
399
+ width: 2rem;
400
+ height: 2rem;
401
+ display: flex;
402
+ align-items: center;
403
+ justify-content: center;
404
+ border-radius: 0.5rem;
405
+ background: rgba(255, 255, 255, 0.1);
406
+ font-family: monospace;
407
+ font-size: 0.75rem;
408
+ font-weight: bold;
409
+ color: #fafafa;
410
+ `,
411
+ title: `
412
+ font-size: 1.25rem;
413
+ font-weight: 300;
414
+ margin: 0;
415
+ margin-left: 0.5rem;
416
+ color: #fafafa;
417
+ `,
418
+ closeBtn: `
419
+ background: none;
420
+ border: none;
421
+ font-size: 1.5rem;
422
+ cursor: pointer;
423
+ color: rgba(250, 250, 250, 0.6);
424
+ line-height: 1;
425
+ `,
426
+ details: `
427
+ margin-bottom: 1.5rem;
428
+ padding: 1rem;
429
+ border-radius: 0.5rem;
430
+ border: 1px solid rgba(255, 255, 255, 0.1);
431
+ background: rgba(255, 255, 255, 0.02);
432
+ `,
433
+ row: `
434
+ display: flex;
435
+ justify-content: space-between;
436
+ margin-bottom: 0.75rem;
437
+ `,
438
+ rowLast: `
439
+ display: flex;
440
+ justify-content: space-between;
441
+ `,
442
+ label: `
443
+ font-family: monospace;
444
+ font-size: 0.75rem;
445
+ color: rgba(250, 250, 250, 0.6);
446
+ `,
447
+ value: `
448
+ font-size: 0.875rem;
449
+ color: #fafafa;
450
+ `,
451
+ valueAmount: `
452
+ font-size: 1.125rem;
453
+ font-weight: 500;
454
+ color: #fafafa;
455
+ `,
456
+ valueMono: `
457
+ font-family: monospace;
458
+ font-size: 0.875rem;
459
+ color: #fafafa;
460
+ `,
461
+ button: `
462
+ width: 100%;
463
+ padding: 0.75rem 1rem;
464
+ border-radius: 0.5rem;
465
+ border: 1px solid rgba(255, 255, 255, 0.1);
466
+ background: rgba(255, 255, 255, 0.05);
467
+ font-size: 0.875rem;
468
+ font-weight: 500;
469
+ cursor: pointer;
470
+ transition: background 0.2s;
471
+ color: #fafafa;
472
+ `,
473
+ buttonPrimary: `
474
+ flex: 1;
475
+ padding: 0.75rem 1rem;
476
+ border-radius: 0.5rem;
477
+ border: 1px solid rgba(255, 255, 255, 0.1);
478
+ background: rgba(255, 255, 255, 0.1);
479
+ font-size: 0.875rem;
480
+ font-weight: 500;
481
+ cursor: pointer;
482
+ color: #fafafa;
483
+ `,
484
+ buttonSecondary: `
485
+ flex: 1;
486
+ padding: 0.75rem 1rem;
487
+ border-radius: 0.5rem;
488
+ border: 1px solid rgba(255, 255, 255, 0.1);
489
+ background: rgba(255, 255, 255, 0.02);
490
+ font-size: 0.875rem;
491
+ cursor: pointer;
492
+ color: rgba(250, 250, 250, 0.8);
493
+ `,
494
+ walletBox: `
495
+ margin-bottom: 1rem;
496
+ padding: 0.75rem;
497
+ border-radius: 0.5rem;
498
+ border: 1px solid rgba(255, 255, 255, 0.1);
499
+ background: rgba(255, 255, 255, 0.02);
500
+ `,
501
+ walletLabel: `
502
+ margin: 0 0 0.25rem 0;
503
+ font-family: monospace;
504
+ font-size: 0.75rem;
505
+ color: rgba(250, 250, 250, 0.6);
506
+ `,
507
+ walletAddress: `
508
+ margin: 0;
509
+ font-family: monospace;
510
+ font-size: 0.875rem;
511
+ color: #fafafa;
512
+ `,
513
+ buttonGroup: `
514
+ display: flex;
515
+ gap: 0.75rem;
516
+ `
517
+ };
518
+ function formatAddress(address) {
519
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
520
+ }
521
+ async function createVanillaPaymentModal(request) {
522
+ return new Promise((resolve) => {
523
+ const overlay = document.createElement("div");
524
+ overlay.style.cssText = STYLES.overlay;
525
+ const modal = document.createElement("div");
526
+ modal.style.cssText = STYLES.modal;
527
+ let isProcessing = false;
528
+ const cleanup = () => {
529
+ if (document.body.contains(overlay)) {
530
+ document.body.removeChild(overlay);
531
+ }
532
+ };
533
+ const header = document.createElement("div");
534
+ header.style.cssText = STYLES.header;
535
+ const headerLeft = document.createElement("div");
536
+ headerLeft.style.cssText = "display: flex; align-items: center;";
537
+ const logo = document.createElement("div");
538
+ logo.style.cssText = STYLES.logo;
539
+ logo.textContent = "x402";
540
+ const title = document.createElement("h2");
541
+ title.style.cssText = STYLES.title;
542
+ title.textContent = "Payment Required";
543
+ headerLeft.appendChild(logo);
544
+ headerLeft.appendChild(title);
545
+ const closeBtn = document.createElement("button");
546
+ closeBtn.innerHTML = "×";
547
+ closeBtn.style.cssText = STYLES.closeBtn;
548
+ closeBtn.onclick = () => {
549
+ cleanup();
550
+ resolve(null);
551
+ };
552
+ header.appendChild(headerLeft);
553
+ header.appendChild(closeBtn);
554
+ const details = document.createElement("div");
555
+ details.style.cssText = STYLES.details;
556
+ const amountRow = document.createElement("div");
557
+ amountRow.style.cssText = STYLES.row;
558
+ amountRow.innerHTML = `
559
+ <span style="${STYLES.label}">Amount</span>
560
+ <span style="${STYLES.valueAmount}">${request.amount} ${request.token}</span>
561
+ `;
562
+ const networkRow = document.createElement("div");
563
+ networkRow.style.cssText = STYLES.row;
564
+ networkRow.innerHTML = `
565
+ <span style="${STYLES.label}">Network</span>
566
+ <span style="${STYLES.value}">${request.network}</span>
567
+ `;
568
+ const recipientRow = document.createElement("div");
569
+ recipientRow.style.cssText = STYLES.rowLast;
570
+ recipientRow.innerHTML = `
571
+ <span style="${STYLES.label}">Recipient</span>
572
+ <span style="${STYLES.valueMono}">${formatAddress(request.recipient)}</span>
573
+ `;
574
+ details.appendChild(amountRow);
575
+ details.appendChild(networkRow);
576
+ details.appendChild(recipientRow);
577
+ const content = document.createElement("div");
578
+ const connectBtn = document.createElement("button");
579
+ connectBtn.textContent = "Connect Wallet";
580
+ connectBtn.style.cssText = STYLES.button;
581
+ connectBtn.onmouseover = () => {
582
+ connectBtn.style.background = "rgba(255, 255, 255, 0.1)";
583
+ };
584
+ connectBtn.onmouseout = () => {
585
+ connectBtn.style.background = "rgba(255, 255, 255, 0.05)";
586
+ };
587
+ connectBtn.onclick = async () => {
588
+ try {
589
+ connectBtn.setAttribute("disabled", "true");
590
+ connectBtn.textContent = "Connecting...";
591
+ connectBtn.style.opacity = "0.7";
592
+ connectBtn.style.cursor = "not-allowed";
593
+ const wallet = detectWalletProvider();
594
+ if (!wallet) {
595
+ alert("No wallet found. Please install MetaMask.");
596
+ connectBtn.removeAttribute("disabled");
597
+ connectBtn.textContent = "Connect Wallet";
598
+ connectBtn.style.opacity = "1";
599
+ connectBtn.style.cursor = "pointer";
600
+ return;
601
+ }
602
+ const address = await connectWallet(wallet);
603
+ content.innerHTML = "";
604
+ const walletBox = document.createElement("div");
605
+ walletBox.style.cssText = STYLES.walletBox;
606
+ walletBox.innerHTML = `
607
+ <p style="${STYLES.walletLabel}">Connected Wallet</p>
608
+ <p style="${STYLES.walletAddress}">${formatAddress(address)}</p>
609
+ `;
610
+ const buttonGroup = document.createElement("div");
611
+ buttonGroup.style.cssText = STYLES.buttonGroup;
612
+ const cancelBtn = document.createElement("button");
613
+ cancelBtn.textContent = "Cancel";
614
+ cancelBtn.style.cssText = STYLES.buttonSecondary;
615
+ cancelBtn.onclick = () => {
616
+ cleanup();
617
+ resolve(null);
618
+ };
619
+ const payBtn = document.createElement("button");
620
+ payBtn.textContent = `Pay ${request.amount} ${request.token}`;
621
+ payBtn.style.cssText = STYLES.buttonPrimary;
622
+ payBtn.onclick = async () => {
623
+ if (isProcessing) return;
624
+ isProcessing = true;
625
+ payBtn.setAttribute("disabled", "true");
626
+ payBtn.textContent = "Processing...";
627
+ payBtn.style.opacity = "0.7";
628
+ payBtn.style.cursor = "not-allowed";
629
+ try {
630
+ const w = detectWalletProvider();
631
+ if (!w) throw new Error("Wallet not connected");
632
+ const payment = await processPayment(request, w);
633
+ cleanup();
634
+ resolve(payment);
635
+ } catch (error) {
636
+ alert(`Payment failed: ${error instanceof Error ? error.message : String(error)}`);
637
+ isProcessing = false;
638
+ payBtn.removeAttribute("disabled");
639
+ payBtn.textContent = `Pay ${request.amount} ${request.token}`;
640
+ payBtn.style.opacity = "1";
641
+ payBtn.style.cursor = "pointer";
642
+ }
643
+ };
644
+ buttonGroup.appendChild(cancelBtn);
645
+ buttonGroup.appendChild(payBtn);
646
+ content.appendChild(walletBox);
647
+ content.appendChild(buttonGroup);
648
+ } catch (error) {
649
+ alert(`Connection failed: ${error instanceof Error ? error.message : String(error)}`);
650
+ connectBtn.removeAttribute("disabled");
651
+ connectBtn.textContent = "Connect Wallet";
652
+ connectBtn.style.opacity = "1";
653
+ connectBtn.style.cursor = "pointer";
654
+ }
655
+ };
656
+ content.appendChild(connectBtn);
657
+ modal.appendChild(header);
658
+ modal.appendChild(details);
659
+ modal.appendChild(content);
660
+ overlay.appendChild(modal);
661
+ document.body.appendChild(overlay);
662
+ overlay.onclick = (e) => {
663
+ if (e.target === overlay) {
664
+ cleanup();
665
+ resolve(null);
666
+ }
667
+ };
668
+ const handleEscape = (e) => {
669
+ if (e.key === "Escape") {
670
+ cleanup();
671
+ resolve(null);
672
+ document.removeEventListener("keydown", handleEscape);
673
+ }
674
+ };
675
+ document.addEventListener("keydown", handleEscape);
676
+ });
677
+ }
678
+
679
+ // src/client/modal.ts
680
+ async function createPaymentModal(request) {
681
+ if (typeof window === "undefined") {
682
+ return null;
683
+ }
684
+ return createVanillaPaymentModal(request);
685
+ }
686
+
687
+ // src/client/client.ts
688
+ function parse402Response(response) {
689
+ if (response.status !== 402) {
690
+ return null;
691
+ }
692
+ const amount = response.headers.get("X-402-Amount") || response.headers.get("x-402-amount");
693
+ const token = response.headers.get("X-402-Token") || response.headers.get("x-402-token");
694
+ const network = response.headers.get("X-402-Network") || response.headers.get("x-402-network");
695
+ const recipient = response.headers.get("X-402-Recipient") || response.headers.get("x-402-recipient");
696
+ if (!amount || !token || !network || !recipient) {
697
+ return null;
698
+ }
699
+ return { amount, token, network, recipient };
700
+ }
701
+ function addPaymentHeaders(headers, payment) {
702
+ const newHeaders = new Headers(headers);
703
+ newHeaders.set("X-402-Transaction-Hash", payment.transactionHash);
704
+ if (payment.timestamp) {
705
+ newHeaders.set("X-402-Timestamp", payment.timestamp);
706
+ }
707
+ return newHeaders;
708
+ }
709
+ var X402Client = class {
710
+ constructor(options = {}) {
711
+ this.wallet = null;
712
+ this.options = {
713
+ autoRetry: true,
714
+ ...options
715
+ };
716
+ }
717
+ /**
718
+ * Initialize wallet connection
719
+ */
720
+ async initialize() {
721
+ if (this.options.walletProvider) {
722
+ this.wallet = this.options.walletProvider;
723
+ } else {
724
+ this.wallet = detectWalletProvider();
725
+ }
726
+ }
727
+ /**
728
+ * Fetch with automatic 402 handling
729
+ */
730
+ async fetch(input, init) {
731
+ const response = await globalThis.fetch(input, init);
732
+ const paymentRequest = parse402Response(response);
733
+ if (!paymentRequest) {
734
+ return response;
735
+ }
736
+ let payment = null;
737
+ if (this.options.paymentModal) {
738
+ payment = await this.options.paymentModal(paymentRequest);
739
+ } else {
740
+ payment = await createPaymentModal(paymentRequest);
741
+ }
742
+ if (!payment) {
743
+ return response;
744
+ }
745
+ if (this.options.autoRetry !== false) {
746
+ const newHeaders = addPaymentHeaders(init?.headers || {}, payment);
747
+ return globalThis.fetch(input, {
748
+ ...init,
749
+ headers: newHeaders
750
+ });
751
+ }
752
+ return new Response(JSON.stringify(payment), {
753
+ status: 200,
754
+ headers: { "Content-Type": "application/json" }
755
+ });
756
+ }
757
+ };
758
+ function x402Client(options) {
759
+ return new X402Client(options);
760
+ }
761
+ async function x402Fetch(input, init, options) {
762
+ const client = x402Client(options);
763
+ await client.initialize();
764
+ return client.fetch(input, init);
765
+ }
766
+ export {
767
+ MetaMaskProvider,
768
+ NETWORKS,
769
+ PLATFORM_FEE_BPS,
770
+ TOKENS,
771
+ TREASURY_ADDRESS,
772
+ TREASURY_ADMIN,
773
+ X402Client,
774
+ connectWallet,
775
+ createPaymentModal,
776
+ createVanillaPaymentModal,
777
+ detectWalletProvider,
778
+ ensureNetwork,
779
+ getAddNetworkParams,
780
+ getAvailableNetworks,
781
+ getChainId,
782
+ getNetworkConfig,
783
+ getNetworksByEnvironment,
784
+ getTokenConfig,
785
+ isMainnet,
786
+ isTestnet,
787
+ processPayment,
788
+ registerCustomNetwork,
789
+ registerCustomTokens,
790
+ x402Client,
791
+ x402Fetch
792
+ };
793
+ //# sourceMappingURL=index.js.map