@voyage_ai/v402-web-ts 0.2.1 → 1.0.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.
- package/README.md +8 -4
- package/dist/index.d.mts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +301 -133
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +303 -141
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +140 -11
- package/dist/react/index.d.ts +140 -11
- package/dist/react/index.js +1717 -314
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1734 -327
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/styles.css +1 -1
- package/package.json +9 -2
package/dist/react/index.js
CHANGED
|
@@ -98,6 +98,28 @@ var init_types = __esm({
|
|
|
98
98
|
});
|
|
99
99
|
|
|
100
100
|
// src/utils/wallet.ts
|
|
101
|
+
var wallet_exports = {};
|
|
102
|
+
__export(wallet_exports, {
|
|
103
|
+
clearAllWalletAddresses: () => clearAllWalletAddresses,
|
|
104
|
+
clearWalletDisconnection: () => clearWalletDisconnection,
|
|
105
|
+
formatAddress: () => formatAddress,
|
|
106
|
+
getAllConnectedWalletIds: () => getAllConnectedWalletIds,
|
|
107
|
+
getAllWalletAddresses: () => getAllWalletAddresses,
|
|
108
|
+
getCachedWalletAddress: () => getCachedWalletAddress,
|
|
109
|
+
getConnectedNetworkType: () => getConnectedNetworkType,
|
|
110
|
+
getConnectedWalletId: () => getConnectedWalletId,
|
|
111
|
+
getWalletDisplayName: () => getWalletDisplayName,
|
|
112
|
+
getWalletInstallUrl: () => getWalletInstallUrl,
|
|
113
|
+
getWalletProvider: () => getWalletProvider,
|
|
114
|
+
isWalletInstalled: () => isWalletInstalled,
|
|
115
|
+
isWalletManuallyDisconnected: () => isWalletManuallyDisconnected,
|
|
116
|
+
markWalletDisconnected: () => markWalletDisconnected,
|
|
117
|
+
removeConnectedWalletId: () => removeConnectedWalletId,
|
|
118
|
+
removeWalletAddress: () => removeWalletAddress,
|
|
119
|
+
saveConnectedNetworkType: () => saveConnectedNetworkType,
|
|
120
|
+
saveConnectedWalletId: () => saveConnectedWalletId,
|
|
121
|
+
saveWalletAddress: () => saveWalletAddress
|
|
122
|
+
});
|
|
101
123
|
function isWalletInstalled(networkType) {
|
|
102
124
|
if (typeof window === "undefined") {
|
|
103
125
|
return false;
|
|
@@ -112,6 +134,20 @@ function isWalletInstalled(networkType) {
|
|
|
112
134
|
return false;
|
|
113
135
|
}
|
|
114
136
|
}
|
|
137
|
+
function getWalletProvider(networkType) {
|
|
138
|
+
if (typeof window === "undefined") {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
switch (networkType) {
|
|
142
|
+
case "evm" /* EVM */:
|
|
143
|
+
return window.ethereum;
|
|
144
|
+
case "solana" /* SOLANA */:
|
|
145
|
+
case "svm" /* SVM */:
|
|
146
|
+
return window.solana || window.phantom;
|
|
147
|
+
default:
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
115
151
|
function formatAddress(address) {
|
|
116
152
|
if (!address || address.length < 10) {
|
|
117
153
|
return address;
|
|
@@ -186,6 +222,17 @@ function getWalletInstallUrl(networkType) {
|
|
|
186
222
|
return "#";
|
|
187
223
|
}
|
|
188
224
|
}
|
|
225
|
+
function getWalletDisplayName(networkType) {
|
|
226
|
+
switch (networkType) {
|
|
227
|
+
case "evm" /* EVM */:
|
|
228
|
+
return "MetaMask";
|
|
229
|
+
case "solana" /* SOLANA */:
|
|
230
|
+
case "svm" /* SVM */:
|
|
231
|
+
return "Phantom";
|
|
232
|
+
default:
|
|
233
|
+
return "Unknown Wallet";
|
|
234
|
+
}
|
|
235
|
+
}
|
|
189
236
|
function getAllWalletAddresses() {
|
|
190
237
|
if (typeof window === "undefined") {
|
|
191
238
|
return {};
|
|
@@ -218,7 +265,44 @@ function removeWalletAddress(networkType) {
|
|
|
218
265
|
delete addresses[networkType];
|
|
219
266
|
localStorage.setItem(WALLET_ADDRESSES_KEY, JSON.stringify(addresses));
|
|
220
267
|
}
|
|
221
|
-
|
|
268
|
+
function clearAllWalletAddresses() {
|
|
269
|
+
if (typeof window !== "undefined") {
|
|
270
|
+
localStorage.removeItem(WALLET_ADDRESSES_KEY);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function getAllConnectedWalletIds() {
|
|
274
|
+
if (typeof window === "undefined") {
|
|
275
|
+
return {};
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
const cached = localStorage.getItem(CONNECTED_WALLET_IDS_KEY);
|
|
279
|
+
return cached ? JSON.parse(cached) : {};
|
|
280
|
+
} catch (error) {
|
|
281
|
+
console.error("Failed to parse connected wallet IDs:", error);
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function saveConnectedWalletId(networkType, walletId) {
|
|
286
|
+
if (typeof window === "undefined") {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const walletIds = getAllConnectedWalletIds();
|
|
290
|
+
walletIds[networkType] = walletId;
|
|
291
|
+
localStorage.setItem(CONNECTED_WALLET_IDS_KEY, JSON.stringify(walletIds));
|
|
292
|
+
}
|
|
293
|
+
function getConnectedWalletId(networkType) {
|
|
294
|
+
const walletIds = getAllConnectedWalletIds();
|
|
295
|
+
return walletIds[networkType] || null;
|
|
296
|
+
}
|
|
297
|
+
function removeConnectedWalletId(networkType) {
|
|
298
|
+
if (typeof window === "undefined") {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const walletIds = getAllConnectedWalletIds();
|
|
302
|
+
delete walletIds[networkType];
|
|
303
|
+
localStorage.setItem(CONNECTED_WALLET_IDS_KEY, JSON.stringify(walletIds));
|
|
304
|
+
}
|
|
305
|
+
var WALLET_DISCONNECTED_KEY, WALLET_DISCONNECTED_NETWORKS_KEY, CONNECTED_NETWORK_TYPE_KEY, WALLET_ADDRESSES_KEY, CONNECTED_WALLET_IDS_KEY;
|
|
222
306
|
var init_wallet = __esm({
|
|
223
307
|
"src/utils/wallet.ts"() {
|
|
224
308
|
"use strict";
|
|
@@ -226,17 +310,24 @@ var init_wallet = __esm({
|
|
|
226
310
|
WALLET_DISCONNECTED_NETWORKS_KEY = "wallet_disconnected_networks";
|
|
227
311
|
CONNECTED_NETWORK_TYPE_KEY = "connected_network_type";
|
|
228
312
|
WALLET_ADDRESSES_KEY = "wallet_addresses_cache";
|
|
313
|
+
CONNECTED_WALLET_IDS_KEY = "connected_wallet_ids";
|
|
229
314
|
}
|
|
230
315
|
});
|
|
231
316
|
|
|
232
317
|
// src/react/index.ts
|
|
233
318
|
var index_exports = {};
|
|
234
319
|
__export(index_exports, {
|
|
320
|
+
AnimationStyles: () => AnimationStyles,
|
|
321
|
+
Toast: () => Toast,
|
|
235
322
|
V402Checkout: () => V402Checkout,
|
|
323
|
+
V402CheckoutV2: () => V402CheckoutV2,
|
|
236
324
|
WalletConnect: () => WalletConnect,
|
|
325
|
+
WalletSelectModal: () => WalletSelectModal,
|
|
326
|
+
checkoutAnimations: () => checkoutAnimations,
|
|
237
327
|
usePageNetwork: () => usePageNetwork,
|
|
238
328
|
usePayment: () => usePayment,
|
|
239
329
|
usePaymentInfo: () => usePaymentInfo,
|
|
330
|
+
useToast: () => useToast,
|
|
240
331
|
useWallet: () => useWallet
|
|
241
332
|
});
|
|
242
333
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -250,45 +341,143 @@ init_wallet();
|
|
|
250
341
|
|
|
251
342
|
// src/utils/wallet-connect.ts
|
|
252
343
|
init_wallet();
|
|
253
|
-
async function connectWallet(networkType) {
|
|
344
|
+
async function connectWallet(networkType, forceSelect = false) {
|
|
254
345
|
if (typeof window === "undefined") {
|
|
255
|
-
throw new Error("
|
|
346
|
+
throw new Error("Please use in browser environment");
|
|
256
347
|
}
|
|
257
348
|
let address;
|
|
258
349
|
switch (networkType) {
|
|
259
350
|
case "evm" /* EVM */: {
|
|
260
351
|
if (!window.ethereum) {
|
|
261
|
-
throw new Error("
|
|
352
|
+
throw new Error("Please install MetaMask or another Ethereum wallet");
|
|
262
353
|
}
|
|
263
354
|
const ethereum = window.ethereum;
|
|
355
|
+
if (forceSelect) {
|
|
356
|
+
try {
|
|
357
|
+
const permissions = await ethereum.request({
|
|
358
|
+
method: "wallet_requestPermissions",
|
|
359
|
+
params: [{ eth_accounts: {} }]
|
|
360
|
+
});
|
|
361
|
+
const accountsPermission = permissions?.find(
|
|
362
|
+
(p) => p.parentCapability === "eth_accounts"
|
|
363
|
+
);
|
|
364
|
+
if (accountsPermission?.caveats?.[0]?.value?.length > 0) {
|
|
365
|
+
address = accountsPermission.caveats[0].value[0];
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
} catch (err) {
|
|
369
|
+
if (err.code === 4001) {
|
|
370
|
+
throw new Error("User cancelled wallet connection");
|
|
371
|
+
}
|
|
372
|
+
console.warn("wallet_requestPermissions failed, falling back to eth_requestAccounts");
|
|
373
|
+
}
|
|
374
|
+
}
|
|
264
375
|
const accounts = await ethereum.request({
|
|
265
376
|
method: "eth_requestAccounts",
|
|
266
377
|
params: []
|
|
267
378
|
});
|
|
268
379
|
if (!accounts || accounts.length === 0) {
|
|
269
|
-
throw new Error("
|
|
380
|
+
throw new Error("Failed to get wallet address");
|
|
270
381
|
}
|
|
271
382
|
address = accounts[0];
|
|
272
383
|
break;
|
|
273
384
|
}
|
|
274
385
|
case "solana" /* SOLANA */:
|
|
275
386
|
case "svm" /* SVM */: {
|
|
276
|
-
const
|
|
387
|
+
const phantom = window.phantom?.solana || window.solana;
|
|
388
|
+
const solflare = window.solflare;
|
|
389
|
+
let solana = phantom;
|
|
390
|
+
if (!solana && solflare?.isSolflare) {
|
|
391
|
+
solana = solflare;
|
|
392
|
+
}
|
|
277
393
|
if (!solana) {
|
|
278
|
-
throw new Error("
|
|
394
|
+
throw new Error("Please install Phantom or another Solana wallet");
|
|
395
|
+
}
|
|
396
|
+
if (forceSelect) {
|
|
397
|
+
try {
|
|
398
|
+
if (phantom?.isConnected) {
|
|
399
|
+
await phantom.disconnect();
|
|
400
|
+
}
|
|
401
|
+
if (solflare?.isConnected) {
|
|
402
|
+
await solflare.disconnect();
|
|
403
|
+
}
|
|
404
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
405
|
+
} catch (err) {
|
|
406
|
+
console.warn("Failed to disconnect Solana wallet:", err);
|
|
407
|
+
}
|
|
408
|
+
} else if (solana.isConnected) {
|
|
409
|
+
try {
|
|
410
|
+
await solana.disconnect();
|
|
411
|
+
} catch (err) {
|
|
412
|
+
console.warn("Failed to disconnect Solana wallet:", err);
|
|
413
|
+
}
|
|
279
414
|
}
|
|
280
415
|
const response = await solana.connect();
|
|
281
416
|
address = response.publicKey.toString();
|
|
282
417
|
break;
|
|
283
418
|
}
|
|
284
419
|
default:
|
|
285
|
-
throw new Error("
|
|
420
|
+
throw new Error("Unsupported network type");
|
|
286
421
|
}
|
|
287
422
|
clearWalletDisconnection(networkType);
|
|
288
423
|
saveConnectedNetworkType(networkType);
|
|
289
424
|
saveWalletAddress(networkType, address);
|
|
290
425
|
return address;
|
|
291
426
|
}
|
|
427
|
+
async function disconnectAllSolanaWallets() {
|
|
428
|
+
if (typeof window === "undefined") return;
|
|
429
|
+
const phantom = window.phantom?.solana || window.solana;
|
|
430
|
+
const solflare = window.solflare;
|
|
431
|
+
const disconnectPromises = [];
|
|
432
|
+
if (phantom?.isConnected) {
|
|
433
|
+
disconnectPromises.push(
|
|
434
|
+
phantom.disconnect().catch(
|
|
435
|
+
(err) => console.warn("Failed to disconnect Phantom:", err)
|
|
436
|
+
)
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (solflare?.isConnected) {
|
|
440
|
+
disconnectPromises.push(
|
|
441
|
+
solflare.disconnect().catch(
|
|
442
|
+
(err) => console.warn("Failed to disconnect Solflare:", err)
|
|
443
|
+
)
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
await Promise.all(disconnectPromises);
|
|
447
|
+
}
|
|
448
|
+
async function disconnectWallet(networkType, clearAll = false) {
|
|
449
|
+
const targetNetwork = networkType || getConnectedNetworkType();
|
|
450
|
+
if (targetNetwork && typeof window !== "undefined") {
|
|
451
|
+
try {
|
|
452
|
+
switch (targetNetwork) {
|
|
453
|
+
case "solana" /* SOLANA */:
|
|
454
|
+
case "svm" /* SVM */: {
|
|
455
|
+
await disconnectAllSolanaWallets();
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
// EVM wallets (like MetaMask) don't have a real disconnect API
|
|
459
|
+
// Only clear local state, will request permissions again on next connection
|
|
460
|
+
case "evm" /* EVM */:
|
|
461
|
+
default:
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
} catch (err) {
|
|
465
|
+
console.warn("Failed to disconnect wallet:", err);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (clearAll) {
|
|
469
|
+
const { clearAllWalletAddresses: clearAllWalletAddresses2 } = (init_wallet(), __toCommonJS(wallet_exports));
|
|
470
|
+
clearAllWalletAddresses2();
|
|
471
|
+
markWalletDisconnected();
|
|
472
|
+
await disconnectAllSolanaWallets();
|
|
473
|
+
} else if (networkType) {
|
|
474
|
+
removeWalletAddress(networkType);
|
|
475
|
+
} else {
|
|
476
|
+
if (targetNetwork) {
|
|
477
|
+
removeWalletAddress(targetNetwork);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
292
481
|
async function getCurrentWallet(networkType) {
|
|
293
482
|
if (typeof window === "undefined") {
|
|
294
483
|
return null;
|
|
@@ -298,36 +487,32 @@ async function getCurrentWallet(networkType) {
|
|
|
298
487
|
return null;
|
|
299
488
|
}
|
|
300
489
|
const cachedAddress = getCachedWalletAddress(type);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
490
|
+
if (type === "evm" /* EVM */) {
|
|
491
|
+
if (cachedAddress) {
|
|
492
|
+
return cachedAddress;
|
|
493
|
+
}
|
|
494
|
+
if (window.ethereum) {
|
|
495
|
+
try {
|
|
306
496
|
const accounts = await window.ethereum.request({
|
|
307
497
|
method: "eth_accounts",
|
|
308
498
|
params: []
|
|
309
499
|
});
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
case "svm" /* SVM */: {
|
|
315
|
-
const solana = window.solana;
|
|
316
|
-
if (!solana || !solana.isConnected) return cachedAddress;
|
|
317
|
-
currentAddress = solana.publicKey?.toString() || null;
|
|
318
|
-
break;
|
|
500
|
+
return accounts && accounts.length > 0 ? accounts[0] : null;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
console.error("Failed to get EVM accounts:", error);
|
|
503
|
+
return null;
|
|
319
504
|
}
|
|
320
|
-
default:
|
|
321
|
-
return cachedAddress;
|
|
322
505
|
}
|
|
323
|
-
|
|
324
|
-
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
if (type === "solana" /* SOLANA */ || type === "svm" /* SVM */) {
|
|
509
|
+
const solana = window.solana;
|
|
510
|
+
if (!solana || !solana.isConnected) {
|
|
511
|
+
return cachedAddress;
|
|
325
512
|
}
|
|
326
|
-
return
|
|
327
|
-
} catch (error) {
|
|
328
|
-
console.error("Failed to get current wallet:", error);
|
|
329
|
-
return cachedAddress;
|
|
513
|
+
return solana.publicKey?.toString() || cachedAddress;
|
|
330
514
|
}
|
|
515
|
+
return cachedAddress;
|
|
331
516
|
}
|
|
332
517
|
function onAccountsChanged(callback) {
|
|
333
518
|
if (typeof window === "undefined" || !window.ethereum) {
|
|
@@ -390,12 +575,251 @@ async function switchNetwork(networkType) {
|
|
|
390
575
|
return null;
|
|
391
576
|
}
|
|
392
577
|
|
|
578
|
+
// src/utils/wallet-discovery.ts
|
|
579
|
+
init_wallet();
|
|
580
|
+
var SOLANA_WALLETS = [
|
|
581
|
+
{
|
|
582
|
+
id: "phantom",
|
|
583
|
+
name: "Phantom",
|
|
584
|
+
// Phantom official icon
|
|
585
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNBQjlGRjIiLz4KPHBhdGggZD0iTTExMC41IDY0QzExMC41IDg5Ljk1NjggODkuMjAxIDExMSA2My41IDExMUg0MS41QzM2LjI1MzMgMTExIDMyIDEwNi43NDcgMzIgMTAxLjVWNTQuNUMzMiAzMS4wMjggNTEuMDI4IDEyIDc0LjUgMTJDOTcuOTcyIDEyIDExNyAzMS4wMjggMTE3IDU0LjVWNTUuNUMxMTcgNTguNTM3NiAxMTQuNTM4IDYxIDExMS41IDYxSDEwOS41QzEwNi40NjIgNjEgMTA0IDYzLjQ2MjQgMTA0IDY2LjVWNjhDMTA0IDcxLjg2NiAxMDcuMTM0IDc1IDExMSA3NUgxMTEuNUMxMTQuNTM4IDc1IDExNyA3Mi41Mzc2IDExNyA2OS41VjY0SDExMC41WiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzEyOF8xMjgpIi8+CjxwYXRoIGQ9Ik00OC41IDY3QzUxLjUzNzYgNjcgNTQgNjQuNTM3NiA1NCA2MS41QzU0IDU4LjQ2MjQgNTEuNTM3NiA1NiA0OC41IDU2QzQ1LjQ2MjQgNTYgNDMgNTguNDYyNCA0MyA2MS41QzQzIDY0LjUzNzYgNDUuNDYyNCA2NyA0OC41IDY3WiIgZmlsbD0iIzFCMUIxQiIvPgo8cGF0aCBkPSJNNzMuNSA2N0M3Ni41Mzc2IDY3IDc5IDY0LjUzNzYgNzkgNjEuNUM3OSA1OC40NjI0IDc2LjUzNzYgNTYgNzMuNSA1NkM3MC40NjI0IDU2IDY4IDU4LjQ2MjQgNjggNjEuNUM2OCA2NC41Mzc2IDcwLjQ2MjQgNjcgNzMuNSA2N1oiIGZpbGw9IiMxQjFCMUIiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl8xMjhfMTI4IiB4MT0iMTE3IiB5MT0iMTIiIHgyPSIxMTciIHkyPSIxMTEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRkZGRiIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkZGRkYiIHN0b3Atb3BhY2l0eT0iMC44MiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPg==",
|
|
586
|
+
detect: () => window.phantom?.solana
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
id: "solflare",
|
|
590
|
+
name: "Solflare",
|
|
591
|
+
// Solflare icon
|
|
592
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNGQzZEMDEiLz4KPHBhdGggZD0iTTk2IDY0TDY0IDMyTDMyIDY0TDY0IDk2TDk2IDY0WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+",
|
|
593
|
+
detect: () => window.solflare
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
id: "backpack",
|
|
597
|
+
name: "Backpack",
|
|
598
|
+
// Backpack icon (red coral color)
|
|
599
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiNFMzM0MzAiLz4KPHBhdGggZD0iTTQwIDQ4SDg4VjgwQzg4IDg4LjgzNjYgODAuODM2NiA5NiA3MiA5Nkg1NkM0Ny4xNjM0IDk2IDQwIDg4LjgzNjYgNDAgODBWNDhaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNTIgMzJINzZWNDhINTJWMzJaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4=",
|
|
600
|
+
detect: () => window.backpack
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
id: "okx-solana",
|
|
604
|
+
name: "OKX Wallet",
|
|
605
|
+
// OKX icon
|
|
606
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9ImJsYWNrIi8+CjxyZWN0IHg9IjI0IiB5PSIyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iNTIiIHk9IjI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8cmVjdCB4PSI4MCIgeT0iMjQiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjI0IiB5PSI1MiIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iODAiIHk9IjUyIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8cmVjdCB4PSIyNCIgeT0iODAiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjUyIiB5PSI4MCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHJlY3QgeD0iODAiIHk9IjgwIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4=",
|
|
607
|
+
detect: () => window.okxwallet?.solana
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
id: "coinbase-solana",
|
|
611
|
+
name: "Coinbase Wallet",
|
|
612
|
+
// Coinbase icon (blue)
|
|
613
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiMwMDUyRkYiLz4KPGNpcmNsZSBjeD0iNjQiIGN5PSI2NCIgcj0iMzYiIGZpbGw9IndoaXRlIi8+CjxyZWN0IHg9IjQ4IiB5PSI1NiIgd2lkdGg9IjMyIiBoZWlnaHQ9IjE2IiByeD0iNCIgZmlsbD0iIzAwNTJGRiIvPgo8L3N2Zz4=",
|
|
614
|
+
detect: () => window.coinbaseSolana
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
id: "trust-solana",
|
|
618
|
+
name: "Trust Wallet",
|
|
619
|
+
// Trust Wallet icon
|
|
620
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjYiIGZpbGw9IiMwNTAwRkYiLz4KPHBhdGggZD0iTTY0IDI0QzY0IDI0IDk2IDQwIDk2IDY0Qzk2IDg4IDY0IDEwNCA2NCAxMDRDNjQgMTA0IDMyIDg4IDMyIDY0QzMyIDQwIDY0IDI0IDY0IDI0WiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSI2IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==",
|
|
621
|
+
detect: () => window.trustwallet?.solana
|
|
622
|
+
}
|
|
623
|
+
];
|
|
624
|
+
var evmWallets = /* @__PURE__ */ new Map();
|
|
625
|
+
var evmDiscoveryListeners = /* @__PURE__ */ new Set();
|
|
626
|
+
var evmDiscoveryInitialized = false;
|
|
627
|
+
var currentConnectedWallet = null;
|
|
628
|
+
function initEVMWalletDiscovery() {
|
|
629
|
+
if (typeof window === "undefined" || evmDiscoveryInitialized) return;
|
|
630
|
+
evmDiscoveryInitialized = true;
|
|
631
|
+
window.addEventListener("eip6963:announceProvider", ((event) => {
|
|
632
|
+
const { info, provider } = event.detail;
|
|
633
|
+
evmWallets.set(info.uuid, { info, provider });
|
|
634
|
+
evmDiscoveryListeners.forEach((listener) => listener());
|
|
635
|
+
}));
|
|
636
|
+
window.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
637
|
+
}
|
|
638
|
+
function getEVMWallets() {
|
|
639
|
+
const wallets = [];
|
|
640
|
+
const detectedNames = /* @__PURE__ */ new Set();
|
|
641
|
+
evmWallets.forEach((detail, uuid) => {
|
|
642
|
+
if (!detectedNames.has(detail.info.name)) {
|
|
643
|
+
wallets.push({
|
|
644
|
+
id: uuid,
|
|
645
|
+
name: detail.info.name,
|
|
646
|
+
icon: detail.info.icon,
|
|
647
|
+
networkType: "evm" /* EVM */,
|
|
648
|
+
provider: detail.provider,
|
|
649
|
+
installed: true
|
|
650
|
+
});
|
|
651
|
+
detectedNames.add(detail.info.name);
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
if (wallets.length === 0 && typeof window !== "undefined" && window.ethereum) {
|
|
655
|
+
const ethereum = window.ethereum;
|
|
656
|
+
const walletName = ethereum.isMetaMask ? "MetaMask" : ethereum.isCoinbaseWallet ? "Coinbase Wallet" : ethereum.isOkxWallet ? "OKX Wallet" : "Browser Wallet";
|
|
657
|
+
if (!detectedNames.has(walletName)) {
|
|
658
|
+
wallets.push({
|
|
659
|
+
id: "injected",
|
|
660
|
+
name: walletName,
|
|
661
|
+
icon: "",
|
|
662
|
+
// Will use first letter as avatar
|
|
663
|
+
networkType: "evm" /* EVM */,
|
|
664
|
+
provider: ethereum,
|
|
665
|
+
installed: true
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return wallets;
|
|
670
|
+
}
|
|
671
|
+
function onEVMWalletsChanged(callback) {
|
|
672
|
+
evmDiscoveryListeners.add(callback);
|
|
673
|
+
return () => {
|
|
674
|
+
evmDiscoveryListeners.delete(callback);
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
function getSolanaWallets() {
|
|
678
|
+
if (typeof window === "undefined") return [];
|
|
679
|
+
const wallets = [];
|
|
680
|
+
const detectedProviders = /* @__PURE__ */ new Set();
|
|
681
|
+
const detectedNames = /* @__PURE__ */ new Set();
|
|
682
|
+
for (const wallet of SOLANA_WALLETS) {
|
|
683
|
+
const provider = wallet.detect();
|
|
684
|
+
if (provider && !detectedNames.has(wallet.name)) {
|
|
685
|
+
wallets.push({
|
|
686
|
+
id: wallet.id,
|
|
687
|
+
name: wallet.name,
|
|
688
|
+
icon: wallet.icon,
|
|
689
|
+
networkType: "solana" /* SOLANA */,
|
|
690
|
+
provider,
|
|
691
|
+
installed: true
|
|
692
|
+
});
|
|
693
|
+
detectedProviders.add(provider);
|
|
694
|
+
detectedNames.add(wallet.name);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
const windowSolana = window.solana;
|
|
698
|
+
if (windowSolana && !detectedProviders.has(windowSolana)) {
|
|
699
|
+
const walletName = windowSolana.isPhantom ? "Phantom" : windowSolana.isSolflare ? "Solflare" : windowSolana.isBackpack ? "Backpack" : windowSolana.walletName || "Solana Wallet";
|
|
700
|
+
if (!detectedNames.has(walletName)) {
|
|
701
|
+
wallets.push({
|
|
702
|
+
id: "solana-unknown",
|
|
703
|
+
name: walletName,
|
|
704
|
+
icon: "",
|
|
705
|
+
// Will use first letter as avatar
|
|
706
|
+
networkType: "solana" /* SOLANA */,
|
|
707
|
+
provider: windowSolana,
|
|
708
|
+
installed: true
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return wallets;
|
|
713
|
+
}
|
|
714
|
+
function getWalletsForNetwork(networkType) {
|
|
715
|
+
switch (networkType) {
|
|
716
|
+
case "evm" /* EVM */:
|
|
717
|
+
return getEVMWallets();
|
|
718
|
+
case "solana" /* SOLANA */:
|
|
719
|
+
case "svm" /* SVM */:
|
|
720
|
+
return getSolanaWallets();
|
|
721
|
+
default:
|
|
722
|
+
return [];
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
function getWalletByName(name, networkType) {
|
|
726
|
+
const wallets = getWalletsForNetwork(networkType);
|
|
727
|
+
return wallets.find((w) => w.name === name) || null;
|
|
728
|
+
}
|
|
729
|
+
async function connectEVMWallet(wallet) {
|
|
730
|
+
if (!wallet.provider) {
|
|
731
|
+
throw new Error(`Wallet ${wallet.name} is not available`);
|
|
732
|
+
}
|
|
733
|
+
const accounts = await wallet.provider.request({
|
|
734
|
+
method: "eth_requestAccounts",
|
|
735
|
+
params: []
|
|
736
|
+
});
|
|
737
|
+
if (!accounts || accounts.length === 0) {
|
|
738
|
+
throw new Error("Failed to get wallet address");
|
|
739
|
+
}
|
|
740
|
+
return accounts[0];
|
|
741
|
+
}
|
|
742
|
+
async function connectSolanaWallet(wallet) {
|
|
743
|
+
if (!wallet.provider) {
|
|
744
|
+
throw new Error(`Wallet ${wallet.name} is not available`);
|
|
745
|
+
}
|
|
746
|
+
if (wallet.provider.isConnected) {
|
|
747
|
+
try {
|
|
748
|
+
await wallet.provider.disconnect();
|
|
749
|
+
} catch (err) {
|
|
750
|
+
console.warn("Failed to disconnect before connecting:", err);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
const response = await wallet.provider.connect();
|
|
754
|
+
return response.publicKey.toString();
|
|
755
|
+
}
|
|
756
|
+
async function connectToWallet(wallet) {
|
|
757
|
+
let address;
|
|
758
|
+
switch (wallet.networkType) {
|
|
759
|
+
case "evm" /* EVM */:
|
|
760
|
+
address = await connectEVMWallet(wallet);
|
|
761
|
+
break;
|
|
762
|
+
case "solana" /* SOLANA */:
|
|
763
|
+
case "svm" /* SVM */:
|
|
764
|
+
address = await connectSolanaWallet(wallet);
|
|
765
|
+
break;
|
|
766
|
+
default:
|
|
767
|
+
throw new Error("Unsupported network type");
|
|
768
|
+
}
|
|
769
|
+
currentConnectedWallet = wallet;
|
|
770
|
+
saveConnectedWalletId(wallet.networkType, wallet.name);
|
|
771
|
+
return address;
|
|
772
|
+
}
|
|
773
|
+
function setCurrentConnectedWallet(wallet) {
|
|
774
|
+
currentConnectedWallet = wallet;
|
|
775
|
+
}
|
|
776
|
+
function clearConnectedWallet(networkType) {
|
|
777
|
+
if (networkType) {
|
|
778
|
+
removeConnectedWalletId(networkType);
|
|
779
|
+
}
|
|
780
|
+
currentConnectedWallet = null;
|
|
781
|
+
}
|
|
782
|
+
function restoreConnectedWallet(networkType) {
|
|
783
|
+
const savedWalletName = getConnectedWalletId(networkType);
|
|
784
|
+
if (!savedWalletName) return null;
|
|
785
|
+
const wallet = getWalletByName(savedWalletName, networkType);
|
|
786
|
+
if (wallet) {
|
|
787
|
+
currentConnectedWallet = wallet;
|
|
788
|
+
console.log(`\u2705 Restored wallet provider: ${wallet.name}`);
|
|
789
|
+
return wallet;
|
|
790
|
+
}
|
|
791
|
+
console.warn(`\u26A0\uFE0F Could not find wallet with name: ${savedWalletName}`);
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
function getWalletProviderForPayment(networkType) {
|
|
795
|
+
if (currentConnectedWallet && currentConnectedWallet.networkType === networkType) {
|
|
796
|
+
return currentConnectedWallet.provider;
|
|
797
|
+
}
|
|
798
|
+
const restoredWallet = restoreConnectedWallet(networkType);
|
|
799
|
+
if (restoredWallet) {
|
|
800
|
+
return restoredWallet.provider;
|
|
801
|
+
}
|
|
802
|
+
if (typeof window === "undefined") return null;
|
|
803
|
+
switch (networkType) {
|
|
804
|
+
case "evm" /* EVM */:
|
|
805
|
+
return window.ethereum;
|
|
806
|
+
case "solana" /* SOLANA */:
|
|
807
|
+
case "svm" /* SVM */:
|
|
808
|
+
return window.phantom?.solana || window.solana;
|
|
809
|
+
default:
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
if (typeof window !== "undefined") {
|
|
814
|
+
initEVMWalletDiscovery();
|
|
815
|
+
}
|
|
816
|
+
|
|
393
817
|
// src/services/svm/payment-header.ts
|
|
394
818
|
var import_web3 = require("@solana/web3.js");
|
|
395
819
|
var import_spl_token = require("@solana/spl-token");
|
|
396
820
|
async function createSvmPaymentHeader(params) {
|
|
397
821
|
const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
|
|
398
|
-
const connection = new import_web3.Connection(rpcUrl
|
|
822
|
+
const connection = new import_web3.Connection(rpcUrl);
|
|
399
823
|
const feePayer = paymentRequirements?.extra?.feePayer;
|
|
400
824
|
if (typeof feePayer !== "string" || !feePayer) {
|
|
401
825
|
throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
|
|
@@ -409,83 +833,85 @@ async function createSvmPaymentHeader(params) {
|
|
|
409
833
|
if (!paymentRequirements?.payTo) {
|
|
410
834
|
throw new Error("Missing payTo in payment requirements");
|
|
411
835
|
}
|
|
412
|
-
const
|
|
413
|
-
const instructions = [];
|
|
414
|
-
instructions.push(
|
|
415
|
-
import_web3.ComputeBudgetProgram.setComputeUnitLimit({
|
|
416
|
-
units: 7e3
|
|
417
|
-
// Sufficient for SPL token transfer
|
|
418
|
-
})
|
|
419
|
-
);
|
|
420
|
-
instructions.push(
|
|
421
|
-
import_web3.ComputeBudgetProgram.setComputeUnitPrice({
|
|
422
|
-
microLamports: 1
|
|
423
|
-
// Minimal price
|
|
424
|
-
})
|
|
425
|
-
);
|
|
836
|
+
const destinationPubkey = new import_web3.PublicKey(paymentRequirements.payTo);
|
|
426
837
|
if (!paymentRequirements.asset) {
|
|
427
838
|
throw new Error("Missing token mint for SPL transfer");
|
|
428
839
|
}
|
|
429
840
|
const mintPubkey = new import_web3.PublicKey(paymentRequirements.asset);
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
841
|
+
const mintAccountInfo = await connection.getAccountInfo(mintPubkey);
|
|
842
|
+
if (!mintAccountInfo) {
|
|
843
|
+
throw new Error(`Mint account ${mintPubkey.toBase58()} not found`);
|
|
844
|
+
}
|
|
845
|
+
const tokenProgramId = mintAccountInfo.owner.equals(import_spl_token.TOKEN_2022_PROGRAM_ID) ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
|
|
846
|
+
const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, tokenProgramId);
|
|
847
|
+
const sourceAta = (0, import_spl_token.getAssociatedTokenAddressSync)(
|
|
434
848
|
mintPubkey,
|
|
435
849
|
userPubkey,
|
|
436
850
|
false,
|
|
437
|
-
|
|
851
|
+
tokenProgramId
|
|
438
852
|
);
|
|
439
|
-
const destinationAta =
|
|
853
|
+
const destinationAta = (0, import_spl_token.getAssociatedTokenAddressSync)(
|
|
440
854
|
mintPubkey,
|
|
441
|
-
|
|
855
|
+
destinationPubkey,
|
|
442
856
|
false,
|
|
443
|
-
|
|
857
|
+
tokenProgramId
|
|
444
858
|
);
|
|
445
|
-
const sourceAtaInfo = await connection.getAccountInfo(sourceAta
|
|
859
|
+
const sourceAtaInfo = await connection.getAccountInfo(sourceAta);
|
|
446
860
|
if (!sourceAtaInfo) {
|
|
447
861
|
throw new Error(
|
|
448
862
|
`User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
|
|
449
863
|
);
|
|
450
864
|
}
|
|
451
|
-
const destAtaInfo = await connection.getAccountInfo(destinationAta
|
|
865
|
+
const destAtaInfo = await connection.getAccountInfo(destinationAta);
|
|
452
866
|
if (!destAtaInfo) {
|
|
453
867
|
throw new Error(
|
|
454
868
|
`Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
|
|
455
869
|
);
|
|
456
870
|
}
|
|
457
|
-
const
|
|
458
|
-
|
|
871
|
+
const instructions = [
|
|
872
|
+
import_web3.ComputeBudgetProgram.setComputeUnitLimit({
|
|
873
|
+
units: 7e3
|
|
874
|
+
// Sufficient for SPL token transfer
|
|
875
|
+
}),
|
|
876
|
+
import_web3.ComputeBudgetProgram.setComputeUnitPrice({
|
|
877
|
+
microLamports: 1
|
|
878
|
+
// Minimal price
|
|
879
|
+
}),
|
|
459
880
|
(0, import_spl_token.createTransferCheckedInstruction)(
|
|
460
881
|
sourceAta,
|
|
461
882
|
mintPubkey,
|
|
462
883
|
destinationAta,
|
|
463
884
|
userPubkey,
|
|
464
|
-
|
|
885
|
+
BigInt(paymentRequirements.maxAmountRequired),
|
|
465
886
|
mint.decimals,
|
|
466
887
|
[],
|
|
467
|
-
|
|
888
|
+
tokenProgramId
|
|
468
889
|
)
|
|
469
|
-
|
|
470
|
-
const { blockhash } = await connection.getLatestBlockhash(
|
|
471
|
-
const
|
|
890
|
+
];
|
|
891
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
892
|
+
const messageV0 = new import_web3.TransactionMessage({
|
|
472
893
|
payerKey: feePayerPubkey,
|
|
473
894
|
recentBlockhash: blockhash,
|
|
474
895
|
instructions
|
|
475
896
|
}).compileToV0Message();
|
|
476
|
-
const transaction = new import_web3.VersionedTransaction(
|
|
897
|
+
const transaction = new import_web3.VersionedTransaction(messageV0);
|
|
477
898
|
if (typeof wallet?.signTransaction !== "function") {
|
|
478
899
|
throw new Error("Connected wallet does not support signTransaction");
|
|
479
900
|
}
|
|
480
|
-
let
|
|
901
|
+
let signedTransaction;
|
|
481
902
|
try {
|
|
482
|
-
|
|
903
|
+
signedTransaction = await wallet.signTransaction(transaction);
|
|
483
904
|
console.log("\u2705 Transaction signed successfully");
|
|
484
905
|
} catch (error) {
|
|
485
906
|
console.error("\u274C Failed to sign transaction:", error);
|
|
486
907
|
throw wrapPaymentError(error);
|
|
487
908
|
}
|
|
488
|
-
const
|
|
909
|
+
const serializedBytes = signedTransaction.serialize();
|
|
910
|
+
let binary = "";
|
|
911
|
+
for (let i = 0; i < serializedBytes.length; i++) {
|
|
912
|
+
binary += String.fromCharCode(serializedBytes[i]);
|
|
913
|
+
}
|
|
914
|
+
const serializedTransaction = btoa(binary);
|
|
489
915
|
const paymentPayload = {
|
|
490
916
|
x402Version,
|
|
491
917
|
scheme: paymentRequirements.scheme,
|
|
@@ -494,7 +920,7 @@ async function createSvmPaymentHeader(params) {
|
|
|
494
920
|
transaction: serializedTransaction
|
|
495
921
|
}
|
|
496
922
|
};
|
|
497
|
-
const paymentHeader =
|
|
923
|
+
const paymentHeader = btoa(JSON.stringify(paymentPayload));
|
|
498
924
|
return paymentHeader;
|
|
499
925
|
}
|
|
500
926
|
function getDefaultSolanaRpcUrl(network) {
|
|
@@ -510,7 +936,7 @@ function getDefaultSolanaRpcUrl(network) {
|
|
|
510
936
|
// src/services/svm/payment-handler.ts
|
|
511
937
|
init_types();
|
|
512
938
|
async function handleSvmPayment(endpoint, config, requestInit) {
|
|
513
|
-
const { wallet,
|
|
939
|
+
const { wallet, rpcUrl, maxPaymentAmount } = config;
|
|
514
940
|
const initialResponse = await fetch(endpoint, {
|
|
515
941
|
...requestInit,
|
|
516
942
|
method: requestInit?.method || "POST"
|
|
@@ -519,26 +945,10 @@ async function handleSvmPayment(endpoint, config, requestInit) {
|
|
|
519
945
|
return initialResponse;
|
|
520
946
|
}
|
|
521
947
|
const rawResponse = await initialResponse.json();
|
|
522
|
-
|
|
523
|
-
"X-PAYMENT header is required",
|
|
524
|
-
"missing X-PAYMENT header",
|
|
525
|
-
"payment_required"
|
|
526
|
-
];
|
|
527
|
-
if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
|
|
948
|
+
if (rawResponse.error && !IGNORED_402_ERRORS.includes(rawResponse.error)) {
|
|
528
949
|
console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
"invalid_signature": "Invalid payment signature",
|
|
532
|
-
"expired": "Payment authorization has expired",
|
|
533
|
-
"already_used": "This payment has already been used",
|
|
534
|
-
"network_mismatch": "Payment network does not match",
|
|
535
|
-
"invalid_payment": "Invalid payment data",
|
|
536
|
-
"verification_failed": "Payment verification failed",
|
|
537
|
-
"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."
|
|
538
|
-
};
|
|
539
|
-
const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
540
|
-
const error = new Error(errorMessage);
|
|
541
|
-
throw wrapPaymentError(error);
|
|
950
|
+
const errorMessage = PAYMENT_ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
951
|
+
throw wrapPaymentError(new Error(errorMessage));
|
|
542
952
|
}
|
|
543
953
|
const x402Version = rawResponse.x402Version;
|
|
544
954
|
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
@@ -588,26 +998,10 @@ async function handleSvmPayment(endpoint, config, requestInit) {
|
|
|
588
998
|
if (retryResponse.status === 402) {
|
|
589
999
|
try {
|
|
590
1000
|
const retryData = await retryResponse.json();
|
|
591
|
-
|
|
592
|
-
"X-PAYMENT header is required",
|
|
593
|
-
"missing X-PAYMENT header",
|
|
594
|
-
"payment_required"
|
|
595
|
-
];
|
|
596
|
-
if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
|
|
1001
|
+
if (retryData.error && !IGNORED_402_ERRORS.includes(retryData.error)) {
|
|
597
1002
|
console.error(`\u274C Payment verification failed: ${retryData.error}`);
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
"invalid_signature": "Invalid payment signature",
|
|
601
|
-
"expired": "Payment authorization has expired",
|
|
602
|
-
"already_used": "This payment has already been used",
|
|
603
|
-
"network_mismatch": "Payment network does not match",
|
|
604
|
-
"invalid_payment": "Invalid payment data",
|
|
605
|
-
"verification_failed": "Payment verification failed",
|
|
606
|
-
"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."
|
|
607
|
-
};
|
|
608
|
-
const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
609
|
-
const error = new Error(errorMessage);
|
|
610
|
-
throw wrapPaymentError(error);
|
|
1003
|
+
const errorMessage = PAYMENT_ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
1004
|
+
throw wrapPaymentError(new Error(errorMessage));
|
|
611
1005
|
}
|
|
612
1006
|
} catch (error) {
|
|
613
1007
|
if (error instanceof PaymentOperationError) {
|
|
@@ -734,6 +1128,15 @@ function getChainIdFromNetwork(network) {
|
|
|
734
1128
|
|
|
735
1129
|
// src/services/evm/payment-handler.ts
|
|
736
1130
|
init_types();
|
|
1131
|
+
var NETWORK_NAMES = {
|
|
1132
|
+
1: "Ethereum Mainnet",
|
|
1133
|
+
11155111: "Sepolia Testnet",
|
|
1134
|
+
8453: "Base Mainnet",
|
|
1135
|
+
84532: "Base Sepolia Testnet",
|
|
1136
|
+
137: "Polygon Mainnet",
|
|
1137
|
+
42161: "Arbitrum One",
|
|
1138
|
+
10: "Optimism Mainnet"
|
|
1139
|
+
};
|
|
737
1140
|
async function handleEvmPayment(endpoint, config, requestInit) {
|
|
738
1141
|
const { wallet, network, maxPaymentAmount } = config;
|
|
739
1142
|
const initialResponse = await fetch(endpoint, {
|
|
@@ -744,25 +1147,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
|
|
|
744
1147
|
return initialResponse;
|
|
745
1148
|
}
|
|
746
1149
|
const rawResponse = await initialResponse.json();
|
|
747
|
-
|
|
748
|
-
"X-PAYMENT header is required",
|
|
749
|
-
"missing X-PAYMENT header",
|
|
750
|
-
"payment_required"
|
|
751
|
-
];
|
|
752
|
-
if (rawResponse.error && !IGNORED_ERRORS.includes(rawResponse.error)) {
|
|
1150
|
+
if (rawResponse.error && !IGNORED_402_ERRORS.includes(rawResponse.error)) {
|
|
753
1151
|
console.error(`\u274C Payment verification failed: ${rawResponse.error}`);
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
"invalid_signature": "Invalid payment signature",
|
|
757
|
-
"expired": "Payment authorization has expired",
|
|
758
|
-
"already_used": "This payment has already been used",
|
|
759
|
-
"network_mismatch": "Payment network does not match",
|
|
760
|
-
"invalid_payment": "Invalid payment data",
|
|
761
|
-
"verification_failed": "Payment verification failed"
|
|
762
|
-
};
|
|
763
|
-
const errorMessage = ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
764
|
-
const error = new Error(errorMessage);
|
|
765
|
-
throw wrapPaymentError(error);
|
|
1152
|
+
const errorMessage = PAYMENT_ERROR_MESSAGES[rawResponse.error] || `Payment failed: ${rawResponse.error}`;
|
|
1153
|
+
throw wrapPaymentError(new Error(errorMessage));
|
|
766
1154
|
}
|
|
767
1155
|
const x402Version = rawResponse.x402Version;
|
|
768
1156
|
const parsedPaymentRequirements = rawResponse.accepts || [];
|
|
@@ -794,19 +1182,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
|
|
|
794
1182
|
console.warn("\u26A0\uFE0F Failed to get current chainId:", error);
|
|
795
1183
|
}
|
|
796
1184
|
}
|
|
797
|
-
const networkNames = {
|
|
798
|
-
1: "Ethereum Mainnet",
|
|
799
|
-
11155111: "Sepolia Testnet",
|
|
800
|
-
8453: "Base Mainnet",
|
|
801
|
-
84532: "Base Sepolia Testnet",
|
|
802
|
-
137: "Polygon Mainnet",
|
|
803
|
-
42161: "Arbitrum One",
|
|
804
|
-
10: "Optimism Mainnet"
|
|
805
|
-
};
|
|
806
1185
|
if (currentChainId && currentChainId !== targetChainId) {
|
|
807
1186
|
if (!wallet.switchChain) {
|
|
808
|
-
const currentNetworkName =
|
|
809
|
-
const targetNetworkName =
|
|
1187
|
+
const currentNetworkName = NETWORK_NAMES[currentChainId] || `Chain ${currentChainId}`;
|
|
1188
|
+
const targetNetworkName = NETWORK_NAMES[targetChainId] || selectedRequirements.network;
|
|
810
1189
|
const error = new Error(
|
|
811
1190
|
`Network mismatch: Your wallet is connected to ${currentNetworkName}, but payment requires ${targetNetworkName}. Please switch to ${targetNetworkName} manually in your wallet.`
|
|
812
1191
|
);
|
|
@@ -818,7 +1197,7 @@ async function handleEvmPayment(endpoint, config, requestInit) {
|
|
|
818
1197
|
console.log(`\u2705 Successfully switched to chain ${targetChainId}`);
|
|
819
1198
|
} catch (error) {
|
|
820
1199
|
console.error("\u274C Failed to switch chain:", error);
|
|
821
|
-
const targetNetworkName =
|
|
1200
|
+
const targetNetworkName = NETWORK_NAMES[targetChainId] || selectedRequirements.network;
|
|
822
1201
|
const wrappedError = wrapPaymentError(error);
|
|
823
1202
|
let finalError;
|
|
824
1203
|
if (wrappedError.code === "USER_REJECTED" /* USER_REJECTED */) {
|
|
@@ -872,25 +1251,10 @@ async function handleEvmPayment(endpoint, config, requestInit) {
|
|
|
872
1251
|
if (retryResponse.status === 402) {
|
|
873
1252
|
try {
|
|
874
1253
|
const retryData = await retryResponse.json();
|
|
875
|
-
|
|
876
|
-
"X-PAYMENT header is required",
|
|
877
|
-
"missing X-PAYMENT header",
|
|
878
|
-
"payment_required"
|
|
879
|
-
];
|
|
880
|
-
if (retryData.error && !IGNORED_ERRORS2.includes(retryData.error)) {
|
|
1254
|
+
if (retryData.error && !IGNORED_402_ERRORS.includes(retryData.error)) {
|
|
881
1255
|
console.error(`\u274C Payment verification failed: ${retryData.error}`);
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
"invalid_signature": "Invalid payment signature",
|
|
885
|
-
"expired": "Payment authorization has expired",
|
|
886
|
-
"already_used": "This payment has already been used",
|
|
887
|
-
"network_mismatch": "Payment network does not match",
|
|
888
|
-
"invalid_payment": "Invalid payment data",
|
|
889
|
-
"verification_failed": "Payment verification failed"
|
|
890
|
-
};
|
|
891
|
-
const errorMessage = ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
892
|
-
const error = new Error(errorMessage);
|
|
893
|
-
throw wrapPaymentError(error);
|
|
1256
|
+
const errorMessage = PAYMENT_ERROR_MESSAGES[retryData.error] || `Payment failed: ${retryData.error}`;
|
|
1257
|
+
throw wrapPaymentError(new Error(errorMessage));
|
|
894
1258
|
}
|
|
895
1259
|
} catch (error) {
|
|
896
1260
|
if (error instanceof PaymentOperationError) {
|
|
@@ -928,7 +1292,7 @@ function getSupportedNetworkTypes(paymentRequirements) {
|
|
|
928
1292
|
});
|
|
929
1293
|
return Array.from(networkTypes);
|
|
930
1294
|
}
|
|
931
|
-
async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams) {
|
|
1295
|
+
async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, additionalParams, expectedAddress) {
|
|
932
1296
|
const fullEndpoint = `${endpoint}/${merchantId}`;
|
|
933
1297
|
let response;
|
|
934
1298
|
const requestInit = additionalParams && Object.keys(additionalParams).length > 0 ? {
|
|
@@ -938,26 +1302,41 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
|
|
|
938
1302
|
}
|
|
939
1303
|
} : {};
|
|
940
1304
|
if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
|
|
941
|
-
const solana =
|
|
1305
|
+
const solana = getWalletProviderForPayment(networkType);
|
|
942
1306
|
if (!solana) {
|
|
943
|
-
throw new Error("
|
|
1307
|
+
throw new Error("Please connect your Solana wallet first.");
|
|
944
1308
|
}
|
|
945
1309
|
if (!solana.isConnected) {
|
|
946
1310
|
await solana.connect();
|
|
947
1311
|
}
|
|
1312
|
+
if (expectedAddress && solana.publicKey) {
|
|
1313
|
+
const currentAddress = solana.publicKey.toString();
|
|
1314
|
+
if (currentAddress !== expectedAddress) {
|
|
1315
|
+
throw new Error(
|
|
1316
|
+
`Wallet account mismatch: the current wallet account is ${currentAddress.slice(0, 8)}...\uFF0CBut the desired account is ${expectedAddress.slice(0, 8)}.... Please switch to the correct account in your wallet.`
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
948
1320
|
response = await handleSvmPayment(fullEndpoint, {
|
|
949
1321
|
wallet: solana,
|
|
950
1322
|
network: "solana"
|
|
951
1323
|
// Will use backend's network configuration
|
|
952
1324
|
}, requestInit);
|
|
953
1325
|
} else if (networkType === "evm" /* EVM */) {
|
|
954
|
-
|
|
955
|
-
|
|
1326
|
+
const ethereum = getWalletProviderForPayment(networkType);
|
|
1327
|
+
if (!ethereum) {
|
|
1328
|
+
throw new Error("Please connect the EVM wallet first");
|
|
956
1329
|
}
|
|
957
|
-
const provider = new import_ethers2.ethers.BrowserProvider(
|
|
1330
|
+
const provider = new import_ethers2.ethers.BrowserProvider(ethereum);
|
|
958
1331
|
const signer = await provider.getSigner();
|
|
1332
|
+
const currentAddress = await signer.getAddress();
|
|
1333
|
+
if (expectedAddress && currentAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
|
|
1334
|
+
throw new Error(
|
|
1335
|
+
`Wallet account mismatch: the current wallet account is ${currentAddress.slice(0, 8)}...\uFF0CBut the desired account is ${expectedAddress.slice(0, 8)}.... Please switch to the correct account in your wallet.`
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
959
1338
|
const wallet = {
|
|
960
|
-
address:
|
|
1339
|
+
address: currentAddress,
|
|
961
1340
|
signTypedData: async (domain, types, message2) => {
|
|
962
1341
|
return await signer.signTypedData(domain, types, message2);
|
|
963
1342
|
},
|
|
@@ -968,7 +1347,7 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
|
|
|
968
1347
|
},
|
|
969
1348
|
// Switch to a different chain
|
|
970
1349
|
switchChain: async (chainId) => {
|
|
971
|
-
await
|
|
1350
|
+
await ethereum.request({
|
|
972
1351
|
method: "wallet_switchEthereumChain",
|
|
973
1352
|
params: [{ chainId }]
|
|
974
1353
|
});
|
|
@@ -980,7 +1359,7 @@ async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL, ad
|
|
|
980
1359
|
// Will use backend's network configuration
|
|
981
1360
|
}, requestInit);
|
|
982
1361
|
} else {
|
|
983
|
-
throw new Error(
|
|
1362
|
+
throw new Error(`Unsupported network types: ${networkType}`);
|
|
984
1363
|
}
|
|
985
1364
|
return response;
|
|
986
1365
|
}
|
|
@@ -1023,6 +1402,21 @@ function getNetworkDisplayName(network) {
|
|
|
1023
1402
|
}
|
|
1024
1403
|
|
|
1025
1404
|
// src/utils/payment-error-handler.ts
|
|
1405
|
+
var IGNORED_402_ERRORS = [
|
|
1406
|
+
"X-PAYMENT header is required",
|
|
1407
|
+
"missing X-PAYMENT header",
|
|
1408
|
+
"payment_required"
|
|
1409
|
+
];
|
|
1410
|
+
var PAYMENT_ERROR_MESSAGES = {
|
|
1411
|
+
"insufficient_funds": "Insufficient balance to complete this payment",
|
|
1412
|
+
"invalid_signature": "Invalid payment signature",
|
|
1413
|
+
"expired": "Payment authorization has expired",
|
|
1414
|
+
"already_used": "This payment has already been used",
|
|
1415
|
+
"network_mismatch": "Payment network does not match",
|
|
1416
|
+
"invalid_payment": "Invalid payment data",
|
|
1417
|
+
"verification_failed": "Payment verification failed",
|
|
1418
|
+
"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."
|
|
1419
|
+
};
|
|
1026
1420
|
function parsePaymentError(error) {
|
|
1027
1421
|
if (!error) {
|
|
1028
1422
|
return {
|
|
@@ -1226,13 +1620,18 @@ var WalletStore = class {
|
|
|
1226
1620
|
});
|
|
1227
1621
|
}
|
|
1228
1622
|
// Connect wallet
|
|
1229
|
-
|
|
1623
|
+
// @param forceSelect - 强制弹出钱包选择界面,用于切换账户
|
|
1624
|
+
async connect(type, forceSelect = false) {
|
|
1230
1625
|
if (this.state.address && this.state.networkType && this.state.networkType !== type) {
|
|
1231
1626
|
saveWalletAddress(this.state.networkType, this.state.address);
|
|
1232
1627
|
}
|
|
1233
1628
|
this.setState({ isConnecting: true, error: null });
|
|
1234
1629
|
try {
|
|
1235
|
-
const walletAddress = await connectWallet(type);
|
|
1630
|
+
const walletAddress = await connectWallet(type, forceSelect);
|
|
1631
|
+
const wallets = getWalletsForNetwork(type);
|
|
1632
|
+
if (wallets.length > 0) {
|
|
1633
|
+
setCurrentConnectedWallet(wallets[0]);
|
|
1634
|
+
}
|
|
1236
1635
|
this.setState({
|
|
1237
1636
|
address: walletAddress,
|
|
1238
1637
|
networkType: type,
|
|
@@ -1246,6 +1645,30 @@ var WalletStore = class {
|
|
|
1246
1645
|
throw err;
|
|
1247
1646
|
}
|
|
1248
1647
|
}
|
|
1648
|
+
// Connect to a specific wallet (from wallet discovery)
|
|
1649
|
+
async connectWithWallet(wallet) {
|
|
1650
|
+
if (this.state.address && this.state.networkType && this.state.networkType !== wallet.networkType) {
|
|
1651
|
+
saveWalletAddress(this.state.networkType, this.state.address);
|
|
1652
|
+
}
|
|
1653
|
+
this.setState({ isConnecting: true, error: null });
|
|
1654
|
+
try {
|
|
1655
|
+
const walletAddress = await connectToWallet(wallet);
|
|
1656
|
+
clearWalletDisconnection(wallet.networkType);
|
|
1657
|
+
saveConnectedNetworkType(wallet.networkType);
|
|
1658
|
+
saveWalletAddress(wallet.networkType, walletAddress);
|
|
1659
|
+
this.setState({
|
|
1660
|
+
address: walletAddress,
|
|
1661
|
+
networkType: wallet.networkType,
|
|
1662
|
+
isConnecting: false
|
|
1663
|
+
});
|
|
1664
|
+
} catch (err) {
|
|
1665
|
+
this.setState({
|
|
1666
|
+
error: err.message || "Failed to connect wallet",
|
|
1667
|
+
isConnecting: false
|
|
1668
|
+
});
|
|
1669
|
+
throw err;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1249
1672
|
// Switch network (use cached wallet if available)
|
|
1250
1673
|
async switchNetwork(type) {
|
|
1251
1674
|
if (this.state.address && this.state.networkType) {
|
|
@@ -1277,9 +1700,15 @@ var WalletStore = class {
|
|
|
1277
1700
|
}
|
|
1278
1701
|
}
|
|
1279
1702
|
// Disconnect wallet
|
|
1280
|
-
disconnect() {
|
|
1703
|
+
async disconnect() {
|
|
1281
1704
|
const currentNetwork = this.state.networkType;
|
|
1705
|
+
clearConnectedWallet(currentNetwork || void 0);
|
|
1282
1706
|
if (currentNetwork) {
|
|
1707
|
+
try {
|
|
1708
|
+
await disconnectWallet(currentNetwork);
|
|
1709
|
+
} catch (err) {
|
|
1710
|
+
console.warn("Failed to disconnect wallet provider:", err);
|
|
1711
|
+
}
|
|
1283
1712
|
this.handleDisconnect(currentNetwork);
|
|
1284
1713
|
} else {
|
|
1285
1714
|
this.setState({
|
|
@@ -1323,7 +1752,8 @@ function useWallet() {
|
|
|
1323
1752
|
);
|
|
1324
1753
|
return {
|
|
1325
1754
|
...state,
|
|
1326
|
-
connect: (type) => walletStore.connect(type),
|
|
1755
|
+
connect: (type, forceSelect) => walletStore.connect(type, forceSelect),
|
|
1756
|
+
connectWithWallet: (wallet) => walletStore.connectWithWallet(wallet),
|
|
1327
1757
|
switchNetwork: (type) => walletStore.switchNetwork(type),
|
|
1328
1758
|
ensureNetwork: (type) => walletStore.ensureNetwork(type),
|
|
1329
1759
|
disconnect: () => walletStore.disconnect(),
|
|
@@ -1431,41 +1861,323 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams)
|
|
|
1431
1861
|
};
|
|
1432
1862
|
}
|
|
1433
1863
|
|
|
1434
|
-
// src/react/
|
|
1864
|
+
// src/react/hooks/useToast.tsx
|
|
1865
|
+
var import_react6 = __toESM(require("react"));
|
|
1866
|
+
|
|
1867
|
+
// src/react/components/ui/Toast.tsx
|
|
1435
1868
|
var import_react5 = __toESM(require("react"));
|
|
1869
|
+
var import_react_dom = require("react-dom");
|
|
1870
|
+
var Toast = ({ message: message2, type, onClose }) => {
|
|
1871
|
+
(0, import_react5.useEffect)(() => {
|
|
1872
|
+
const timer = setTimeout(onClose, 3e3);
|
|
1873
|
+
return () => clearTimeout(timer);
|
|
1874
|
+
}, [onClose]);
|
|
1875
|
+
const bgColor = type === "success" ? "#22c55e" : type === "error" ? "#ef4444" : "#3b82f6";
|
|
1876
|
+
const icon = type === "success" ? "\u2713" : type === "error" ? "\u2717" : "\u2139";
|
|
1877
|
+
return (0, import_react_dom.createPortal)(
|
|
1878
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
1879
|
+
"div",
|
|
1880
|
+
{
|
|
1881
|
+
className: "fixed top-4 right-4 z-[99999] animate-slide-in-right",
|
|
1882
|
+
style: {
|
|
1883
|
+
animation: "slideInRight 0.3s ease-out"
|
|
1884
|
+
}
|
|
1885
|
+
},
|
|
1886
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
1887
|
+
"div",
|
|
1888
|
+
{
|
|
1889
|
+
className: "flex items-center gap-3 px-4 py-3 rounded-lg shadow-lg text-white font-mono text-sm",
|
|
1890
|
+
style: { backgroundColor: bgColor, minWidth: "280px" }
|
|
1891
|
+
},
|
|
1892
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: "text-lg" }, icon),
|
|
1893
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: "flex-1" }, message2),
|
|
1894
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
1895
|
+
"button",
|
|
1896
|
+
{
|
|
1897
|
+
onClick: onClose,
|
|
1898
|
+
className: "text-white/80 hover:text-white transition-colors"
|
|
1899
|
+
},
|
|
1900
|
+
"\xD7"
|
|
1901
|
+
)
|
|
1902
|
+
)
|
|
1903
|
+
),
|
|
1904
|
+
document.body
|
|
1905
|
+
);
|
|
1906
|
+
};
|
|
1436
1907
|
|
|
1437
|
-
// src/react/
|
|
1438
|
-
var
|
|
1439
|
-
|
|
1440
|
-
|
|
1908
|
+
// src/react/hooks/useToast.tsx
|
|
1909
|
+
var useToast = () => {
|
|
1910
|
+
const [toasts, setToasts] = (0, import_react6.useState)([]);
|
|
1911
|
+
const toastIdRef = (0, import_react6.useRef)(0);
|
|
1912
|
+
const showToast = (0, import_react6.useCallback)((message2, type) => {
|
|
1913
|
+
const id = ++toastIdRef.current;
|
|
1914
|
+
setToasts((prev) => [...prev, { id, message: message2, type }]);
|
|
1915
|
+
}, []);
|
|
1916
|
+
const removeToast = (0, import_react6.useCallback)((id) => {
|
|
1917
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
1918
|
+
}, []);
|
|
1919
|
+
const ToastContainer = () => /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, toasts.map((toast, index) => /* @__PURE__ */ import_react6.default.createElement(
|
|
1920
|
+
"div",
|
|
1921
|
+
{
|
|
1922
|
+
key: toast.id,
|
|
1923
|
+
style: { top: `${16 + index * 60}px` },
|
|
1924
|
+
className: "fixed right-4 z-[99999]"
|
|
1925
|
+
},
|
|
1926
|
+
import_react6.default.createElement(Toast, {
|
|
1927
|
+
message: toast.message,
|
|
1928
|
+
type: toast.type,
|
|
1929
|
+
onClose: () => removeToast(toast.id)
|
|
1930
|
+
})
|
|
1931
|
+
)));
|
|
1932
|
+
return { showToast, ToastContainer };
|
|
1441
1933
|
};
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1934
|
+
|
|
1935
|
+
// src/react/components/wallet/WalletConnect.tsx
|
|
1936
|
+
var import_react8 = __toESM(require("react"));
|
|
1937
|
+
|
|
1938
|
+
// src/react/components/wallet/WalletSelectModal.tsx
|
|
1939
|
+
var import_react7 = __toESM(require("react"));
|
|
1940
|
+
var import_react_dom2 = require("react-dom");
|
|
1941
|
+
var overlayStyle = {
|
|
1942
|
+
position: "fixed",
|
|
1943
|
+
top: 0,
|
|
1944
|
+
left: 0,
|
|
1945
|
+
right: 0,
|
|
1946
|
+
bottom: 0,
|
|
1947
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1948
|
+
display: "flex",
|
|
1949
|
+
alignItems: "center",
|
|
1950
|
+
justifyContent: "center",
|
|
1951
|
+
zIndex: 99999
|
|
1952
|
+
};
|
|
1953
|
+
var modalStyle = {
|
|
1954
|
+
backgroundColor: "#ffffff",
|
|
1955
|
+
borderRadius: "12px",
|
|
1956
|
+
padding: "16px",
|
|
1957
|
+
maxWidth: "320px",
|
|
1958
|
+
width: "90%",
|
|
1959
|
+
maxHeight: "70vh",
|
|
1960
|
+
overflow: "auto",
|
|
1961
|
+
boxShadow: "0 10px 25px rgba(0, 0, 0, 0.15)"
|
|
1962
|
+
};
|
|
1963
|
+
var headerStyle = {
|
|
1964
|
+
display: "flex",
|
|
1965
|
+
alignItems: "center",
|
|
1966
|
+
justifyContent: "space-between",
|
|
1967
|
+
marginBottom: "12px"
|
|
1968
|
+
};
|
|
1969
|
+
var titleStyle = {
|
|
1970
|
+
fontSize: "15px",
|
|
1971
|
+
fontWeight: 600,
|
|
1972
|
+
color: "#1a1a1a",
|
|
1973
|
+
margin: 0
|
|
1974
|
+
};
|
|
1975
|
+
var closeButtonStyle = {
|
|
1976
|
+
background: "none",
|
|
1977
|
+
border: "none",
|
|
1978
|
+
fontSize: "20px",
|
|
1979
|
+
cursor: "pointer",
|
|
1980
|
+
color: "#666",
|
|
1981
|
+
padding: "2px 6px",
|
|
1982
|
+
lineHeight: 1,
|
|
1983
|
+
borderRadius: "4px"
|
|
1984
|
+
};
|
|
1985
|
+
var subtitleStyle = {
|
|
1986
|
+
fontSize: "12px",
|
|
1987
|
+
color: "#666",
|
|
1988
|
+
marginBottom: "12px"
|
|
1989
|
+
};
|
|
1990
|
+
var walletListStyle = {
|
|
1991
|
+
display: "flex",
|
|
1992
|
+
flexDirection: "column",
|
|
1993
|
+
gap: "6px"
|
|
1994
|
+
};
|
|
1995
|
+
var getWalletItemStyle = (isHovered) => ({
|
|
1996
|
+
display: "flex",
|
|
1997
|
+
alignItems: "center",
|
|
1998
|
+
gap: "10px",
|
|
1999
|
+
padding: "10px 12px",
|
|
2000
|
+
border: "1px solid #e5e5e5",
|
|
2001
|
+
borderRadius: "8px",
|
|
2002
|
+
cursor: "pointer",
|
|
2003
|
+
transition: "all 0.15s ease",
|
|
2004
|
+
backgroundColor: isHovered ? "#f5f5f5" : "#ffffff",
|
|
2005
|
+
borderColor: isHovered ? "#d0d0d0" : "#e5e5e5"
|
|
2006
|
+
});
|
|
2007
|
+
var walletIconStyle = {
|
|
2008
|
+
width: "32px",
|
|
2009
|
+
height: "32px",
|
|
2010
|
+
borderRadius: "8px",
|
|
2011
|
+
objectFit: "contain",
|
|
2012
|
+
backgroundColor: "#f5f5f5"
|
|
2013
|
+
};
|
|
2014
|
+
var getAvatarColor = (name) => {
|
|
2015
|
+
const colors2 = [
|
|
2016
|
+
"#6366f1",
|
|
2017
|
+
// indigo
|
|
2018
|
+
"#8b5cf6",
|
|
2019
|
+
// violet
|
|
2020
|
+
"#ec4899",
|
|
2021
|
+
// pink
|
|
2022
|
+
"#f43f5e",
|
|
2023
|
+
// rose
|
|
2024
|
+
"#f97316",
|
|
2025
|
+
// orange
|
|
2026
|
+
"#eab308",
|
|
2027
|
+
// yellow
|
|
2028
|
+
"#22c55e",
|
|
2029
|
+
// green
|
|
2030
|
+
"#14b8a6",
|
|
2031
|
+
// teal
|
|
2032
|
+
"#06b6d4",
|
|
2033
|
+
// cyan
|
|
2034
|
+
"#3b82f6"
|
|
2035
|
+
// blue
|
|
2036
|
+
];
|
|
2037
|
+
const index = name.charCodeAt(0) % colors2.length;
|
|
2038
|
+
return colors2[index];
|
|
2039
|
+
};
|
|
2040
|
+
var getWalletIconPlaceholderStyle = (walletName) => ({
|
|
2041
|
+
width: "32px",
|
|
2042
|
+
height: "32px",
|
|
2043
|
+
borderRadius: "8px",
|
|
2044
|
+
backgroundColor: getAvatarColor(walletName),
|
|
2045
|
+
display: "flex",
|
|
2046
|
+
alignItems: "center",
|
|
2047
|
+
justifyContent: "center",
|
|
2048
|
+
fontSize: "14px",
|
|
2049
|
+
fontWeight: 600,
|
|
2050
|
+
color: "#ffffff"
|
|
2051
|
+
});
|
|
2052
|
+
var walletNameStyle = {
|
|
2053
|
+
fontSize: "14px",
|
|
2054
|
+
fontWeight: 500,
|
|
2055
|
+
color: "#1a1a1a"
|
|
2056
|
+
};
|
|
2057
|
+
var emptyStateStyle = {
|
|
2058
|
+
textAlign: "center",
|
|
2059
|
+
padding: "24px 12px",
|
|
2060
|
+
color: "#666"
|
|
2061
|
+
};
|
|
2062
|
+
var emptyTitleStyle = {
|
|
2063
|
+
fontSize: "14px",
|
|
2064
|
+
fontWeight: 500,
|
|
2065
|
+
marginBottom: "6px",
|
|
2066
|
+
color: "#1a1a1a"
|
|
2067
|
+
};
|
|
2068
|
+
var emptyDescStyle = {
|
|
2069
|
+
fontSize: "12px",
|
|
2070
|
+
color: "#888"
|
|
2071
|
+
};
|
|
2072
|
+
function WalletItem({
|
|
2073
|
+
wallet,
|
|
2074
|
+
isHovered,
|
|
2075
|
+
onSelect,
|
|
2076
|
+
onHover
|
|
2077
|
+
}) {
|
|
2078
|
+
const [iconError, setIconError] = (0, import_react7.useState)(false);
|
|
2079
|
+
return /* @__PURE__ */ import_react7.default.createElement(
|
|
2080
|
+
"div",
|
|
2081
|
+
{
|
|
2082
|
+
style: getWalletItemStyle(isHovered),
|
|
2083
|
+
onClick: onSelect,
|
|
2084
|
+
onMouseEnter: () => onHover(true),
|
|
2085
|
+
onMouseLeave: () => onHover(false)
|
|
2086
|
+
},
|
|
2087
|
+
wallet.icon && !iconError ? /* @__PURE__ */ import_react7.default.createElement(
|
|
2088
|
+
"img",
|
|
2089
|
+
{
|
|
2090
|
+
src: wallet.icon,
|
|
2091
|
+
alt: wallet.name,
|
|
2092
|
+
style: walletIconStyle,
|
|
2093
|
+
onError: () => setIconError(true)
|
|
2094
|
+
}
|
|
2095
|
+
) : /* @__PURE__ */ import_react7.default.createElement("div", { style: getWalletIconPlaceholderStyle(wallet.name) }, wallet.name.charAt(0).toUpperCase()),
|
|
2096
|
+
/* @__PURE__ */ import_react7.default.createElement("span", { style: walletNameStyle }, wallet.name)
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
function WalletSelectModal({
|
|
2100
|
+
isOpen,
|
|
2101
|
+
networkType,
|
|
2102
|
+
onSelect,
|
|
2103
|
+
onClose
|
|
2104
|
+
}) {
|
|
2105
|
+
const [wallets, setWallets] = (0, import_react7.useState)([]);
|
|
2106
|
+
const [hoveredWallet, setHoveredWallet] = (0, import_react7.useState)(null);
|
|
2107
|
+
const [mounted, setMounted] = (0, import_react7.useState)(false);
|
|
2108
|
+
(0, import_react7.useEffect)(() => {
|
|
2109
|
+
setMounted(true);
|
|
2110
|
+
return () => setMounted(false);
|
|
2111
|
+
}, []);
|
|
2112
|
+
(0, import_react7.useEffect)(() => {
|
|
2113
|
+
if (!isOpen) return;
|
|
2114
|
+
initEVMWalletDiscovery();
|
|
2115
|
+
const updateWallets = () => {
|
|
2116
|
+
setWallets(getWalletsForNetwork(networkType));
|
|
2117
|
+
};
|
|
2118
|
+
updateWallets();
|
|
2119
|
+
const unsubscribe = onEVMWalletsChanged(updateWallets);
|
|
2120
|
+
const timer = setTimeout(updateWallets, 500);
|
|
2121
|
+
return () => {
|
|
2122
|
+
unsubscribe();
|
|
2123
|
+
clearTimeout(timer);
|
|
2124
|
+
};
|
|
2125
|
+
}, [isOpen, networkType]);
|
|
2126
|
+
if (!isOpen || !mounted) return null;
|
|
2127
|
+
const handleOverlayClick = (e) => {
|
|
2128
|
+
if (e.target === e.currentTarget) {
|
|
2129
|
+
onClose();
|
|
2130
|
+
}
|
|
2131
|
+
};
|
|
2132
|
+
const networkName = getNetworkDisplayName(networkType);
|
|
2133
|
+
const modalContent = /* @__PURE__ */ import_react7.default.createElement("div", { style: overlayStyle, onClick: handleOverlayClick }, /* @__PURE__ */ import_react7.default.createElement("div", { style: modalStyle }, /* @__PURE__ */ import_react7.default.createElement("div", { style: headerStyle }, /* @__PURE__ */ import_react7.default.createElement("h3", { style: titleStyle }, "Select Wallet"), /* @__PURE__ */ import_react7.default.createElement("button", { style: closeButtonStyle, onClick: onClose }, "\xD7")), /* @__PURE__ */ import_react7.default.createElement("p", { style: subtitleStyle }, "Connect a ", networkName, " wallet"), wallets.length > 0 ? /* @__PURE__ */ import_react7.default.createElement("div", { style: walletListStyle }, wallets.map((wallet) => /* @__PURE__ */ import_react7.default.createElement(
|
|
2134
|
+
WalletItem,
|
|
2135
|
+
{
|
|
2136
|
+
key: wallet.id,
|
|
2137
|
+
wallet,
|
|
2138
|
+
isHovered: hoveredWallet === wallet.id,
|
|
2139
|
+
onSelect: () => onSelect(wallet),
|
|
2140
|
+
onHover: (hovered) => setHoveredWallet(hovered ? wallet.id : null)
|
|
2141
|
+
}
|
|
2142
|
+
))) : /* @__PURE__ */ import_react7.default.createElement("div", { style: emptyStateStyle }, /* @__PURE__ */ import_react7.default.createElement("p", { style: emptyTitleStyle }, "No wallets found"), /* @__PURE__ */ import_react7.default.createElement("p", { style: emptyDescStyle }, "Please install a ", networkName, " wallet extension."))));
|
|
2143
|
+
if (typeof document !== "undefined") {
|
|
2144
|
+
return (0, import_react_dom2.createPortal)(modalContent, document.body);
|
|
2145
|
+
}
|
|
2146
|
+
return modalContent;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// src/react/styles/inline-styles.ts
|
|
2150
|
+
var isDarkMode = () => {
|
|
2151
|
+
if (typeof window === "undefined") return false;
|
|
2152
|
+
return window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
|
|
2153
|
+
};
|
|
2154
|
+
var colors = {
|
|
2155
|
+
// Light mode
|
|
2156
|
+
light: {
|
|
2157
|
+
background: "#fafafa",
|
|
2158
|
+
cardBg: "#ffffff",
|
|
2159
|
+
text: "#0a0a0a",
|
|
2160
|
+
textSecondary: "#737373",
|
|
2161
|
+
primary: "#000000",
|
|
2162
|
+
primaryHover: "#262626",
|
|
2163
|
+
danger: "#ef4444",
|
|
2164
|
+
dangerHover: "#dc2626",
|
|
2165
|
+
success: "#10b981",
|
|
2166
|
+
successHover: "#059669",
|
|
2167
|
+
disabled: "#e5e5e5",
|
|
2168
|
+
disabledText: "#a3a3a3",
|
|
2169
|
+
errorBg: "#fef2f2",
|
|
2170
|
+
errorText: "#dc2626"
|
|
2171
|
+
},
|
|
2172
|
+
// Dark mode
|
|
2173
|
+
dark: {
|
|
2174
|
+
background: "#0a0a0a",
|
|
2175
|
+
cardBg: "#171717",
|
|
2176
|
+
text: "#fafafa",
|
|
2177
|
+
textSecondary: "#a3a3a3",
|
|
2178
|
+
primary: "#ffffff",
|
|
2179
|
+
primaryHover: "#e5e5e5",
|
|
2180
|
+
danger: "#f87171",
|
|
1469
2181
|
dangerHover: "#ef4444",
|
|
1470
2182
|
success: "#34d399",
|
|
1471
2183
|
successHover: "#10b981",
|
|
@@ -1549,18 +2261,6 @@ var getDisconnectButtonStyle = (isHovered) => {
|
|
|
1549
2261
|
color: "#ffffff"
|
|
1550
2262
|
};
|
|
1551
2263
|
};
|
|
1552
|
-
var getInstallLinkStyle = (isHovered) => {
|
|
1553
|
-
const c = getColors();
|
|
1554
|
-
return {
|
|
1555
|
-
display: "inline-block",
|
|
1556
|
-
padding: "0.5rem",
|
|
1557
|
-
fontSize: "0.8125rem",
|
|
1558
|
-
color: c.textSecondary,
|
|
1559
|
-
textDecoration: isHovered ? "underline" : "none",
|
|
1560
|
-
textAlign: "center",
|
|
1561
|
-
fontWeight: 500
|
|
1562
|
-
};
|
|
1563
|
-
};
|
|
1564
2264
|
var walletAddressStyle = {
|
|
1565
2265
|
display: "flex",
|
|
1566
2266
|
flexDirection: "column",
|
|
@@ -1613,51 +2313,60 @@ var getErrorStyle = () => {
|
|
|
1613
2313
|
};
|
|
1614
2314
|
};
|
|
1615
2315
|
|
|
1616
|
-
// src/react/components/WalletConnect.tsx
|
|
2316
|
+
// src/react/components/wallet/WalletConnect.tsx
|
|
1617
2317
|
function WalletConnect({
|
|
1618
2318
|
supportedNetworks = ["solana" /* SOLANA */, "evm" /* EVM */],
|
|
1619
2319
|
className = "",
|
|
1620
2320
|
onConnect,
|
|
1621
|
-
onDisconnect
|
|
2321
|
+
onDisconnect,
|
|
2322
|
+
showSwitchWallet = true
|
|
1622
2323
|
}) {
|
|
1623
|
-
const { address, networkType, isConnecting, error,
|
|
1624
|
-
const [hoveredButton, setHoveredButton] = (0,
|
|
1625
|
-
const [
|
|
1626
|
-
const
|
|
2324
|
+
const { address, networkType, isConnecting, error, connectWithWallet, disconnect } = useWallet();
|
|
2325
|
+
const [hoveredButton, setHoveredButton] = (0, import_react8.useState)(null);
|
|
2326
|
+
const [walletSelectOpen, setWalletSelectOpen] = (0, import_react8.useState)(false);
|
|
2327
|
+
const [selectedNetworkType, setSelectedNetworkType] = (0, import_react8.useState)(null);
|
|
2328
|
+
const handleOpenWalletSelect = (network) => {
|
|
2329
|
+
setSelectedNetworkType(network);
|
|
2330
|
+
setWalletSelectOpen(true);
|
|
2331
|
+
};
|
|
2332
|
+
const handleWalletSelect = async (wallet) => {
|
|
2333
|
+
setWalletSelectOpen(false);
|
|
1627
2334
|
try {
|
|
1628
|
-
await
|
|
2335
|
+
await connectWithWallet(wallet);
|
|
1629
2336
|
} catch (err) {
|
|
1630
2337
|
}
|
|
1631
2338
|
};
|
|
1632
|
-
const handleDisconnect = () => {
|
|
1633
|
-
disconnect();
|
|
2339
|
+
const handleDisconnect = async () => {
|
|
2340
|
+
await disconnect();
|
|
1634
2341
|
onDisconnect?.();
|
|
1635
2342
|
};
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
2343
|
+
const handleSwitchWallet = () => {
|
|
2344
|
+
if (networkType) {
|
|
2345
|
+
setSelectedNetworkType(networkType);
|
|
2346
|
+
setWalletSelectOpen(true);
|
|
2347
|
+
}
|
|
2348
|
+
};
|
|
2349
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement("div", { style: { ...containerStyle, ...className ? {} : {} }, className }, !address ? /* @__PURE__ */ import_react8.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react8.default.createElement("h3", { style: getTitleStyle() }, "Connect Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react8.default.createElement("p", { style: getHintStyle() }, "Please install a supported wallet extension") : /* @__PURE__ */ import_react8.default.createElement("div", { style: buttonsContainerStyle }, supportedNetworks.map((network) => /* @__PURE__ */ import_react8.default.createElement("div", { key: network, style: walletOptionStyle }, /* @__PURE__ */ import_react8.default.createElement(
|
|
2350
|
+
"button",
|
|
2351
|
+
{
|
|
2352
|
+
style: getConnectButtonStyle(isConnecting, hoveredButton === network),
|
|
2353
|
+
onClick: () => handleOpenWalletSelect(network),
|
|
2354
|
+
disabled: isConnecting,
|
|
2355
|
+
onMouseEnter: () => setHoveredButton(network),
|
|
2356
|
+
onMouseLeave: () => setHoveredButton(null)
|
|
2357
|
+
},
|
|
2358
|
+
isConnecting ? "Connecting..." : getNetworkDisplayName(network)
|
|
2359
|
+
)))), error && /* @__PURE__ */ import_react8.default.createElement("p", { style: getErrorStyle() }, error), /* @__PURE__ */ import_react8.default.createElement("p", { style: getHintStyle() }, "Select a network to see available wallets")) : /* @__PURE__ */ import_react8.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react8.default.createElement("div", { style: walletAddressStyle }, /* @__PURE__ */ import_react8.default.createElement("span", { style: getLabelStyle() }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`), /* @__PURE__ */ import_react8.default.createElement("span", { style: getAddressStyle() }, formatAddress(address))), /* @__PURE__ */ import_react8.default.createElement("div", { style: walletActionsStyle }, showSwitchWallet && /* @__PURE__ */ import_react8.default.createElement(
|
|
2360
|
+
"button",
|
|
2361
|
+
{
|
|
2362
|
+
style: getConnectButtonStyle(isConnecting, hoveredButton === "switch"),
|
|
2363
|
+
onClick: handleSwitchWallet,
|
|
2364
|
+
disabled: isConnecting,
|
|
2365
|
+
onMouseEnter: () => setHoveredButton("switch"),
|
|
2366
|
+
onMouseLeave: () => setHoveredButton(null)
|
|
2367
|
+
},
|
|
2368
|
+
isConnecting ? "Switching..." : "Switch Wallet"
|
|
2369
|
+
), /* @__PURE__ */ import_react8.default.createElement(
|
|
1661
2370
|
"button",
|
|
1662
2371
|
{
|
|
1663
2372
|
style: getDisconnectButtonStyle(hoveredButton === "disconnect"),
|
|
@@ -1666,19 +2375,27 @@ function WalletConnect({
|
|
|
1666
2375
|
onMouseLeave: () => setHoveredButton(null)
|
|
1667
2376
|
},
|
|
1668
2377
|
"Disconnect"
|
|
1669
|
-
)), /* @__PURE__ */
|
|
2378
|
+
)), /* @__PURE__ */ import_react8.default.createElement("p", { style: getHintStyle() }, 'Click "Switch Wallet" to change wallet or account'))), selectedNetworkType && /* @__PURE__ */ import_react8.default.createElement(
|
|
2379
|
+
WalletSelectModal,
|
|
2380
|
+
{
|
|
2381
|
+
isOpen: walletSelectOpen,
|
|
2382
|
+
networkType: selectedNetworkType,
|
|
2383
|
+
onSelect: handleWalletSelect,
|
|
2384
|
+
onClose: () => setWalletSelectOpen(false)
|
|
2385
|
+
}
|
|
2386
|
+
));
|
|
1670
2387
|
}
|
|
1671
2388
|
|
|
1672
|
-
// src/react/components/V402Checkout.tsx
|
|
1673
|
-
var
|
|
2389
|
+
// src/react/components/checkout/V402Checkout.tsx
|
|
2390
|
+
var import_react10 = __toESM(require("react"));
|
|
1674
2391
|
var import_antd = require("antd");
|
|
1675
2392
|
var import_icons = require("@ant-design/icons");
|
|
1676
2393
|
init_common();
|
|
1677
2394
|
|
|
1678
2395
|
// src/react/utils/CryptoIcons.tsx
|
|
1679
|
-
var
|
|
2396
|
+
var import_react9 = __toESM(require("react"));
|
|
1680
2397
|
var SolanaIcon = ({ width = 16, height = 16, className, style }) => {
|
|
1681
|
-
return /* @__PURE__ */
|
|
2398
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1682
2399
|
"svg",
|
|
1683
2400
|
{
|
|
1684
2401
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1688,14 +2405,14 @@ var SolanaIcon = ({ width = 16, height = 16, className, style }) => {
|
|
|
1688
2405
|
className,
|
|
1689
2406
|
style
|
|
1690
2407
|
},
|
|
1691
|
-
/* @__PURE__ */
|
|
1692
|
-
/* @__PURE__ */
|
|
2408
|
+
/* @__PURE__ */ import_react9.default.createElement("desc", null, "Solana SOL Fill Streamline Icon: https://streamlinehq.com"),
|
|
2409
|
+
/* @__PURE__ */ import_react9.default.createElement("g", { fill: "none", fillRule: "evenodd" }, /* @__PURE__ */ import_react9.default.createElement(
|
|
1693
2410
|
"path",
|
|
1694
2411
|
{
|
|
1695
2412
|
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",
|
|
1696
2413
|
strokeWidth: "0.6667"
|
|
1697
2414
|
}
|
|
1698
|
-
), /* @__PURE__ */
|
|
2415
|
+
), /* @__PURE__ */ import_react9.default.createElement(
|
|
1699
2416
|
"path",
|
|
1700
2417
|
{
|
|
1701
2418
|
fill: "#000000",
|
|
@@ -1706,7 +2423,7 @@ var SolanaIcon = ({ width = 16, height = 16, className, style }) => {
|
|
|
1706
2423
|
);
|
|
1707
2424
|
};
|
|
1708
2425
|
var BaseIcon = ({ width = 24, height = 24, className, style }) => {
|
|
1709
|
-
return /* @__PURE__ */
|
|
2426
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1710
2427
|
"svg",
|
|
1711
2428
|
{
|
|
1712
2429
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1720,8 +2437,8 @@ var BaseIcon = ({ width = 24, height = 24, className, style }) => {
|
|
|
1720
2437
|
className,
|
|
1721
2438
|
style
|
|
1722
2439
|
},
|
|
1723
|
-
/* @__PURE__ */
|
|
1724
|
-
/* @__PURE__ */
|
|
2440
|
+
/* @__PURE__ */ import_react9.default.createElement("desc", null, "Brand Coinbase Streamline Icon: https://streamlinehq.com"),
|
|
2441
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1725
2442
|
"path",
|
|
1726
2443
|
{
|
|
1727
2444
|
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",
|
|
@@ -1741,7 +2458,7 @@ var getNetworkIcon = (network) => {
|
|
|
1741
2458
|
return BaseIcon;
|
|
1742
2459
|
};
|
|
1743
2460
|
|
|
1744
|
-
// src/react/components/V402Checkout.tsx
|
|
2461
|
+
// src/react/components/checkout/V402Checkout.tsx
|
|
1745
2462
|
var { Title, Text } = import_antd.Typography;
|
|
1746
2463
|
var notify = {
|
|
1747
2464
|
success: (title, msg) => {
|
|
@@ -1779,14 +2496,14 @@ function V402Checkout({
|
|
|
1779
2496
|
{ autoSwitch: !!targetNetwork, switchOnMount: true }
|
|
1780
2497
|
);
|
|
1781
2498
|
const { isProcessing, setIsProcessing, result, setResult, error, setError } = usePayment();
|
|
1782
|
-
const [paymentDetails, setPaymentDetails] = (0,
|
|
2499
|
+
const [paymentDetails, setPaymentDetails] = (0, import_react10.useState)(null);
|
|
1783
2500
|
const handleDisconnect = () => {
|
|
1784
2501
|
disconnect();
|
|
1785
2502
|
setResult(null);
|
|
1786
2503
|
setError(null);
|
|
1787
2504
|
notify.info("Wallet Disconnected", "Your wallet has been disconnected successfully.");
|
|
1788
2505
|
};
|
|
1789
|
-
(0,
|
|
2506
|
+
(0, import_react10.useEffect)(() => {
|
|
1790
2507
|
if (paymentInfo && paymentInfo.length > 0) {
|
|
1791
2508
|
const firstPayment = paymentInfo[0];
|
|
1792
2509
|
const rawAmount = firstPayment.maxAmountRequired?.toString() || "0";
|
|
@@ -1801,7 +2518,7 @@ function V402Checkout({
|
|
|
1801
2518
|
});
|
|
1802
2519
|
}
|
|
1803
2520
|
}, [paymentInfo]);
|
|
1804
|
-
(0,
|
|
2521
|
+
(0, import_react10.useEffect)(() => {
|
|
1805
2522
|
if (targetNetwork && !fetchingPaymentInfo && ensureNetwork) {
|
|
1806
2523
|
ensureNetwork(targetNetwork).catch((err) => {
|
|
1807
2524
|
console.error("Failed to ensure network:", err);
|
|
@@ -1817,7 +2534,7 @@ function V402Checkout({
|
|
|
1817
2534
|
setError(null);
|
|
1818
2535
|
setIsProcessing(true);
|
|
1819
2536
|
try {
|
|
1820
|
-
const response = await makePayment(networkType, checkoutId, endpoint, additionalParams);
|
|
2537
|
+
const response = await makePayment(networkType, checkoutId, endpoint, additionalParams, address || void 0);
|
|
1821
2538
|
const data = await response.json();
|
|
1822
2539
|
setResult(data);
|
|
1823
2540
|
notify.success("Payment Successful!", "Your payment has been processed successfully.");
|
|
@@ -1841,12 +2558,12 @@ function V402Checkout({
|
|
|
1841
2558
|
const networkColor = paymentDetails ? getNetworkColor(paymentDetails.network) : "#8c8c8c";
|
|
1842
2559
|
const loadingColor = "#8c8c8c";
|
|
1843
2560
|
const hasInvalidCheckoutId = !fetchingPaymentInfo && (!paymentInfo || paymentInfo.length === 0);
|
|
1844
|
-
return /* @__PURE__ */
|
|
2561
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
1845
2562
|
"div",
|
|
1846
2563
|
{
|
|
1847
2564
|
className: isModal ? "bg-white" : "h-screen bg-white flex items-center justify-center p-4 overflow-hidden"
|
|
1848
2565
|
},
|
|
1849
|
-
/* @__PURE__ */
|
|
2566
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1850
2567
|
"div",
|
|
1851
2568
|
{
|
|
1852
2569
|
className: "flex gap-4 items-center justify-center",
|
|
@@ -1856,7 +2573,7 @@ function V402Checkout({
|
|
|
1856
2573
|
width: "100%"
|
|
1857
2574
|
}
|
|
1858
2575
|
},
|
|
1859
|
-
/* @__PURE__ */
|
|
2576
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1860
2577
|
import_antd.Card,
|
|
1861
2578
|
{
|
|
1862
2579
|
className: "flex-shrink-0",
|
|
@@ -1872,7 +2589,7 @@ function V402Checkout({
|
|
|
1872
2589
|
},
|
|
1873
2590
|
styles: { body: { padding: isModal ? "0px" : "32px 24px" } }
|
|
1874
2591
|
},
|
|
1875
|
-
/* @__PURE__ */
|
|
2592
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-3 mb-4" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
1876
2593
|
"div",
|
|
1877
2594
|
{
|
|
1878
2595
|
className: "w-12 h-12 rounded-xl flex items-center justify-center",
|
|
@@ -1881,22 +2598,22 @@ function V402Checkout({
|
|
|
1881
2598
|
transition: "background 0.3s ease"
|
|
1882
2599
|
}
|
|
1883
2600
|
},
|
|
1884
|
-
hasInvalidCheckoutId ? /* @__PURE__ */
|
|
1885
|
-
), /* @__PURE__ */
|
|
2601
|
+
hasInvalidCheckoutId ? /* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "20px", color: "white", fontWeight: "bold" } }, "\u2717") : paymentDetails && NetworkIcon ? /* @__PURE__ */ import_react10.default.createElement(NetworkIcon, { width: 24, height: 24 }) : /* @__PURE__ */ import_react10.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: "20px", color: "white" }, spin: true })
|
|
2602
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react10.default.createElement(Title, { level: 4, style: { margin: 0, fontSize: "18px", fontWeight: 600 } }, title || "Echo Payment OnVoyage"), !hasInvalidCheckoutId && /* @__PURE__ */ import_react10.default.createElement(
|
|
1886
2603
|
import_antd.Tooltip,
|
|
1887
2604
|
{
|
|
1888
2605
|
title: tooltipText,
|
|
1889
2606
|
placement: "top"
|
|
1890
2607
|
},
|
|
1891
|
-
/* @__PURE__ */
|
|
2608
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1892
2609
|
import_icons.InfoCircleOutlined,
|
|
1893
2610
|
{
|
|
1894
2611
|
style: { fontSize: "14px", color: "#8c8c8c", cursor: "help" }
|
|
1895
2612
|
}
|
|
1896
2613
|
)
|
|
1897
|
-
)), /* @__PURE__ */
|
|
1898
|
-
/* @__PURE__ */
|
|
1899
|
-
hasInvalidCheckoutId && /* @__PURE__ */
|
|
2614
|
+
)), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, subtitle))),
|
|
2615
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center mb-5" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "inline-flex items-center justify-center w-12 h-12 rounded-full bg-gray-50 mb-3" }, /* @__PURE__ */ import_react10.default.createElement(import_icons.LockOutlined, { style: { fontSize: "20px", color: "#595959" } })), /* @__PURE__ */ import_react10.default.createElement(Title, { level: 3, style: { margin: "0 0 6px 0", fontSize: "20px", fontWeight: 600 } }, "Payment Required"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Pay ", paymentDetails ? `$${paymentDetails.amount} ${paymentDetails.currency}` : "the required amount", " to access")),
|
|
2616
|
+
hasInvalidCheckoutId && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
1900
2617
|
"div",
|
|
1901
2618
|
{
|
|
1902
2619
|
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
@@ -1905,15 +2622,15 @@ function V402Checkout({
|
|
|
1905
2622
|
boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
|
|
1906
2623
|
}
|
|
1907
2624
|
},
|
|
1908
|
-
/* @__PURE__ */
|
|
1909
|
-
), /* @__PURE__ */
|
|
2625
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "!")
|
|
2626
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
1910
2627
|
Title,
|
|
1911
2628
|
{
|
|
1912
2629
|
level: 4,
|
|
1913
2630
|
style: { margin: "0 0 12px 0", fontSize: "18px", fontWeight: 600, color: "#262626" }
|
|
1914
2631
|
},
|
|
1915
2632
|
"Invalid Checkout ID"
|
|
1916
|
-
), /* @__PURE__ */
|
|
2633
|
+
), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", display: "block", marginBottom: "16px" } }, "The checkout ID you provided is invalid or has expired."), /* @__PURE__ */ import_react10.default.createElement(
|
|
1917
2634
|
"div",
|
|
1918
2635
|
{
|
|
1919
2636
|
style: {
|
|
@@ -1924,33 +2641,33 @@ function V402Checkout({
|
|
|
1924
2641
|
marginTop: "16px"
|
|
1925
2642
|
}
|
|
1926
2643
|
},
|
|
1927
|
-
/* @__PURE__ */
|
|
2644
|
+
/* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
1928
2645
|
fontSize: "13px",
|
|
1929
2646
|
color: "#dc2626",
|
|
1930
2647
|
lineHeight: "1.6",
|
|
1931
2648
|
fontWeight: 500
|
|
1932
2649
|
} }, "Failed to load payment information. Please check your checkout ID.")
|
|
1933
2650
|
)),
|
|
1934
|
-
!hasInvalidCheckoutId && fetchingPaymentInfo && /* @__PURE__ */
|
|
1935
|
-
!hasInvalidCheckoutId && !fetchingPaymentInfo && !address && /* @__PURE__ */
|
|
1936
|
-
!hasInvalidCheckoutId && address && /* @__PURE__ */
|
|
2651
|
+
!hasInvalidCheckoutId && fetchingPaymentInfo && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center py-6" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { color: "#8c8c8c" } }, "Loading payment information...")),
|
|
2652
|
+
!hasInvalidCheckoutId && !fetchingPaymentInfo && !address && /* @__PURE__ */ import_react10.default.createElement("div", null, /* @__PURE__ */ import_react10.default.createElement(WalletConnect, { supportedNetworks })),
|
|
2653
|
+
!hasInvalidCheckoutId && address && /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(
|
|
1937
2654
|
"div",
|
|
1938
2655
|
{
|
|
1939
2656
|
className: "bg-gray-50 rounded-lg p-3 mb-4",
|
|
1940
2657
|
style: { border: "1px solid #f0f0f0" }
|
|
1941
2658
|
},
|
|
1942
|
-
/* @__PURE__ */
|
|
2659
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-3 flex-1" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
1943
2660
|
"div",
|
|
1944
2661
|
{
|
|
1945
2662
|
className: "w-10 h-10 rounded-full bg-black flex items-center justify-center text-white text-sm font-semibold"
|
|
1946
2663
|
},
|
|
1947
2664
|
address.slice(0, 2).toUpperCase()
|
|
1948
|
-
), /* @__PURE__ */
|
|
2665
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
1949
2666
|
display: "block",
|
|
1950
2667
|
fontSize: "12px",
|
|
1951
2668
|
color: "#8c8c8c",
|
|
1952
2669
|
marginBottom: "2px"
|
|
1953
|
-
} }, "Connected Wallet"), /* @__PURE__ */
|
|
2670
|
+
} }, "Connected Wallet"), /* @__PURE__ */ import_react10.default.createElement(
|
|
1954
2671
|
Text,
|
|
1955
2672
|
{
|
|
1956
2673
|
style: {
|
|
@@ -1960,17 +2677,17 @@ function V402Checkout({
|
|
|
1960
2677
|
}
|
|
1961
2678
|
},
|
|
1962
2679
|
formatAddress(address)
|
|
1963
|
-
))), /* @__PURE__ */
|
|
2680
|
+
))), /* @__PURE__ */ import_react10.default.createElement(
|
|
1964
2681
|
import_antd.Button,
|
|
1965
2682
|
{
|
|
1966
2683
|
type: "text",
|
|
1967
2684
|
size: "small",
|
|
1968
|
-
icon: /* @__PURE__ */
|
|
2685
|
+
icon: /* @__PURE__ */ import_react10.default.createElement(import_icons.DisconnectOutlined, null),
|
|
1969
2686
|
onClick: handleDisconnect,
|
|
1970
2687
|
style: { color: "#ff4d4f" }
|
|
1971
2688
|
}
|
|
1972
2689
|
))
|
|
1973
|
-
), paymentDetails && /* @__PURE__ */
|
|
2690
|
+
), paymentDetails && /* @__PURE__ */ import_react10.default.createElement("div", { className: "bg-gray-50 rounded-lg p-3 mb-4", style: { border: "1px solid #f0f0f0" } }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Payment Amount"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "18px", fontWeight: 600 } }, "$", paymentDetails.amount)), /* @__PURE__ */ import_react10.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Currency"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.currency)), /* @__PURE__ */ import_react10.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Network"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", fontWeight: 500 } }, paymentDetails.network)), /* @__PURE__ */ import_react10.default.createElement(import_antd.Divider, { style: { margin: "6px 0" } }), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Wallet Address"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
1974
2691
|
fontSize: "11px",
|
|
1975
2692
|
fontWeight: 500,
|
|
1976
2693
|
fontFamily: "Monaco, monospace",
|
|
@@ -1978,15 +2695,15 @@ function V402Checkout({
|
|
|
1978
2695
|
textAlign: "right",
|
|
1979
2696
|
maxWidth: "60%",
|
|
1980
2697
|
lineHeight: 1.4
|
|
1981
|
-
} }, address))), /* @__PURE__ */
|
|
2698
|
+
} }, address))), /* @__PURE__ */ import_react10.default.createElement(
|
|
1982
2699
|
"div",
|
|
1983
2700
|
{
|
|
1984
2701
|
className: "flex items-center justify-center gap-2 mb-3 p-2 rounded-lg",
|
|
1985
2702
|
style: { background: "#f6ffed", border: "1px solid #d9f7be" }
|
|
1986
2703
|
},
|
|
1987
|
-
/* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
1989
|
-
), /* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ import_react10.default.createElement(import_icons.SafetyOutlined, { style: { color: "#52c41a", fontSize: "13px" } }),
|
|
2705
|
+
/* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "12px", color: "#52c41a", fontWeight: 500 } }, "Secure payment powered by v402pay")
|
|
2706
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
1990
2707
|
import_antd.Button,
|
|
1991
2708
|
{
|
|
1992
2709
|
type: "primary",
|
|
@@ -2008,7 +2725,7 @@ function V402Checkout({
|
|
|
2008
2725
|
}
|
|
2009
2726
|
},
|
|
2010
2727
|
isProcessing ? "Processing..." : !paymentDetails ? "Loading..." : `Pay $${paymentDetails.amount} ${paymentDetails.currency}`
|
|
2011
|
-
), /* @__PURE__ */
|
|
2728
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#8c8c8c" } }, "Don't have USDC?", " "), /* @__PURE__ */ import_react10.default.createElement(
|
|
2012
2729
|
"a",
|
|
2013
2730
|
{
|
|
2014
2731
|
href: "https://faucet.circle.com/",
|
|
@@ -2017,26 +2734,26 @@ function V402Checkout({
|
|
|
2017
2734
|
className: "text-blue-600 hover:text-blue-700 text-sm font-medium inline-flex items-center gap-1"
|
|
2018
2735
|
},
|
|
2019
2736
|
"Get it here ",
|
|
2020
|
-
/* @__PURE__ */
|
|
2021
|
-
)), isModal && result && /* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ import_react10.default.createElement(import_icons.LinkOutlined, { style: { fontSize: "12px" } })
|
|
2738
|
+
)), isModal && result && /* @__PURE__ */ import_react10.default.createElement(
|
|
2022
2739
|
"div",
|
|
2023
2740
|
{
|
|
2024
2741
|
className: "mt-4 p-4 rounded-lg",
|
|
2025
2742
|
style: { background: "#f6ffed", border: "1px solid #b7eb8f" }
|
|
2026
2743
|
},
|
|
2027
|
-
/* @__PURE__ */
|
|
2744
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "20px" } }, "\u2713"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
2028
2745
|
fontSize: "14px",
|
|
2029
2746
|
color: "#52c41a",
|
|
2030
2747
|
fontWeight: 600,
|
|
2031
2748
|
marginLeft: "8px"
|
|
2032
2749
|
} }, "Payment Successful!"))
|
|
2033
|
-
), isModal && error && /* @__PURE__ */
|
|
2750
|
+
), isModal && error && /* @__PURE__ */ import_react10.default.createElement(
|
|
2034
2751
|
"div",
|
|
2035
2752
|
{
|
|
2036
2753
|
className: "mt-4 p-4 rounded-lg",
|
|
2037
2754
|
style: { background: "#fff2f0", border: "1px solid #ffccc7" }
|
|
2038
2755
|
},
|
|
2039
|
-
/* @__PURE__ */
|
|
2756
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center mb-3" }, /* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "20px" } }, "\u2717"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
2040
2757
|
fontSize: "14px",
|
|
2041
2758
|
color: "#ff4d4f",
|
|
2042
2759
|
fontWeight: 600,
|
|
@@ -2044,7 +2761,7 @@ function V402Checkout({
|
|
|
2044
2761
|
display: "block",
|
|
2045
2762
|
marginTop: "4px"
|
|
2046
2763
|
} }, "Payment Failed")),
|
|
2047
|
-
/* @__PURE__ */
|
|
2764
|
+
/* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
2048
2765
|
fontSize: "13px",
|
|
2049
2766
|
color: "#ff4d4f",
|
|
2050
2767
|
display: "block",
|
|
@@ -2052,11 +2769,11 @@ function V402Checkout({
|
|
|
2052
2769
|
} }, error)
|
|
2053
2770
|
))
|
|
2054
2771
|
),
|
|
2055
|
-
!isModal && (isProcessing || result || error) && /* @__PURE__ */
|
|
2772
|
+
!isModal && (isProcessing || result || error) && /* @__PURE__ */ import_react10.default.createElement(
|
|
2056
2773
|
import_antd.Card,
|
|
2057
2774
|
{
|
|
2058
|
-
title: /* @__PURE__ */
|
|
2059
|
-
extra: !isProcessing && /* @__PURE__ */
|
|
2775
|
+
title: /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, isProcessing && !result && !error ? /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(import_icons.LoadingOutlined, { style: { color: "#14b8a6", fontSize: "16px" } }), /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Processing Payment")) : result ? /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement("span", { style: { color: "#52c41a", fontSize: "18px" } }, "\u2713"), /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Successful")) : /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement("span", { style: { color: "#ff4d4f", fontSize: "18px" } }, "\u2717"), /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: { fontSize: "16px", color: "#262626" } }, "Payment Failed"))),
|
|
2776
|
+
extra: !isProcessing && /* @__PURE__ */ import_react10.default.createElement(
|
|
2060
2777
|
import_antd.Button,
|
|
2061
2778
|
{
|
|
2062
2779
|
type: "text",
|
|
@@ -2084,7 +2801,7 @@ function V402Checkout({
|
|
|
2084
2801
|
}
|
|
2085
2802
|
}
|
|
2086
2803
|
},
|
|
2087
|
-
isProcessing && !result && !error && /* @__PURE__ */
|
|
2804
|
+
isProcessing && !result && !error && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center py-10" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "relative inline-block" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
2088
2805
|
"div",
|
|
2089
2806
|
{
|
|
2090
2807
|
className: "absolute inset-0 rounded-full blur-xl opacity-40",
|
|
@@ -2093,12 +2810,12 @@ function V402Checkout({
|
|
|
2093
2810
|
animation: "pulse 2s ease-in-out infinite"
|
|
2094
2811
|
}
|
|
2095
2812
|
}
|
|
2096
|
-
), /* @__PURE__ */
|
|
2813
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
2097
2814
|
import_antd.Spin,
|
|
2098
2815
|
{
|
|
2099
|
-
indicator: /* @__PURE__ */
|
|
2816
|
+
indicator: /* @__PURE__ */ import_react10.default.createElement(import_icons.LoadingOutlined, { style: { fontSize: 56, color: "#14b8a6" } })
|
|
2100
2817
|
}
|
|
2101
|
-
)), /* @__PURE__ */
|
|
2818
|
+
)), /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-6" }, /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: { fontSize: "18px", color: "#262626", letterSpacing: "-0.02em" } }, "Verifying Payment")), /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-2 mb-6" }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c", lineHeight: "1.6" } }, "Please wait while we confirm your transaction")), /* @__PURE__ */ import_react10.default.createElement(
|
|
2102
2819
|
"div",
|
|
2103
2820
|
{
|
|
2104
2821
|
className: "mt-4 p-4 rounded-xl",
|
|
@@ -2107,9 +2824,9 @@ function V402Checkout({
|
|
|
2107
2824
|
border: "1px solid #ccfbf1"
|
|
2108
2825
|
}
|
|
2109
2826
|
},
|
|
2110
|
-
/* @__PURE__ */
|
|
2827
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center justify-center gap-2" }, /* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "16px" } }, "\u23F1\uFE0F"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "13px", color: "#0f766e", fontWeight: 500 } }, "This may take a few moments"))
|
|
2111
2828
|
)),
|
|
2112
|
-
result && /* @__PURE__ */
|
|
2829
|
+
result && /* @__PURE__ */ import_react10.default.createElement("div", null, /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
2113
2830
|
"div",
|
|
2114
2831
|
{
|
|
2115
2832
|
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
@@ -2118,13 +2835,13 @@ function V402Checkout({
|
|
|
2118
2835
|
boxShadow: "0 4px 20px rgba(16, 185, 129, 0.3)"
|
|
2119
2836
|
}
|
|
2120
2837
|
},
|
|
2121
|
-
/* @__PURE__ */
|
|
2122
|
-
), /* @__PURE__ */
|
|
2838
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2713")
|
|
2839
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", null, /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: {
|
|
2123
2840
|
fontSize: "20px",
|
|
2124
2841
|
color: "#262626",
|
|
2125
2842
|
display: "block",
|
|
2126
2843
|
marginBottom: "8px"
|
|
2127
|
-
} }, "Payment Successful!"), /* @__PURE__ */
|
|
2844
|
+
} }, "Payment Successful!"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Your transaction has been confirmed"))), /* @__PURE__ */ import_react10.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "RESPONSE DATA")), /* @__PURE__ */ import_react10.default.createElement(
|
|
2128
2845
|
"pre",
|
|
2129
2846
|
{
|
|
2130
2847
|
style: {
|
|
@@ -2144,7 +2861,7 @@ function V402Checkout({
|
|
|
2144
2861
|
},
|
|
2145
2862
|
JSON.stringify(result, null, 2)
|
|
2146
2863
|
)),
|
|
2147
|
-
error && /* @__PURE__ */
|
|
2864
|
+
error && /* @__PURE__ */ import_react10.default.createElement("div", null, /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center mb-6" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
2148
2865
|
"div",
|
|
2149
2866
|
{
|
|
2150
2867
|
className: "inline-flex items-center justify-center w-16 h-16 rounded-full mb-4",
|
|
@@ -2153,13 +2870,13 @@ function V402Checkout({
|
|
|
2153
2870
|
boxShadow: "0 4px 20px rgba(239, 68, 68, 0.3)"
|
|
2154
2871
|
}
|
|
2155
2872
|
},
|
|
2156
|
-
/* @__PURE__ */
|
|
2157
|
-
), /* @__PURE__ */
|
|
2873
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { style: { fontSize: "32px", color: "white" } }, "\u2717")
|
|
2874
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", null, /* @__PURE__ */ import_react10.default.createElement(Text, { strong: true, style: {
|
|
2158
2875
|
fontSize: "20px",
|
|
2159
2876
|
color: "#262626",
|
|
2160
2877
|
display: "block",
|
|
2161
2878
|
marginBottom: "8px"
|
|
2162
|
-
} }, "Payment Failed"), /* @__PURE__ */
|
|
2879
|
+
} }, "Payment Failed"), /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "14px", color: "#8c8c8c" } }, "Something went wrong with your transaction"))), /* @__PURE__ */ import_react10.default.createElement(import_antd.Divider, { style: { margin: "20px 0", borderColor: "#f0f0f0" } }, /* @__PURE__ */ import_react10.default.createElement(Text, { style: { fontSize: "12px", color: "#8c8c8c", fontWeight: 500 } }, "ERROR DETAILS")), /* @__PURE__ */ import_react10.default.createElement(
|
|
2163
2880
|
"div",
|
|
2164
2881
|
{
|
|
2165
2882
|
style: {
|
|
@@ -2169,13 +2886,13 @@ function V402Checkout({
|
|
|
2169
2886
|
border: "1px solid #fee2e2"
|
|
2170
2887
|
}
|
|
2171
2888
|
},
|
|
2172
|
-
/* @__PURE__ */
|
|
2889
|
+
/* @__PURE__ */ import_react10.default.createElement(Text, { style: {
|
|
2173
2890
|
fontSize: "14px",
|
|
2174
2891
|
color: "#dc2626",
|
|
2175
2892
|
lineHeight: "1.6",
|
|
2176
2893
|
fontWeight: 500
|
|
2177
2894
|
} }, error)
|
|
2178
|
-
), /* @__PURE__ */
|
|
2895
|
+
), /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-4 text-center" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
2179
2896
|
import_antd.Button,
|
|
2180
2897
|
{
|
|
2181
2898
|
size: "large",
|
|
@@ -2196,7 +2913,7 @@ function V402Checkout({
|
|
|
2196
2913
|
)))
|
|
2197
2914
|
)
|
|
2198
2915
|
),
|
|
2199
|
-
/* @__PURE__ */
|
|
2916
|
+
/* @__PURE__ */ import_react10.default.createElement("style", { dangerouslySetInnerHTML: {
|
|
2200
2917
|
__html: `
|
|
2201
2918
|
@keyframes slideInRight {
|
|
2202
2919
|
from {
|
|
@@ -2223,13 +2940,699 @@ function V402Checkout({
|
|
|
2223
2940
|
} })
|
|
2224
2941
|
);
|
|
2225
2942
|
}
|
|
2943
|
+
|
|
2944
|
+
// src/react/components/checkout/V402CheckoutV2.tsx
|
|
2945
|
+
var import_react15 = __toESM(require("react"));
|
|
2946
|
+
init_common();
|
|
2947
|
+
|
|
2948
|
+
// src/react/styles/animations.tsx
|
|
2949
|
+
var import_react11 = __toESM(require("react"));
|
|
2950
|
+
var checkoutAnimations = `
|
|
2951
|
+
@keyframes spin {
|
|
2952
|
+
from { transform: rotate(0deg); }
|
|
2953
|
+
to { transform: rotate(360deg); }
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
@keyframes receiptShake {
|
|
2957
|
+
0%, 100% { transform: rotate(-0.3deg); }
|
|
2958
|
+
50% { transform: rotate(0.3deg); }
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
@keyframes slideInRight {
|
|
2962
|
+
from {
|
|
2963
|
+
opacity: 0;
|
|
2964
|
+
transform: translateX(100px);
|
|
2965
|
+
}
|
|
2966
|
+
to {
|
|
2967
|
+
opacity: 1;
|
|
2968
|
+
transform: translateX(0);
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
@keyframes pulse {
|
|
2973
|
+
0%, 100% { opacity: 1; }
|
|
2974
|
+
50% { opacity: 0.4; }
|
|
2975
|
+
}
|
|
2976
|
+
`;
|
|
2977
|
+
var AnimationStyles = () => /* @__PURE__ */ import_react11.default.createElement("style", { dangerouslySetInnerHTML: { __html: checkoutAnimations } });
|
|
2978
|
+
|
|
2979
|
+
// src/react/components/checkout/Receipt.tsx
|
|
2980
|
+
var import_react12 = __toESM(require("react"));
|
|
2981
|
+
var Receipt = ({
|
|
2982
|
+
isLoading,
|
|
2983
|
+
isVisible,
|
|
2984
|
+
result,
|
|
2985
|
+
error,
|
|
2986
|
+
paymentDetails,
|
|
2987
|
+
address,
|
|
2988
|
+
onClose,
|
|
2989
|
+
primaryColor,
|
|
2990
|
+
receiptTitle,
|
|
2991
|
+
tempReceiptId
|
|
2992
|
+
}) => {
|
|
2993
|
+
const [animationState, setAnimationState] = (0, import_react12.useState)("hidden");
|
|
2994
|
+
(0, import_react12.useEffect)(() => {
|
|
2995
|
+
if (isLoading) {
|
|
2996
|
+
setAnimationState("printing");
|
|
2997
|
+
} else if (isVisible && (result || error)) {
|
|
2998
|
+
setAnimationState("visible");
|
|
2999
|
+
const timer = setTimeout(() => setAnimationState("bounce"), 50);
|
|
3000
|
+
return () => clearTimeout(timer);
|
|
3001
|
+
} else if (!isVisible) {
|
|
3002
|
+
setAnimationState("hidden");
|
|
3003
|
+
}
|
|
3004
|
+
}, [isLoading, isVisible, result, error]);
|
|
3005
|
+
(0, import_react12.useEffect)(() => {
|
|
3006
|
+
if (animationState === "bounce") {
|
|
3007
|
+
const timer = setTimeout(() => setAnimationState("visible"), 150);
|
|
3008
|
+
return () => clearTimeout(timer);
|
|
3009
|
+
}
|
|
3010
|
+
}, [animationState]);
|
|
3011
|
+
const now = /* @__PURE__ */ new Date();
|
|
3012
|
+
const dateStr = `${String(now.getMonth() + 1).padStart(2, "0")}/${String(now.getDate()).padStart(2, "0")}/${String(now.getFullYear()).slice(-2)}`;
|
|
3013
|
+
const timeStr = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
|
|
3014
|
+
const receiptId = result?.transactionHash ? result.transactionHash.slice(-8).toUpperCase() : tempReceiptId;
|
|
3015
|
+
const getAnimationStyles = () => {
|
|
3016
|
+
const baseTransition = animationState === "bounce" ? "all 0.15s cubic-bezier(0.34, 1.56, 0.64, 1)" : "all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)";
|
|
3017
|
+
switch (animationState) {
|
|
3018
|
+
case "hidden":
|
|
3019
|
+
return {
|
|
3020
|
+
opacity: 0,
|
|
3021
|
+
transform: "translateY(50px)",
|
|
3022
|
+
marginBottom: 0,
|
|
3023
|
+
transition: baseTransition
|
|
3024
|
+
};
|
|
3025
|
+
case "printing":
|
|
3026
|
+
return {
|
|
3027
|
+
opacity: 1,
|
|
3028
|
+
transform: "translateY(0)",
|
|
3029
|
+
marginBottom: "-4px",
|
|
3030
|
+
// 负边距让小票贴着机器,还没撕开的感觉
|
|
3031
|
+
animation: "receiptShake 0.12s ease-in-out infinite",
|
|
3032
|
+
transition: baseTransition
|
|
3033
|
+
};
|
|
3034
|
+
case "visible":
|
|
3035
|
+
return {
|
|
3036
|
+
opacity: 1,
|
|
3037
|
+
transform: "translateY(0)",
|
|
3038
|
+
marginBottom: "8px",
|
|
3039
|
+
transition: baseTransition
|
|
3040
|
+
};
|
|
3041
|
+
case "bounce":
|
|
3042
|
+
return {
|
|
3043
|
+
opacity: 1,
|
|
3044
|
+
transform: "translateY(-8px)",
|
|
3045
|
+
marginBottom: "8px",
|
|
3046
|
+
transition: baseTransition
|
|
3047
|
+
};
|
|
3048
|
+
default:
|
|
3049
|
+
return {};
|
|
3050
|
+
}
|
|
3051
|
+
};
|
|
3052
|
+
const getContentStyles = () => {
|
|
3053
|
+
const baseTransition = "all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)";
|
|
3054
|
+
switch (animationState) {
|
|
3055
|
+
case "hidden":
|
|
3056
|
+
return {
|
|
3057
|
+
maxHeight: 0,
|
|
3058
|
+
overflow: "hidden",
|
|
3059
|
+
transition: baseTransition
|
|
3060
|
+
};
|
|
3061
|
+
case "printing":
|
|
3062
|
+
return {
|
|
3063
|
+
maxHeight: "80px",
|
|
3064
|
+
overflow: "hidden",
|
|
3065
|
+
transition: baseTransition
|
|
3066
|
+
};
|
|
3067
|
+
case "visible":
|
|
3068
|
+
case "bounce":
|
|
3069
|
+
return {
|
|
3070
|
+
maxHeight: "600px",
|
|
3071
|
+
overflow: "visible",
|
|
3072
|
+
transition: baseTransition
|
|
3073
|
+
};
|
|
3074
|
+
default:
|
|
3075
|
+
return {};
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
if (animationState === "hidden" && !isLoading) return null;
|
|
3079
|
+
return /* @__PURE__ */ import_react12.default.createElement(
|
|
3080
|
+
"div",
|
|
3081
|
+
{
|
|
3082
|
+
className: "w-full flex justify-center",
|
|
3083
|
+
style: getAnimationStyles()
|
|
3084
|
+
},
|
|
3085
|
+
/* @__PURE__ */ import_react12.default.createElement(
|
|
3086
|
+
"div",
|
|
3087
|
+
{
|
|
3088
|
+
className: "relative bg-white shadow-2xl",
|
|
3089
|
+
style: {
|
|
3090
|
+
width: "75%",
|
|
3091
|
+
maxWidth: "280px",
|
|
3092
|
+
backgroundImage: `
|
|
3093
|
+
repeating-linear-gradient(
|
|
3094
|
+
0deg,
|
|
3095
|
+
transparent,
|
|
3096
|
+
transparent 1px,
|
|
3097
|
+
rgba(0,0,0,0.02) 1px,
|
|
3098
|
+
rgba(0,0,0,0.02) 2px
|
|
3099
|
+
)
|
|
3100
|
+
`
|
|
3101
|
+
}
|
|
3102
|
+
},
|
|
3103
|
+
/* @__PURE__ */ import_react12.default.createElement(
|
|
3104
|
+
"div",
|
|
3105
|
+
{
|
|
3106
|
+
className: "absolute top-0 left-0 right-0",
|
|
3107
|
+
style: {
|
|
3108
|
+
height: "8px",
|
|
3109
|
+
transform: "translateY(-100%)",
|
|
3110
|
+
background: `radial-gradient(circle at 50% 100%, white 5px, transparent 5px)`,
|
|
3111
|
+
backgroundSize: "12px 8px",
|
|
3112
|
+
backgroundPosition: "6px 0",
|
|
3113
|
+
backgroundRepeat: "repeat-x"
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
),
|
|
3117
|
+
/* @__PURE__ */ import_react12.default.createElement(
|
|
3118
|
+
"div",
|
|
3119
|
+
{
|
|
3120
|
+
className: "absolute left-0 right-0 bg-white",
|
|
3121
|
+
style: {
|
|
3122
|
+
height: "4px",
|
|
3123
|
+
top: "-4px"
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
),
|
|
3127
|
+
!isLoading && /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement(
|
|
3128
|
+
"div",
|
|
3129
|
+
{
|
|
3130
|
+
className: "absolute bottom-0 left-0 right-0",
|
|
3131
|
+
style: {
|
|
3132
|
+
height: "8px",
|
|
3133
|
+
transform: "translateY(100%)",
|
|
3134
|
+
background: `radial-gradient(circle at 50% 0%, white 5px, transparent 5px)`,
|
|
3135
|
+
backgroundSize: "12px 8px",
|
|
3136
|
+
backgroundPosition: "6px 0",
|
|
3137
|
+
backgroundRepeat: "repeat-x"
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
), /* @__PURE__ */ import_react12.default.createElement(
|
|
3141
|
+
"div",
|
|
3142
|
+
{
|
|
3143
|
+
className: "absolute left-0 right-0 bg-white",
|
|
3144
|
+
style: {
|
|
3145
|
+
height: "4px",
|
|
3146
|
+
bottom: "-4px"
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
)),
|
|
3150
|
+
!isLoading && (result || error) && /* @__PURE__ */ import_react12.default.createElement(
|
|
3151
|
+
"button",
|
|
3152
|
+
{
|
|
3153
|
+
onClick: onClose,
|
|
3154
|
+
className: "absolute top-3 right-3 text-gray-300 hover:text-gray-500 transition-colors bg-transparent border-none outline-none p-0 cursor-pointer",
|
|
3155
|
+
style: { background: "none", border: "none" }
|
|
3156
|
+
},
|
|
3157
|
+
/* @__PURE__ */ import_react12.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ import_react12.default.createElement("path", { d: "M18 6L6 18M6 6l12 12" }))
|
|
3158
|
+
),
|
|
3159
|
+
/* @__PURE__ */ import_react12.default.createElement("div", { className: "p-4 font-mono text-sm", style: getContentStyles() }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center mb-3" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-base font-bold tracking-wider text-gray-800" }, receiptTitle), /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between text-xs text-gray-500 mt-1" }, /* @__PURE__ */ import_react12.default.createElement("span", null, "ID: ", receiptId), /* @__PURE__ */ import_react12.default.createElement("span", null, dateStr, " ", timeStr))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "border-t border-dashed border-gray-300 my-2" }), /* @__PURE__ */ import_react12.default.createElement(
|
|
3160
|
+
"div",
|
|
3161
|
+
{
|
|
3162
|
+
className: "max-h-64 overflow-y-auto pr-1",
|
|
3163
|
+
style: {
|
|
3164
|
+
scrollbarWidth: "thin",
|
|
3165
|
+
scrollbarColor: "#d1d5db transparent"
|
|
3166
|
+
}
|
|
3167
|
+
},
|
|
3168
|
+
isLoading ? /* @__PURE__ */ import_react12.default.createElement(LoadingContent, { primaryColor }) : error ? /* @__PURE__ */ import_react12.default.createElement(ErrorContent, { error }) : result ? /* @__PURE__ */ import_react12.default.createElement(
|
|
3169
|
+
SuccessContent,
|
|
3170
|
+
{
|
|
3171
|
+
result,
|
|
3172
|
+
paymentDetails,
|
|
3173
|
+
address,
|
|
3174
|
+
primaryColor
|
|
3175
|
+
}
|
|
3176
|
+
) : null
|
|
3177
|
+
), /* @__PURE__ */ import_react12.default.createElement("div", { className: "border-t border-dashed border-gray-300 my-2" }), /* @__PURE__ */ import_react12.default.createElement(Barcode, null), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center text-xs text-gray-400 mt-1 tracking-widest" }, "POWERED BY", " ", /* @__PURE__ */ import_react12.default.createElement(
|
|
3178
|
+
"a",
|
|
3179
|
+
{
|
|
3180
|
+
href: "https://v402pay.onvoyage.ai",
|
|
3181
|
+
target: "_blank",
|
|
3182
|
+
rel: "noopener noreferrer",
|
|
3183
|
+
className: "text-gray-500 hover:text-gray-700 underline transition-colors"
|
|
3184
|
+
},
|
|
3185
|
+
"V402PAY"
|
|
3186
|
+
)))
|
|
3187
|
+
)
|
|
3188
|
+
);
|
|
3189
|
+
};
|
|
3190
|
+
var LoadingContent = ({ primaryColor }) => /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center py-4" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
3191
|
+
"div",
|
|
3192
|
+
{
|
|
3193
|
+
className: "inline-block w-8 h-8 border-2 border-gray-200 rounded-full mb-2",
|
|
3194
|
+
style: {
|
|
3195
|
+
borderTopColor: primaryColor,
|
|
3196
|
+
animation: "spin 0.8s linear infinite"
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-gray-700 font-semibold text-sm" }, "Processing..."), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-gray-400 text-xs mt-1" }, "Please wait"));
|
|
3200
|
+
var ErrorContent = ({ error }) => /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center py-3" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-red-500 text-2xl mb-2" }, "\u2717"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-red-600 font-semibold mb-1 text-sm" }, "FAILED"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-red-500 text-xs break-words px-2" }, error));
|
|
3201
|
+
var SuccessContent = ({
|
|
3202
|
+
result,
|
|
3203
|
+
paymentDetails,
|
|
3204
|
+
address,
|
|
3205
|
+
primaryColor
|
|
3206
|
+
}) => {
|
|
3207
|
+
const [copied, setCopied] = (0, import_react12.useState)(false);
|
|
3208
|
+
const handleCopy = async () => {
|
|
3209
|
+
try {
|
|
3210
|
+
await navigator.clipboard.writeText(JSON.stringify(result, null, 2));
|
|
3211
|
+
setCopied(true);
|
|
3212
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
3213
|
+
} catch (err) {
|
|
3214
|
+
console.error("Failed to copy:", err);
|
|
3215
|
+
}
|
|
3216
|
+
};
|
|
3217
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", null, /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-center mb-2" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-2xl mb-1", style: { color: primaryColor } }, "\u2713"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "font-semibold text-sm", style: { color: primaryColor } }, "SUCCESS")), /* @__PURE__ */ import_react12.default.createElement("div", { className: "space-y-1 text-xs" }, paymentDetails && /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-gray-500" }, "Amount:"), /* @__PURE__ */ import_react12.default.createElement("span", { className: "font-semibold" }, "$", paymentDetails.amount, " ", paymentDetails.currency)), /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-gray-500" }, "Network:"), /* @__PURE__ */ import_react12.default.createElement("span", { className: "font-semibold" }, paymentDetails.network))), address && /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-gray-500" }, "From:"), /* @__PURE__ */ import_react12.default.createElement("span", { className: "font-semibold" }, formatAddress(address))), result.transactionHash && /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-gray-500" }, "TX:"), /* @__PURE__ */ import_react12.default.createElement("span", { className: "font-semibold" }, formatAddress(result.transactionHash)))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "border-t border-dashed border-gray-300 my-2" }), /* @__PURE__ */ import_react12.default.createElement("div", { className: "text-xs" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex justify-between items-center mb-1" }, /* @__PURE__ */ import_react12.default.createElement("span", { className: "text-gray-500" }, "Response:"), /* @__PURE__ */ import_react12.default.createElement(
|
|
3218
|
+
"button",
|
|
3219
|
+
{
|
|
3220
|
+
onClick: handleCopy,
|
|
3221
|
+
className: "text-gray-300 hover:text-gray-500 transition-colors flex items-center gap-1 bg-transparent border-none outline-none p-0 cursor-pointer",
|
|
3222
|
+
style: { background: "none", border: "none" }
|
|
3223
|
+
},
|
|
3224
|
+
copied ? /* @__PURE__ */ import_react12.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }, /* @__PURE__ */ import_react12.default.createElement("path", { d: "M20 6L9 17l-5-5" })) : /* @__PURE__ */ import_react12.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ import_react12.default.createElement("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }), /* @__PURE__ */ import_react12.default.createElement("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" }))
|
|
3225
|
+
)), /* @__PURE__ */ import_react12.default.createElement(
|
|
3226
|
+
"pre",
|
|
3227
|
+
{
|
|
3228
|
+
className: "bg-gray-50 p-2 rounded text-xs overflow-auto whitespace-pre-wrap break-words",
|
|
3229
|
+
style: { maxHeight: "80px", fontSize: "10px" }
|
|
3230
|
+
},
|
|
3231
|
+
JSON.stringify(result, null, 2)
|
|
3232
|
+
)));
|
|
3233
|
+
};
|
|
3234
|
+
var Barcode = () => {
|
|
3235
|
+
const pattern = [2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1];
|
|
3236
|
+
const heights = [10, 12, 11, 13, 10, 14, 11, 12, 13, 10, 11, 14, 12, 10, 13, 11, 12, 14, 10, 11];
|
|
3237
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex items-center justify-center gap-0.5 h-4 opacity-60" }, pattern.map((width, i) => /* @__PURE__ */ import_react12.default.createElement(
|
|
3238
|
+
"div",
|
|
3239
|
+
{
|
|
3240
|
+
key: i,
|
|
3241
|
+
className: "bg-gray-800",
|
|
3242
|
+
style: {
|
|
3243
|
+
width: `${width}px`,
|
|
3244
|
+
height: `${heights[i]}px`
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
)));
|
|
3248
|
+
};
|
|
3249
|
+
|
|
3250
|
+
// src/react/components/checkout/TerminalScreen.tsx
|
|
3251
|
+
var import_react13 = __toESM(require("react"));
|
|
3252
|
+
var TerminalScreen = ({
|
|
3253
|
+
title,
|
|
3254
|
+
tooltipText,
|
|
3255
|
+
hasInvalidCheckoutId,
|
|
3256
|
+
fetchingPaymentInfo,
|
|
3257
|
+
address,
|
|
3258
|
+
paymentDetails,
|
|
3259
|
+
screenText,
|
|
3260
|
+
supportedNetworks
|
|
3261
|
+
}) => {
|
|
3262
|
+
return /* @__PURE__ */ import_react13.default.createElement(
|
|
3263
|
+
"div",
|
|
3264
|
+
{
|
|
3265
|
+
className: "rounded-xl p-3 mb-3",
|
|
3266
|
+
style: {
|
|
3267
|
+
backgroundColor: "#0a1a0a",
|
|
3268
|
+
boxShadow: "inset 0 3px 16px rgba(0,0,0,0.5)",
|
|
3269
|
+
border: "3px solid rgba(0,0,0,0.3)"
|
|
3270
|
+
}
|
|
3271
|
+
},
|
|
3272
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "flex items-center gap-1.5 flex-1 min-w-0" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "w-2.5 h-2.5 rounded border border-green-700 flex-shrink-0" }), title ? /* @__PURE__ */ import_react13.default.createElement(
|
|
3273
|
+
"span",
|
|
3274
|
+
{
|
|
3275
|
+
className: "text-xs font-mono",
|
|
3276
|
+
style: { color: "#22c55e80" },
|
|
3277
|
+
title
|
|
3278
|
+
},
|
|
3279
|
+
title.length > 26 ? `${title.slice(0, 13)}...${title.slice(-13)}` : title
|
|
3280
|
+
) : /* @__PURE__ */ import_react13.default.createElement("span", { className: "text-xs font-mono", style: { color: "#22c55e80" } }, "CHECKOUT")), /* @__PURE__ */ import_react13.default.createElement(
|
|
3281
|
+
"div",
|
|
3282
|
+
{
|
|
3283
|
+
className: "flex gap-0.5 flex-shrink-0 cursor-help",
|
|
3284
|
+
title: tooltipText
|
|
3285
|
+
},
|
|
3286
|
+
/* @__PURE__ */ import_react13.default.createElement(
|
|
3287
|
+
"div",
|
|
3288
|
+
{
|
|
3289
|
+
className: "w-1 h-1.5 rounded-sm",
|
|
3290
|
+
style: { backgroundColor: address ? "#22c55e80" : "#22c55e30" }
|
|
3291
|
+
}
|
|
3292
|
+
),
|
|
3293
|
+
/* @__PURE__ */ import_react13.default.createElement(
|
|
3294
|
+
"div",
|
|
3295
|
+
{
|
|
3296
|
+
className: "w-1 h-1.5 rounded-sm",
|
|
3297
|
+
style: { backgroundColor: address ? "#22c55e80" : "#22c55e30" }
|
|
3298
|
+
}
|
|
3299
|
+
),
|
|
3300
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "w-1 h-1.5 rounded-sm", style: { backgroundColor: "#22c55e80" } })
|
|
3301
|
+
)),
|
|
3302
|
+
/* @__PURE__ */ import_react13.default.createElement("div", { className: "min-h-[120px]" }, hasInvalidCheckoutId ? /* @__PURE__ */ import_react13.default.createElement(InvalidIdContent, null) : fetchingPaymentInfo ? /* @__PURE__ */ import_react13.default.createElement(LoadingContent2, null) : !address ? /* @__PURE__ */ import_react13.default.createElement(ConnectWalletContent, { supportedNetworks }) : /* @__PURE__ */ import_react13.default.createElement(
|
|
3303
|
+
PaymentInfoContent,
|
|
3304
|
+
{
|
|
3305
|
+
screenText,
|
|
3306
|
+
paymentDetails,
|
|
3307
|
+
address
|
|
3308
|
+
}
|
|
3309
|
+
))
|
|
3310
|
+
);
|
|
3311
|
+
};
|
|
3312
|
+
var InvalidIdContent = () => /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-center py-3" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-red-500 text-xl mb-1" }, "\u2717"), /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-red-500 font-mono text-sm mb-1" }, "INVALID ID"), /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-red-400 font-mono text-xs" }, "Check your checkout ID"));
|
|
3313
|
+
var LoadingContent2 = () => /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-center py-4" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
3314
|
+
"div",
|
|
3315
|
+
{
|
|
3316
|
+
className: "inline-block w-5 h-5 border-2 rounded-full mb-2",
|
|
3317
|
+
style: {
|
|
3318
|
+
borderColor: "#22c55e40",
|
|
3319
|
+
borderTopColor: "#22c55e",
|
|
3320
|
+
animation: "spin 1s linear infinite"
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
), /* @__PURE__ */ import_react13.default.createElement("div", { className: "font-mono text-sm", style: { color: "#22c55e" } }, "LOADING..."));
|
|
3324
|
+
var ConnectWalletContent = ({ supportedNetworks }) => /* @__PURE__ */ import_react13.default.createElement("div", null, /* @__PURE__ */ import_react13.default.createElement(
|
|
3325
|
+
"div",
|
|
3326
|
+
{
|
|
3327
|
+
className: "font-mono text-base mb-3 tracking-wider",
|
|
3328
|
+
style: { color: "#f97316", textShadow: "0 0 10px #f9731640" }
|
|
3329
|
+
},
|
|
3330
|
+
"CONNECT WALLET..."
|
|
3331
|
+
), /* @__PURE__ */ import_react13.default.createElement(WalletConnect, { supportedNetworks, showSwitchWallet: false }));
|
|
3332
|
+
var PaymentInfoContent = ({
|
|
3333
|
+
screenText,
|
|
3334
|
+
paymentDetails,
|
|
3335
|
+
address
|
|
3336
|
+
}) => /* @__PURE__ */ import_react13.default.createElement("div", null, /* @__PURE__ */ import_react13.default.createElement(
|
|
3337
|
+
"div",
|
|
3338
|
+
{
|
|
3339
|
+
className: "font-mono text-base mb-3 tracking-wider",
|
|
3340
|
+
style: { color: "#f97316", textShadow: "0 0 10px #f9731640" }
|
|
3341
|
+
},
|
|
3342
|
+
screenText
|
|
3343
|
+
), paymentDetails && /* @__PURE__ */ import_react13.default.createElement("div", { className: "text-xs font-mono" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "grid grid-cols-2 gap-1.5 mb-1.5" }, /* @__PURE__ */ import_react13.default.createElement("div", null, /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e60" } }, "AMOUNT"), /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e" } }, "$", paymentDetails.amount)), /* @__PURE__ */ import_react13.default.createElement("div", null, /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e60" } }, "CURRENCY"), /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e" } }, paymentDetails.currency))), /* @__PURE__ */ import_react13.default.createElement("div", null, /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e60" } }, "WALLET"), /* @__PURE__ */ import_react13.default.createElement("div", { style: { color: "#22c55e", wordBreak: "break-all" } }, address))));
|
|
3344
|
+
|
|
3345
|
+
// src/react/components/checkout/TerminalButtons.tsx
|
|
3346
|
+
var import_react14 = __toESM(require("react"));
|
|
3347
|
+
var TerminalButtons = ({
|
|
3348
|
+
address,
|
|
3349
|
+
showReceipt,
|
|
3350
|
+
isProcessing,
|
|
3351
|
+
paymentDetails,
|
|
3352
|
+
hasInvalidCheckoutId,
|
|
3353
|
+
onDisconnect,
|
|
3354
|
+
onClearReceipt,
|
|
3355
|
+
onPayment
|
|
3356
|
+
}) => {
|
|
3357
|
+
const isPayDisabled = isProcessing || !paymentDetails || !address || hasInvalidCheckoutId;
|
|
3358
|
+
return /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center justify-between px-1" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ import_react14.default.createElement(
|
|
3359
|
+
CircleButton,
|
|
3360
|
+
{
|
|
3361
|
+
onClick: () => address && onDisconnect(),
|
|
3362
|
+
disabled: !address,
|
|
3363
|
+
title: "Disconnect",
|
|
3364
|
+
size: "small"
|
|
3365
|
+
},
|
|
3366
|
+
/* @__PURE__ */ import_react14.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2" }, /* @__PURE__ */ import_react14.default.createElement("path", { d: "M18 6L6 18M6 6l12 12" }))
|
|
3367
|
+
), /* @__PURE__ */ import_react14.default.createElement(
|
|
3368
|
+
CircleButton,
|
|
3369
|
+
{
|
|
3370
|
+
onClick: onClearReceipt,
|
|
3371
|
+
disabled: !showReceipt || isProcessing,
|
|
3372
|
+
title: "Clear",
|
|
3373
|
+
size: "small"
|
|
3374
|
+
},
|
|
3375
|
+
/* @__PURE__ */ import_react14.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "2" }, /* @__PURE__ */ import_react14.default.createElement("path", { d: "M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14z" }))
|
|
3376
|
+
)), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-col gap-0.5 opacity-40" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-6 h-0.5 rounded", style: { backgroundColor: "rgba(0,0,0,0.3)" } }), /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-6 h-0.5 rounded", style: { backgroundColor: "rgba(0,0,0,0.3)" } }), /* @__PURE__ */ import_react14.default.createElement("div", { className: "w-6 h-0.5 rounded", style: { backgroundColor: "rgba(0,0,0,0.3)" } })), /* @__PURE__ */ import_react14.default.createElement(
|
|
3377
|
+
"button",
|
|
3378
|
+
{
|
|
3379
|
+
onClick: onPayment,
|
|
3380
|
+
disabled: isPayDisabled,
|
|
3381
|
+
className: "px-5 py-2.5 rounded-xl font-bold text-white flex items-center gap-2 transition-all active:scale-95",
|
|
3382
|
+
style: {
|
|
3383
|
+
backgroundColor: isPayDisabled ? "#9ca3af" : "#ea580c",
|
|
3384
|
+
boxShadow: isPayDisabled ? "none" : "0 4px 12px rgba(234,88,12,0.4), inset 0 -2px 4px rgba(0,0,0,0.2)",
|
|
3385
|
+
cursor: isPayDisabled ? "not-allowed" : "pointer"
|
|
3386
|
+
}
|
|
3387
|
+
},
|
|
3388
|
+
isProcessing ? /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement(
|
|
3389
|
+
"div",
|
|
3390
|
+
{
|
|
3391
|
+
className: "w-4 h-4 border-2 border-white/30 border-t-white rounded-full",
|
|
3392
|
+
style: { animation: "spin 0.8s linear infinite" }
|
|
3393
|
+
}
|
|
3394
|
+
), /* @__PURE__ */ import_react14.default.createElement("span", { className: "font-mono tracking-wider text-sm" }, "PAYING...")) : /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement("span", { className: "font-mono tracking-wider text-sm" }, "PAY"), /* @__PURE__ */ import_react14.default.createElement(
|
|
3395
|
+
"svg",
|
|
3396
|
+
{
|
|
3397
|
+
width: "18",
|
|
3398
|
+
height: "18",
|
|
3399
|
+
viewBox: "0 0 24 24",
|
|
3400
|
+
fill: "none",
|
|
3401
|
+
stroke: "currentColor",
|
|
3402
|
+
strokeWidth: "2"
|
|
3403
|
+
},
|
|
3404
|
+
/* @__PURE__ */ import_react14.default.createElement("path", { d: "M12 2v20M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6" })
|
|
3405
|
+
))
|
|
3406
|
+
));
|
|
3407
|
+
};
|
|
3408
|
+
var CircleButton = ({ onClick, disabled, title, size = "normal", children }) => {
|
|
3409
|
+
const sizeClass = size === "small" ? "w-10 h-10" : "w-12 h-12";
|
|
3410
|
+
return /* @__PURE__ */ import_react14.default.createElement(
|
|
3411
|
+
"button",
|
|
3412
|
+
{
|
|
3413
|
+
onClick,
|
|
3414
|
+
disabled,
|
|
3415
|
+
className: `${sizeClass} rounded-full flex items-center justify-center transition-transform active:scale-95`,
|
|
3416
|
+
style: {
|
|
3417
|
+
backgroundColor: "#374151",
|
|
3418
|
+
boxShadow: "inset 0 -2px 4px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2)",
|
|
3419
|
+
opacity: disabled ? 0.5 : 1
|
|
3420
|
+
},
|
|
3421
|
+
title
|
|
3422
|
+
},
|
|
3423
|
+
children
|
|
3424
|
+
);
|
|
3425
|
+
};
|
|
3426
|
+
|
|
3427
|
+
// src/react/components/checkout/V402CheckoutV2.tsx
|
|
3428
|
+
var generateRandomId = () => {
|
|
3429
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
3430
|
+
return Array.from({ length: 8 }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
|
|
3431
|
+
};
|
|
3432
|
+
function V402CheckoutV2({
|
|
3433
|
+
checkoutId,
|
|
3434
|
+
headerInfo = {},
|
|
3435
|
+
primaryColor = "#84cc16",
|
|
3436
|
+
isModal = false,
|
|
3437
|
+
onPaymentComplete,
|
|
3438
|
+
additionalParams = {},
|
|
3439
|
+
expectedNetwork
|
|
3440
|
+
}) {
|
|
3441
|
+
const {
|
|
3442
|
+
title = "V402Pay Checkout",
|
|
3443
|
+
brandName = "V402PAY",
|
|
3444
|
+
receiptTitle = "V402 PAYMENT",
|
|
3445
|
+
tooltipText = "V402Pay - Accept Crypto Payments Easier"
|
|
3446
|
+
} = headerInfo;
|
|
3447
|
+
const endpoint = PROD_BACK_URL;
|
|
3448
|
+
const {
|
|
3449
|
+
supportedNetworks,
|
|
3450
|
+
isLoading: fetchingPaymentInfo,
|
|
3451
|
+
paymentInfo
|
|
3452
|
+
} = usePaymentInfo(checkoutId, endpoint, additionalParams);
|
|
3453
|
+
const targetNetwork = expectedNetwork || supportedNetworks[0];
|
|
3454
|
+
const { address, networkType, disconnect, ensureNetwork } = usePageNetwork(
|
|
3455
|
+
targetNetwork,
|
|
3456
|
+
{ autoSwitch: !!targetNetwork, switchOnMount: true }
|
|
3457
|
+
);
|
|
3458
|
+
const { isProcessing, setIsProcessing, result, setResult, error, setError } = usePayment();
|
|
3459
|
+
const [paymentDetails, setPaymentDetails] = (0, import_react15.useState)(null);
|
|
3460
|
+
const [showReceipt, setShowReceipt] = (0, import_react15.useState)(false);
|
|
3461
|
+
const [tempReceiptId, setTempReceiptId] = (0, import_react15.useState)(() => generateRandomId());
|
|
3462
|
+
const handleDisconnect = () => {
|
|
3463
|
+
disconnect();
|
|
3464
|
+
setResult(null);
|
|
3465
|
+
setError(null);
|
|
3466
|
+
setShowReceipt(false);
|
|
3467
|
+
};
|
|
3468
|
+
const handlePayment = async () => {
|
|
3469
|
+
if (!networkType) return;
|
|
3470
|
+
setTempReceiptId(generateRandomId());
|
|
3471
|
+
setResult(null);
|
|
3472
|
+
setError(null);
|
|
3473
|
+
setIsProcessing(true);
|
|
3474
|
+
setShowReceipt(true);
|
|
3475
|
+
try {
|
|
3476
|
+
const response = await makePayment(networkType, checkoutId, endpoint, additionalParams, address || void 0);
|
|
3477
|
+
const data = await response.json();
|
|
3478
|
+
setResult(data);
|
|
3479
|
+
if (onPaymentComplete) {
|
|
3480
|
+
onPaymentComplete(data);
|
|
3481
|
+
}
|
|
3482
|
+
} catch (err) {
|
|
3483
|
+
setError(err.message || "Payment failed");
|
|
3484
|
+
} finally {
|
|
3485
|
+
setIsProcessing(false);
|
|
3486
|
+
}
|
|
3487
|
+
};
|
|
3488
|
+
const handleCloseReceipt = () => {
|
|
3489
|
+
setShowReceipt(false);
|
|
3490
|
+
setResult(null);
|
|
3491
|
+
setError(null);
|
|
3492
|
+
};
|
|
3493
|
+
(0, import_react15.useEffect)(() => {
|
|
3494
|
+
if (paymentInfo && paymentInfo.length > 0) {
|
|
3495
|
+
const firstPayment = paymentInfo[0];
|
|
3496
|
+
const rawAmount = firstPayment.maxAmountRequired?.toString() || "0";
|
|
3497
|
+
const decimals = 6;
|
|
3498
|
+
const humanReadableAmount = (Number(rawAmount) / Math.pow(10, decimals)).toFixed(2);
|
|
3499
|
+
const network = firstPayment.network || "Unknown";
|
|
3500
|
+
const currency = "USDC";
|
|
3501
|
+
setPaymentDetails({ amount: humanReadableAmount, currency, network });
|
|
3502
|
+
}
|
|
3503
|
+
}, [paymentInfo]);
|
|
3504
|
+
(0, import_react15.useEffect)(() => {
|
|
3505
|
+
if (targetNetwork && !fetchingPaymentInfo && ensureNetwork) {
|
|
3506
|
+
ensureNetwork(targetNetwork).catch((err) => {
|
|
3507
|
+
console.error("Failed to ensure network:", err);
|
|
3508
|
+
});
|
|
3509
|
+
}
|
|
3510
|
+
}, [targetNetwork, fetchingPaymentInfo]);
|
|
3511
|
+
(0, import_react15.useEffect)(() => {
|
|
3512
|
+
if (isProcessing || result || error) {
|
|
3513
|
+
setShowReceipt(true);
|
|
3514
|
+
}
|
|
3515
|
+
}, [isProcessing, result, error]);
|
|
3516
|
+
const hasInvalidCheckoutId = !fetchingPaymentInfo && (!paymentInfo || paymentInfo.length === 0);
|
|
3517
|
+
const NetworkIcon = paymentDetails ? getNetworkIcon(paymentDetails.network) : null;
|
|
3518
|
+
const screenText = paymentDetails ? `PAY $${paymentDetails.amount} ${paymentDetails.currency}` : "AWAITING...";
|
|
3519
|
+
const getStatusText = () => {
|
|
3520
|
+
if (hasInvalidCheckoutId) return "ERROR";
|
|
3521
|
+
if (fetchingPaymentInfo) return "LOADING";
|
|
3522
|
+
if (!address) return "CONNECT";
|
|
3523
|
+
if (isProcessing) return "PAYING";
|
|
3524
|
+
return "READY";
|
|
3525
|
+
};
|
|
3526
|
+
return /* @__PURE__ */ import_react15.default.createElement("div", { className: isModal ? "bg-transparent" : "min-h-screen bg-gray-100 flex items-center justify-center p-4" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
3527
|
+
"div",
|
|
3528
|
+
{
|
|
3529
|
+
className: "flex flex-col items-center",
|
|
3530
|
+
style: { width: isModal ? "100%" : "380px", maxWidth: "100%" }
|
|
3531
|
+
},
|
|
3532
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
3533
|
+
Receipt,
|
|
3534
|
+
{
|
|
3535
|
+
isLoading: isProcessing,
|
|
3536
|
+
isVisible: showReceipt,
|
|
3537
|
+
result,
|
|
3538
|
+
error,
|
|
3539
|
+
paymentDetails,
|
|
3540
|
+
address,
|
|
3541
|
+
onClose: handleCloseReceipt,
|
|
3542
|
+
primaryColor,
|
|
3543
|
+
receiptTitle,
|
|
3544
|
+
tempReceiptId
|
|
3545
|
+
}
|
|
3546
|
+
),
|
|
3547
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
3548
|
+
"div",
|
|
3549
|
+
{
|
|
3550
|
+
className: "relative rounded-2xl p-3 shadow-2xl w-full",
|
|
3551
|
+
style: {
|
|
3552
|
+
backgroundColor: primaryColor,
|
|
3553
|
+
boxShadow: `0 16px 48px -8px ${primaryColor}66, 0 8px 24px -4px rgba(0,0,0,0.3);padding-bottom: 0px`
|
|
3554
|
+
}
|
|
3555
|
+
},
|
|
3556
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
3557
|
+
"div",
|
|
3558
|
+
{
|
|
3559
|
+
className: "absolute top-0 left-1/2 -translate-x-1/2 w-1/3 h-2.5 rounded-b-lg",
|
|
3560
|
+
style: { backgroundColor: "rgba(0,0,0,0.4)" }
|
|
3561
|
+
}
|
|
3562
|
+
),
|
|
3563
|
+
/* @__PURE__ */ import_react15.default.createElement("div", { className: "flex justify-between items-center mb-2 mt-1 px-1" }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
3564
|
+
"div",
|
|
3565
|
+
{
|
|
3566
|
+
className: "w-2 h-2 rounded-full",
|
|
3567
|
+
style: {
|
|
3568
|
+
backgroundColor: address ? "#22c55e" : "#ef4444",
|
|
3569
|
+
animation: "pulse 2s ease-in-out infinite"
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
), /* @__PURE__ */ import_react15.default.createElement(
|
|
3573
|
+
"span",
|
|
3574
|
+
{
|
|
3575
|
+
className: "text-xs font-mono font-bold tracking-wider",
|
|
3576
|
+
style: { color: "rgba(0,0,0,0.7)" }
|
|
3577
|
+
},
|
|
3578
|
+
getStatusText()
|
|
3579
|
+
)), /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-1.5" }, paymentDetails && NetworkIcon && /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react15.default.createElement(NetworkIcon, { width: 12, height: 12, style: { color: "rgba(0,0,0,0.7)" } }), /* @__PURE__ */ import_react15.default.createElement("span", { className: "text-xs font-mono font-bold", style: { color: "rgba(0,0,0,0.7)" } }, paymentDetails.network)))),
|
|
3580
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
3581
|
+
TerminalScreen,
|
|
3582
|
+
{
|
|
3583
|
+
title,
|
|
3584
|
+
tooltipText,
|
|
3585
|
+
hasInvalidCheckoutId,
|
|
3586
|
+
fetchingPaymentInfo,
|
|
3587
|
+
address,
|
|
3588
|
+
paymentDetails,
|
|
3589
|
+
screenText,
|
|
3590
|
+
supportedNetworks
|
|
3591
|
+
}
|
|
3592
|
+
),
|
|
3593
|
+
/* @__PURE__ */ import_react15.default.createElement(
|
|
3594
|
+
TerminalButtons,
|
|
3595
|
+
{
|
|
3596
|
+
address,
|
|
3597
|
+
showReceipt,
|
|
3598
|
+
isProcessing,
|
|
3599
|
+
paymentDetails,
|
|
3600
|
+
hasInvalidCheckoutId,
|
|
3601
|
+
onDisconnect: handleDisconnect,
|
|
3602
|
+
onClearReceipt: handleCloseReceipt,
|
|
3603
|
+
onPayment: handlePayment
|
|
3604
|
+
}
|
|
3605
|
+
),
|
|
3606
|
+
brandName && /* @__PURE__ */ import_react15.default.createElement("div", { className: "text-center mt-0 mb-0" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
3607
|
+
"div",
|
|
3608
|
+
{
|
|
3609
|
+
className: "inline-block px-2 py-0.5 rounded text-[10px] font-mono font-bold tracking-[0.2em]",
|
|
3610
|
+
style: {
|
|
3611
|
+
backgroundColor: "#1a1a1a",
|
|
3612
|
+
color: "#9acd32",
|
|
3613
|
+
boxShadow: "inset 0 1px 3px rgba(0,0,0,0.8), 0 1px 0 rgba(255,255,255,0.1)",
|
|
3614
|
+
border: "1px solid rgba(0,0,0,0.5)",
|
|
3615
|
+
textShadow: "0 0 4px #9acd3280"
|
|
3616
|
+
}
|
|
3617
|
+
},
|
|
3618
|
+
brandName
|
|
3619
|
+
))
|
|
3620
|
+
)
|
|
3621
|
+
), /* @__PURE__ */ import_react15.default.createElement(AnimationStyles, null));
|
|
3622
|
+
}
|
|
2226
3623
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2227
3624
|
0 && (module.exports = {
|
|
3625
|
+
AnimationStyles,
|
|
3626
|
+
Toast,
|
|
2228
3627
|
V402Checkout,
|
|
3628
|
+
V402CheckoutV2,
|
|
2229
3629
|
WalletConnect,
|
|
3630
|
+
WalletSelectModal,
|
|
3631
|
+
checkoutAnimations,
|
|
2230
3632
|
usePageNetwork,
|
|
2231
3633
|
usePayment,
|
|
2232
3634
|
usePaymentInfo,
|
|
3635
|
+
useToast,
|
|
2233
3636
|
useWallet
|
|
2234
3637
|
});
|
|
2235
3638
|
//# sourceMappingURL=index.js.map
|