@voyage_ai/v402-web-ts 0.1.2 → 0.1.3

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.
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,63 +30,75 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/react/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- WalletConnect: () => WalletConnect,
34
- usePayment: () => usePayment,
35
- usePaymentInfo: () => usePaymentInfo,
36
- useWallet: () => useWallet
37
- });
38
- module.exports = __toCommonJS(index_exports);
39
-
40
- // src/react/hooks/useWalletStore.ts
41
- var import_react = require("react");
42
-
43
- // src/types/index.ts
44
- var import_types3 = require("x402/types");
45
-
46
33
  // src/types/common.ts
47
- var PROD_BACK_URL = "https://v402.onvoyage.ai/api/pay";
34
+ var PROD_BACK_URL, DEV_BACK_URL;
35
+ var init_common = __esm({
36
+ "src/types/common.ts"() {
37
+ "use strict";
38
+ PROD_BACK_URL = "https://v402.onvoyage.ai/api/pay";
39
+ DEV_BACK_URL = "http://localhost:3000/api/pay";
40
+ }
41
+ });
48
42
 
49
43
  // src/types/svm.ts
50
- var import_zod = require("zod");
51
- var import_types = require("x402/types");
52
- var SolanaNetworkSchema = import_zod.z.enum([
53
- "solana-devnet",
54
- "solana",
55
- "solana-mainnet"
56
- // Alias for mainnet
57
- ]);
58
- var SolanaPaymentPayloadSchema = import_zod.z.object({
59
- x402Version: import_zod.z.literal(1),
60
- scheme: import_zod.z.literal("exact"),
61
- network: SolanaNetworkSchema,
62
- payload: import_types.ExactSvmPayloadSchema
44
+ var import_zod, import_types, SolanaNetworkSchema, SolanaPaymentPayloadSchema;
45
+ var init_svm = __esm({
46
+ "src/types/svm.ts"() {
47
+ "use strict";
48
+ import_zod = require("zod");
49
+ import_types = require("x402/types");
50
+ SolanaNetworkSchema = import_zod.z.enum([
51
+ "solana-devnet",
52
+ "solana",
53
+ "solana-mainnet"
54
+ // Alias for mainnet
55
+ ]);
56
+ SolanaPaymentPayloadSchema = import_zod.z.object({
57
+ x402Version: import_zod.z.literal(1),
58
+ scheme: import_zod.z.literal("exact"),
59
+ network: SolanaNetworkSchema,
60
+ payload: import_types.ExactSvmPayloadSchema
61
+ });
62
+ }
63
63
  });
64
64
 
65
65
  // src/types/evm.ts
66
- var import_zod2 = require("zod");
67
- var import_types2 = require("x402/types");
68
- var EvmNetworkSchema = import_zod2.z.enum([
69
- "ethereum",
70
- "sepolia",
71
- "base",
72
- "base-sepolia",
73
- "polygon",
74
- "arbitrum",
75
- "optimism"
76
- ]);
77
- var EvmPaymentPayloadSchema = import_zod2.z.object({
78
- x402Version: import_zod2.z.literal(1),
79
- scheme: import_zod2.z.literal("exact"),
80
- network: EvmNetworkSchema,
81
- payload: import_types2.ExactEvmPayloadSchema
66
+ var import_zod2, import_types2, EvmNetworkSchema, EvmPaymentPayloadSchema;
67
+ var init_evm = __esm({
68
+ "src/types/evm.ts"() {
69
+ "use strict";
70
+ import_zod2 = require("zod");
71
+ import_types2 = require("x402/types");
72
+ EvmNetworkSchema = import_zod2.z.enum([
73
+ "ethereum",
74
+ "sepolia",
75
+ "base",
76
+ "base-sepolia",
77
+ "polygon",
78
+ "arbitrum",
79
+ "optimism"
80
+ ]);
81
+ EvmPaymentPayloadSchema = import_zod2.z.object({
82
+ x402Version: import_zod2.z.literal(1),
83
+ scheme: import_zod2.z.literal("exact"),
84
+ network: EvmNetworkSchema,
85
+ payload: import_types2.ExactEvmPayloadSchema
86
+ });
87
+ }
88
+ });
89
+
90
+ // src/types/index.ts
91
+ var import_types3;
92
+ var init_types = __esm({
93
+ "src/types/index.ts"() {
94
+ "use strict";
95
+ import_types3 = require("x402/types");
96
+ init_svm();
97
+ init_evm();
98
+ }
82
99
  });
83
100
 
84
101
  // src/utils/wallet.ts
85
- var WALLET_DISCONNECTED_KEY = "wallet_manually_disconnected";
86
- var CONNECTED_NETWORK_TYPE_KEY = "connected_network_type";
87
102
  function isWalletInstalled(networkType) {
88
103
  if (typeof window === "undefined") {
89
104
  return false;
@@ -104,22 +119,50 @@ function formatAddress(address) {
104
119
  }
105
120
  return `${address.slice(0, 6)}...${address.slice(-4)}`;
106
121
  }
107
- function markWalletDisconnected() {
122
+ function getDisconnectedNetworks() {
123
+ if (typeof window === "undefined") {
124
+ return {};
125
+ }
126
+ try {
127
+ const cached = localStorage.getItem(WALLET_DISCONNECTED_NETWORKS_KEY);
128
+ return cached ? JSON.parse(cached) : {};
129
+ } catch (error) {
130
+ return {};
131
+ }
132
+ }
133
+ function markWalletDisconnected(networkType) {
108
134
  if (typeof window !== "undefined") {
109
- localStorage.setItem(WALLET_DISCONNECTED_KEY, "true");
110
- localStorage.removeItem(CONNECTED_NETWORK_TYPE_KEY);
135
+ if (networkType) {
136
+ const disconnected = getDisconnectedNetworks();
137
+ disconnected[networkType] = true;
138
+ localStorage.setItem(WALLET_DISCONNECTED_NETWORKS_KEY, JSON.stringify(disconnected));
139
+ } else {
140
+ localStorage.setItem(WALLET_DISCONNECTED_KEY, "true");
141
+ localStorage.removeItem(CONNECTED_NETWORK_TYPE_KEY);
142
+ }
111
143
  }
112
144
  }
113
- function clearWalletDisconnection() {
145
+ function clearWalletDisconnection(networkType) {
114
146
  if (typeof window !== "undefined") {
115
- localStorage.removeItem(WALLET_DISCONNECTED_KEY);
147
+ if (networkType) {
148
+ const disconnected = getDisconnectedNetworks();
149
+ delete disconnected[networkType];
150
+ localStorage.setItem(WALLET_DISCONNECTED_NETWORKS_KEY, JSON.stringify(disconnected));
151
+ } else {
152
+ localStorage.removeItem(WALLET_DISCONNECTED_KEY);
153
+ }
116
154
  }
117
155
  }
118
- function isWalletManuallyDisconnected() {
156
+ function isWalletManuallyDisconnected(networkType) {
119
157
  if (typeof window === "undefined") {
120
158
  return false;
121
159
  }
122
- return localStorage.getItem(WALLET_DISCONNECTED_KEY) === "true";
160
+ if (networkType) {
161
+ const disconnected = getDisconnectedNetworks();
162
+ return disconnected[networkType] === true;
163
+ } else {
164
+ return localStorage.getItem(WALLET_DISCONNECTED_KEY) === "true";
165
+ }
123
166
  }
124
167
  function saveConnectedNetworkType(networkType) {
125
168
  if (typeof window !== "undefined") {
@@ -144,8 +187,70 @@ function getWalletInstallUrl(networkType) {
144
187
  return "#";
145
188
  }
146
189
  }
190
+ function getAllWalletAddresses() {
191
+ if (typeof window === "undefined") {
192
+ return {};
193
+ }
194
+ try {
195
+ const cached = localStorage.getItem(WALLET_ADDRESSES_KEY);
196
+ return cached ? JSON.parse(cached) : {};
197
+ } catch (error) {
198
+ console.error("Failed to parse wallet addresses cache:", error);
199
+ return {};
200
+ }
201
+ }
202
+ function saveWalletAddress(networkType, address) {
203
+ if (typeof window === "undefined") {
204
+ return;
205
+ }
206
+ const addresses = getAllWalletAddresses();
207
+ addresses[networkType] = address;
208
+ localStorage.setItem(WALLET_ADDRESSES_KEY, JSON.stringify(addresses));
209
+ }
210
+ function getCachedWalletAddress(networkType) {
211
+ const addresses = getAllWalletAddresses();
212
+ return addresses[networkType] || null;
213
+ }
214
+ function removeWalletAddress(networkType) {
215
+ if (typeof window === "undefined") {
216
+ return;
217
+ }
218
+ const addresses = getAllWalletAddresses();
219
+ delete addresses[networkType];
220
+ localStorage.setItem(WALLET_ADDRESSES_KEY, JSON.stringify(addresses));
221
+ }
222
+ var WALLET_DISCONNECTED_KEY, WALLET_DISCONNECTED_NETWORKS_KEY, CONNECTED_NETWORK_TYPE_KEY, WALLET_ADDRESSES_KEY;
223
+ var init_wallet = __esm({
224
+ "src/utils/wallet.ts"() {
225
+ "use strict";
226
+ WALLET_DISCONNECTED_KEY = "wallet_manually_disconnected";
227
+ WALLET_DISCONNECTED_NETWORKS_KEY = "wallet_disconnected_networks";
228
+ CONNECTED_NETWORK_TYPE_KEY = "connected_network_type";
229
+ WALLET_ADDRESSES_KEY = "wallet_addresses_cache";
230
+ }
231
+ });
232
+
233
+ // src/react/index.ts
234
+ var index_exports = {};
235
+ __export(index_exports, {
236
+ V402Checkout: () => V402Checkout,
237
+ WalletConnect: () => WalletConnect,
238
+ usePageNetwork: () => usePageNetwork,
239
+ usePayment: () => usePayment,
240
+ usePaymentInfo: () => usePaymentInfo,
241
+ useWallet: () => useWallet
242
+ });
243
+ module.exports = __toCommonJS(index_exports);
244
+ var import_styles = require("./styles.css");
245
+
246
+ // src/react/hooks/useWalletStore.ts
247
+ var import_react = require("react");
248
+
249
+ // src/utils/index.ts
250
+ init_wallet();
147
251
 
148
252
  // src/utils/wallet-connect.ts
253
+ init_wallet();
149
254
  async function connectWallet(networkType) {
150
255
  if (typeof window === "undefined") {
151
256
  throw new Error("\u8BF7\u5728\u6D4F\u89C8\u5668\u73AF\u5883\u4E2D\u4F7F\u7528");
@@ -180,13 +285,11 @@ async function connectWallet(networkType) {
180
285
  default:
181
286
  throw new Error("\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B");
182
287
  }
183
- clearWalletDisconnection();
288
+ clearWalletDisconnection(networkType);
184
289
  saveConnectedNetworkType(networkType);
290
+ saveWalletAddress(networkType, address);
185
291
  return address;
186
292
  }
187
- function disconnectWallet() {
188
- markWalletDisconnected();
189
- }
190
293
  async function getCurrentWallet(networkType) {
191
294
  if (typeof window === "undefined") {
192
295
  return null;
@@ -195,28 +298,36 @@ async function getCurrentWallet(networkType) {
195
298
  if (!type) {
196
299
  return null;
197
300
  }
301
+ const cachedAddress = getCachedWalletAddress(type);
198
302
  try {
303
+ let currentAddress = null;
199
304
  switch (type) {
200
305
  case "evm" /* EVM */: {
201
- if (!window.ethereum) return null;
306
+ if (!window.ethereum) return cachedAddress;
202
307
  const accounts = await window.ethereum.request({
203
308
  method: "eth_accounts",
204
309
  params: []
205
310
  });
206
- return accounts && accounts.length > 0 ? accounts[0] : null;
311
+ currentAddress = accounts && accounts.length > 0 ? accounts[0] : null;
312
+ break;
207
313
  }
208
314
  case "solana" /* SOLANA */:
209
315
  case "svm" /* SVM */: {
210
316
  const solana = window.solana;
211
- if (!solana || !solana.isConnected) return null;
212
- return solana.publicKey?.toString() || null;
317
+ if (!solana || !solana.isConnected) return cachedAddress;
318
+ currentAddress = solana.publicKey?.toString() || null;
319
+ break;
213
320
  }
214
321
  default:
215
- return null;
322
+ return cachedAddress;
323
+ }
324
+ if (currentAddress && currentAddress !== cachedAddress) {
325
+ saveWalletAddress(type, currentAddress);
216
326
  }
327
+ return currentAddress || cachedAddress;
217
328
  } catch (error) {
218
329
  console.error("Failed to get current wallet:", error);
219
- return null;
330
+ return cachedAddress;
220
331
  }
221
332
  }
222
333
  function onAccountsChanged(callback) {
@@ -267,16 +378,534 @@ function onWalletDisconnect(callback) {
267
378
  solana.removeListener?.("disconnect", handler);
268
379
  };
269
380
  }
381
+ async function switchNetwork(networkType) {
382
+ const cachedAddress = getCachedWalletAddress(networkType);
383
+ if (cachedAddress) {
384
+ saveConnectedNetworkType(networkType);
385
+ clearWalletDisconnection(networkType);
386
+ const currentAddress = await getCurrentWallet(networkType);
387
+ if (currentAddress) {
388
+ return currentAddress;
389
+ }
390
+ }
391
+ return null;
392
+ }
270
393
 
271
394
  // src/services/svm/payment-header.ts
272
395
  var import_web3 = require("@solana/web3.js");
273
396
  var import_spl_token = require("@solana/spl-token");
397
+ async function createSvmPaymentHeader(params) {
398
+ const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
399
+ const connection = new import_web3.Connection(rpcUrl, "confirmed");
400
+ const feePayer = paymentRequirements?.extra?.feePayer;
401
+ if (typeof feePayer !== "string" || !feePayer) {
402
+ throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
403
+ }
404
+ const feePayerPubkey = new import_web3.PublicKey(feePayer);
405
+ const walletAddress = wallet?.publicKey?.toString() || wallet?.address;
406
+ if (!walletAddress) {
407
+ throw new Error("Missing connected Solana wallet address or publicKey");
408
+ }
409
+ const userPubkey = new import_web3.PublicKey(walletAddress);
410
+ if (!paymentRequirements?.payTo) {
411
+ throw new Error("Missing payTo in payment requirements");
412
+ }
413
+ const destination = new import_web3.PublicKey(paymentRequirements.payTo);
414
+ const instructions = [];
415
+ instructions.push(
416
+ import_web3.ComputeBudgetProgram.setComputeUnitLimit({
417
+ units: 7e3
418
+ // Sufficient for SPL token transfer
419
+ })
420
+ );
421
+ instructions.push(
422
+ import_web3.ComputeBudgetProgram.setComputeUnitPrice({
423
+ microLamports: 1
424
+ // Minimal price
425
+ })
426
+ );
427
+ if (!paymentRequirements.asset) {
428
+ throw new Error("Missing token mint for SPL transfer");
429
+ }
430
+ const mintPubkey = new import_web3.PublicKey(paymentRequirements.asset);
431
+ const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
432
+ const programId = mintInfo?.owner?.toBase58() === import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58() ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
433
+ const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
434
+ const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
435
+ mintPubkey,
436
+ userPubkey,
437
+ false,
438
+ programId
439
+ );
440
+ const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
441
+ mintPubkey,
442
+ destination,
443
+ false,
444
+ programId
445
+ );
446
+ const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
447
+ if (!sourceAtaInfo) {
448
+ throw new Error(
449
+ `User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
450
+ );
451
+ }
452
+ const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
453
+ if (!destAtaInfo) {
454
+ throw new Error(
455
+ `Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
456
+ );
457
+ }
458
+ const amount = BigInt(paymentRequirements.maxAmountRequired);
459
+ instructions.push(
460
+ (0, import_spl_token.createTransferCheckedInstruction)(
461
+ sourceAta,
462
+ mintPubkey,
463
+ destinationAta,
464
+ userPubkey,
465
+ amount,
466
+ mint.decimals,
467
+ [],
468
+ programId
469
+ )
470
+ );
471
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
472
+ const message2 = new import_web3.TransactionMessage({
473
+ payerKey: feePayerPubkey,
474
+ recentBlockhash: blockhash,
475
+ instructions
476
+ }).compileToV0Message();
477
+ const transaction = new import_web3.VersionedTransaction(message2);
478
+ if (typeof wallet?.signTransaction !== "function") {
479
+ throw new Error("Connected wallet does not support signTransaction");
480
+ }
481
+ let userSignedTx;
482
+ try {
483
+ userSignedTx = await wallet.signTransaction(transaction);
484
+ console.log("\u2705 Transaction signed successfully");
485
+ } catch (error) {
486
+ console.error("\u274C Failed to sign transaction:", error);
487
+ throw wrapPaymentError(error);
488
+ }
489
+ const serializedTransaction = Buffer.from(userSignedTx.serialize()).toString("base64");
490
+ const paymentPayload = {
491
+ x402Version,
492
+ scheme: paymentRequirements.scheme,
493
+ network: paymentRequirements.network,
494
+ payload: {
495
+ transaction: serializedTransaction
496
+ }
497
+ };
498
+ const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
499
+ return paymentHeader;
500
+ }
501
+ function getDefaultSolanaRpcUrl(network) {
502
+ const normalized = network.toLowerCase();
503
+ if (normalized === "solana" || normalized === "solana-mainnet") {
504
+ return "https://cathee-fu8ezd-fast-mainnet.helius-rpc.com";
505
+ } else if (normalized === "solana-devnet") {
506
+ return "https://api.devnet.solana.com";
507
+ }
508
+ throw new Error(`Unsupported Solana network: ${network}`);
509
+ }
510
+
511
+ // src/services/svm/payment-handler.ts
512
+ init_types();
513
+ async function handleSvmPayment(endpoint, config, requestInit) {
514
+ const { wallet, network, rpcUrl, maxPaymentAmount } = config;
515
+ const initialResponse = await fetch(endpoint, {
516
+ ...requestInit,
517
+ method: requestInit?.method || "POST"
518
+ });
519
+ if (initialResponse.status !== 402) {
520
+ return initialResponse;
521
+ }
522
+ const rawResponse = await initialResponse.json();
523
+ const IGNORED_ERRORS = [
524
+ "X-PAYMENT header is required",
525
+ "missing X-PAYMENT header",
526
+ "payment_required"
527
+ ];
528
+ if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
529
+ console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
530
+ const ERROR_MESSAGES = {
531
+ "insufficient_funds": "Insufficient balance to complete this payment",
532
+ "invalid_signature": "Invalid payment signature",
533
+ "expired": "Payment authorization has expired",
534
+ "already_used": "This payment has already been used",
535
+ "network_mismatch": "Payment network does not match",
536
+ "invalid_payment": "Invalid payment data",
537
+ "verification_failed": "Payment verification failed",
538
+ "invalid_exact_svm_payload_transaction_simulation_failed": "Transaction simulation failed due to insufficient balance. Please check your wallet balance carefully and ensure you have enough funds to cover the payment and transaction fees."
539
+ };
540
+ const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
541
+ const error = new Error(errorMessage);
542
+ throw wrapPaymentError(error);
543
+ }
544
+ const x402Version = rawResponse.x402Version;
545
+ const parsedPaymentRequirements = rawResponse.accepts || [];
546
+ const selectedRequirements = parsedPaymentRequirements.find(
547
+ (req) => req.scheme === "exact" && SolanaNetworkSchema.safeParse(req.network.toLowerCase()).success
548
+ );
549
+ if (!selectedRequirements) {
550
+ console.error(
551
+ "\u274C No suitable Solana payment requirements found. Available networks:",
552
+ parsedPaymentRequirements.map((req) => req.network)
553
+ );
554
+ throw new Error("No suitable Solana payment requirements found");
555
+ }
556
+ if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
557
+ if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
558
+ throw new Error(
559
+ `Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
560
+ );
561
+ }
562
+ }
563
+ const effectiveRpcUrl = rpcUrl || getDefaultSolanaRpcUrl(selectedRequirements.network);
564
+ console.log(`\u{1F4CD} Using Solana RPC: ${effectiveRpcUrl.substring(0, 40)}...`);
565
+ console.log(`\u{1F4CD} Network from backend: ${selectedRequirements.network}`);
566
+ let paymentHeader;
567
+ try {
568
+ paymentHeader = await createSvmPaymentHeader({
569
+ wallet,
570
+ paymentRequirements: selectedRequirements,
571
+ x402Version,
572
+ rpcUrl: effectiveRpcUrl
573
+ });
574
+ console.log("\u2705 Payment header created successfully");
575
+ } catch (error) {
576
+ console.error("\u274C Failed to create payment header:", error);
577
+ throw wrapPaymentError(error);
578
+ }
579
+ const newInit = {
580
+ ...requestInit,
581
+ method: requestInit?.method || "POST",
582
+ headers: {
583
+ ...requestInit?.headers || {},
584
+ "X-PAYMENT": paymentHeader,
585
+ "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
586
+ }
587
+ };
588
+ const retryResponse = await fetch(endpoint, newInit);
589
+ if (retryResponse.status === 402) {
590
+ try {
591
+ const retryData = await retryResponse.json();
592
+ const IGNORED_ERRORS2 = [
593
+ "X-PAYMENT header is required",
594
+ "missing X-PAYMENT header",
595
+ "payment_required"
596
+ ];
597
+ if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
598
+ console.error(`\u274C Payment verification failed: ${retryData.error}`);
599
+ const ERROR_MESSAGES = {
600
+ "insufficient_funds": "Insufficient balance to complete this payment",
601
+ "invalid_signature": "Invalid payment signature",
602
+ "expired": "Payment authorization has expired",
603
+ "already_used": "This payment has already been used",
604
+ "network_mismatch": "Payment network does not match",
605
+ "invalid_payment": "Invalid payment data",
606
+ "verification_failed": "Payment verification failed",
607
+ "invalid_exact_svm_payload_transaction_simulation_failed": "Transaction simulation failed due to insufficient balance. Please check your wallet balance carefully and ensure you have enough funds to cover the payment and transaction fees."
608
+ };
609
+ const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
610
+ const error = new Error(errorMessage);
611
+ throw wrapPaymentError(error);
612
+ }
613
+ } catch (error) {
614
+ if (error instanceof PaymentOperationError) {
615
+ throw error;
616
+ }
617
+ console.warn("\u26A0\uFE0F Could not parse retry 402 response:", error);
618
+ }
619
+ }
620
+ return retryResponse;
621
+ }
274
622
 
275
623
  // src/services/evm/payment-header.ts
276
624
  var import_ethers = require("ethers");
625
+ async function createEvmPaymentHeader(params) {
626
+ const { wallet, paymentRequirements, x402Version, chainId } = params;
627
+ if (!paymentRequirements?.payTo) {
628
+ throw new Error("Missing payTo in payment requirements");
629
+ }
630
+ if (!paymentRequirements?.asset) {
631
+ throw new Error("Missing asset (token contract) in payment requirements");
632
+ }
633
+ if (wallet.getChainId) {
634
+ try {
635
+ const currentChainIdHex = await wallet.getChainId();
636
+ const currentChainId = parseInt(currentChainIdHex, 16);
637
+ if (currentChainId !== chainId) {
638
+ const networkNames = {
639
+ 1: "Ethereum Mainnet",
640
+ 11155111: "Sepolia Testnet",
641
+ 8453: "Base Mainnet",
642
+ 84532: "Base Sepolia Testnet",
643
+ 137: "Polygon Mainnet",
644
+ 42161: "Arbitrum One",
645
+ 10: "Optimism Mainnet"
646
+ };
647
+ const currentNetworkName = networkNames[currentChainId] || `Chain ${currentChainId}`;
648
+ const targetNetworkName = networkNames[chainId] || `Chain ${chainId}`;
649
+ throw new Error(
650
+ `Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch your wallet to the correct network.`
651
+ );
652
+ }
653
+ console.log(`\u2705 Chain ID verified: ${chainId}`);
654
+ } catch (error) {
655
+ if (error.message.includes("Network mismatch")) {
656
+ throw wrapPaymentError(error);
657
+ }
658
+ console.warn("Could not verify chainId:", error);
659
+ }
660
+ }
661
+ const now = Math.floor(Date.now() / 1e3);
662
+ const nonceBytes = import_ethers.ethers.randomBytes(32);
663
+ const nonceBytes32 = import_ethers.ethers.hexlify(nonceBytes);
664
+ const domain = {
665
+ name: paymentRequirements.extra?.name || "USDC",
666
+ version: paymentRequirements.extra?.version || "2",
667
+ chainId,
668
+ verifyingContract: paymentRequirements.asset
669
+ };
670
+ const types = {
671
+ TransferWithAuthorization: [
672
+ { name: "from", type: "address" },
673
+ { name: "to", type: "address" },
674
+ { name: "value", type: "uint256" },
675
+ { name: "validAfter", type: "uint256" },
676
+ { name: "validBefore", type: "uint256" },
677
+ { name: "nonce", type: "bytes32" }
678
+ ]
679
+ };
680
+ const authorization = {
681
+ from: wallet.address,
682
+ to: paymentRequirements.payTo,
683
+ value: paymentRequirements.maxAmountRequired,
684
+ validAfter: "0",
685
+ // Effective immediately
686
+ validBefore: String(now + (paymentRequirements.maxTimeoutSeconds || 3600)),
687
+ nonce: nonceBytes32
688
+ };
689
+ let signature;
690
+ try {
691
+ signature = await wallet.signTypedData(domain, types, authorization);
692
+ console.log("\u2705 Signature created successfully");
693
+ } catch (error) {
694
+ console.error("\u274C Failed to create signature:", error);
695
+ throw wrapPaymentError(error);
696
+ }
697
+ const headerPayload = {
698
+ x402_version: x402Version,
699
+ x402Version,
700
+ scheme: paymentRequirements.scheme,
701
+ network: paymentRequirements.network,
702
+ payload: {
703
+ signature,
704
+ authorization: {
705
+ from: authorization.from,
706
+ to: authorization.to,
707
+ value: String(authorization.value),
708
+ valid_after: authorization.validAfter,
709
+ validAfter: authorization.validAfter,
710
+ valid_before: authorization.validBefore,
711
+ validBefore: authorization.validBefore,
712
+ nonce: authorization.nonce
713
+ }
714
+ }
715
+ };
716
+ const paymentHeader = btoa(JSON.stringify(headerPayload));
717
+ return paymentHeader;
718
+ }
719
+ function getChainIdFromNetwork(network) {
720
+ const chainIdMap = {
721
+ "ethereum": 1,
722
+ "sepolia": 11155111,
723
+ "base": 8453,
724
+ "base-sepolia": 84532,
725
+ "polygon": 137,
726
+ "arbitrum": 42161,
727
+ "optimism": 10
728
+ };
729
+ const chainId = chainIdMap[network.toLowerCase()];
730
+ if (!chainId) {
731
+ throw new Error(`Unknown network: ${network}`);
732
+ }
733
+ return chainId;
734
+ }
735
+
736
+ // src/services/evm/payment-handler.ts
737
+ init_types();
738
+ async function handleEvmPayment(endpoint, config, requestInit) {
739
+ const { wallet, network, maxPaymentAmount } = config;
740
+ const initialResponse = await fetch(endpoint, {
741
+ ...requestInit,
742
+ method: requestInit?.method || "POST"
743
+ });
744
+ if (initialResponse.status !== 402) {
745
+ return initialResponse;
746
+ }
747
+ const rawResponse = await initialResponse.json();
748
+ const IGNORED_ERRORS = [
749
+ "X-PAYMENT header is required",
750
+ "missing X-PAYMENT header",
751
+ "payment_required"
752
+ ];
753
+ if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
754
+ console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
755
+ const ERROR_MESSAGES = {
756
+ "insufficient_funds": "Insufficient balance to complete this payment",
757
+ "invalid_signature": "Invalid payment signature",
758
+ "expired": "Payment authorization has expired",
759
+ "already_used": "This payment has already been used",
760
+ "network_mismatch": "Payment network does not match",
761
+ "invalid_payment": "Invalid payment data",
762
+ "verification_failed": "Payment verification failed"
763
+ };
764
+ const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
765
+ const error = new Error(errorMessage);
766
+ throw wrapPaymentError(error);
767
+ }
768
+ const x402Version = rawResponse.x402Version;
769
+ const parsedPaymentRequirements = rawResponse.accepts || [];
770
+ const selectedRequirements = parsedPaymentRequirements.find(
771
+ (req) => req.scheme === "exact" && EvmNetworkSchema.safeParse(req.network.toLowerCase()).success
772
+ );
773
+ if (!selectedRequirements) {
774
+ console.error(
775
+ "\u274C No suitable EVM payment requirements found. Available networks:",
776
+ parsedPaymentRequirements.map((req) => req.network)
777
+ );
778
+ throw new Error("No suitable EVM payment requirements found");
779
+ }
780
+ if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
781
+ if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
782
+ throw new Error(
783
+ `Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
784
+ );
785
+ }
786
+ }
787
+ const targetChainId = getChainIdFromNetwork(selectedRequirements.network);
788
+ let currentChainId;
789
+ if (wallet.getChainId) {
790
+ try {
791
+ const chainIdHex = await wallet.getChainId();
792
+ currentChainId = parseInt(chainIdHex, 16);
793
+ console.log(`\u{1F4CD} Current wallet chain: ${currentChainId}`);
794
+ } catch (error) {
795
+ console.warn("\u26A0\uFE0F Failed to get current chainId:", error);
796
+ }
797
+ }
798
+ const networkNames = {
799
+ 1: "Ethereum Mainnet",
800
+ 11155111: "Sepolia Testnet",
801
+ 8453: "Base Mainnet",
802
+ 84532: "Base Sepolia Testnet",
803
+ 137: "Polygon Mainnet",
804
+ 42161: "Arbitrum One",
805
+ 10: "Optimism Mainnet"
806
+ };
807
+ if (currentChainId && currentChainId !== targetChainId) {
808
+ if (!wallet.switchChain) {
809
+ const currentNetworkName = networkNames[currentChainId] || `Chain ${currentChainId}`;
810
+ const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
811
+ const error = new Error(
812
+ `Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch to ${targetNetworkName} manually in your wallet.`
813
+ );
814
+ throw wrapPaymentError(error);
815
+ }
816
+ try {
817
+ console.log(`\u{1F504} Switching to chain ${targetChainId}...`);
818
+ await wallet.switchChain(`0x${targetChainId.toString(16)}`);
819
+ console.log(`\u2705 Successfully switched to chain ${targetChainId}`);
820
+ } catch (error) {
821
+ console.error("\u274C Failed to switch chain:", error);
822
+ const targetNetworkName = networkNames[targetChainId] || selectedRequirements.network;
823
+ const wrappedError = wrapPaymentError(error);
824
+ let finalError;
825
+ if (wrappedError.code === "USER_REJECTED" /* USER_REJECTED */) {
826
+ finalError = new PaymentOperationError({
827
+ code: wrappedError.code,
828
+ message: wrappedError.message,
829
+ userMessage: `You rejected the network switch request. Please switch to ${targetNetworkName} manually.`,
830
+ originalError: wrappedError.originalError
831
+ });
832
+ } else {
833
+ finalError = new PaymentOperationError({
834
+ code: "NETWORK_SWITCH_FAILED" /* NETWORK_SWITCH_FAILED */,
835
+ message: wrappedError.message,
836
+ userMessage: `Failed to switch to ${targetNetworkName}. Please switch manually in your wallet.`,
837
+ originalError: wrappedError.originalError
838
+ });
839
+ }
840
+ throw finalError;
841
+ }
842
+ } else if (wallet.switchChain && !currentChainId) {
843
+ try {
844
+ console.log(`\u{1F504} Attempting to switch to chain ${targetChainId}...`);
845
+ await wallet.switchChain(`0x${targetChainId.toString(16)}`);
846
+ console.log(`\u2705 Switch attempted successfully`);
847
+ } catch (error) {
848
+ console.warn("\u26A0\uFE0F Failed to switch chain (best effort):", error);
849
+ }
850
+ }
851
+ let paymentHeader;
852
+ try {
853
+ paymentHeader = await createEvmPaymentHeader({
854
+ wallet,
855
+ paymentRequirements: selectedRequirements,
856
+ x402Version,
857
+ chainId: targetChainId
858
+ });
859
+ } catch (error) {
860
+ console.error("\u274C Failed to create payment header:", error);
861
+ throw wrapPaymentError(error);
862
+ }
863
+ const newInit = {
864
+ ...requestInit,
865
+ method: requestInit?.method || "POST",
866
+ headers: {
867
+ ...requestInit?.headers || {},
868
+ "X-PAYMENT": paymentHeader,
869
+ "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
870
+ }
871
+ };
872
+ const retryResponse = await fetch(endpoint, newInit);
873
+ if (retryResponse.status === 402) {
874
+ try {
875
+ const retryData = await retryResponse.json();
876
+ const IGNORED_ERRORS2 = [
877
+ "X-PAYMENT header is required",
878
+ "missing X-PAYMENT header",
879
+ "payment_required"
880
+ ];
881
+ if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
882
+ console.error(`\u274C Payment verification failed: ${retryData.error}`);
883
+ const ERROR_MESSAGES = {
884
+ "insufficient_funds": "Insufficient balance to complete this payment",
885
+ "invalid_signature": "Invalid payment signature",
886
+ "expired": "Payment authorization has expired",
887
+ "already_used": "This payment has already been used",
888
+ "network_mismatch": "Payment network does not match",
889
+ "invalid_payment": "Invalid payment data",
890
+ "verification_failed": "Payment verification failed"
891
+ };
892
+ const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
893
+ const error = new Error(errorMessage);
894
+ throw wrapPaymentError(error);
895
+ }
896
+ } catch (error) {
897
+ if (error instanceof PaymentOperationError) {
898
+ throw error;
899
+ }
900
+ console.warn("\u26A0\uFE0F Could not parse retry 402 response:", error);
901
+ }
902
+ }
903
+ return retryResponse;
904
+ }
277
905
 
278
906
  // src/utils/payment-helpers.ts
279
907
  var import_ethers2 = require("ethers");
908
+ init_common();
280
909
  function parsePaymentRequired(response) {
281
910
  if (response && typeof response === "object") {
282
911
  if ("x402Version" in response && "accepts" in response) {
@@ -300,6 +929,62 @@ function getSupportedNetworkTypes(paymentRequirements) {
300
929
  });
301
930
  return Array.from(networkTypes);
302
931
  }
932
+ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams) {
933
+ const fullEndpoint = `${endpoint}/${merchantId}`;
934
+ let response;
935
+ const requestInit = additionalParams && Object.keys(additionalParams).length > 0 ? {
936
+ body: JSON.stringify(additionalParams),
937
+ headers: {
938
+ "Content-Type": "application/json"
939
+ }
940
+ } : {};
941
+ if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
942
+ const solana = window.solana;
943
+ if (!solana) {
944
+ throw new Error("\u8BF7\u5B89\u88C5 Phantom \u94B1\u5305");
945
+ }
946
+ if (!solana.isConnected) {
947
+ await solana.connect();
948
+ }
949
+ response = await handleSvmPayment(fullEndpoint, {
950
+ wallet: solana,
951
+ network: "solana"
952
+ // Will use backend's network configuration
953
+ }, requestInit);
954
+ } else if (networkType === "evm" /* EVM */) {
955
+ if (!window.ethereum) {
956
+ throw new Error("\u8BF7\u5B89\u88C5 MetaMask \u94B1\u5305");
957
+ }
958
+ const provider = new import_ethers2.ethers.BrowserProvider(window.ethereum);
959
+ const signer = await provider.getSigner();
960
+ const wallet = {
961
+ address: await signer.getAddress(),
962
+ signTypedData: async (domain, types, message2) => {
963
+ return await signer.signTypedData(domain, types, message2);
964
+ },
965
+ // Get current chain ID from wallet
966
+ getChainId: async () => {
967
+ const network = await provider.getNetwork();
968
+ return `0x${network.chainId.toString(16)}`;
969
+ },
970
+ // Switch to a different chain
971
+ switchChain: async (chainId) => {
972
+ await window.ethereum.request({
973
+ method: "wallet_switchEthereumChain",
974
+ params: [{ chainId }]
975
+ });
976
+ }
977
+ };
978
+ response = await handleEvmPayment(fullEndpoint, {
979
+ wallet,
980
+ network: "base"
981
+ // Will use backend's network configuration
982
+ }, requestInit);
983
+ } else {
984
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B: ${networkType}`);
985
+ }
986
+ return response;
987
+ }
303
988
 
304
989
  // src/utils/network.ts
305
990
  var NETWORK_TYPE_MAP = {
@@ -338,6 +1023,138 @@ function getNetworkDisplayName(network) {
338
1023
  return displayNames[network.toLowerCase()] || network;
339
1024
  }
340
1025
 
1026
+ // src/utils/payment-error-handler.ts
1027
+ function parsePaymentError(error) {
1028
+ if (!error) {
1029
+ return {
1030
+ code: "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
1031
+ message: "Unknown error occurred",
1032
+ userMessage: "An unknown error occurred. Please try again.",
1033
+ originalError: error
1034
+ };
1035
+ }
1036
+ const errorMessage = error.message || error.toString();
1037
+ const errorCode = error.code;
1038
+ if (errorCode === 4001 || errorCode === "ACTION_REJECTED" || errorMessage.includes("User rejected") || errorMessage.includes("user rejected") || errorMessage.includes("User denied") || errorMessage.includes("user denied") || errorMessage.includes("ethers-user-denied")) {
1039
+ return {
1040
+ code: "USER_REJECTED" /* USER_REJECTED */,
1041
+ message: "User rejected the transaction",
1042
+ userMessage: "You rejected the signature request. Please try again if you want to proceed.",
1043
+ originalError: error
1044
+ };
1045
+ }
1046
+ if (errorMessage.includes("chainId") && (errorMessage.includes("must match") || errorMessage.includes("does not match"))) {
1047
+ const match = errorMessage.match(/chainId.*?"(\d+)".*?active.*?"(\d+)"/i) || errorMessage.match(/chain (\d+).*?chain (\d+)/i);
1048
+ if (match) {
1049
+ const [, requestedChain, activeChain] = match;
1050
+ return {
1051
+ code: "CHAIN_ID_MISMATCH" /* CHAIN_ID_MISMATCH */,
1052
+ message: `Network mismatch (wallet is on different chain): Requested ${requestedChain}, but wallet is on ${activeChain}`,
1053
+ userMessage: `Your wallet is on the wrong network. Please switch to the correct network and try again.`,
1054
+ originalError: error
1055
+ };
1056
+ }
1057
+ return {
1058
+ code: "CHAIN_ID_MISMATCH" /* CHAIN_ID_MISMATCH */,
1059
+ message: "Network mismatch (wallet selected network does not match)",
1060
+ userMessage: "Your wallet is on the wrong network. Please switch to the correct network.",
1061
+ originalError: error
1062
+ };
1063
+ }
1064
+ if (errorMessage.includes("Network mismatch") || errorMessage.includes("Wrong network") || errorMessage.includes("Incorrect network")) {
1065
+ return {
1066
+ code: "NETWORK_MISMATCH" /* NETWORK_MISMATCH */,
1067
+ message: errorMessage,
1068
+ userMessage: "Please switch your wallet to the correct network.",
1069
+ originalError: error
1070
+ };
1071
+ }
1072
+ if (errorMessage.includes("locked") || errorMessage.includes("Wallet is locked")) {
1073
+ return {
1074
+ code: "WALLET_LOCKED" /* WALLET_LOCKED */,
1075
+ message: "Wallet is locked",
1076
+ userMessage: "Please unlock your wallet and try again.",
1077
+ originalError: error
1078
+ };
1079
+ }
1080
+ if (errorMessage.includes("insufficient") && (errorMessage.includes("balance") || errorMessage.includes("funds"))) {
1081
+ return {
1082
+ code: "INSUFFICIENT_BALANCE" /* INSUFFICIENT_BALANCE */,
1083
+ message: "Insufficient balance",
1084
+ userMessage: "You don't have enough balance to complete this payment.",
1085
+ originalError: error
1086
+ };
1087
+ }
1088
+ if (errorMessage.includes("Failed to switch") || errorMessage.includes("switch chain")) {
1089
+ return {
1090
+ code: "NETWORK_SWITCH_FAILED" /* NETWORK_SWITCH_FAILED */,
1091
+ message: errorMessage,
1092
+ userMessage: "Failed to switch network. Please switch manually in your wallet.",
1093
+ originalError: error
1094
+ };
1095
+ }
1096
+ if (errorMessage.includes("not connected") || errorMessage.includes("No wallet") || errorMessage.includes("Connect wallet")) {
1097
+ return {
1098
+ code: "WALLET_NOT_CONNECTED" /* WALLET_NOT_CONNECTED */,
1099
+ message: "Wallet not connected",
1100
+ userMessage: "Please connect your wallet first.",
1101
+ originalError: error
1102
+ };
1103
+ }
1104
+ if (errorMessage.includes("No suitable") || errorMessage.includes("payment requirements") || errorMessage.includes("Missing payTo") || errorMessage.includes("Missing asset")) {
1105
+ return {
1106
+ code: "INVALID_PAYMENT_REQUIREMENTS" /* INVALID_PAYMENT_REQUIREMENTS */,
1107
+ message: errorMessage,
1108
+ userMessage: "Invalid payment configuration. Please contact support.",
1109
+ originalError: error
1110
+ };
1111
+ }
1112
+ if (errorMessage.includes("exceeds maximum")) {
1113
+ return {
1114
+ code: "AMOUNT_EXCEEDED" /* AMOUNT_EXCEEDED */,
1115
+ message: errorMessage,
1116
+ userMessage: "Payment amount exceeds the maximum allowed.",
1117
+ originalError: error
1118
+ };
1119
+ }
1120
+ if (errorMessage.includes("signature") || errorMessage.includes("sign") || errorCode === "UNKNOWN_ERROR") {
1121
+ return {
1122
+ code: "SIGNATURE_FAILED" /* SIGNATURE_FAILED */,
1123
+ message: errorMessage,
1124
+ userMessage: "Failed to sign the transaction. Please try again.",
1125
+ originalError: error
1126
+ };
1127
+ }
1128
+ return {
1129
+ code: "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
1130
+ message: errorMessage,
1131
+ userMessage: "An unexpected error occurred. Please try again or contact support.",
1132
+ originalError: error
1133
+ };
1134
+ }
1135
+ var PaymentOperationError = class _PaymentOperationError extends Error {
1136
+ constructor(paymentError) {
1137
+ super(paymentError.message);
1138
+ this.name = "PaymentOperationError";
1139
+ this.code = paymentError.code;
1140
+ this.userMessage = paymentError.userMessage;
1141
+ this.originalError = paymentError.originalError;
1142
+ if (Error.captureStackTrace) {
1143
+ Error.captureStackTrace(this, _PaymentOperationError);
1144
+ }
1145
+ }
1146
+ /**
1147
+ * Get a formatted error message for logging
1148
+ */
1149
+ toLogString() {
1150
+ return `[${this.code}] ${this.message} | User Message: ${this.userMessage}`;
1151
+ }
1152
+ };
1153
+ function wrapPaymentError(error) {
1154
+ const parsedError = parsePaymentError(error);
1155
+ return new PaymentOperationError(parsedError);
1156
+ }
1157
+
341
1158
  // src/react/store/walletStore.ts
342
1159
  var WalletStore = class {
343
1160
  constructor() {
@@ -354,60 +1171,28 @@ var WalletStore = class {
354
1171
  init() {
355
1172
  if (this.initialized) return;
356
1173
  this.initialized = true;
357
- this.autoReconnect();
358
1174
  onAccountsChanged((accounts) => {
359
- const connectedType = getConnectedNetworkType();
360
- if (connectedType === "evm" /* EVM */) {
1175
+ if (this.state.networkType === "evm" /* EVM */) {
361
1176
  if (accounts.length === 0) {
362
1177
  this.setState({ address: null });
363
- console.log("\u{1F50C} Wallet disconnected");
364
- } else {
365
- if (!isWalletManuallyDisconnected()) {
366
- this.setState({ address: accounts[0] });
367
- console.log("\u{1F504} Account changed:", accounts[0]);
368
- }
1178
+ } else if (!isWalletManuallyDisconnected("evm" /* EVM */)) {
1179
+ this.setState({ address: accounts[0] });
1180
+ saveWalletAddress("evm" /* EVM */, accounts[0]);
369
1181
  }
370
1182
  }
371
1183
  });
372
1184
  onChainChanged(() => {
373
- const connectedType = getConnectedNetworkType();
374
- if (connectedType === "evm" /* EVM */) {
375
- console.log("\u26A0\uFE0F Network changed detected - disconnecting wallet");
376
- disconnectWallet();
377
- this.setState({
378
- address: null,
379
- networkType: null,
380
- error: "Network changed. Please reconnect your wallet."
381
- });
1185
+ if (this.state.networkType === "evm" /* EVM */) {
1186
+ this.handleDisconnect("evm" /* EVM */, "Chain changed. Please reconnect your wallet.");
382
1187
  }
383
1188
  });
384
1189
  onWalletDisconnect(() => {
385
- const connectedType = getConnectedNetworkType();
386
- if (connectedType === "solana" /* SOLANA */ || connectedType === "svm" /* SVM */) {
387
- console.log("\u26A0\uFE0F Solana wallet disconnected");
388
- disconnectWallet();
389
- this.setState({
390
- address: null,
391
- networkType: null
392
- });
1190
+ const svmTypes = ["solana" /* SOLANA */, "svm" /* SVM */];
1191
+ if (this.state.networkType && svmTypes.includes(this.state.networkType)) {
1192
+ this.handleDisconnect(this.state.networkType);
393
1193
  }
394
1194
  });
395
1195
  }
396
- async autoReconnect() {
397
- if (!isWalletManuallyDisconnected()) {
398
- const connectedType = getConnectedNetworkType();
399
- if (connectedType) {
400
- const currentAddress = await getCurrentWallet(connectedType);
401
- if (currentAddress) {
402
- this.setState({
403
- address: currentAddress,
404
- networkType: connectedType
405
- });
406
- console.log("\u{1F504} Auto-reconnected wallet:", currentAddress);
407
- }
408
- }
409
- }
410
- }
411
1196
  // Get current state
412
1197
  getState() {
413
1198
  return this.state;
@@ -428,18 +1213,32 @@ var WalletStore = class {
428
1213
  notifyListeners() {
429
1214
  this.listeners.forEach((listener) => listener());
430
1215
  }
1216
+ // Handle wallet disconnect (internal helper)
1217
+ handleDisconnect(networkType, error) {
1218
+ removeWalletAddress(networkType);
1219
+ markWalletDisconnected(networkType);
1220
+ if (typeof window !== "undefined") {
1221
+ localStorage.removeItem("connected_network_type");
1222
+ }
1223
+ this.setState({
1224
+ address: null,
1225
+ networkType: null,
1226
+ error: error || null
1227
+ });
1228
+ }
431
1229
  // Connect wallet
432
1230
  async connect(type) {
1231
+ if (this.state.address && this.state.networkType && this.state.networkType !== type) {
1232
+ saveWalletAddress(this.state.networkType, this.state.address);
1233
+ }
433
1234
  this.setState({ isConnecting: true, error: null });
434
1235
  try {
435
1236
  const walletAddress = await connectWallet(type);
436
- console.log("\u2705 Wallet connected:", walletAddress, "Network:", type);
437
1237
  this.setState({
438
1238
  address: walletAddress,
439
1239
  networkType: type,
440
1240
  isConnecting: false
441
1241
  });
442
- console.log("\u{1F4DD} Store state updated");
443
1242
  } catch (err) {
444
1243
  this.setState({
445
1244
  error: err.message || "Failed to connect wallet",
@@ -448,20 +1247,67 @@ var WalletStore = class {
448
1247
  throw err;
449
1248
  }
450
1249
  }
1250
+ // Switch network (use cached wallet if available)
1251
+ async switchNetwork(type) {
1252
+ if (this.state.address && this.state.networkType) {
1253
+ saveWalletAddress(this.state.networkType, this.state.address);
1254
+ }
1255
+ this.setState({ isConnecting: true, error: null });
1256
+ try {
1257
+ const address = await switchNetwork(type);
1258
+ if (address) {
1259
+ this.setState({
1260
+ address,
1261
+ networkType: type,
1262
+ isConnecting: false
1263
+ });
1264
+ } else {
1265
+ this.setState({
1266
+ address: null,
1267
+ networkType: type,
1268
+ isConnecting: true
1269
+ });
1270
+ await this.connect(type);
1271
+ }
1272
+ } catch (err) {
1273
+ this.setState({
1274
+ error: err.message || "Failed to switch network",
1275
+ isConnecting: false
1276
+ });
1277
+ throw err;
1278
+ }
1279
+ }
451
1280
  // Disconnect wallet
452
1281
  disconnect() {
453
- disconnectWallet();
454
- this.setState({
455
- address: null,
456
- networkType: null,
457
- error: null
458
- });
459
- console.log("\u{1F50C} Wallet disconnected from store");
1282
+ const currentNetwork = this.state.networkType;
1283
+ if (currentNetwork) {
1284
+ this.handleDisconnect(currentNetwork);
1285
+ } else {
1286
+ this.setState({
1287
+ address: null,
1288
+ networkType: null,
1289
+ error: null
1290
+ });
1291
+ }
460
1292
  }
461
1293
  // Clear error
462
1294
  clearError() {
463
1295
  this.setState({ error: null });
464
1296
  }
1297
+ // Ensure network matches expected type (for page-specific network requirements)
1298
+ async ensureNetwork(expectedNetwork) {
1299
+ if (isWalletManuallyDisconnected(expectedNetwork)) {
1300
+ return;
1301
+ }
1302
+ if (this.state.networkType === expectedNetwork && this.state.address) {
1303
+ return;
1304
+ }
1305
+ if (this.state.networkType !== expectedNetwork) {
1306
+ await this.switchNetwork(expectedNetwork);
1307
+ } else if (!this.state.address) {
1308
+ await this.connect(expectedNetwork);
1309
+ }
1310
+ }
465
1311
  };
466
1312
  var walletStore = new WalletStore();
467
1313
  if (typeof window !== "undefined") {
@@ -479,24 +1325,43 @@ function useWallet() {
479
1325
  return {
480
1326
  ...state,
481
1327
  connect: (type) => walletStore.connect(type),
1328
+ switchNetwork: (type) => walletStore.switchNetwork(type),
1329
+ ensureNetwork: (type) => walletStore.ensureNetwork(type),
482
1330
  disconnect: () => walletStore.disconnect(),
483
1331
  clearError: () => walletStore.clearError()
484
1332
  };
485
1333
  }
486
1334
 
487
- // src/react/hooks/usePayment.ts
1335
+ // src/react/hooks/usePageNetwork.ts
488
1336
  var import_react2 = require("react");
1337
+ function usePageNetwork(expectedNetwork, options = {}) {
1338
+ const {
1339
+ autoSwitch = true,
1340
+ switchOnMount = true
1341
+ } = options;
1342
+ const wallet = useWallet();
1343
+ (0, import_react2.useEffect)(() => {
1344
+ if (!autoSwitch || !switchOnMount) return;
1345
+ wallet.ensureNetwork(expectedNetwork).catch((err) => {
1346
+ console.error("Failed to ensure network:", err);
1347
+ });
1348
+ }, [expectedNetwork]);
1349
+ return wallet;
1350
+ }
1351
+
1352
+ // src/react/hooks/usePayment.ts
1353
+ var import_react3 = require("react");
489
1354
  function usePayment() {
490
- const [isProcessing, setIsProcessing] = (0, import_react2.useState)(false);
491
- const [result, setResult] = (0, import_react2.useState)(null);
492
- const [error, setError] = (0, import_react2.useState)(null);
493
- const clearResult = (0, import_react2.useCallback)(() => {
1355
+ const [isProcessing, setIsProcessing] = (0, import_react3.useState)(false);
1356
+ const [result, setResult] = (0, import_react3.useState)(null);
1357
+ const [error, setError] = (0, import_react3.useState)(null);
1358
+ const clearResult = (0, import_react3.useCallback)(() => {
494
1359
  setResult(null);
495
1360
  }, []);
496
- const clearError = (0, import_react2.useCallback)(() => {
1361
+ const clearError = (0, import_react3.useCallback)(() => {
497
1362
  setError(null);
498
1363
  }, []);
499
- const reset = (0, import_react2.useCallback)(() => {
1364
+ const reset = (0, import_react3.useCallback)(() => {
500
1365
  setIsProcessing(false);
501
1366
  setResult(null);
502
1367
  setError(null);
@@ -515,12 +1380,13 @@ function usePayment() {
515
1380
  }
516
1381
 
517
1382
  // src/react/hooks/usePaymentInfo.ts
518
- var import_react3 = require("react");
1383
+ var import_react4 = require("react");
1384
+ init_common();
519
1385
  function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams) {
520
- const [paymentInfo, setPaymentInfo] = (0, import_react3.useState)(null);
521
- const [supportedNetworks, setSupportedNetworks] = (0, import_react3.useState)([]);
522
- const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
523
- const [error, setError] = (0, import_react3.useState)(null);
1386
+ const [paymentInfo, setPaymentInfo] = (0, import_react4.useState)(null);
1387
+ const [supportedNetworks, setSupportedNetworks] = (0, import_react4.useState)([]);
1388
+ const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
1389
+ const [error, setError] = (0, import_react4.useState)(null);
524
1390
  const fetchPaymentInfo = async () => {
525
1391
  setIsLoading(true);
526
1392
  setError(null);
@@ -554,7 +1420,7 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams)
554
1420
  setIsLoading(false);
555
1421
  }
556
1422
  };
557
- (0, import_react3.useEffect)(() => {
1423
+ (0, import_react4.useEffect)(() => {
558
1424
  fetchPaymentInfo();
559
1425
  }, [endpoint, merchantId]);
560
1426
  return {
@@ -567,7 +1433,7 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams)
567
1433
  }
568
1434
 
569
1435
  // src/react/components/WalletConnect.tsx
570
- var import_react4 = __toESM(require("react"));
1436
+ var import_react5 = __toESM(require("react"));
571
1437
 
572
1438
  // src/react/styles/inline-styles.ts
573
1439
  var isDarkMode = () => {
@@ -756,8 +1622,8 @@ function WalletConnect({
756
1622
  onDisconnect
757
1623
  }) {
758
1624
  const { address, networkType, isConnecting, error, connect, disconnect } = useWallet();
759
- const [hoveredButton, setHoveredButton] = (0, import_react4.useState)(null);
760
- const [hoveredLink, setHoveredLink] = (0, import_react4.useState)(null);
1625
+ const [hoveredButton, setHoveredButton] = (0, import_react5.useState)(null);
1626
+ const [hoveredLink, setHoveredLink] = (0, import_react5.useState)(null);
761
1627
  const handleConnect = async (network) => {
762
1628
  try {
763
1629
  await connect(network);
@@ -768,9 +1634,9 @@ function WalletConnect({
768
1634
  disconnect();
769
1635
  onDisconnect?.();
770
1636
  };
771
- return /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...containerStyle, ...className ? {} : {} }, className }, !address ? /* @__PURE__ */ import_react4.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react4.default.createElement("h3", { style: getTitleStyle() }, "Connect Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "Please install a supported wallet extension") : /* @__PURE__ */ import_react4.default.createElement("div", { style: buttonsContainerStyle }, supportedNetworks.map((network) => {
1637
+ return /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...containerStyle, ...className ? {} : {} }, className }, !address ? /* @__PURE__ */ import_react5.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react5.default.createElement("h3", { style: getTitleStyle() }, "Connect Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "Please install a supported wallet extension") : /* @__PURE__ */ import_react5.default.createElement("div", { style: buttonsContainerStyle }, supportedNetworks.map((network) => {
772
1638
  const installed = isWalletInstalled(network);
773
- return /* @__PURE__ */ import_react4.default.createElement("div", { key: network, style: walletOptionStyle }, /* @__PURE__ */ import_react4.default.createElement(
1639
+ return /* @__PURE__ */ import_react5.default.createElement("div", { key: network, style: walletOptionStyle }, /* @__PURE__ */ import_react5.default.createElement(
774
1640
  "button",
775
1641
  {
776
1642
  style: getConnectButtonStyle(isConnecting || !installed, hoveredButton === network),
@@ -780,7 +1646,7 @@ function WalletConnect({
780
1646
  onMouseLeave: () => setHoveredButton(null)
781
1647
  },
782
1648
  isConnecting ? "Connecting..." : getNetworkDisplayName(network)
783
- ), !installed && /* @__PURE__ */ import_react4.default.createElement(
1649
+ ), !installed && /* @__PURE__ */ import_react5.default.createElement(
784
1650
  "a",
785
1651
  {
786
1652
  href: getWalletInstallUrl(network),
@@ -792,7 +1658,7 @@ function WalletConnect({
792
1658
  },
793
1659
  "Install Wallet"
794
1660
  ));
795
- })), error && /* @__PURE__ */ import_react4.default.createElement("p", { style: getErrorStyle() }, error), /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "To switch accounts, please change it in your wallet extension")) : /* @__PURE__ */ import_react4.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react4.default.createElement("div", { style: walletAddressStyle }, /* @__PURE__ */ import_react4.default.createElement("span", { style: getLabelStyle() }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`), /* @__PURE__ */ import_react4.default.createElement("span", { style: getAddressStyle() }, formatAddress(address))), /* @__PURE__ */ import_react4.default.createElement("div", { style: walletActionsStyle }, /* @__PURE__ */ import_react4.default.createElement(
1661
+ })), error && /* @__PURE__ */ import_react5.default.createElement("p", { style: getErrorStyle() }, error), /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "To switch accounts, please change it in your wallet extension")) : /* @__PURE__ */ import_react5.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react5.default.createElement("div", { style: walletAddressStyle }, /* @__PURE__ */ import_react5.default.createElement("span", { style: getLabelStyle() }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`), /* @__PURE__ */ import_react5.default.createElement("span", { style: getAddressStyle() }, formatAddress(address))), /* @__PURE__ */ import_react5.default.createElement("div", { style: walletActionsStyle }, /* @__PURE__ */ import_react5.default.createElement(
796
1662
  "button",
797
1663
  {
798
1664
  style: getDisconnectButtonStyle(hoveredButton === "disconnect"),
@@ -801,11 +1667,568 @@ function WalletConnect({
801
1667
  onMouseLeave: () => setHoveredButton(null)
802
1668
  },
803
1669
  "Disconnect"
804
- )), /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "Switch account in your wallet to change address")));
1670
+ )), /* @__PURE__ */ import_react5.default.createElement("p", { style: getHintStyle() }, "Switch account in your wallet to change address")));
1671
+ }
1672
+
1673
+ // src/react/components/V402Checkout.tsx
1674
+ var import_react7 = __toESM(require("react"));
1675
+ var import_antd = require("antd");
1676
+ var import_icons = require("@ant-design/icons");
1677
+ init_common();
1678
+
1679
+ // src/react/utils/CryptoIcons.tsx
1680
+ var import_react6 = __toESM(require("react"));
1681
+ var SolanaIcon = ({ width = 16, height = 16, className, style }) => {
1682
+ return /* @__PURE__ */ import_react6.default.createElement(
1683
+ "svg",
1684
+ {
1685
+ xmlns: "http://www.w3.org/2000/svg",
1686
+ viewBox: "0 0 16 16",
1687
+ width,
1688
+ height,
1689
+ className,
1690
+ style
1691
+ },
1692
+ /* @__PURE__ */ import_react6.default.createElement("desc", null, "Solana SOL Fill Streamline Icon: https://streamlinehq.com"),
1693
+ /* @__PURE__ */ import_react6.default.createElement("g", { fill: "none", fillRule: "evenodd" }, /* @__PURE__ */ import_react6.default.createElement(
1694
+ "path",
1695
+ {
1696
+ d: "M16 0v16H0V0h16ZM8.395333333333333 15.505333333333333l-0.007333333333333332 0.0013333333333333333 -0.047333333333333324 0.023333333333333334 -0.013333333333333332 0.0026666666666666666 -0.009333333333333332 -0.0026666666666666666 -0.047333333333333324 -0.023333333333333334c-0.006666666666666666 -0.0026666666666666666 -0.012666666666666666 -0.0006666666666666666 -0.016 0.003333333333333333l-0.0026666666666666666 0.006666666666666666 -0.011333333333333334 0.2853333333333333 0.003333333333333333 0.013333333333333332 0.006666666666666666 0.008666666666666666 0.06933333333333333 0.049333333333333326 0.009999999999999998 0.0026666666666666666 0.008 -0.0026666666666666666 0.06933333333333333 -0.049333333333333326 0.008 -0.010666666666666666 0.0026666666666666666 -0.011333333333333334 -0.011333333333333334 -0.2846666666666666c-0.0013333333333333333 -0.006666666666666666 -0.005999999999999999 -0.011333333333333334 -0.011333333333333334 -0.011999999999999999Zm0.17666666666666667 -0.07533333333333334 -0.008666666666666666 0.0013333333333333333 -0.12333333333333332 0.062 -0.006666666666666666 0.006666666666666666 -0.002 0.007333333333333332 0.011999999999999999 0.2866666666666666 0.003333333333333333 0.008 0.005333333333333333 0.004666666666666666 0.134 0.062c0.008 0.0026666666666666666 0.015333333333333332 0 0.019333333333333334 -0.005333333333333333l0.0026666666666666666 -0.009333333333333332 -0.02266666666666667 -0.4093333333333333c-0.002 -0.008 -0.006666666666666666 -0.013333333333333332 -0.013333333333333332 -0.014666666666666665Zm-0.4766666666666666 0.0013333333333333333a0.015333333333333332 0.015333333333333332 0 0 0 -0.018 0.004l-0.004 0.009333333333333332 -0.02266666666666667 0.4093333333333333c0 0.008 0.004666666666666666 0.013333333333333332 0.011333333333333334 0.016l0.009999999999999998 -0.0013333333333333333 0.134 -0.062 0.006666666666666666 -0.005333333333333333 0.0026666666666666666 -0.007333333333333332 0.011333333333333334 -0.2866666666666666 -0.002 -0.008 -0.006666666666666666 -0.006666666666666666 -0.12266666666666666 -0.06133333333333333Z",
1697
+ strokeWidth: "0.6667"
1698
+ }
1699
+ ), /* @__PURE__ */ import_react6.default.createElement(
1700
+ "path",
1701
+ {
1702
+ fill: "#000000",
1703
+ d: "M4.862 2.862A0.6666666666666666 0.6666666666666666 0 0 1 5.333333333333333 2.6666666666666665h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.47133333333333327 1.138l-2 2A0.6666666666666666 0.6666666666666666 0 0 1 12 6H3.333333333333333a0.6666666666666666 0.6666666666666666 0 0 1 -0.47133333333333327 -1.138l2 -2Zm-2.1166666666666663 4.156666666666666A0.6666666666666666 0.6666666666666666 0 0 1 3.333333333333333 6.666666666666666h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.5546666666666666 0.29666666666666663l1.3333333333333333 2A0.6666666666666666 0.6666666666666666 0 0 1 13.333333333333332 10H4.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 -0.5546666666666666 -0.29666666666666663l-1.3333333333333333 -2a0.6666666666666666 0.6666666666666666 0 0 1 -0.03333333333333333 -0.6846666666666665Zm1.4499999999999997 3.843333333333333A0.6666666666666666 0.6666666666666666 0 0 1 4.666666666666666 10.666666666666666h8.666666666666666a0.6666666666666666 0.6666666666666666 0 0 1 0.47133333333333327 1.138l-2 2A0.6666666666666666 0.6666666666666666 0 0 1 11.333333333333332 14H2.6666666666666665a0.6666666666666666 0.6666666666666666 0 0 1 -0.47133333333333327 -1.138l2 -2Z",
1704
+ strokeWidth: "0.6667"
1705
+ }
1706
+ ))
1707
+ );
1708
+ };
1709
+ var BaseIcon = ({ width = 24, height = 24, className, style }) => {
1710
+ return /* @__PURE__ */ import_react6.default.createElement(
1711
+ "svg",
1712
+ {
1713
+ xmlns: "http://www.w3.org/2000/svg",
1714
+ viewBox: "0 0 24 24",
1715
+ fill: "none",
1716
+ stroke: "#000000",
1717
+ strokeLinecap: "round",
1718
+ strokeLinejoin: "round",
1719
+ width,
1720
+ height,
1721
+ className,
1722
+ style
1723
+ },
1724
+ /* @__PURE__ */ import_react6.default.createElement("desc", null, "Brand Coinbase Streamline Icon: https://streamlinehq.com"),
1725
+ /* @__PURE__ */ import_react6.default.createElement(
1726
+ "path",
1727
+ {
1728
+ d: "M12.95 22c-4.503 0 -8.445 -3.04 -9.61 -7.413 -1.165 -4.373 0.737 -8.988 4.638 -11.25a9.906 9.906 0 0 1 12.008 1.598l-3.335 3.367a5.185 5.185 0 0 0 -7.354 0.013 5.252 5.252 0 0 0 0 7.393 5.185 5.185 0 0 0 7.354 0.013L20 19.088A9.887 9.887 0 0 1 12.95 22z",
1729
+ strokeWidth: "2"
1730
+ }
1731
+ )
1732
+ );
1733
+ };
1734
+ var getNetworkIcon = (network) => {
1735
+ const networkLower = network.toLowerCase();
1736
+ if (networkLower.includes("solana")) {
1737
+ return SolanaIcon;
1738
+ }
1739
+ if (networkLower.includes("base")) {
1740
+ return BaseIcon;
1741
+ }
1742
+ return BaseIcon;
1743
+ };
1744
+
1745
+ // src/react/components/V402Checkout.tsx
1746
+ var { Title, Text } = import_antd.Typography;
1747
+ var notify = {
1748
+ success: (title, msg) => {
1749
+ import_antd.message.success(`${title}: ${msg}`);
1750
+ },
1751
+ error: (title, msg) => {
1752
+ import_antd.message.error(`${title}: ${msg}`);
1753
+ },
1754
+ info: (title, msg) => {
1755
+ import_antd.message.info(`${title}: ${msg}`);
1756
+ }
1757
+ };
1758
+ function V402Checkout({
1759
+ merchantId,
1760
+ headerInfo = {},
1761
+ isModal = false,
1762
+ onPaymentComplete,
1763
+ additionalParams = {},
1764
+ expectedNetwork
1765
+ }) {
1766
+ const {
1767
+ title = "V402Pay - Make x402Pay Easier",
1768
+ subtitle = "onvoyage.ai",
1769
+ tooltipText = "V402Pay - Accept Crypto Payments Easier"
1770
+ } = headerInfo;
1771
+ let endpoint = DEV_BACK_URL;
1772
+ const {
1773
+ supportedNetworks,
1774
+ isLoading: fetchingPaymentInfo,
1775
+ paymentInfo
1776
+ } = usePaymentInfo(merchantId, endpoint, additionalParams);
1777
+ const targetNetwork = expectedNetwork || supportedNetworks[0];
1778
+ const { address, networkType, disconnect, ensureNetwork } = usePageNetwork(
1779
+ targetNetwork,
1780
+ { autoSwitch: !!targetNetwork, switchOnMount: true }
1781
+ );
1782
+ const { isProcessing, setIsProcessing, result, setResult, error, setError } = usePayment();
1783
+ const [paymentDetails, setPaymentDetails] = (0, import_react7.useState)(null);
1784
+ const handleDisconnect = () => {
1785
+ disconnect();
1786
+ setResult(null);
1787
+ setError(null);
1788
+ notify.info("Wallet Disconnected", "Your wallet has been disconnected successfully.");
1789
+ };
1790
+ (0, import_react7.useEffect)(() => {
1791
+ if (paymentInfo && paymentInfo.length > 0) {
1792
+ const firstPayment = paymentInfo[0];
1793
+ const rawAmount = firstPayment.maxAmountRequired?.toString() || "0";
1794
+ const decimals = 6;
1795
+ const humanReadableAmount = (Number(rawAmount) / Math.pow(10, decimals)).toFixed(2);
1796
+ const network = firstPayment.network || "Unknown";
1797
+ const currency = "USDC";
1798
+ setPaymentDetails({
1799
+ amount: humanReadableAmount,
1800
+ currency,
1801
+ network
1802
+ });
1803
+ }
1804
+ }, [paymentInfo]);
1805
+ (0, import_react7.useEffect)(() => {
1806
+ if (targetNetwork && !fetchingPaymentInfo && ensureNetwork) {
1807
+ ensureNetwork(targetNetwork).catch((err) => {
1808
+ console.error("Failed to ensure network:", err);
1809
+ });
1810
+ }
1811
+ }, [targetNetwork, fetchingPaymentInfo]);
1812
+ const handlePayment = async () => {
1813
+ if (!networkType) {
1814
+ notify.error("Wallet Not Connected", "Please connect your wallet first.");
1815
+ return;
1816
+ }
1817
+ setResult(null);
1818
+ setError(null);
1819
+ setIsProcessing(true);
1820
+ try {
1821
+ const response = await makePayment(networkType, merchantId, endpoint, additionalParams);
1822
+ const data = await response.json();
1823
+ setResult(data);
1824
+ notify.success("Payment Successful!", "Your payment has been processed successfully.");
1825
+ if (onPaymentComplete) {
1826
+ onPaymentComplete(data);
1827
+ }
1828
+ } catch (err) {
1829
+ const errorMessage = err.message || "Payment failed";
1830
+ setError(errorMessage);
1831
+ notify.error("Payment Failed", errorMessage);
1832
+ } finally {
1833
+ setIsProcessing(false);
1834
+ }
1835
+ };
1836
+ const getNetworkColor = (network) => {
1837
+ if (network.toLowerCase().includes("solana")) return "#14F195";
1838
+ if (network.toLowerCase().includes("evm") || network.toLowerCase().includes("base")) return "#0052FF";
1839
+ return "#8c8c8c";
1840
+ };
1841
+ const NetworkIcon = paymentDetails ? getNetworkIcon(paymentDetails.network) : null;
1842
+ const networkColor = paymentDetails ? getNetworkColor(paymentDetails.network) : "#8c8c8c";
1843
+ const loadingColor = "#8c8c8c";
1844
+ const hasInvalidCheckoutId = !fetchingPaymentInfo && (!paymentInfo || paymentInfo.length === 0);
1845
+ return /* @__PURE__ */ import_react7.default.createElement(
1846
+ "div",
1847
+ {
1848
+ className: isModal ? "bg-white" : "h-screen bg-white flex items-center justify-center p-4 overflow-hidden"
1849
+ },
1850
+ /* @__PURE__ */ import_react7.default.createElement(
1851
+ "div",
1852
+ {
1853
+ className: "flex gap-4 items-center justify-center",
1854
+ style: {
1855
+ maxWidth: isProcessing || result || error ? "1200px" : "480px",
1856
+ transition: "max-width 0.4s ease-in-out",
1857
+ width: "100%"
1858
+ }
1859
+ },
1860
+ /* @__PURE__ */ import_react7.default.createElement(
1861
+ import_antd.Card,
1862
+ {
1863
+ className: "flex-shrink-0",
1864
+ style: {
1865
+ border: isModal ? "none" : "1px solid #e8e8e8",
1866
+ borderRadius: isModal ? "0" : "16px",
1867
+ boxShadow: isModal ? "none" : "0 4px 24px rgba(0, 0, 0, 0.06)",
1868
+ maxHeight: isModal ? "calc(100vh - 100px)" : "calc(100vh - 32px)",
1869
+ overflow: "auto",
1870
+ width: isModal ? "100%" : "480px",
1871
+ transition: "all 0.4s ease-in-out",
1872
+ transform: result || error ? "translateX(0)" : "translateX(0)"
1873
+ },
1874
+ styles: { body: { padding: isModal ? "0px" : "32px 24px" } }
1875
+ },
1876
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-3 mb-4" }, /* @__PURE__ */ import_react7.default.createElement(
1877
+ "div",
1878
+ {
1879
+ className: "w-12 h-12 rounded-xl flex items-center justify-center",
1880
+ style: {
1881
+ background: hasInvalidCheckoutId ? "#ff4d4f" : paymentDetails ? networkColor : loadingColor,
1882
+ transition: "background 0.3s ease"
1883
+ }
1884
+ },
1885
+ hasInvalidCheckoutId ? /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px", color: "white", fontWeight: "bold" } }, "\u2717") : paymentDetails && NetworkIcon ? /* @__PURE__ */ import_react7.default.createElement(NetworkIcon, { width: 24, height: 24 }) : /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: "20px", color: "white" }, spin: true })
1886
+ ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react7.default.createElement(Title, { level: 4, style: { margin: 0, fontSize: "18px", fontWeight: 600 } }, title || "Echo Payment OnVoyage"), !hasInvalidCheckoutId && /* @__PURE__ */ import_react7.default.createElement(
1887
+ import_antd.Tooltip,
1888
+ {
1889
+ title: tooltipText,
1890
+ placement: "top"
1891
+ },
1892
+ /* @__PURE__ */ import_react7.default.createElement(
1893
+ import_icons.InfoCircleOutlined,
1894
+ {
1895
+ style: { fontSize: "14px", color: "#8c8c8c", cursor: "help" }
1896
+ }
1897
+ )
1898
+ )), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, subtitle))),
1899
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-5" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "inline-flex items-center justify-center w-12 h-12 rounded-full bg-gray-50 mb-3" }, /* @__PURE__ */ import_react7.default.createElement(import_icons.LockOutlined, { style: { fontSize: "20px", color: "#595959" } })), /* @__PURE__ */ import_react7.default.createElement(Title, { level: 3, style: { margin: "0 0 6px 0", fontSize: "20px", fontWeight: 600 } }, "Payment Required"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Pay ", paymentDetails ? `$${paymentDetails.amount} ${paymentDetails.currency}` : "the required amount", " to access")),
1900
+ hasInvalidCheckoutId && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react7.default.createElement(
1901
+ "div",
1902
+ {
1903
+ className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
1904
+ style: {
1905
+ background: "linear-gradient(135deg, #ef4444 0%, #f87171 100%)",
1906
+ boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
1907
+ }
1908
+ },
1909
+ /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "!")
1910
+ ), /* @__PURE__ */ import_react7.default.createElement(
1911
+ Title,
1912
+ {
1913
+ level: 4,
1914
+ style: { margin: "0 0 12px 0", fontSize: "18px", fontWeight: 600, color: "#262626" }
1915
+ },
1916
+ "Invalid Checkout ID"
1917
+ ), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", display: "block", marginBottom: "16px" } }, "The checkout ID you provided is invalid or has expired."), /* @__PURE__ */ import_react7.default.createElement(
1918
+ "div",
1919
+ {
1920
+ style: {
1921
+ background: "#fef2f2",
1922
+ padding: "16px",
1923
+ borderRadius: "12px",
1924
+ border: "1px solid #fee2e2",
1925
+ marginTop: "16px"
1926
+ }
1927
+ },
1928
+ /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
1929
+ fontSize: "13px",
1930
+ color: "#dc2626",
1931
+ lineHeight: "1.6",
1932
+ fontWeight: 500
1933
+ } }, "Failed to load payment information. Please check your checkout ID.")
1934
+ )),
1935
+ !hasInvalidCheckoutId && fetchingPaymentInfo && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { color: "#8c8c8c" } }, "Loading payment information...")),
1936
+ !hasInvalidCheckoutId && !fetchingPaymentInfo && !address && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(WalletConnect, { supportedNetworks })),
1937
+ !hasInvalidCheckoutId && address && /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(
1938
+ "div",
1939
+ {
1940
+ className: "bg-gray-50 rounded-lg p-3 mb-4",
1941
+ style: { border: "1px solid #f0f0f0" }
1942
+ },
1943
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-3 flex-1" }, /* @__PURE__ */ import_react7.default.createElement(
1944
+ "div",
1945
+ {
1946
+ className: "w-10 h-10 rounded-full bg-black flex items-center justify-center text-white text-sm font-semibold"
1947
+ },
1948
+ address.slice(0, 2).toUpperCase()
1949
+ ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
1950
+ display: "block",
1951
+ fontSize: "12px",
1952
+ color: "#8c8c8c",
1953
+ marginBottom: "2px"
1954
+ } }, "Connected Wallet"), /* @__PURE__ */ import_react7.default.createElement(
1955
+ Text,
1956
+ {
1957
+ style: {
1958
+ fontSize: "13px",
1959
+ fontWeight: 600,
1960
+ fontFamily: "Monaco, monospace"
1961
+ }
1962
+ },
1963
+ formatAddress(address)
1964
+ ))), /* @__PURE__ */ import_react7.default.createElement(
1965
+ import_antd.Button,
1966
+ {
1967
+ type: "text",
1968
+ size: "small",
1969
+ icon: /* @__PURE__ */ import_react7.default.createElement(import_icons.DisconnectOutlined, null),
1970
+ onClick: handleDisconnect,
1971
+ style: { color: "#ff4d4f" }
1972
+ }
1973
+ ))
1974
+ ), paymentDetails && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bg-gray-50 rounded-lg p-3 mb-4", style: { border: "1px solid #f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Payment Amount"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "18px", fontWeight: 600 } }, "$", paymentDetails.amount)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Currency"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.currency)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Network"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.network)), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Wallet Address"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
1975
+ fontSize: "11px",
1976
+ fontWeight: 500,
1977
+ fontFamily: "Monaco, monospace",
1978
+ wordBreak: "break-all",
1979
+ textAlign: "right",
1980
+ maxWidth: "60%",
1981
+ lineHeight: 1.4
1982
+ } }, address))), /* @__PURE__ */ import_react7.default.createElement(
1983
+ "div",
1984
+ {
1985
+ className: "flex items-center justify-center gap-2 mb-3 p-2 rounded-lg",
1986
+ style: { background: "#f6ffed", border: "1px solid #d9f7be" }
1987
+ },
1988
+ /* @__PURE__ */ import_react7.default.createElement(import_icons.SafetyOutlined, { style: { color: "#52c41a", fontSize: "13px" } }),
1989
+ /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#52c41a", fontWeight: 500 } }, "Secure payment powered by v402pay")
1990
+ ), /* @__PURE__ */ import_react7.default.createElement(
1991
+ import_antd.Button,
1992
+ {
1993
+ type: "primary",
1994
+ size: "large",
1995
+ onClick: handlePayment,
1996
+ disabled: isProcessing || !paymentDetails,
1997
+ loading: isProcessing,
1998
+ block: true,
1999
+ style: {
2000
+ height: "44px",
2001
+ fontSize: "14px",
2002
+ fontWeight: 600,
2003
+ borderRadius: "8px",
2004
+ ...!isProcessing && paymentDetails && {
2005
+ background: "#1a1a1a",
2006
+ borderColor: "#1a1a1a"
2007
+ },
2008
+ marginBottom: "10px"
2009
+ }
2010
+ },
2011
+ isProcessing ? "Processing..." : !paymentDetails ? "Loading..." : `Pay $${paymentDetails.amount} ${paymentDetails.currency}`
2012
+ ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Don't have USDC?", " "), /* @__PURE__ */ import_react7.default.createElement(
2013
+ "a",
2014
+ {
2015
+ href: "https://faucet.circle.com/",
2016
+ target: "_blank",
2017
+ rel: "noopener noreferrer",
2018
+ className: "text-blue-600 hover:text-blue-700 text-sm font-medium inline-flex items-center gap-1"
2019
+ },
2020
+ "Get it here ",
2021
+ /* @__PURE__ */ import_react7.default.createElement(import_icons.LinkOutlined, { style: { fontSize: "12px" } })
2022
+ )), isModal && result && /* @__PURE__ */ import_react7.default.createElement(
2023
+ "div",
2024
+ {
2025
+ className: "mt-4 p-4 rounded-lg",
2026
+ style: { background: "#f6ffed", border: "1px solid #b7eb8f" }
2027
+ },
2028
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px" } }, "\u2713"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
2029
+ fontSize: "14px",
2030
+ color: "#52c41a",
2031
+ fontWeight: 600,
2032
+ marginLeft: "8px"
2033
+ } }, "Payment Successful!"))
2034
+ ), isModal && error && /* @__PURE__ */ import_react7.default.createElement(
2035
+ "div",
2036
+ {
2037
+ className: "mt-4 p-4 rounded-lg",
2038
+ style: { background: "#fff2f0", border: "1px solid #ffccc7" }
2039
+ },
2040
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-3" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "20px" } }, "\u2717"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
2041
+ fontSize: "14px",
2042
+ color: "#ff4d4f",
2043
+ fontWeight: 600,
2044
+ marginLeft: "8px",
2045
+ display: "block",
2046
+ marginTop: "4px"
2047
+ } }, "Payment Failed")),
2048
+ /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
2049
+ fontSize: "13px",
2050
+ color: "#ff4d4f",
2051
+ display: "block",
2052
+ textAlign: "center"
2053
+ } }, error)
2054
+ ))
2055
+ ),
2056
+ !isModal && (isProcessing || result || error) && /* @__PURE__ */ import_react7.default.createElement(
2057
+ import_antd.Card,
2058
+ {
2059
+ title: /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center gap-2" }, isProcessing && !result && !error ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { color: "#14b8a6", fontSize: "16px" } }), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Processing Payment")) : result ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("span", { style: { color: "#52c41a", fontSize: "18px" } }, "\u2713"), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Successful")) : /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("span", { style: { color: "#ff4d4f", fontSize: "18px" } }, "\u2717"), /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Failed"))),
2060
+ extra: !isProcessing && /* @__PURE__ */ import_react7.default.createElement(
2061
+ import_antd.Button,
2062
+ {
2063
+ type: "text",
2064
+ size: "small",
2065
+ onClick: () => {
2066
+ setResult(null);
2067
+ setError(null);
2068
+ }
2069
+ },
2070
+ "Close"
2071
+ ),
2072
+ style: {
2073
+ border: "1px solid #e8e8e8",
2074
+ borderRadius: "16px",
2075
+ boxShadow: "0 4px 24px rgba(0, 0, 0, 0.06)",
2076
+ maxHeight: "calc(100vh - 32px)",
2077
+ width: "480px",
2078
+ animation: "slideInRight 0.4s ease-out"
2079
+ },
2080
+ styles: {
2081
+ body: {
2082
+ padding: "24px",
2083
+ maxHeight: "calc(100vh - 120px)",
2084
+ overflow: "auto"
2085
+ }
2086
+ }
2087
+ },
2088
+ isProcessing && !result && !error && /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center py-10" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "relative inline-block" }, /* @__PURE__ */ import_react7.default.createElement(
2089
+ "div",
2090
+ {
2091
+ className: "absolute inset-0 rounded-full blur-xl opacity-40",
2092
+ style: {
2093
+ background: "linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%)",
2094
+ animation: "pulse 2s ease-in-out infinite"
2095
+ }
2096
+ }
2097
+ ), /* @__PURE__ */ import_react7.default.createElement(
2098
+ import_antd.Spin,
2099
+ {
2100
+ indicator: /* @__PURE__ */ import_react7.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: 56, color: "#14b8a6" } })
2101
+ }
2102
+ )), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: { fontSize: "18px", color: "#262626", letterSpacing: "-0.02em" } }, "Verifying Payment")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-2 mb-6" }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", lineHeight: "1.6" } }, "Please wait while we confirm your transaction")), /* @__PURE__ */ import_react7.default.createElement(
2103
+ "div",
2104
+ {
2105
+ className: "mt-4 p-4 rounded-xl",
2106
+ style: {
2107
+ background: "linear-gradient(135deg, #f0fdfa 0%, #ecfeff 100%)",
2108
+ border: "1px solid #ccfbf1"
2109
+ }
2110
+ },
2111
+ /* @__PURE__ */ import_react7.default.createElement("div", { className: "flex items-center justify-center gap-2" }, /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "16px" } }, "\u23F1\uFE0F"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "13px", color: "#0f766e", fontWeight: 500 } }, "This may take a few moments"))
2112
+ )),
2113
+ result && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react7.default.createElement(
2114
+ "div",
2115
+ {
2116
+ className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
2117
+ style: {
2118
+ background: "linear-gradient(135deg, #10b981 0%, #34d399 100%)",
2119
+ boxShadow: "0 4px 20px rgba(16, 185, 129, 0.3)"
2120
+ }
2121
+ },
2122
+ /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2713")
2123
+ ), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: {
2124
+ fontSize: "20px",
2125
+ color: "#262626",
2126
+ display: "block",
2127
+ marginBottom: "8px"
2128
+ } }, "Payment Successful!"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Your transaction has been confirmed"))), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "RESPONSE DATA")), /* @__PURE__ */ import_react7.default.createElement(
2129
+ "pre",
2130
+ {
2131
+ style: {
2132
+ background: "#fafafa",
2133
+ padding: "20px",
2134
+ borderRadius: "12px",
2135
+ fontSize: "12px",
2136
+ lineHeight: "1.8",
2137
+ overflow: "auto",
2138
+ margin: 0,
2139
+ fontFamily: "Monaco, Courier New, monospace",
2140
+ whiteSpace: "pre-wrap",
2141
+ wordBreak: "break-word",
2142
+ border: "1px solid #e8e8e8",
2143
+ color: "#262626"
2144
+ }
2145
+ },
2146
+ JSON.stringify(result, null, 2)
2147
+ )),
2148
+ error && /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react7.default.createElement(
2149
+ "div",
2150
+ {
2151
+ className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
2152
+ style: {
2153
+ background: "linear-gradient(135deg, #ef4444 0%, #f87171 100%)",
2154
+ boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
2155
+ }
2156
+ },
2157
+ /* @__PURE__ */ import_react7.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2717")
2158
+ ), /* @__PURE__ */ import_react7.default.createElement("div", null, /* @__PURE__ */ import_react7.default.createElement(Text, { strong: true, style: {
2159
+ fontSize: "20px",
2160
+ color: "#262626",
2161
+ display: "block",
2162
+ marginBottom: "8px"
2163
+ } }, "Payment Failed"), /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Something went wrong with your transaction"))), /* @__PURE__ */ import_react7.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react7.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "ERROR DETAILS")), /* @__PURE__ */ import_react7.default.createElement(
2164
+ "div",
2165
+ {
2166
+ style: {
2167
+ background: "#fef2f2",
2168
+ padding: "20px",
2169
+ borderRadius: "12px",
2170
+ border: "1px solid #fee2e2"
2171
+ }
2172
+ },
2173
+ /* @__PURE__ */ import_react7.default.createElement(Text, { style: {
2174
+ fontSize: "14px",
2175
+ color: "#dc2626",
2176
+ lineHeight: "1.6",
2177
+ fontWeight: 500
2178
+ } }, error)
2179
+ ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "mt-4 text-center" }, /* @__PURE__ */ import_react7.default.createElement(
2180
+ import_antd.Button,
2181
+ {
2182
+ size: "large",
2183
+ onClick: handlePayment,
2184
+ style: {
2185
+ height: "44px",
2186
+ fontSize: "14px",
2187
+ fontWeight: 600,
2188
+ borderRadius: "8px",
2189
+ background: "#1a1a1a",
2190
+ borderColor: "#1a1a1a",
2191
+ color: "white",
2192
+ paddingLeft: "32px",
2193
+ paddingRight: "32px"
2194
+ }
2195
+ },
2196
+ "Try Again"
2197
+ )))
2198
+ )
2199
+ ),
2200
+ /* @__PURE__ */ import_react7.default.createElement("style", { dangerouslySetInnerHTML: {
2201
+ __html: `
2202
+ @keyframes slideInRight {
2203
+ from {
2204
+ opacity: 0;
2205
+ transform: translateX(100px);
2206
+ }
2207
+ to {
2208
+ opacity: 1;
2209
+ transform: translateX(0);
2210
+ }
2211
+ }
2212
+
2213
+ @keyframes pulse {
2214
+ 0%, 100% {
2215
+ transform: scale(1);
2216
+ opacity: 0.4;
2217
+ }
2218
+ 50% {
2219
+ transform: scale(1.1);
2220
+ opacity: 0.6;
2221
+ }
2222
+ }
2223
+ `
2224
+ } })
2225
+ );
805
2226
  }
806
2227
  // Annotate the CommonJS export names for ESM import in node:
807
2228
  0 && (module.exports = {
2229
+ V402Checkout,
808
2230
  WalletConnect,
2231
+ usePageNetwork,
809
2232
  usePayment,
810
2233
  usePaymentInfo,
811
2234
  useWallet