@dj-test/payment-sdk 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/dist/index.mjs ADDED
@@ -0,0 +1,3789 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/core/constants.ts
8
+ var SDK_VERSION = "1.0.0";
9
+ var API_ENDPOINTS = {
10
+ ORDERS: "/payments",
11
+ PRODUCTS: "/products"
12
+ };
13
+ var ENVIRONMENT_URLS = {
14
+ production: "https://pay.com",
15
+ sandbox: "http://localhost:8080"
16
+ };
17
+ var PAYMENT_DOMAINS = {
18
+ production: "https://pay-home.com",
19
+ sandbox: "http://localhost:3000"
20
+ };
21
+ var DEFAULT_TIMEOUT = 3e4;
22
+ var ORDER_EXPIRY_MINUTES = 30;
23
+ var MIN_WITHDRAWAL_AMOUNT = 0.01;
24
+ var SUPPORTED_CHAINS = {
25
+ ETHEREUM: "1",
26
+ SEPOLIA: "11155111",
27
+ POLYGON: "137"
28
+ };
29
+ var ERROR_CODES = {
30
+ INVALID_API_KEY: "INVALID_API_KEY",
31
+ INVALID_PRODUCT: "INVALID_PRODUCT",
32
+ ORDER_NOT_FOUND: "ORDER_NOT_FOUND",
33
+ ORDER_EXPIRED: "ORDER_EXPIRED",
34
+ INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
35
+ SELF_TRANSFER: "SELF_TRANSFER",
36
+ INVALID_ADDRESS: "INVALID_ADDRESS",
37
+ NETWORK_ERROR: "NETWORK_ERROR"
38
+ };
39
+
40
+ // src/core/config.ts
41
+ var Config = class _Config {
42
+ constructor() {
43
+ this.config = null;
44
+ }
45
+ static getInstance() {
46
+ if (!_Config.instance) {
47
+ _Config.instance = new _Config();
48
+ }
49
+ return _Config.instance;
50
+ }
51
+ initialize(config2) {
52
+ if (!config2.baseUrl && config2.environment) {
53
+ config2.baseUrl = ENVIRONMENT_URLS[config2.environment];
54
+ }
55
+ if (!config2.timeout) {
56
+ config2.timeout = DEFAULT_TIMEOUT;
57
+ }
58
+ this.config = config2;
59
+ }
60
+ getConfig() {
61
+ if (!this.config) {
62
+ return {
63
+ environment: "sandbox",
64
+ baseUrl: ENVIRONMENT_URLS.sandbox,
65
+ timeout: DEFAULT_TIMEOUT
66
+ };
67
+ }
68
+ return this.config;
69
+ }
70
+ isInitialized() {
71
+ return this.config !== null;
72
+ }
73
+ reset() {
74
+ this.config = null;
75
+ }
76
+ };
77
+ var config = Config.getInstance();
78
+
79
+ // src/core/wagmi-config.ts
80
+ import { http, createConfig } from "wagmi";
81
+ import {
82
+ mainnet,
83
+ sepolia,
84
+ polygon,
85
+ polygonAmoy,
86
+ base,
87
+ baseSepolia
88
+ } from "wagmi/chains";
89
+ import { injected, walletConnect } from "@wagmi/connectors";
90
+ var supportedEvmChains = [
91
+ mainnet,
92
+ sepolia,
93
+ polygon,
94
+ polygonAmoy,
95
+ base,
96
+ baseSepolia
97
+ ];
98
+ var supportedChains = supportedEvmChains;
99
+ var createWagmiConfig = (projectId) => {
100
+ const connectors = [injected()];
101
+ if (projectId) {
102
+ const sdkConfig = config.getConfig();
103
+ const environment = sdkConfig.environment || "sandbox";
104
+ const paymentDomain = PAYMENT_DOMAINS[environment];
105
+ connectors.push(
106
+ walletConnect({
107
+ projectId,
108
+ metadata: {
109
+ name: "Payment SDK",
110
+ description: "Multi-chain Payment SDK",
111
+ url: paymentDomain,
112
+ icons: [`${paymentDomain}/icon.png`]
113
+ },
114
+ showQrModal: true
115
+ })
116
+ );
117
+ }
118
+ return createConfig({
119
+ chains: [mainnet, sepolia, polygon, polygonAmoy, base, baseSepolia],
120
+ connectors,
121
+ transports: {
122
+ [mainnet.id]: http(),
123
+ [sepolia.id]: http(),
124
+ [polygon.id]: http(),
125
+ [polygonAmoy.id]: http(),
126
+ [base.id]: http(),
127
+ [baseSepolia.id]: http()
128
+ },
129
+ ssr: true
130
+ });
131
+ };
132
+ var getEvmChainById = (chainId) => {
133
+ return supportedEvmChains.find((chain) => chain.id === chainId);
134
+ };
135
+ var getChainById = getEvmChainById;
136
+
137
+ // src/core/WalletContext.tsx
138
+ import { createContext, useContext } from "react";
139
+ import { jsx } from "react/jsx-runtime";
140
+ var WalletContext = createContext(null);
141
+ var useWalletContext = () => {
142
+ const context = useContext(WalletContext);
143
+ if (!context) {
144
+ throw new Error("useWalletContext must be used within WalletProvider");
145
+ }
146
+ return context;
147
+ };
148
+ var WalletContextProvider = ({ factory, children }) => {
149
+ return /* @__PURE__ */ jsx(WalletContext.Provider, { value: { factory }, children });
150
+ };
151
+
152
+ // src/components/PaymentProvider.tsx
153
+ import { createContext as createContext2, useEffect } from "react";
154
+ import { jsx as jsx2 } from "react/jsx-runtime";
155
+ var PaymentContext = createContext2(null);
156
+ var isValidUrl = (url) => {
157
+ try {
158
+ new URL(url);
159
+ return true;
160
+ } catch {
161
+ return false;
162
+ }
163
+ };
164
+ var PaymentProvider = ({
165
+ baseUrl,
166
+ paymentDomain,
167
+ redirectUrl,
168
+ webhookUrl,
169
+ environment = "sandbox",
170
+ timeout,
171
+ children
172
+ }) => {
173
+ useEffect(() => {
174
+ if (redirectUrl && !isValidUrl(redirectUrl)) {
175
+ console.error("Invalid redirectUrl");
176
+ }
177
+ if (webhookUrl && !isValidUrl(webhookUrl)) {
178
+ console.error("Invalid webhookUrl");
179
+ }
180
+ if (paymentDomain && !isValidUrl(paymentDomain)) {
181
+ console.error("Invalid paymentDomain");
182
+ }
183
+ const sdkConfig = {
184
+ environment,
185
+ baseUrl,
186
+ paymentDomain,
187
+ redirectUrl,
188
+ webhookUrl,
189
+ timeout
190
+ };
191
+ config.initialize(sdkConfig);
192
+ }, [environment, baseUrl, paymentDomain, redirectUrl, webhookUrl, timeout]);
193
+ const contextValue = {
194
+ config: {
195
+ environment,
196
+ baseUrl,
197
+ paymentDomain,
198
+ redirectUrl,
199
+ webhookUrl,
200
+ timeout
201
+ },
202
+ isInitialized: config.isInitialized()
203
+ };
204
+ return /* @__PURE__ */ jsx2(PaymentContext.Provider, { value: contextValue, children });
205
+ };
206
+
207
+ // src/components/PaymentButton.tsx
208
+ import { useState as useState8, useContext as useContext3 } from "react";
209
+
210
+ // src/hooks/usePayment.ts
211
+ import { useState, useCallback, useContext as useContext2 } from "react";
212
+
213
+ // src/api/orders.ts
214
+ var orders_exports = {};
215
+ __export(orders_exports, {
216
+ createOrder: () => createOrder,
217
+ getOrder: () => getOrder,
218
+ getOrders: () => getOrders
219
+ });
220
+
221
+ // src/api/client.ts
222
+ import axios from "axios";
223
+
224
+ // src/types/sdk.ts
225
+ var SDKError = class extends Error {
226
+ constructor(message, code, details) {
227
+ super(message);
228
+ this.code = code;
229
+ this.details = details;
230
+ this.name = "SDKError";
231
+ }
232
+ };
233
+ var APIError = class extends SDKError {
234
+ constructor(message, statusCode, details) {
235
+ super(message, "API_ERROR", details);
236
+ this.statusCode = statusCode;
237
+ this.name = "APIError";
238
+ }
239
+ };
240
+
241
+ // src/api/client.ts
242
+ var APIClient = class {
243
+ constructor() {
244
+ this.instance = null;
245
+ }
246
+ getClient() {
247
+ if (!this.instance) {
248
+ const sdkConfig = config.getConfig();
249
+ this.instance = axios.create({
250
+ baseURL: sdkConfig.baseUrl,
251
+ timeout: sdkConfig.timeout,
252
+ headers: {
253
+ "Content-Type": "application/json"
254
+ },
255
+ withCredentials: true
256
+ // 기존 프로젝트 패턴과 일치
257
+ });
258
+ this.instance.interceptors.request.use(
259
+ (requestConfig) => {
260
+ return requestConfig;
261
+ },
262
+ (error) => Promise.reject(error)
263
+ );
264
+ this.instance.interceptors.response.use(
265
+ (response) => response,
266
+ (error) => {
267
+ const status = error.response?.status;
268
+ const data = error.response?.data;
269
+ const message = data?.message || error.message;
270
+ const details = error.response?.data;
271
+ throw new APIError(message, status, details);
272
+ }
273
+ );
274
+ }
275
+ return this.instance;
276
+ }
277
+ reset() {
278
+ this.instance = null;
279
+ }
280
+ };
281
+ var apiClient = new APIClient();
282
+
283
+ // src/api/orders.ts
284
+ var createOrder = async (productId, redirectUrl, webhookUrl) => {
285
+ const request = {
286
+ productId,
287
+ redirectUrl,
288
+ webhookUrl
289
+ };
290
+ const response = await apiClient.getClient().post(API_ENDPOINTS.ORDERS, request);
291
+ const order = response.data.output;
292
+ return {
293
+ orderId: order.uuid,
294
+ publicOrderId: order.uuid,
295
+ paymentUrl: "",
296
+ // 사용 안 함
297
+ amount: 0,
298
+ // 주문 생성 시점에는 없음
299
+ coinId: "",
300
+ // 주문 생성 시점에는 없음
301
+ chainId: "",
302
+ // 주문 생성 시점에는 없음
303
+ status: order.status,
304
+ expiresAt: "",
305
+ // 주문 생성 시점에는 없음
306
+ redirectUrl: order.redirectUrl || null
307
+ // 서버 응답의 redirectUrl
308
+ };
309
+ };
310
+ var getOrder = async (publicOrderId) => {
311
+ const response = await apiClient.getClient().get(`${API_ENDPOINTS.ORDERS}/${publicOrderId}`);
312
+ const orderData = response.data.output;
313
+ if (!orderData || typeof orderData !== "object") {
314
+ throw new Error("Order data is null or invalid");
315
+ }
316
+ if (!orderData.orderId || orderData.orderStat === void 0 || orderData.orderStat === null) {
317
+ throw new Error("Order data is incomplete - missing required fields");
318
+ }
319
+ return orderData;
320
+ };
321
+ var getOrders = async () => {
322
+ const response = await apiClient.getClient().get(API_ENDPOINTS.ORDERS);
323
+ return response.data.output;
324
+ };
325
+
326
+ // src/utils/errors.ts
327
+ import { AxiosError as AxiosError2 } from "axios";
328
+ var handleAPIError = (error) => {
329
+ if (error instanceof SDKError) {
330
+ return error;
331
+ }
332
+ if (error instanceof AxiosError2) {
333
+ const status = error.response?.status;
334
+ const message = error.response?.data?.message || error.message;
335
+ const details = error.response?.data;
336
+ return new APIError(message, status, details);
337
+ }
338
+ if (error instanceof Error) {
339
+ return new SDKError(error.message);
340
+ }
341
+ return new SDKError("Unknown error occurred");
342
+ };
343
+ var getErrorMessage = (error) => {
344
+ const sdkError = handleAPIError(error);
345
+ if (sdkError instanceof APIError) {
346
+ switch (sdkError.statusCode) {
347
+ case 401:
348
+ return "\uC778\uC99D\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. API \uD0A4\uB97C \uD655\uC778\uD574\uC8FC\uC138\uC694.";
349
+ case 403:
350
+ return "\uC811\uADFC \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
351
+ case 404:
352
+ return "\uC694\uCCAD\uD55C \uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";
353
+ case 429:
354
+ return "\uC694\uCCAD \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.";
355
+ case 500:
356
+ return "\uC11C\uBC84 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.";
357
+ default:
358
+ return sdkError.message;
359
+ }
360
+ }
361
+ return sdkError.message;
362
+ };
363
+
364
+ // src/utils/validation.ts
365
+ var validation_exports = {};
366
+ __export(validation_exports, {
367
+ validateProductId: () => validateProductId,
368
+ validateWithdrawalAddress: () => validateWithdrawalAddress
369
+ });
370
+
371
+ // src/utils/address.ts
372
+ function isEvmAddress(address) {
373
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
374
+ }
375
+ function isTronAddress(address) {
376
+ return /^T[A-Za-z0-9]{33}$/.test(address);
377
+ }
378
+ function detectChainType(address) {
379
+ if (isEvmAddress(address)) {
380
+ return "evm";
381
+ }
382
+ if (isTronAddress(address)) {
383
+ return "tron";
384
+ }
385
+ return null;
386
+ }
387
+ function isValidAddress(address) {
388
+ return isEvmAddress(address) || isTronAddress(address);
389
+ }
390
+
391
+ // src/utils/validation.ts
392
+ var validateWithdrawalAddress = (fromAddress, toAddress) => {
393
+ const normalizedFrom = fromAddress.trim();
394
+ const normalizedTo = toAddress.trim();
395
+ if (isEvmAddress(normalizedFrom) && isEvmAddress(normalizedTo)) {
396
+ if (normalizedFrom.toLowerCase() === normalizedTo.toLowerCase()) {
397
+ return {
398
+ valid: false,
399
+ error: "Cannot send to your own wallet address"
400
+ };
401
+ }
402
+ } else if (isTronAddress(normalizedFrom) && isTronAddress(normalizedTo)) {
403
+ if (normalizedFrom === normalizedTo) {
404
+ return {
405
+ valid: false,
406
+ error: "Cannot send to your own wallet address"
407
+ };
408
+ }
409
+ }
410
+ if (!isValidAddress(toAddress)) {
411
+ return {
412
+ valid: false,
413
+ error: "Invalid wallet address format"
414
+ };
415
+ }
416
+ return { valid: true };
417
+ };
418
+ var validateProductId = (productId) => {
419
+ if (!productId || productId.trim().length === 0) {
420
+ return {
421
+ valid: false,
422
+ error: "Product ID is required"
423
+ };
424
+ }
425
+ return { valid: true };
426
+ };
427
+
428
+ // src/hooks/usePayment.ts
429
+ var usePayment = () => {
430
+ const context = useContext2(PaymentContext);
431
+ if (!context) {
432
+ throw new Error("usePayment must be used within PaymentProvider");
433
+ }
434
+ const { config: config2 } = context;
435
+ const [isLoading, setIsLoading] = useState(false);
436
+ const [error, setError] = useState(null);
437
+ const [order, setOrder] = useState(null);
438
+ const create = useCallback(
439
+ async (params) => {
440
+ setIsLoading(true);
441
+ setError(null);
442
+ try {
443
+ const validation = validateProductId(params.productId);
444
+ if (!validation.valid) {
445
+ throw new Error(validation.error);
446
+ }
447
+ const orderResponse = await createOrder(
448
+ params.productId,
449
+ config2.redirectUrl || "",
450
+ config2.webhookUrl || ""
451
+ );
452
+ setOrder(orderResponse);
453
+ return orderResponse;
454
+ } catch (err) {
455
+ const sdkError = handleAPIError(err);
456
+ setError(sdkError);
457
+ throw sdkError;
458
+ } finally {
459
+ setIsLoading(false);
460
+ }
461
+ },
462
+ [config2.redirectUrl, config2.webhookUrl]
463
+ );
464
+ return {
465
+ createOrder: create,
466
+ isLoading,
467
+ error,
468
+ order,
469
+ errorMessage: error ? getErrorMessage(error) : null
470
+ };
471
+ };
472
+
473
+ // src/components/PaymentModal.tsx
474
+ import { useEffect as useEffect8 } from "react";
475
+
476
+ // src/components/OrderPayment.tsx
477
+ import { useEffect as useEffect7, useState as useState7 } from "react";
478
+
479
+ // src/hooks/useOrder.ts
480
+ import { useState as useState2, useEffect as useEffect2, useRef } from "react";
481
+
482
+ // src/utils/orderStatus.ts
483
+ var isOrderSuccess = (status) => {
484
+ return status === "S" || status === "1";
485
+ };
486
+ var isOrderFailed = (status) => {
487
+ return status === "F" || status === "4";
488
+ };
489
+ var isOrderRefundInsufficient = (status) => {
490
+ return status === "R1" || status === "2";
491
+ };
492
+ var isOrderRefundExcess = (status) => {
493
+ return status === "R2" || status === "3";
494
+ };
495
+ var isOrderFinalState = (status) => {
496
+ return isOrderSuccess(status) || isOrderFailed(status) || isOrderRefundInsufficient(status) || isOrderRefundExcess(status);
497
+ };
498
+ var getOrderState = (status) => {
499
+ if (isOrderSuccess(status)) return "success" /* SUCCESS */;
500
+ if (isOrderFailed(status)) return "failed" /* FAILED */;
501
+ if (isOrderRefundInsufficient(status)) return "refund_insufficient" /* REFUND_INSUFFICIENT */;
502
+ if (isOrderRefundExcess(status)) return "refund_excess" /* REFUND_EXCESS */;
503
+ return "waiting" /* WAITING */;
504
+ };
505
+ var getOrderStatusMessage = (status) => {
506
+ const state = getOrderState(status);
507
+ switch (state) {
508
+ case "success" /* SUCCESS */:
509
+ return "Payment successful";
510
+ case "failed" /* FAILED */:
511
+ return "Payment failed";
512
+ case "refund_insufficient" /* REFUND_INSUFFICIENT */:
513
+ return "Payment refunded - Insufficient amount";
514
+ case "refund_excess" /* REFUND_EXCESS */:
515
+ return "Payment refunded - Excess amount";
516
+ case "waiting" /* WAITING */:
517
+ default:
518
+ return "Waiting for payment";
519
+ }
520
+ };
521
+
522
+ // src/hooks/useOrder.ts
523
+ var useOrder = (publicOrderId, options) => {
524
+ const [order, setOrder] = useState2(null);
525
+ const [isLoading, setIsLoading] = useState2(true);
526
+ const [error, setError] = useState2(null);
527
+ const pollingInterval = options?.pollingInterval || 5e3;
528
+ const enablePolling = options?.enablePolling ?? true;
529
+ const intervalRef = useRef(null);
530
+ const isInitialFetch = useRef(true);
531
+ useEffect2(() => {
532
+ if (!publicOrderId) return;
533
+ let retryCount = 0;
534
+ const maxRetries = 5;
535
+ const fetchOrder = async (isInitial = false) => {
536
+ if (isInitial) {
537
+ setIsLoading(true);
538
+ }
539
+ setError(null);
540
+ try {
541
+ const orderData = await getOrder(publicOrderId);
542
+ setOrder(orderData);
543
+ retryCount = 0;
544
+ if (enablePolling && isOrderFinalState(orderData.orderStat)) {
545
+ if (intervalRef.current) {
546
+ clearInterval(intervalRef.current);
547
+ intervalRef.current = null;
548
+ }
549
+ }
550
+ } catch (err) {
551
+ const sdkError = handleAPIError(err);
552
+ if (isInitial && retryCount < maxRetries && (sdkError.message.includes("incomplete") || sdkError.message.includes("null or invalid"))) {
553
+ retryCount++;
554
+ console.log(`[useOrder] Retrying order fetch (${retryCount}/${maxRetries})...`);
555
+ setTimeout(() => fetchOrder(true), 500);
556
+ return;
557
+ }
558
+ setError(sdkError);
559
+ } finally {
560
+ if (isInitial && retryCount === 0) {
561
+ setIsLoading(false);
562
+ }
563
+ }
564
+ };
565
+ fetchOrder(true);
566
+ isInitialFetch.current = false;
567
+ if (enablePolling) {
568
+ intervalRef.current = setInterval(() => fetchOrder(false), pollingInterval);
569
+ }
570
+ return () => {
571
+ if (intervalRef.current) {
572
+ clearInterval(intervalRef.current);
573
+ intervalRef.current = null;
574
+ }
575
+ };
576
+ }, [publicOrderId, pollingInterval, enablePolling]);
577
+ const refetch = async () => {
578
+ if (!publicOrderId) return;
579
+ setIsLoading(true);
580
+ try {
581
+ const orderData = await getOrder(publicOrderId);
582
+ setOrder(orderData);
583
+ } catch (err) {
584
+ const sdkError = handleAPIError(err);
585
+ setError(sdkError);
586
+ } finally {
587
+ setIsLoading(false);
588
+ }
589
+ };
590
+ return {
591
+ order,
592
+ isLoading,
593
+ error,
594
+ refetch
595
+ };
596
+ };
597
+
598
+ // src/components/PaymentFlow.tsx
599
+ import { useState as useState6, useEffect as useEffect6 } from "react";
600
+
601
+ // src/components/PayWithWallet.tsx
602
+ import { useState as useState4, useEffect as useEffect4, useMemo } from "react";
603
+ import { parseUnits } from "viem";
604
+
605
+ // src/hooks/useWalletAdapter.ts
606
+ import { useState as useState3, useEffect as useEffect3 } from "react";
607
+ import { watchChainId } from "@wagmi/core";
608
+
609
+ // src/adapters/EvmWalletAdapter.ts
610
+ import {
611
+ getAccount,
612
+ getBalance,
613
+ getChainId,
614
+ connect,
615
+ disconnect,
616
+ switchChain,
617
+ sendTransaction,
618
+ writeContract,
619
+ getConnections,
620
+ getConnectors
621
+ } from "@wagmi/core";
622
+ var ERC20_ABI = [
623
+ {
624
+ name: "transfer",
625
+ type: "function",
626
+ stateMutability: "nonpayable",
627
+ inputs: [
628
+ { name: "to", type: "address" },
629
+ { name: "amount", type: "uint256" }
630
+ ],
631
+ outputs: [{ name: "", type: "bool" }]
632
+ }
633
+ ];
634
+ var EvmWalletAdapter = class {
635
+ constructor(config2) {
636
+ this.type = "evm";
637
+ this.chainType = "evm";
638
+ this.config = config2;
639
+ }
640
+ // 연결 상태
641
+ isConnected() {
642
+ const account = getAccount(this.config);
643
+ return account.isConnected;
644
+ }
645
+ getAddress() {
646
+ const account = getAccount(this.config);
647
+ return account.address || null;
648
+ }
649
+ getChainId() {
650
+ try {
651
+ return getChainId(this.config);
652
+ } catch {
653
+ return null;
654
+ }
655
+ }
656
+ async getBalance() {
657
+ const account = getAccount(this.config);
658
+ if (!account.address) return null;
659
+ try {
660
+ const balance = await getBalance(this.config, {
661
+ address: account.address
662
+ });
663
+ return {
664
+ value: balance.value,
665
+ decimals: balance.decimals,
666
+ symbol: balance.symbol,
667
+ formatted: balance.formatted
668
+ };
669
+ } catch (error) {
670
+ console.error("[EvmWalletAdapter] Failed to get balance:", error);
671
+ return null;
672
+ }
673
+ }
674
+ getConnectionInfo() {
675
+ const account = getAccount(this.config);
676
+ if (!account.isConnected || !account.address) {
677
+ return null;
678
+ }
679
+ const currentChainId = this.getChainId();
680
+ console.log("[EvmWalletAdapter] getConnectionInfo:", {
681
+ isConnected: account.isConnected,
682
+ address: account.address,
683
+ accountChainId: account.chainId,
684
+ currentChainId,
685
+ status: account.status
686
+ });
687
+ if (!currentChainId) {
688
+ return null;
689
+ }
690
+ return {
691
+ address: account.address,
692
+ chainId: currentChainId,
693
+ // 실제 현재 체인 ID 사용
694
+ chainType: this.chainType,
695
+ isConnected: account.isConnected,
696
+ connector: account.connector ? {
697
+ id: account.connector.id,
698
+ name: account.connector.name,
699
+ icon: account.connector.icon
700
+ } : void 0
701
+ };
702
+ }
703
+ // 연결 관리
704
+ async connect(connectorId) {
705
+ try {
706
+ const connectors = getConnectors(this.config);
707
+ const connector = connectorId ? connectors.find((c) => c.id === connectorId) : connectors[0];
708
+ if (!connector) {
709
+ throw new Error(
710
+ connectorId ? `Connector ${connectorId} not found` : "No connectors available"
711
+ );
712
+ }
713
+ await connect(this.config, { connector });
714
+ } catch (error) {
715
+ console.error("[EvmWalletAdapter] Connection failed:", error);
716
+ throw error;
717
+ }
718
+ }
719
+ async disconnect() {
720
+ try {
721
+ const connections = getConnections(this.config);
722
+ if (connections.length > 0) {
723
+ await disconnect(this.config, {
724
+ connector: connections[0].connector
725
+ });
726
+ }
727
+ } catch (error) {
728
+ console.error("[EvmWalletAdapter] Disconnect failed:", error);
729
+ throw error;
730
+ }
731
+ }
732
+ async switchChain(chainId) {
733
+ if (typeof chainId === "string") {
734
+ throw new Error("EVM adapter expects numeric chainId");
735
+ }
736
+ const currentChainId = getAccount(this.config).chainId;
737
+ console.log(`[EvmWalletAdapter] Switching chain from ${currentChainId} to ${chainId}`);
738
+ try {
739
+ await switchChain(this.config, { chainId });
740
+ console.log(`[EvmWalletAdapter] Switch chain completed for chainId: ${chainId}`);
741
+ } catch (error) {
742
+ console.error("[EvmWalletAdapter] Switch chain failed:", error);
743
+ console.error("[EvmWalletAdapter] Error details:", {
744
+ message: error.message,
745
+ code: error.code,
746
+ name: error.name
747
+ });
748
+ throw error;
749
+ }
750
+ }
751
+ // 트랜잭션
752
+ async sendPayment(tx) {
753
+ try {
754
+ const account = getAccount(this.config);
755
+ if (!account.isConnected || !account.address) {
756
+ throw new Error("Wallet not connected");
757
+ }
758
+ if (typeof tx.chainId === "string") {
759
+ throw new Error("EVM adapter expects numeric chainId");
760
+ }
761
+ const currentChainId = getChainId(this.config);
762
+ console.log("[EvmWalletAdapter] sendPayment - Current chain check:", {
763
+ currentChainId,
764
+ accountChainId: account.chainId,
765
+ requestedChainId: tx.chainId
766
+ });
767
+ if (currentChainId !== tx.chainId) {
768
+ console.log(`[EvmWalletAdapter] Chain mismatch! Switching from ${currentChainId} to ${tx.chainId}`);
769
+ await this.switchChain(tx.chainId);
770
+ const chainIdAfterSwitch = getChainId(this.config);
771
+ console.log("[EvmWalletAdapter] After switch:", {
772
+ chainId: chainIdAfterSwitch,
773
+ expected: tx.chainId
774
+ });
775
+ if (chainIdAfterSwitch !== tx.chainId) {
776
+ throw new Error(`Failed to switch to chain ${tx.chainId}. Current chain: ${chainIdAfterSwitch}`);
777
+ }
778
+ }
779
+ let hash;
780
+ const chain = this.config.chains.find((c) => c.id === tx.chainId);
781
+ if (!chain) {
782
+ throw new Error(`Chain ${tx.chainId} not found in wagmi config`);
783
+ }
784
+ if (tx.tokenAddress && tx.decimals !== void 0) {
785
+ console.log("[EvmWalletAdapter] ERC20 Transfer:", {
786
+ token: tx.tokenAddress,
787
+ to: tx.to,
788
+ value: tx.value.toString(),
789
+ decimals: tx.decimals,
790
+ chainId: tx.chainId,
791
+ chainName: chain.name
792
+ });
793
+ hash = await writeContract(this.config, {
794
+ address: tx.tokenAddress,
795
+ abi: ERC20_ABI,
796
+ functionName: "transfer",
797
+ args: [tx.to, tx.value],
798
+ chain
799
+ });
800
+ console.log("[EvmWalletAdapter] ERC20 Transfer hash:", hash);
801
+ } else {
802
+ console.log("[EvmWalletAdapter] Native Transfer:", {
803
+ to: tx.to,
804
+ value: tx.value.toString(),
805
+ chainId: tx.chainId,
806
+ chainName: chain.name
807
+ });
808
+ hash = await sendTransaction(this.config, {
809
+ to: tx.to,
810
+ value: tx.value,
811
+ chainId: tx.chainId
812
+ });
813
+ console.log("[EvmWalletAdapter] Native Transfer hash:", hash);
814
+ }
815
+ return { success: true, hash };
816
+ } catch (error) {
817
+ console.error("[EvmWalletAdapter] Payment failed:", error);
818
+ return {
819
+ success: false,
820
+ hash: "0x",
821
+ error: error?.message ?? "Transaction failed"
822
+ };
823
+ }
824
+ }
825
+ // 지원 여부 확인
826
+ isChainSupported(chainId) {
827
+ if (typeof chainId === "string") return false;
828
+ return this.config.chains.some((chain) => chain.id === chainId);
829
+ }
830
+ getChainType(_chainId) {
831
+ return this.chainType;
832
+ }
833
+ // 커넥터 정보
834
+ getConnectors() {
835
+ const connectors = getConnectors(this.config);
836
+ return connectors.map((c) => ({
837
+ id: c.id,
838
+ name: c.name,
839
+ icon: c.icon
840
+ }));
841
+ }
842
+ checkWalletInstalled(connectorId) {
843
+ const connectors = getConnectors(this.config);
844
+ return connectors.some((c) => c.id === connectorId);
845
+ }
846
+ };
847
+
848
+ // src/hooks/useWalletAdapter.ts
849
+ var useWalletAdapter = (options) => {
850
+ const { factory } = useWalletContext();
851
+ const { chainId, depositAddress } = typeof options === "object" && options !== null ? options : { chainId: options, depositAddress: void 0 };
852
+ const [activeAdapter, setActiveAdapter] = useState3(
853
+ null
854
+ );
855
+ const [connectionInfo, setConnectionInfo] = useState3(null);
856
+ const [balance, setBalance] = useState3(null);
857
+ const [isSending, setIsSending] = useState3(false);
858
+ const [txHash, setTxHash] = useState3(null);
859
+ useEffect3(() => {
860
+ if (depositAddress) {
861
+ const adapter = factory.getAdapterByAddress(depositAddress);
862
+ setActiveAdapter(adapter);
863
+ return;
864
+ }
865
+ if (chainId) {
866
+ const adapter = factory.getAdapterForChain(chainId);
867
+ setActiveAdapter(adapter);
868
+ return;
869
+ }
870
+ const connected = factory.getConnectedAdapter();
871
+ setActiveAdapter(connected);
872
+ }, [chainId, depositAddress, factory]);
873
+ useEffect3(() => {
874
+ if (!activeAdapter) return;
875
+ const updateConnectionInfo = () => {
876
+ const info = activeAdapter.getConnectionInfo();
877
+ setConnectionInfo(info);
878
+ if (info?.isConnected) {
879
+ activeAdapter.getBalance().then(setBalance);
880
+ }
881
+ };
882
+ updateConnectionInfo();
883
+ if (activeAdapter.type === "evm" && activeAdapter instanceof EvmWalletAdapter) {
884
+ const unwatch = watchChainId(activeAdapter.config, {
885
+ onChange: (chainId2) => {
886
+ console.log("[useWalletAdapter] Chain changed to:", chainId2);
887
+ updateConnectionInfo();
888
+ }
889
+ });
890
+ return unwatch;
891
+ }
892
+ }, [activeAdapter]);
893
+ const connect2 = async (walletType, connectorId) => {
894
+ try {
895
+ const adapter = factory.getAdapter(walletType);
896
+ if (!adapter) {
897
+ throw new Error(`Adapter for ${walletType} not found`);
898
+ }
899
+ await adapter.connect(connectorId);
900
+ setActiveAdapter(adapter);
901
+ const info = adapter.getConnectionInfo();
902
+ setConnectionInfo(info);
903
+ if (info?.isConnected) {
904
+ const bal = await adapter.getBalance();
905
+ setBalance(bal);
906
+ }
907
+ } catch (error) {
908
+ console.error("[useWalletAdapter] Connection failed:", error);
909
+ throw error;
910
+ }
911
+ };
912
+ const disconnect2 = async () => {
913
+ if (!activeAdapter) return;
914
+ try {
915
+ await activeAdapter.disconnect();
916
+ setConnectionInfo(null);
917
+ setBalance(null);
918
+ if (!depositAddress && !chainId) {
919
+ setActiveAdapter(null);
920
+ }
921
+ } catch (error) {
922
+ console.error("[useWalletAdapter] Disconnect failed:", error);
923
+ throw error;
924
+ }
925
+ };
926
+ const switchChain2 = async (targetChainId) => {
927
+ if (!activeAdapter) {
928
+ throw new Error("No active adapter");
929
+ }
930
+ try {
931
+ await activeAdapter.switchChain(targetChainId);
932
+ const info = activeAdapter.getConnectionInfo();
933
+ setConnectionInfo(info);
934
+ } catch (error) {
935
+ console.error("[useWalletAdapter] Switch chain failed:", error);
936
+ throw error;
937
+ }
938
+ };
939
+ const sendPayment = async (tx) => {
940
+ if (!activeAdapter) {
941
+ throw new Error("No active adapter");
942
+ }
943
+ setIsSending(true);
944
+ setTxHash(null);
945
+ try {
946
+ const result = await activeAdapter.sendPayment(tx);
947
+ if (result.success) {
948
+ setTxHash(result.hash);
949
+ }
950
+ return result;
951
+ } catch (error) {
952
+ console.error("[useWalletAdapter] Payment failed:", error);
953
+ return {
954
+ success: false,
955
+ hash: "",
956
+ error: error?.message || "Payment failed"
957
+ };
958
+ } finally {
959
+ setIsSending(false);
960
+ }
961
+ };
962
+ const getAllConnectors = () => {
963
+ const adapters = factory.getAllAdapters();
964
+ const connectors = [];
965
+ adapters.forEach((adapter) => {
966
+ const adapterConnectors = adapter.getConnectors();
967
+ adapterConnectors.forEach((conn) => {
968
+ connectors.push({
969
+ ...conn,
970
+ walletType: adapter.type
971
+ });
972
+ });
973
+ });
974
+ return connectors;
975
+ };
976
+ const getConnectors2 = (walletType) => {
977
+ if (walletType) {
978
+ const adapter = factory.getAdapter(walletType);
979
+ return adapter?.getConnectors() || [];
980
+ }
981
+ if (activeAdapter) {
982
+ return activeAdapter.getConnectors();
983
+ }
984
+ return [];
985
+ };
986
+ const checkWalletInstalled = (walletType, connectorId) => {
987
+ const adapter = factory.getAdapter(walletType);
988
+ return adapter?.checkWalletInstalled(connectorId) || false;
989
+ };
990
+ const getChainType = (chainId2) => {
991
+ try {
992
+ return factory.getChainType(chainId2);
993
+ } catch {
994
+ return null;
995
+ }
996
+ };
997
+ const getWallet = () => {
998
+ if (!activeAdapter) return null;
999
+ return activeAdapter.getConnectionInfo();
1000
+ };
1001
+ return {
1002
+ // 연결 정보
1003
+ wallet: connectionInfo,
1004
+ address: connectionInfo?.address || null,
1005
+ chainId: connectionInfo?.chainId || null,
1006
+ chainType: connectionInfo?.chainType || null,
1007
+ isConnected: connectionInfo?.isConnected || false,
1008
+ balance,
1009
+ // 어댑터 정보
1010
+ activeAdapter,
1011
+ adapterType: activeAdapter?.type || null,
1012
+ // 연결 관리
1013
+ connect: connect2,
1014
+ disconnect: disconnect2,
1015
+ switchChain: switchChain2,
1016
+ // 커넥터
1017
+ connectors: getConnectors2(),
1018
+ allConnectors: getAllConnectors(),
1019
+ checkWalletInstalled,
1020
+ // 트랜잭션
1021
+ sendPayment,
1022
+ isSending,
1023
+ txHash,
1024
+ // 유틸리티
1025
+ getChainType,
1026
+ getWallet,
1027
+ factory
1028
+ };
1029
+ };
1030
+
1031
+ // src/utils/format.ts
1032
+ var truncateAddress = (address, startChars = 6, endChars = 6) => {
1033
+ if (!address) return "";
1034
+ if (address.length <= startChars + endChars) return address;
1035
+ return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;
1036
+ };
1037
+ var truncateHash = (hash) => {
1038
+ return truncateAddress(hash, 10, 8);
1039
+ };
1040
+ var truncateOrderId = (orderId) => {
1041
+ return truncateAddress(orderId, 6, 6);
1042
+ };
1043
+ var shortenErrorMessage = (error) => {
1044
+ const message = typeof error === "string" ? error : error.message;
1045
+ const patterns = [
1046
+ {
1047
+ pattern: /User rejected the request|User denied transaction signature/i,
1048
+ replacement: "Transaction cancelled"
1049
+ },
1050
+ {
1051
+ pattern: /insufficient funds|Insufficient balance/i,
1052
+ replacement: "Insufficient balance"
1053
+ },
1054
+ {
1055
+ pattern: /Failed to fetch|Network request failed/i,
1056
+ replacement: "Network error"
1057
+ },
1058
+ {
1059
+ pattern: /Cannot read properties of null/i,
1060
+ replacement: "Data not ready"
1061
+ },
1062
+ {
1063
+ pattern: /Order data is incomplete - missing required fields/i,
1064
+ replacement: "Payment details loading..."
1065
+ }
1066
+ ];
1067
+ for (const { pattern, replacement } of patterns) {
1068
+ if (pattern.test(message)) {
1069
+ return replacement;
1070
+ }
1071
+ }
1072
+ if (message.length > 100) {
1073
+ return message.slice(0, 97) + "...";
1074
+ }
1075
+ return message;
1076
+ };
1077
+
1078
+ // src/components/PayWithWallet.tsx
1079
+ import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
1080
+ var PayWithWallet = ({
1081
+ toAddress,
1082
+ amount,
1083
+ coinId,
1084
+ chainId,
1085
+ chainInfo,
1086
+ tokenAddress,
1087
+ decimals,
1088
+ publicOrderId,
1089
+ onSuccess,
1090
+ onError,
1091
+ className = "",
1092
+ children
1093
+ }) => {
1094
+ const adapter = useWalletAdapter({ depositAddress: toAddress });
1095
+ const {
1096
+ wallet,
1097
+ connect: connect2,
1098
+ disconnect: disconnect2,
1099
+ connectors,
1100
+ sendPayment,
1101
+ txHash,
1102
+ checkWalletInstalled,
1103
+ switchChain: switchChain2,
1104
+ adapterType,
1105
+ getWallet
1106
+ } = adapter;
1107
+ const [showWalletSelector, setShowWalletSelector] = useState4(false);
1108
+ const [error, setError] = useState4(null);
1109
+ const [hasNotified] = useState4(false);
1110
+ const [isProcessing, setIsProcessing] = useState4(false);
1111
+ const [isConnecting, setIsConnecting] = useState4(false);
1112
+ const installedWallets = useMemo(() => {
1113
+ if (!adapterType) return [];
1114
+ console.log("[PayWithWallet] Checking installed wallets...", {
1115
+ adapterType,
1116
+ connectors: connectors.map((c) => c.id)
1117
+ });
1118
+ const installed = connectors.filter((c) => {
1119
+ const isInstalled = checkWalletInstalled(adapterType, c.id);
1120
+ console.log(
1121
+ `[PayWithWallet] Connector ${c.id}: ${isInstalled ? "INSTALLED" : "NOT INSTALLED"}`
1122
+ );
1123
+ return isInstalled;
1124
+ });
1125
+ console.log(
1126
+ "[PayWithWallet] Installed wallets:",
1127
+ installed.map((w) => w.id)
1128
+ );
1129
+ return installed;
1130
+ }, [adapterType, connectors, checkWalletInstalled]);
1131
+ console.log("[PayWithWallet] Render state:", {
1132
+ depositAddress: toAddress,
1133
+ adapterType,
1134
+ connectors: connectors.map((c) => c.id),
1135
+ installedWallets: installedWallets.map((w) => w.id),
1136
+ hasInstalledWallets: installedWallets.length > 0
1137
+ });
1138
+ useEffect4(() => {
1139
+ if (txHash) {
1140
+ setIsProcessing(false);
1141
+ }
1142
+ }, [txHash]);
1143
+ useEffect4(() => {
1144
+ }, [txHash, publicOrderId, hasNotified, onSuccess]);
1145
+ const handleConnect = async (connectorId) => {
1146
+ if (!adapterType) {
1147
+ setError("Wallet adapter not initialized");
1148
+ return;
1149
+ }
1150
+ try {
1151
+ setError(null);
1152
+ setIsConnecting(true);
1153
+ await connect2(adapterType, connectorId);
1154
+ setShowWalletSelector(false);
1155
+ } catch (err) {
1156
+ const errorMsg = shortenErrorMessage(
1157
+ err instanceof Error ? err : "Failed to connect wallet"
1158
+ );
1159
+ setError(errorMsg);
1160
+ } finally {
1161
+ setIsConnecting(false);
1162
+ }
1163
+ };
1164
+ const handlePay = async () => {
1165
+ if (!wallet) {
1166
+ setError("Please connect your wallet first");
1167
+ return;
1168
+ }
1169
+ try {
1170
+ setError(null);
1171
+ setIsProcessing(true);
1172
+ const validation = validateWithdrawalAddress(wallet.address, toAddress);
1173
+ if (!validation.valid) {
1174
+ setError("Invalid wallet address");
1175
+ setIsProcessing(false);
1176
+ return;
1177
+ }
1178
+ if (wallet.chainId !== chainId) {
1179
+ if (adapterType === "tron") {
1180
+ const networkNames = {
1181
+ 728126428: "Mainnet",
1182
+ 2494104990: "Shasta",
1183
+ 3448148188: "Nile"
1184
+ };
1185
+ const requiredNetwork = networkNames[chainId] || chainId;
1186
+ setError(`Switch to ${requiredNetwork} network`);
1187
+ setIsProcessing(false);
1188
+ return;
1189
+ }
1190
+ console.log(`[PayWithWallet] Switching chain from ${wallet.chainId} to ${chainId}`);
1191
+ await switchChain2(chainId);
1192
+ let attempts = 0;
1193
+ let switched = false;
1194
+ while (attempts < 30) {
1195
+ await new Promise((resolve) => setTimeout(resolve, 100));
1196
+ const currentWallet = getWallet();
1197
+ console.log(`[PayWithWallet] Attempt ${attempts}: current chainId = ${currentWallet?.chainId}, target = ${chainId}`);
1198
+ if (currentWallet && currentWallet.chainId === chainId) {
1199
+ console.log(`[PayWithWallet] Chain switched successfully to ${chainId}`);
1200
+ switched = true;
1201
+ break;
1202
+ }
1203
+ attempts++;
1204
+ }
1205
+ if (!switched) {
1206
+ setError(`Please switch to ${chainInfo.name} network in your wallet`);
1207
+ setIsProcessing(false);
1208
+ return;
1209
+ }
1210
+ }
1211
+ const finalCheck = getWallet();
1212
+ if (!finalCheck || finalCheck.chainId !== chainId) {
1213
+ console.error(`[PayWithWallet] Chain mismatch before sending! Current: ${finalCheck?.chainId}, Required: ${chainId}`);
1214
+ setError(`Wrong network. Please switch to ${chainInfo.name} in MetaMask`);
1215
+ setIsProcessing(false);
1216
+ return;
1217
+ }
1218
+ console.log(`[PayWithWallet] Chain verified: ${chainId}, proceeding with payment`);
1219
+ let value;
1220
+ if (tokenAddress && decimals !== void 0) {
1221
+ value = parseUnits(amount, decimals);
1222
+ } else {
1223
+ value = parseUnits(amount, chainInfo.coinDigit);
1224
+ }
1225
+ const result = await sendPayment({
1226
+ to: toAddress,
1227
+ value,
1228
+ chainId,
1229
+ coinId,
1230
+ tokenAddress,
1231
+ decimals
1232
+ });
1233
+ if (!result.success) {
1234
+ const errorMsg = shortenErrorMessage(
1235
+ result.error || "Transaction failed"
1236
+ );
1237
+ setError(errorMsg);
1238
+ onError?.(errorMsg);
1239
+ setIsProcessing(false);
1240
+ }
1241
+ } catch (err) {
1242
+ const errorMsg = shortenErrorMessage(
1243
+ err instanceof Error ? err : "Payment failed"
1244
+ );
1245
+ setError(errorMsg);
1246
+ onError?.(errorMsg);
1247
+ setIsProcessing(false);
1248
+ }
1249
+ };
1250
+ return /* @__PURE__ */ jsxs("div", { className: `payment-with-wallet ${className}`, children: [
1251
+ children ? children : /* @__PURE__ */ jsxs("div", { className: "payment-container", children: [
1252
+ /* @__PURE__ */ jsx3("h3", { children: "Payment Details" }),
1253
+ /* @__PURE__ */ jsxs("div", { className: "payment-info", children: [
1254
+ /* @__PURE__ */ jsxs("div", { className: "info-row", children: [
1255
+ /* @__PURE__ */ jsx3("span", { className: "label", children: "Amount" }),
1256
+ /* @__PURE__ */ jsxs("span", { className: "value amount-value", children: [
1257
+ amount,
1258
+ " ",
1259
+ coinId
1260
+ ] })
1261
+ ] }),
1262
+ /* @__PURE__ */ jsxs("div", { className: "info-row", children: [
1263
+ /* @__PURE__ */ jsx3("span", { className: "label", children: "Network" }),
1264
+ /* @__PURE__ */ jsx3("span", { className: "value", children: chainInfo.name })
1265
+ ] }),
1266
+ /* @__PURE__ */ jsxs("div", { className: "info-row", children: [
1267
+ /* @__PURE__ */ jsx3("span", { className: "label", children: "To" }),
1268
+ /* @__PURE__ */ jsx3("span", { className: "value address", children: truncateAddress(toAddress) })
1269
+ ] })
1270
+ ] }),
1271
+ isProcessing && !txHash ? /* @__PURE__ */ jsxs("div", { className: "waiting-verification", children: [
1272
+ /* @__PURE__ */ jsx3("div", { className: "waiting-icon", children: /* @__PURE__ */ jsx3("div", { className: "waiting-spinner-large" }) }),
1273
+ /* @__PURE__ */ jsx3("h3", { children: "Waiting for Approval" }),
1274
+ /* @__PURE__ */ jsxs("p", { className: "waiting-message", children: [
1275
+ "Please approve the transaction in your wallet",
1276
+ /* @__PURE__ */ jsx3("br", {}),
1277
+ "Check your wallet extension to continue"
1278
+ ] }),
1279
+ /* @__PURE__ */ jsxs("div", { className: "verification-notice", children: [
1280
+ /* @__PURE__ */ jsx3(
1281
+ "svg",
1282
+ {
1283
+ width: "16",
1284
+ height: "16",
1285
+ viewBox: "0 0 16 16",
1286
+ fill: "currentColor",
1287
+ children: /* @__PURE__ */ jsx3("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zM8 11a.75.75 0 01-.75-.75v-4.5a.75.75 0 011.5 0v4.5A.75.75 0 018 11z" })
1288
+ }
1289
+ ),
1290
+ /* @__PURE__ */ jsx3("span", { children: "Do not close this window" })
1291
+ ] })
1292
+ ] }) : txHash ? /* @__PURE__ */ jsxs("div", { className: "waiting-verification", children: [
1293
+ /* @__PURE__ */ jsx3("div", { className: "waiting-icon", children: /* @__PURE__ */ jsx3("div", { className: "waiting-spinner-large" }) }),
1294
+ /* @__PURE__ */ jsx3("h3", { children: "Processing Payment" }),
1295
+ /* @__PURE__ */ jsxs("p", { className: "waiting-message", children: [
1296
+ "Your transaction is being processed",
1297
+ /* @__PURE__ */ jsx3("br", {}),
1298
+ "Please wait for confirmation"
1299
+ ] }),
1300
+ /* @__PURE__ */ jsxs("div", { className: "tx-info", children: [
1301
+ /* @__PURE__ */ jsx3("span", { className: "tx-label", children: "Transaction Hash" }),
1302
+ /* @__PURE__ */ jsx3("code", { className: "tx-hash-code", children: truncateHash(txHash) })
1303
+ ] }),
1304
+ /* @__PURE__ */ jsxs("div", { className: "verification-notice", children: [
1305
+ /* @__PURE__ */ jsx3(
1306
+ "svg",
1307
+ {
1308
+ width: "16",
1309
+ height: "16",
1310
+ viewBox: "0 0 16 16",
1311
+ fill: "currentColor",
1312
+ children: /* @__PURE__ */ jsx3("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zM8 11a.75.75 0 01-.75-.75v-4.5a.75.75 0 011.5 0v4.5A.75.75 0 018 11z" })
1313
+ }
1314
+ ),
1315
+ /* @__PURE__ */ jsx3("span", { children: "This may take a few moments" })
1316
+ ] })
1317
+ ] }) : !wallet?.isConnected ? /* @__PURE__ */ jsxs("div", { className: "wallet-connection", children: [
1318
+ /* @__PURE__ */ jsx3("p", { children: "Connect your wallet to continue" }),
1319
+ installedWallets.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1320
+ /* @__PURE__ */ jsx3(
1321
+ "button",
1322
+ {
1323
+ onClick: () => setShowWalletSelector(!showWalletSelector),
1324
+ className: "btn-primary",
1325
+ disabled: isConnecting,
1326
+ children: isConnecting ? "Connecting..." : "Select Wallet"
1327
+ }
1328
+ ),
1329
+ showWalletSelector && /* @__PURE__ */ jsx3("div", { className: "wallet-selector", children: installedWallets.map((connector) => /* @__PURE__ */ jsxs(
1330
+ "button",
1331
+ {
1332
+ onClick: () => handleConnect(connector.id),
1333
+ className: "wallet-option",
1334
+ children: [
1335
+ connector.icon && /* @__PURE__ */ jsx3("img", { src: connector.icon, alt: connector.name }),
1336
+ /* @__PURE__ */ jsx3("span", { children: connector.name })
1337
+ ]
1338
+ },
1339
+ connector.id
1340
+ )) })
1341
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "no-wallets", children: [
1342
+ /* @__PURE__ */ jsx3("p", { children: "No compatible wallet detected" }),
1343
+ /* @__PURE__ */ jsx3("p", { className: "wallet-hint", children: adapterType === "tron" ? "Please install TronLink extension to continue" : "Please install MetaMask, Trust Wallet, or WalletConnect to continue" })
1344
+ ] })
1345
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "wallet-connected", children: [
1346
+ /* @__PURE__ */ jsxs("div", { className: "connected-info", children: [
1347
+ /* @__PURE__ */ jsx3("p", { className: "connected-address", children: truncateAddress(wallet.address, 6, 4) }),
1348
+ /* @__PURE__ */ jsx3("button", { onClick: () => disconnect2(), className: "btn-disconnect", children: "Disconnect" })
1349
+ ] }),
1350
+ /* @__PURE__ */ jsx3(
1351
+ "button",
1352
+ {
1353
+ onClick: handlePay,
1354
+ className: "btn-primary",
1355
+ disabled: isProcessing,
1356
+ children: isProcessing ? "Sending..." : `Pay ${amount} ${coinId}`
1357
+ }
1358
+ )
1359
+ ] }),
1360
+ error && /* @__PURE__ */ jsx3("div", { className: "error-message", children: error })
1361
+ ] }),
1362
+ /* @__PURE__ */ jsx3("style", { children: `
1363
+ .payment-with-wallet {
1364
+ padding: 1.5rem;
1365
+ }
1366
+
1367
+ .payment-container {
1368
+ max-width: 500px;
1369
+ margin: 0 auto;
1370
+ }
1371
+
1372
+ h3 {
1373
+ font-size: 1.25rem;
1374
+ font-weight: 600;
1375
+ margin-bottom: 1.5rem;
1376
+ color: hsl(222.2 47.4% 11.2%);
1377
+ }
1378
+
1379
+ .payment-info {
1380
+ background: hsl(0 0% 100%);
1381
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1382
+ padding: 1.25rem;
1383
+ border-radius: 0.75rem;
1384
+ margin-bottom: 1.5rem;
1385
+ }
1386
+
1387
+ .info-row {
1388
+ display: flex;
1389
+ justify-content: space-between;
1390
+ align-items: center;
1391
+ padding: 0.625rem 0;
1392
+ border-bottom: 1px solid hsl(214.3 31.8% 91.4%);
1393
+ }
1394
+
1395
+ .info-row:last-child {
1396
+ border-bottom: none;
1397
+ padding-bottom: 0;
1398
+ }
1399
+
1400
+ .info-row:first-child {
1401
+ padding-top: 0;
1402
+ }
1403
+
1404
+ .label {
1405
+ font-size: 0.875rem;
1406
+ color: hsl(215.4 16.3% 46.9%);
1407
+ font-weight: 500;
1408
+ }
1409
+
1410
+ .value {
1411
+ font-size: 0.875rem;
1412
+ color: hsl(222.2 47.4% 11.2%);
1413
+ font-weight: 500;
1414
+ }
1415
+
1416
+ .amount-value {
1417
+ font-size: 1.125rem;
1418
+ font-weight: 600;
1419
+ color: hsl(222.2 47.4% 11.2%);
1420
+ }
1421
+
1422
+ .address {
1423
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
1424
+ font-size: 0.8125rem;
1425
+ color: hsl(215.4 16.3% 46.9%);
1426
+ }
1427
+
1428
+ .waiting-verification {
1429
+ text-align: center;
1430
+ padding: 2.5rem 1.5rem;
1431
+ background: hsl(0 0% 100%);
1432
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1433
+ border-radius: 0.75rem;
1434
+ }
1435
+
1436
+ .waiting-icon {
1437
+ margin: 0 auto 1.5rem;
1438
+ display: flex;
1439
+ justify-content: center;
1440
+ }
1441
+
1442
+ .waiting-spinner-large {
1443
+ width: 48px;
1444
+ height: 48px;
1445
+ border: 3px solid hsl(214.3 31.8% 91.4%);
1446
+ border-top-color: hsl(222.2 47.4% 11.2%);
1447
+ border-radius: 50%;
1448
+ animation: spin 0.8s linear infinite;
1449
+ }
1450
+
1451
+ .waiting-verification h3 {
1452
+ font-size: 1.125rem;
1453
+ font-weight: 600;
1454
+ color: hsl(222.2 47.4% 11.2%);
1455
+ margin-bottom: 0.75rem;
1456
+ }
1457
+
1458
+ .waiting-message {
1459
+ color: hsl(215.4 16.3% 46.9%);
1460
+ line-height: 1.6;
1461
+ margin-bottom: 1.5rem;
1462
+ font-size: 0.875rem;
1463
+ }
1464
+
1465
+ .tx-info {
1466
+ background: hsl(210 40% 98%);
1467
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1468
+ padding: 1rem;
1469
+ border-radius: 0.5rem;
1470
+ margin-bottom: 1.5rem;
1471
+ }
1472
+
1473
+ .tx-label {
1474
+ display: block;
1475
+ font-size: 0.8125rem;
1476
+ color: hsl(215.4 16.3% 46.9%);
1477
+ margin-bottom: 0.5rem;
1478
+ font-weight: 500;
1479
+ }
1480
+
1481
+ .tx-hash-code {
1482
+ display: block;
1483
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
1484
+ font-size: 0.8125rem;
1485
+ color: hsl(222.2 47.4% 11.2%);
1486
+ word-break: break-all;
1487
+ }
1488
+
1489
+ .verification-notice {
1490
+ display: flex;
1491
+ align-items: flex-start;
1492
+ gap: 0.75rem;
1493
+ padding: 0.875rem 1rem;
1494
+ background: hsl(210 40% 98%);
1495
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1496
+ border-radius: 0.5rem;
1497
+ text-align: left;
1498
+ }
1499
+
1500
+ .verification-notice svg {
1501
+ flex-shrink: 0;
1502
+ color: hsl(215.4 16.3% 46.9%);
1503
+ margin-top: 1px;
1504
+ }
1505
+
1506
+ .verification-notice span {
1507
+ font-size: 0.8125rem;
1508
+ color: hsl(215.4 16.3% 46.9%);
1509
+ line-height: 1.5;
1510
+ }
1511
+
1512
+ .wallet-connection,
1513
+ .wallet-connected {
1514
+ margin-top: 1.5rem;
1515
+ }
1516
+
1517
+ .wallet-selector {
1518
+ margin-top: 1rem;
1519
+ display: flex;
1520
+ flex-direction: column;
1521
+ gap: 0.625rem;
1522
+ }
1523
+
1524
+ .wallet-option {
1525
+ display: flex;
1526
+ align-items: center;
1527
+ gap: 0.75rem;
1528
+ padding: 0.875rem 1rem;
1529
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1530
+ border-radius: 0.5rem;
1531
+ background: hsl(0 0% 100%);
1532
+ cursor: pointer;
1533
+ transition: all 0.15s;
1534
+ font-weight: 500;
1535
+ font-size: 0.875rem;
1536
+ }
1537
+
1538
+ .wallet-option:hover {
1539
+ background: hsl(210 40% 98%);
1540
+ border-color: hsl(217.2 32.6% 17.5%);
1541
+ }
1542
+
1543
+ .wallet-option img {
1544
+ width: 20px;
1545
+ height: 20px;
1546
+ }
1547
+
1548
+ .connected-info {
1549
+ display: flex;
1550
+ justify-content: space-between;
1551
+ align-items: center;
1552
+ margin-bottom: 1rem;
1553
+ padding: 0.875rem 1rem;
1554
+ background: hsl(142.1 76.2% 97.3%);
1555
+ border: 1px solid hsl(142.1 76.2% 90%);
1556
+ border-radius: 0.5rem;
1557
+ }
1558
+
1559
+ .connected-address {
1560
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
1561
+ font-size: 0.8125rem;
1562
+ color: hsl(142.1 70.6% 45.3%);
1563
+ font-weight: 500;
1564
+ margin: 0;
1565
+ }
1566
+
1567
+ .btn-primary,
1568
+ .btn-disconnect {
1569
+ border: none;
1570
+ border-radius: 0.5rem;
1571
+ font-weight: 600;
1572
+ cursor: pointer;
1573
+ transition: all 0.15s;
1574
+ font-size: 0.875rem;
1575
+ display: inline-flex;
1576
+ align-items: center;
1577
+ justify-content: center;
1578
+ }
1579
+
1580
+ .btn-primary {
1581
+ padding: 0.625rem 1.25rem;
1582
+ background: hsl(222.2 47.4% 11.2%);
1583
+ color: hsl(210 40% 98%);
1584
+ width: 100%;
1585
+ height: 2.5rem;
1586
+ }
1587
+
1588
+ .btn-primary:hover:not(:disabled) {
1589
+ background: hsl(222.2 47.4% 8%);
1590
+ }
1591
+
1592
+ .btn-primary:disabled {
1593
+ background: hsl(215.4 16.3% 46.9%);
1594
+ cursor: not-allowed;
1595
+ opacity: 0.5;
1596
+ }
1597
+
1598
+ .btn-disconnect {
1599
+ background: transparent;
1600
+ color: hsl(215.4 16.3% 46.9%);
1601
+ width: auto;
1602
+ padding: 0.375rem 0.875rem;
1603
+ font-size: 0.8125rem;
1604
+ font-weight: 500;
1605
+ }
1606
+
1607
+ .btn-disconnect:hover {
1608
+ background: hsl(210 40% 96.1%);
1609
+ color: hsl(222.2 47.4% 11.2%);
1610
+ }
1611
+
1612
+ .no-wallets {
1613
+ padding: 1.25rem;
1614
+ background: hsl(47.9 95.8% 96.1%);
1615
+ border: 1px solid hsl(47.9 95.8% 82%);
1616
+ border-radius: 0.5rem;
1617
+ text-align: center;
1618
+ }
1619
+
1620
+ .no-wallets p {
1621
+ color: hsl(25 95.8% 25%);
1622
+ font-size: 0.875rem;
1623
+ margin: 0;
1624
+ font-weight: 600;
1625
+ }
1626
+
1627
+ .wallet-hint {
1628
+ margin-top: 0.5rem !important;
1629
+ font-weight: 400 !important;
1630
+ color: hsl(25 95.8% 35%) !important;
1631
+ }
1632
+
1633
+ @keyframes spin {
1634
+ to { transform: rotate(360deg); }
1635
+ }
1636
+
1637
+ .error-message {
1638
+ margin-top: 1rem;
1639
+ padding: 0.875rem 1rem;
1640
+ background: hsl(0 84.2% 97.3%);
1641
+ border: 1px solid hsl(0 84.2% 92%);
1642
+ border-radius: 0.5rem;
1643
+ color: hsl(0 74.3% 42%);
1644
+ font-size: 0.875rem;
1645
+ line-height: 1.5;
1646
+ }
1647
+ ` })
1648
+ ] });
1649
+ };
1650
+
1651
+ // src/components/PayWithAddress.tsx
1652
+ import { useState as useState5, useEffect as useEffect5 } from "react";
1653
+ import { QRCodeSVG } from "qrcode.react";
1654
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1655
+ var PayWithAddress = ({
1656
+ walletAddress,
1657
+ amount,
1658
+ coinId,
1659
+ chainId: _chainId,
1660
+ chainInfo,
1661
+ publicOrderId,
1662
+ expiresAt,
1663
+ onCopy,
1664
+ className = "",
1665
+ children
1666
+ }) => {
1667
+ const [copied, setCopied] = useState5(false);
1668
+ const [showQR, setShowQR] = useState5(true);
1669
+ const [currentTime, setCurrentTime] = useState5(Date.now());
1670
+ useEffect5(() => {
1671
+ if (!expiresAt) return;
1672
+ const interval = setInterval(() => {
1673
+ setCurrentTime(Date.now());
1674
+ }, 1e3);
1675
+ return () => clearInterval(interval);
1676
+ }, [expiresAt]);
1677
+ const handleCopy = async () => {
1678
+ try {
1679
+ await navigator.clipboard.writeText(walletAddress);
1680
+ setCopied(true);
1681
+ onCopy?.();
1682
+ setTimeout(() => setCopied(false), 2e3);
1683
+ } catch (err) {
1684
+ console.error("Failed to copy:", err);
1685
+ }
1686
+ };
1687
+ const formatExpiryTime = (expiryString) => {
1688
+ if (!expiryString) return null;
1689
+ const expiry = new Date(expiryString);
1690
+ const diff = expiry.getTime() - currentTime;
1691
+ if (diff <= 0) return "Expired";
1692
+ const minutes = Math.floor(diff / 1e3 / 60);
1693
+ const seconds = Math.floor(diff / 1e3 % 60);
1694
+ return `${minutes}:${seconds.toString().padStart(2, "0")}`;
1695
+ };
1696
+ return /* @__PURE__ */ jsxs2("div", { className: `payment-with-address ${className}`, children: [
1697
+ children ? children : /* @__PURE__ */ jsxs2("div", { className: "payment-container", children: [
1698
+ /* @__PURE__ */ jsx4("h3", { children: "Payment Address" }),
1699
+ /* @__PURE__ */ jsxs2("div", { className: "payment-info", children: [
1700
+ /* @__PURE__ */ jsxs2("div", { className: "info-row", children: [
1701
+ /* @__PURE__ */ jsx4("span", { className: "label", children: "Amount" }),
1702
+ /* @__PURE__ */ jsxs2("span", { className: "value amount-value", children: [
1703
+ amount,
1704
+ " ",
1705
+ coinId
1706
+ ] })
1707
+ ] }),
1708
+ /* @__PURE__ */ jsxs2("div", { className: "info-row", children: [
1709
+ /* @__PURE__ */ jsx4("span", { className: "label", children: "Network" }),
1710
+ /* @__PURE__ */ jsx4("span", { className: "value", children: chainInfo.name })
1711
+ ] }),
1712
+ publicOrderId && /* @__PURE__ */ jsxs2("div", { className: "info-row", children: [
1713
+ /* @__PURE__ */ jsx4("span", { className: "label", children: "Order ID" }),
1714
+ /* @__PURE__ */ jsx4("span", { className: "value order-id", children: truncateOrderId(publicOrderId) })
1715
+ ] }),
1716
+ expiresAt && /* @__PURE__ */ jsxs2("div", { className: "info-row expiry", children: [
1717
+ /* @__PURE__ */ jsx4("span", { className: "label", children: "Time Remaining" }),
1718
+ /* @__PURE__ */ jsx4("span", { className: "value time", children: formatExpiryTime(expiresAt) })
1719
+ ] })
1720
+ ] }),
1721
+ /* @__PURE__ */ jsxs2("div", { className: "payment-methods", children: [
1722
+ /* @__PURE__ */ jsxs2("div", { className: "method-toggle", children: [
1723
+ /* @__PURE__ */ jsx4(
1724
+ "button",
1725
+ {
1726
+ onClick: () => setShowQR(true),
1727
+ className: showQR ? "active" : "",
1728
+ children: "QR Code"
1729
+ }
1730
+ ),
1731
+ /* @__PURE__ */ jsx4(
1732
+ "button",
1733
+ {
1734
+ onClick: () => setShowQR(false),
1735
+ className: !showQR ? "active" : "",
1736
+ children: "Address"
1737
+ }
1738
+ )
1739
+ ] }),
1740
+ showQR ? /* @__PURE__ */ jsxs2("div", { className: "qr-section", children: [
1741
+ /* @__PURE__ */ jsx4("div", { className: "qr-code", children: /* @__PURE__ */ jsx4(
1742
+ QRCodeSVG,
1743
+ {
1744
+ value: walletAddress,
1745
+ size: 200,
1746
+ level: "H",
1747
+ includeMargin: true
1748
+ }
1749
+ ) }),
1750
+ /* @__PURE__ */ jsx4("p", { className: "qr-instruction", children: "Scan QR code with your wallet app" })
1751
+ ] }) : /* @__PURE__ */ jsxs2("div", { className: "address-section", children: [
1752
+ /* @__PURE__ */ jsx4("div", { className: "address-display", children: /* @__PURE__ */ jsx4("code", { children: walletAddress }) }),
1753
+ /* @__PURE__ */ jsx4(
1754
+ "button",
1755
+ {
1756
+ onClick: handleCopy,
1757
+ className: "copy-button",
1758
+ children: copied ? "Copied!" : "Copy Address"
1759
+ }
1760
+ )
1761
+ ] })
1762
+ ] }),
1763
+ /* @__PURE__ */ jsxs2("div", { className: "payment-status", children: [
1764
+ /* @__PURE__ */ jsxs2("div", { className: "status-badge waiting", children: [
1765
+ /* @__PURE__ */ jsx4("div", { className: "status-spinner" }),
1766
+ /* @__PURE__ */ jsx4("span", { children: "Waiting for Payment" })
1767
+ ] }),
1768
+ /* @__PURE__ */ jsx4("p", { className: "status-text", children: "We're checking for your payment on the blockchain" })
1769
+ ] }),
1770
+ /* @__PURE__ */ jsxs2("div", { className: "warning", children: [
1771
+ /* @__PURE__ */ jsx4("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx4("path", { d: "M8 1a7 7 0 100 14A7 7 0 008 1zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zM8 11a.75.75 0 01-.75-.75v-4.5a.75.75 0 011.5 0v4.5A.75.75 0 018 11z" }) }),
1772
+ /* @__PURE__ */ jsx4("span", { children: "Send only to this address. Sending to wrong address may result in loss of funds." })
1773
+ ] })
1774
+ ] }),
1775
+ /* @__PURE__ */ jsx4("style", { children: `
1776
+ .payment-with-address {
1777
+ padding: 1.5rem;
1778
+ }
1779
+
1780
+ .payment-container {
1781
+ max-width: 500px;
1782
+ margin: 0 auto;
1783
+ }
1784
+
1785
+ h3 {
1786
+ font-size: 1.25rem;
1787
+ font-weight: 600;
1788
+ margin-bottom: 1.5rem;
1789
+ color: hsl(222.2 47.4% 11.2%);
1790
+ }
1791
+
1792
+ .payment-info {
1793
+ background: hsl(0 0% 100%);
1794
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1795
+ padding: 1.25rem;
1796
+ border-radius: 0.75rem;
1797
+ margin-bottom: 1.5rem;
1798
+ }
1799
+
1800
+ .info-row {
1801
+ display: flex;
1802
+ justify-content: space-between;
1803
+ align-items: center;
1804
+ padding: 0.625rem 0;
1805
+ border-bottom: 1px solid hsl(214.3 31.8% 91.4%);
1806
+ }
1807
+
1808
+ .info-row:last-child {
1809
+ border-bottom: none;
1810
+ padding-bottom: 0;
1811
+ }
1812
+
1813
+ .info-row:first-child {
1814
+ padding-top: 0;
1815
+ }
1816
+
1817
+ .label {
1818
+ font-size: 0.875rem;
1819
+ color: hsl(215.4 16.3% 46.9%);
1820
+ font-weight: 500;
1821
+ }
1822
+
1823
+ .value {
1824
+ font-size: 0.875rem;
1825
+ color: hsl(222.2 47.4% 11.2%);
1826
+ font-weight: 500;
1827
+ }
1828
+
1829
+ .amount-value {
1830
+ font-size: 1.125rem;
1831
+ font-weight: 600;
1832
+ color: hsl(222.2 47.4% 11.2%);
1833
+ }
1834
+
1835
+ .order-id {
1836
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
1837
+ font-size: 0.8125rem;
1838
+ color: hsl(215.4 16.3% 46.9%);
1839
+ }
1840
+
1841
+ .expiry {
1842
+ border-top: 2px solid hsl(214.3 31.8% 91.4%);
1843
+ padding-top: 0.75rem;
1844
+ margin-top: 0.5rem;
1845
+ }
1846
+
1847
+ .time {
1848
+ font-weight: 600;
1849
+ font-size: 0.9375rem;
1850
+ color: hsl(0 74.3% 42%);
1851
+ }
1852
+
1853
+ .payment-methods {
1854
+ margin: 1.5rem 0;
1855
+ }
1856
+
1857
+ .method-toggle {
1858
+ display: flex;
1859
+ gap: 0.5rem;
1860
+ padding: 0.25rem;
1861
+ background: hsl(210 40% 98%);
1862
+ border-radius: 0.5rem;
1863
+ margin-bottom: 1.5rem;
1864
+ }
1865
+
1866
+ .method-toggle button {
1867
+ flex: 1;
1868
+ padding: 0.5rem 1rem;
1869
+ border: none;
1870
+ border-radius: 0.375rem;
1871
+ background: transparent;
1872
+ cursor: pointer;
1873
+ transition: all 0.15s;
1874
+ font-weight: 500;
1875
+ font-size: 0.875rem;
1876
+ color: hsl(215.4 16.3% 46.9%);
1877
+ }
1878
+
1879
+ .method-toggle button.active {
1880
+ background: hsl(0 0% 100%);
1881
+ color: hsl(222.2 47.4% 11.2%);
1882
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
1883
+ }
1884
+
1885
+ .method-toggle button:hover:not(.active) {
1886
+ color: hsl(222.2 47.4% 11.2%);
1887
+ }
1888
+
1889
+ .qr-section {
1890
+ display: flex;
1891
+ flex-direction: column;
1892
+ align-items: center;
1893
+ padding: 1.5rem;
1894
+ background: hsl(0 0% 100%);
1895
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1896
+ border-radius: 0.75rem;
1897
+ }
1898
+
1899
+ .qr-code {
1900
+ padding: 1rem;
1901
+ background: hsl(0 0% 100%);
1902
+ border-radius: 0.5rem;
1903
+ }
1904
+
1905
+ .qr-instruction {
1906
+ margin-top: 1rem;
1907
+ color: hsl(215.4 16.3% 46.9%);
1908
+ text-align: center;
1909
+ font-size: 0.875rem;
1910
+ }
1911
+
1912
+ .address-section {
1913
+ display: flex;
1914
+ flex-direction: column;
1915
+ gap: 1rem;
1916
+ }
1917
+
1918
+ .address-display {
1919
+ padding: 1rem;
1920
+ background: hsl(210 40% 98%);
1921
+ border: 1px solid hsl(214.3 31.8% 91.4%);
1922
+ border-radius: 0.5rem;
1923
+ overflow: auto;
1924
+ }
1925
+
1926
+ .address-display code {
1927
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace;
1928
+ font-size: 0.8125rem;
1929
+ word-break: break-all;
1930
+ color: hsl(222.2 47.4% 11.2%);
1931
+ }
1932
+
1933
+ .copy-button {
1934
+ padding: 0.625rem 1.25rem;
1935
+ background: hsl(222.2 47.4% 11.2%);
1936
+ color: hsl(210 40% 98%);
1937
+ border: none;
1938
+ border-radius: 0.5rem;
1939
+ font-weight: 600;
1940
+ cursor: pointer;
1941
+ transition: all 0.15s;
1942
+ font-size: 0.875rem;
1943
+ height: 2.5rem;
1944
+ }
1945
+
1946
+ .copy-button:hover {
1947
+ background: hsl(222.2 47.4% 8%);
1948
+ }
1949
+
1950
+ .payment-status {
1951
+ margin: 1.5rem 0;
1952
+ padding: 1rem 1.25rem;
1953
+ background: hsl(47.9 95.8% 96.1%);
1954
+ border-radius: 0.5rem;
1955
+ border: 1px solid hsl(47.9 95.8% 82%);
1956
+ }
1957
+
1958
+ .status-badge {
1959
+ display: flex;
1960
+ align-items: center;
1961
+ gap: 0.625rem;
1962
+ margin-bottom: 0.5rem;
1963
+ }
1964
+
1965
+ .status-badge.waiting {
1966
+ color: hsl(25 95.8% 25%);
1967
+ font-weight: 600;
1968
+ font-size: 0.875rem;
1969
+ }
1970
+
1971
+ .status-spinner {
1972
+ width: 14px;
1973
+ height: 14px;
1974
+ border: 2px solid hsl(25 95.8% 55%);
1975
+ border-top-color: transparent;
1976
+ border-radius: 50%;
1977
+ animation: spin 0.8s linear infinite;
1978
+ }
1979
+
1980
+ @keyframes spin {
1981
+ to { transform: rotate(360deg); }
1982
+ }
1983
+
1984
+ .status-text {
1985
+ color: hsl(25 95.8% 35%);
1986
+ font-size: 0.8125rem;
1987
+ margin: 0;
1988
+ line-height: 1.5;
1989
+ }
1990
+
1991
+ .warning {
1992
+ display: flex;
1993
+ gap: 0.75rem;
1994
+ padding: 0.875rem 1rem;
1995
+ background: hsl(47.9 95.8% 96.1%);
1996
+ border-radius: 0.5rem;
1997
+ border: 1px solid hsl(47.9 95.8% 82%);
1998
+ color: hsl(25 95.8% 25%);
1999
+ font-size: 0.8125rem;
2000
+ line-height: 1.5;
2001
+ }
2002
+
2003
+ .warning svg {
2004
+ flex-shrink: 0;
2005
+ margin-top: 1px;
2006
+ color: hsl(25 95.8% 45%);
2007
+ }
2008
+ ` })
2009
+ ] });
2010
+ };
2011
+
2012
+ // src/api/coins.ts
2013
+ var coins_exports = {};
2014
+ __export(coins_exports, {
2015
+ findChainByCoinAndChainId: () => findChainByCoinAndChainId,
2016
+ getCoinChains: () => getCoinChains
2017
+ });
2018
+ async function getCoinChains(coinId) {
2019
+ try {
2020
+ const response = await apiClient.getClient().get(
2021
+ `/coins/${coinId}`
2022
+ );
2023
+ if (!response.data.isSuccess) {
2024
+ throw new Error(response.data.message || "Failed to fetch coin chains");
2025
+ }
2026
+ return response.data.output.chains;
2027
+ } catch (error) {
2028
+ if (error.response?.data?.message) {
2029
+ throw new Error(error.response.data.message);
2030
+ }
2031
+ throw new Error("Failed to fetch coin chains");
2032
+ }
2033
+ }
2034
+ async function findChainByCoinAndChainId(coinId, chainId) {
2035
+ const chains = await getCoinChains(coinId);
2036
+ return chains.find((chain) => chain.chainId === chainId) || null;
2037
+ }
2038
+
2039
+ // src/components/PaymentFlow.tsx
2040
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
2041
+ var PaymentFlow = ({
2042
+ toAddress,
2043
+ amount,
2044
+ coinId,
2045
+ chainId,
2046
+ tokenAddress,
2047
+ decimals,
2048
+ publicOrderId,
2049
+ expiresAt,
2050
+ defaultMethod = "wallet",
2051
+ allowMethodSwitch = true,
2052
+ onSuccess,
2053
+ onError,
2054
+ onMethodChange,
2055
+ className = "",
2056
+ children
2057
+ }) => {
2058
+ const [selectedMethod, setSelectedMethod] = useState6(defaultMethod);
2059
+ const [chainInfo, setChainInfo] = useState6(null);
2060
+ const [isLoadingChain, setIsLoadingChain] = useState6(true);
2061
+ const [chainError, setChainError] = useState6(null);
2062
+ useEffect6(() => {
2063
+ const fetchChainInfo = async () => {
2064
+ try {
2065
+ setIsLoadingChain(true);
2066
+ setChainError(null);
2067
+ console.log("[PaymentFlow] Fetching chain info:", {
2068
+ coinId,
2069
+ requestedChainId: chainId,
2070
+ requestedChainIdType: typeof chainId
2071
+ });
2072
+ const chains = await getCoinChains(coinId);
2073
+ console.log("[PaymentFlow] Available chains:", chains.map((c) => ({
2074
+ chainId: c.chainId,
2075
+ name: c.name
2076
+ })));
2077
+ const matchingChain = chains.find(
2078
+ (chain) => chain.chainId === chainId.toString()
2079
+ );
2080
+ if (!matchingChain) {
2081
+ console.error("[PaymentFlow] No matching chain found!", {
2082
+ requestedChainId: chainId.toString(),
2083
+ availableChainIds: chains.map((c) => c.chainId)
2084
+ });
2085
+ setChainError(`Chain ${chainId} not supported for ${coinId}`);
2086
+ } else {
2087
+ console.log("[PaymentFlow] Matching chain found:", {
2088
+ chainId: matchingChain.chainId,
2089
+ name: matchingChain.name
2090
+ });
2091
+ setChainInfo(matchingChain);
2092
+ }
2093
+ } catch (error) {
2094
+ console.error("[PaymentFlow] Failed to fetch chain info:", error);
2095
+ setChainError(error.message || "Failed to load chain information");
2096
+ } finally {
2097
+ setIsLoadingChain(false);
2098
+ }
2099
+ };
2100
+ fetchChainInfo();
2101
+ }, [coinId, chainId]);
2102
+ const handleMethodChange = (method) => {
2103
+ setSelectedMethod(method);
2104
+ onMethodChange?.(method);
2105
+ };
2106
+ const handleWalletSuccess = (txHash) => {
2107
+ onSuccess?.({ txHash, publicOrderId });
2108
+ };
2109
+ if (children) {
2110
+ return /* @__PURE__ */ jsx5("div", { className, children });
2111
+ }
2112
+ if (isLoadingChain) {
2113
+ return /* @__PURE__ */ jsx5("div", { className: `payment-flow loading ${className}`, children: /* @__PURE__ */ jsxs3("div", { className: "loading-spinner", children: [
2114
+ /* @__PURE__ */ jsx5("div", { className: "spinner" }),
2115
+ /* @__PURE__ */ jsx5("p", { children: "Loading chain information..." })
2116
+ ] }) });
2117
+ }
2118
+ if (chainError || !chainInfo) {
2119
+ return /* @__PURE__ */ jsx5("div", { className: `payment-flow error ${className}`, children: /* @__PURE__ */ jsx5("div", { className: "error-message", children: /* @__PURE__ */ jsxs3("p", { children: [
2120
+ "\u26A0\uFE0F ",
2121
+ chainError || "Chain information not available"
2122
+ ] }) }) });
2123
+ }
2124
+ return /* @__PURE__ */ jsxs3("div", { className: `payment-flow ${className}`, children: [
2125
+ allowMethodSwitch && /* @__PURE__ */ jsxs3("div", { className: "payment-method-selector", children: [
2126
+ /* @__PURE__ */ jsxs3(
2127
+ "button",
2128
+ {
2129
+ onClick: () => handleMethodChange("wallet"),
2130
+ className: `method-button ${selectedMethod === "wallet" ? "active" : ""}`,
2131
+ children: [
2132
+ /* @__PURE__ */ jsxs3("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: [
2133
+ /* @__PURE__ */ jsx5("path", { d: "M21 12a9 9 0 11-18 0 9 9 0 0118 0z", strokeWidth: "2", strokeLinecap: "round" }),
2134
+ /* @__PURE__ */ jsx5("path", { d: "M9 12l2 2 4-4", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
2135
+ ] }),
2136
+ /* @__PURE__ */ jsx5("span", { children: "Connect Wallet" })
2137
+ ]
2138
+ }
2139
+ ),
2140
+ /* @__PURE__ */ jsxs3(
2141
+ "button",
2142
+ {
2143
+ onClick: () => handleMethodChange("address"),
2144
+ className: `method-button ${selectedMethod === "address" ? "active" : ""}`,
2145
+ children: [
2146
+ /* @__PURE__ */ jsxs3("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: [
2147
+ /* @__PURE__ */ jsx5("rect", { x: "3", y: "11", width: "18", height: "10", rx: "2", strokeWidth: "2" }),
2148
+ /* @__PURE__ */ jsx5("path", { d: "M7 11V7a5 5 0 0110 0v4", strokeWidth: "2", strokeLinecap: "round" })
2149
+ ] }),
2150
+ /* @__PURE__ */ jsx5("span", { children: "QR / Address" })
2151
+ ]
2152
+ }
2153
+ )
2154
+ ] }),
2155
+ /* @__PURE__ */ jsx5("div", { className: "payment-content", children: selectedMethod === "wallet" ? /* @__PURE__ */ jsx5(
2156
+ PayWithWallet,
2157
+ {
2158
+ toAddress,
2159
+ amount,
2160
+ coinId,
2161
+ chainId: parseInt(chainInfo.chainId),
2162
+ chainInfo,
2163
+ tokenAddress,
2164
+ decimals,
2165
+ publicOrderId,
2166
+ onSuccess: handleWalletSuccess,
2167
+ onError
2168
+ }
2169
+ ) : /* @__PURE__ */ jsx5(
2170
+ PayWithAddress,
2171
+ {
2172
+ walletAddress: toAddress,
2173
+ amount,
2174
+ coinId,
2175
+ chainId: parseInt(chainInfo.chainId),
2176
+ chainInfo,
2177
+ publicOrderId,
2178
+ expiresAt,
2179
+ onCopy: () => console.log("Address copied")
2180
+ }
2181
+ ) }),
2182
+ /* @__PURE__ */ jsx5("style", { children: `
2183
+ .payment-flow {
2184
+ width: 100%;
2185
+ max-width: 600px;
2186
+ margin: 0 auto;
2187
+ }
2188
+
2189
+ .payment-method-selector {
2190
+ display: flex;
2191
+ gap: 0.5rem;
2192
+ margin-bottom: 1.5rem;
2193
+ padding: 0.25rem;
2194
+ background: hsl(210 40% 98%);
2195
+ border-radius: 0.5rem;
2196
+ }
2197
+
2198
+ .method-button {
2199
+ flex: 1;
2200
+ display: flex;
2201
+ align-items: center;
2202
+ justify-content: center;
2203
+ gap: 0.5rem;
2204
+ padding: 0.625rem 1rem;
2205
+ border: none;
2206
+ border-radius: 0.375rem;
2207
+ background: transparent;
2208
+ cursor: pointer;
2209
+ transition: all 0.15s;
2210
+ font-weight: 500;
2211
+ font-size: 0.875rem;
2212
+ color: hsl(215.4 16.3% 46.9%);
2213
+ }
2214
+
2215
+ .method-button:hover:not(.active) {
2216
+ color: hsl(222.2 47.4% 11.2%);
2217
+ }
2218
+
2219
+ .method-button.active {
2220
+ background: hsl(0 0% 100%);
2221
+ color: hsl(222.2 47.4% 11.2%);
2222
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
2223
+ }
2224
+
2225
+ .method-button svg {
2226
+ width: 18px;
2227
+ height: 18px;
2228
+ }
2229
+
2230
+ .payment-content {
2231
+ background: hsl(0 0% 100%);
2232
+ border: 1px solid hsl(214.3 31.8% 91.4%);
2233
+ border-radius: 0.75rem;
2234
+ padding: 0;
2235
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
2236
+ }
2237
+ ` })
2238
+ ] });
2239
+ };
2240
+
2241
+ // src/components/OrderStatusScreen.tsx
2242
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2243
+ var OrderStatusScreen = ({
2244
+ state,
2245
+ publicOrderId,
2246
+ amount,
2247
+ coinId,
2248
+ onRetry
2249
+ }) => {
2250
+ const getContent = () => {
2251
+ switch (state) {
2252
+ case "success" /* SUCCESS */:
2253
+ return {
2254
+ icon: /* @__PURE__ */ jsxs4("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", children: [
2255
+ /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10", fill: "#10b981" }),
2256
+ /* @__PURE__ */ jsx6(
2257
+ "path",
2258
+ {
2259
+ d: "M8 12l2 2 6-6",
2260
+ stroke: "white",
2261
+ strokeWidth: "2",
2262
+ strokeLinecap: "round",
2263
+ strokeLinejoin: "round"
2264
+ }
2265
+ )
2266
+ ] }),
2267
+ title: "Payment Successful!",
2268
+ message: "Your payment has been processed successfully.",
2269
+ color: "#10b981"
2270
+ };
2271
+ case "failed" /* FAILED */:
2272
+ return {
2273
+ icon: /* @__PURE__ */ jsxs4("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", children: [
2274
+ /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }),
2275
+ /* @__PURE__ */ jsx6(
2276
+ "path",
2277
+ {
2278
+ d: "M8 8l8 8M16 8l-8 8",
2279
+ stroke: "white",
2280
+ strokeWidth: "2",
2281
+ strokeLinecap: "round"
2282
+ }
2283
+ )
2284
+ ] }),
2285
+ title: "Payment Failed",
2286
+ message: "The payment transaction could not be completed.",
2287
+ color: "#ef4444",
2288
+ showRetry: true
2289
+ };
2290
+ case "refund_insufficient" /* REFUND_INSUFFICIENT */:
2291
+ return {
2292
+ icon: /* @__PURE__ */ jsxs4("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", children: [
2293
+ /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10", fill: "#f59e0b" }),
2294
+ /* @__PURE__ */ jsx6(
2295
+ "path",
2296
+ {
2297
+ d: "M12 8v4M12 16h.01",
2298
+ stroke: "white",
2299
+ strokeWidth: "2",
2300
+ strokeLinecap: "round"
2301
+ }
2302
+ )
2303
+ ] }),
2304
+ title: "Insufficient Amount - Refund Issued",
2305
+ message: "The payment amount was less than required. A refund has been initiated.",
2306
+ color: "#f59e0b",
2307
+ showRetry: true
2308
+ };
2309
+ case "refund_excess" /* REFUND_EXCESS */:
2310
+ return {
2311
+ icon: /* @__PURE__ */ jsxs4("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", children: [
2312
+ /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10", fill: "#f59e0b" }),
2313
+ /* @__PURE__ */ jsx6(
2314
+ "path",
2315
+ {
2316
+ d: "M12 8v4M12 16h.01",
2317
+ stroke: "white",
2318
+ strokeWidth: "2",
2319
+ strokeLinecap: "round"
2320
+ }
2321
+ )
2322
+ ] }),
2323
+ title: "Excess Amount - Partial Refund Issued",
2324
+ message: "The payment amount exceeded the required amount. The excess has been refunded.",
2325
+ color: "#f59e0b",
2326
+ showRetry: true
2327
+ };
2328
+ default:
2329
+ return null;
2330
+ }
2331
+ };
2332
+ const content = getContent();
2333
+ if (!content) return null;
2334
+ return /* @__PURE__ */ jsxs4("div", { className: "order-status-screen", children: [
2335
+ /* @__PURE__ */ jsxs4("div", { className: "status-container", children: [
2336
+ /* @__PURE__ */ jsx6("div", { className: "status-icon", children: content.icon }),
2337
+ /* @__PURE__ */ jsx6("h3", { style: { color: content.color }, children: content.title }),
2338
+ /* @__PURE__ */ jsx6("p", { children: content.message }),
2339
+ /* @__PURE__ */ jsxs4("div", { className: "order-details", children: [
2340
+ amount && coinId && /* @__PURE__ */ jsxs4("div", { className: "detail-row", children: [
2341
+ /* @__PURE__ */ jsx6("span", { children: "Amount:" }),
2342
+ /* @__PURE__ */ jsxs4("span", { className: "detail-value", children: [
2343
+ amount,
2344
+ " ",
2345
+ coinId
2346
+ ] })
2347
+ ] }),
2348
+ /* @__PURE__ */ jsxs4("div", { className: "detail-row", children: [
2349
+ /* @__PURE__ */ jsx6("span", { children: "Order ID:" }),
2350
+ /* @__PURE__ */ jsxs4("span", { className: "detail-value", children: [
2351
+ publicOrderId.slice(0, 8),
2352
+ "..."
2353
+ ] })
2354
+ ] })
2355
+ ] }),
2356
+ content.showRetry && onRetry && /* @__PURE__ */ jsx6("button", { onClick: onRetry, className: "retry-button", children: "Try Again" })
2357
+ ] }),
2358
+ /* @__PURE__ */ jsx6("style", { children: `
2359
+ .order-status-screen {
2360
+ display: flex;
2361
+ align-items: center;
2362
+ justify-content: center;
2363
+ min-height: 400px;
2364
+ }
2365
+
2366
+ .status-container {
2367
+ text-align: center;
2368
+ max-width: 400px;
2369
+ }
2370
+
2371
+ .status-icon {
2372
+ margin: 0 auto 1.5rem;
2373
+ }
2374
+
2375
+ .status-container h3 {
2376
+ font-size: 1.5rem;
2377
+ font-weight: 600;
2378
+ margin-bottom: 0.5rem;
2379
+ }
2380
+
2381
+ .status-container p {
2382
+ color: #6b7280;
2383
+ margin-bottom: 1.5rem;
2384
+ }
2385
+
2386
+ .order-details {
2387
+ background: #f9fafb;
2388
+ padding: 1rem;
2389
+ border-radius: 8px;
2390
+ margin-bottom: 1.5rem;
2391
+ }
2392
+
2393
+ .detail-row {
2394
+ display: flex;
2395
+ justify-content: space-between;
2396
+ margin-bottom: 0.5rem;
2397
+ }
2398
+
2399
+ .detail-row:last-child {
2400
+ margin-bottom: 0;
2401
+ }
2402
+
2403
+ .detail-value {
2404
+ font-weight: 600;
2405
+ color: #2563eb;
2406
+ }
2407
+
2408
+ .retry-button {
2409
+ padding: 0.75rem 1.5rem;
2410
+ background: #2563eb;
2411
+ color: white;
2412
+ border: none;
2413
+ border-radius: 8px;
2414
+ font-weight: 600;
2415
+ cursor: pointer;
2416
+ transition: background 0.2s;
2417
+ }
2418
+
2419
+ .retry-button:hover {
2420
+ background: #1d4ed8;
2421
+ }
2422
+ ` })
2423
+ ] });
2424
+ };
2425
+
2426
+ // src/components/OrderPayment.tsx
2427
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2428
+ var OrderPayment = ({
2429
+ publicOrderId,
2430
+ onSuccess,
2431
+ onError,
2432
+ className = ""
2433
+ }) => {
2434
+ const { order, isLoading, error } = useOrder(publicOrderId, {
2435
+ pollingInterval: 5e3,
2436
+ enablePolling: true
2437
+ });
2438
+ const [hasNotifiedSuccess, setHasNotifiedSuccess] = useState7(false);
2439
+ useEffect7(() => {
2440
+ if (error) {
2441
+ onError?.(error.message);
2442
+ }
2443
+ }, [error, onError]);
2444
+ useEffect7(() => {
2445
+ if (!order || !order.orderStat) return;
2446
+ const state = getOrderState(order.orderStat);
2447
+ if (state === "success" /* SUCCESS */ && !hasNotifiedSuccess) {
2448
+ setHasNotifiedSuccess(true);
2449
+ onSuccess?.({ publicOrderId });
2450
+ }
2451
+ if (state === "failed" /* FAILED */ || state === "refund_insufficient" /* REFUND_INSUFFICIENT */ || state === "refund_excess" /* REFUND_EXCESS */) {
2452
+ const errorMessage = getOrderStatusMessage(order.orderStat);
2453
+ onError?.(errorMessage);
2454
+ }
2455
+ }, [order, hasNotifiedSuccess, onSuccess, onError, publicOrderId]);
2456
+ const handleWalletPaymentSuccess = (result) => {
2457
+ console.log("[OrderPayment] Wallet payment success, txHash:", result.txHash);
2458
+ };
2459
+ const handleRetry = () => {
2460
+ window.location.reload();
2461
+ };
2462
+ if (isLoading) {
2463
+ return /* @__PURE__ */ jsxs5("div", { className: `order-payment loading ${className}`, children: [
2464
+ /* @__PURE__ */ jsxs5("div", { className: "loading-spinner", children: [
2465
+ /* @__PURE__ */ jsx7("div", { className: "spinner" }),
2466
+ /* @__PURE__ */ jsx7("p", { children: "Loading payment details..." })
2467
+ ] }),
2468
+ /* @__PURE__ */ jsx7("style", { children: `
2469
+ .order-payment.loading {
2470
+ display: flex;
2471
+ align-items: center;
2472
+ justify-content: center;
2473
+ min-height: 400px;
2474
+ }
2475
+
2476
+ .loading-spinner {
2477
+ text-align: center;
2478
+ }
2479
+
2480
+ .spinner {
2481
+ width: 48px;
2482
+ height: 48px;
2483
+ border: 4px solid #e5e7eb;
2484
+ border-top-color: #2563eb;
2485
+ border-radius: 50%;
2486
+ animation: spin 0.8s linear infinite;
2487
+ margin: 0 auto 1rem;
2488
+ }
2489
+
2490
+ @keyframes spin {
2491
+ to { transform: rotate(360deg); }
2492
+ }
2493
+
2494
+ .loading-spinner p {
2495
+ color: #6b7280;
2496
+ font-size: 0.875rem;
2497
+ }
2498
+ ` })
2499
+ ] });
2500
+ }
2501
+ if (error) {
2502
+ return /* @__PURE__ */ jsxs5("div", { className: `order-payment error ${className}`, children: [
2503
+ /* @__PURE__ */ jsxs5("div", { className: "error-container", children: [
2504
+ /* @__PURE__ */ jsxs5("svg", { width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", stroke: "#ef4444", children: [
2505
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10", strokeWidth: "2" }),
2506
+ /* @__PURE__ */ jsx7("path", { d: "M12 8v4M12 16h.01", strokeWidth: "2", strokeLinecap: "round" })
2507
+ ] }),
2508
+ /* @__PURE__ */ jsx7("h3", { children: "Payment Error" }),
2509
+ /* @__PURE__ */ jsx7("p", { children: error.message }),
2510
+ /* @__PURE__ */ jsx7("button", { onClick: () => window.location.reload(), className: "retry-button", children: "Try Again" })
2511
+ ] }),
2512
+ /* @__PURE__ */ jsx7("style", { children: `
2513
+ .order-payment.error {
2514
+ display: flex;
2515
+ align-items: center;
2516
+ justify-content: center;
2517
+ min-height: 400px;
2518
+ }
2519
+
2520
+ .error-container {
2521
+ text-align: center;
2522
+ max-width: 400px;
2523
+ }
2524
+
2525
+ .error-container svg {
2526
+ margin: 0 auto 1rem;
2527
+ }
2528
+
2529
+ .error-container h3 {
2530
+ font-size: 1.25rem;
2531
+ font-weight: 600;
2532
+ color: #ef4444;
2533
+ margin-bottom: 0.5rem;
2534
+ }
2535
+
2536
+ .error-container p {
2537
+ color: #6b7280;
2538
+ margin-bottom: 1.5rem;
2539
+ }
2540
+
2541
+ .retry-button {
2542
+ padding: 0.75rem 1.5rem;
2543
+ background: #2563eb;
2544
+ color: white;
2545
+ border: none;
2546
+ border-radius: 8px;
2547
+ font-weight: 600;
2548
+ cursor: pointer;
2549
+ transition: background 0.2s;
2550
+ }
2551
+
2552
+ .retry-button:hover {
2553
+ background: #1d4ed8;
2554
+ }
2555
+ ` })
2556
+ ] });
2557
+ }
2558
+ if (!order || !order.orderStat) {
2559
+ return null;
2560
+ }
2561
+ const orderState = getOrderState(order.orderStat);
2562
+ const isExpired = new Date(order.expireDt) < /* @__PURE__ */ new Date();
2563
+ if (orderState !== "waiting" /* WAITING */ || isExpired) {
2564
+ return /* @__PURE__ */ jsx7("div", { className, children: /* @__PURE__ */ jsx7(
2565
+ OrderStatusScreen,
2566
+ {
2567
+ state: isExpired ? "failed" /* FAILED */ : orderState,
2568
+ publicOrderId,
2569
+ amount: order.price,
2570
+ coinId: order.coin,
2571
+ onRetry: handleRetry
2572
+ }
2573
+ ) });
2574
+ }
2575
+ const walletInfo = order.walletInfo?.[0];
2576
+ if (!walletInfo?.address) {
2577
+ return /* @__PURE__ */ jsx7(
2578
+ OrderStatusScreen,
2579
+ {
2580
+ state: "failed" /* FAILED */,
2581
+ publicOrderId,
2582
+ onRetry: handleRetry
2583
+ }
2584
+ );
2585
+ }
2586
+ return /* @__PURE__ */ jsx7("div", { className, children: /* @__PURE__ */ jsx7(
2587
+ PaymentFlow,
2588
+ {
2589
+ toAddress: walletInfo.address,
2590
+ amount: order.price.toString(),
2591
+ coinId: order.coin,
2592
+ chainId: parseInt(order.chain),
2593
+ tokenAddress: walletInfo.contractAddr,
2594
+ decimals: walletInfo.digit,
2595
+ publicOrderId,
2596
+ expiresAt: order.expireDt,
2597
+ onSuccess: handleWalletPaymentSuccess,
2598
+ onError,
2599
+ allowMethodSwitch: true,
2600
+ defaultMethod: "wallet"
2601
+ }
2602
+ ) });
2603
+ };
2604
+
2605
+ // src/components/PaymentModal.tsx
2606
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2607
+ var PaymentModal = ({
2608
+ publicOrderId,
2609
+ isOpen,
2610
+ onClose,
2611
+ onSuccess,
2612
+ onError
2613
+ }) => {
2614
+ useEffect8(() => {
2615
+ const handleEscape = (e) => {
2616
+ if (e.key === "Escape" && isOpen) {
2617
+ onClose();
2618
+ }
2619
+ };
2620
+ document.addEventListener("keydown", handleEscape);
2621
+ return () => document.removeEventListener("keydown", handleEscape);
2622
+ }, [isOpen, onClose]);
2623
+ useEffect8(() => {
2624
+ if (isOpen) {
2625
+ document.body.style.overflow = "hidden";
2626
+ } else {
2627
+ document.body.style.overflow = "unset";
2628
+ }
2629
+ return () => {
2630
+ document.body.style.overflow = "unset";
2631
+ };
2632
+ }, [isOpen]);
2633
+ if (!isOpen) return null;
2634
+ return /* @__PURE__ */ jsxs6("div", { className: "payment-modal-overlay", onClick: onClose, children: [
2635
+ /* @__PURE__ */ jsxs6("div", { className: "payment-modal-content", onClick: (e) => e.stopPropagation(), children: [
2636
+ /* @__PURE__ */ jsx8("button", { className: "payment-modal-close", onClick: onClose, type: "button", children: /* @__PURE__ */ jsx8("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", children: /* @__PURE__ */ jsx8("path", { d: "M18 6L6 18M6 6l12 12", strokeWidth: "2", strokeLinecap: "round" }) }) }),
2637
+ /* @__PURE__ */ jsx8(
2638
+ OrderPayment,
2639
+ {
2640
+ publicOrderId,
2641
+ onSuccess: (result) => {
2642
+ onSuccess?.(result);
2643
+ onClose();
2644
+ },
2645
+ onError
2646
+ }
2647
+ )
2648
+ ] }),
2649
+ /* @__PURE__ */ jsx8("style", { children: `
2650
+ .payment-modal-overlay {
2651
+ position: fixed;
2652
+ top: 0;
2653
+ left: 0;
2654
+ right: 0;
2655
+ bottom: 0;
2656
+ background: rgba(0, 0, 0, 0.5);
2657
+ display: flex;
2658
+ align-items: center;
2659
+ justify-content: center;
2660
+ z-index: 9999;
2661
+ padding: 1rem;
2662
+ animation: fadeIn 0.2s ease-out;
2663
+ }
2664
+
2665
+ @keyframes fadeIn {
2666
+ from {
2667
+ opacity: 0;
2668
+ }
2669
+ to {
2670
+ opacity: 1;
2671
+ }
2672
+ }
2673
+
2674
+ .payment-modal-content {
2675
+ position: relative;
2676
+ background: white;
2677
+ border-radius: 16px;
2678
+ max-width: 640px;
2679
+ width: 100%;
2680
+ max-height: 90vh;
2681
+ overflow-y: auto;
2682
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
2683
+ animation: slideUp 0.3s ease-out;
2684
+ }
2685
+
2686
+ @keyframes slideUp {
2687
+ from {
2688
+ transform: translateY(20px);
2689
+ opacity: 0;
2690
+ }
2691
+ to {
2692
+ transform: translateY(0);
2693
+ opacity: 1;
2694
+ }
2695
+ }
2696
+
2697
+ .payment-modal-close {
2698
+ position: absolute;
2699
+ top: 1rem;
2700
+ right: 1rem;
2701
+ width: 40px;
2702
+ height: 40px;
2703
+ border: none;
2704
+ background: rgba(0, 0, 0, 0.05);
2705
+ border-radius: 50%;
2706
+ cursor: pointer;
2707
+ display: flex;
2708
+ align-items: center;
2709
+ justify-content: center;
2710
+ transition: all 0.2s;
2711
+ z-index: 1;
2712
+ }
2713
+
2714
+ .payment-modal-close:hover {
2715
+ background: rgba(0, 0, 0, 0.1);
2716
+ }
2717
+
2718
+ .payment-modal-close svg {
2719
+ width: 20px;
2720
+ height: 20px;
2721
+ color: #6b7280;
2722
+ }
2723
+
2724
+ /* \uBAA8\uBC14\uC77C \uB300\uC751 */
2725
+ @media (max-width: 640px) {
2726
+ .payment-modal-overlay {
2727
+ padding: 0;
2728
+ }
2729
+
2730
+ .payment-modal-content {
2731
+ max-width: 100%;
2732
+ max-height: 100vh;
2733
+ border-radius: 0;
2734
+ }
2735
+ }
2736
+ ` })
2737
+ ] });
2738
+ };
2739
+
2740
+ // src/components/PaymentButton.tsx
2741
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2742
+ var PaymentButton = ({
2743
+ productId,
2744
+ metadata,
2745
+ onSuccess,
2746
+ onError,
2747
+ className = "",
2748
+ disabled = false,
2749
+ children
2750
+ }) => {
2751
+ const context = useContext3(PaymentContext);
2752
+ const { createOrder: createOrder2, isLoading } = usePayment();
2753
+ const [isModalOpen, setIsModalOpen] = useState8(false);
2754
+ const [publicOrderId, setPublicOrderId] = useState8(null);
2755
+ const [isCompleted, setIsCompleted] = useState8(false);
2756
+ const [createdOrder, setCreatedOrder] = useState8(null);
2757
+ const isOurDomain = (url) => {
2758
+ const environment = context?.config?.environment || "sandbox";
2759
+ const ourDomain = PAYMENT_DOMAINS[environment];
2760
+ return url.startsWith(ourDomain);
2761
+ };
2762
+ const handleClick = async () => {
2763
+ if (publicOrderId) {
2764
+ setIsModalOpen(true);
2765
+ return;
2766
+ }
2767
+ try {
2768
+ const params = {
2769
+ productId,
2770
+ metadata
2771
+ };
2772
+ const order = await createOrder2(params);
2773
+ if (order.redirectUrl && order.redirectUrl.trim() !== "") {
2774
+ if (!isOurDomain(order.redirectUrl)) {
2775
+ throw new Error("Invalid redirect URL. Only our domain is allowed.");
2776
+ }
2777
+ const separator = order.redirectUrl.endsWith("/") ? "" : "/";
2778
+ window.location.href = `${order.redirectUrl}${separator}order/${order.publicOrderId}`;
2779
+ return;
2780
+ }
2781
+ setPublicOrderId(order.publicOrderId);
2782
+ setCreatedOrder(order);
2783
+ setIsModalOpen(true);
2784
+ } catch (err) {
2785
+ if (onError && err instanceof Error) {
2786
+ onError(err);
2787
+ }
2788
+ }
2789
+ };
2790
+ const handleModalSuccess = async (result) => {
2791
+ setIsCompleted(true);
2792
+ setIsModalOpen(false);
2793
+ if (!onSuccess) return;
2794
+ try {
2795
+ let orderDetail = null;
2796
+ let retryCount = 0;
2797
+ const maxRetries = 5;
2798
+ while (retryCount < maxRetries) {
2799
+ try {
2800
+ const detail = await getOrder(result.publicOrderId);
2801
+ if (detail && detail.orderId && detail.orderStat !== void 0) {
2802
+ orderDetail = detail;
2803
+ break;
2804
+ }
2805
+ throw new Error("Incomplete order data");
2806
+ } catch (err) {
2807
+ retryCount++;
2808
+ if (retryCount >= maxRetries) {
2809
+ console.error(`[PaymentButton] Failed after ${maxRetries} retries:`, err);
2810
+ throw err;
2811
+ }
2812
+ console.log(`[PaymentButton] Retry ${retryCount}/${maxRetries}...`);
2813
+ await new Promise((resolve) => setTimeout(resolve, 500));
2814
+ }
2815
+ }
2816
+ if (orderDetail) {
2817
+ onSuccess({
2818
+ orderId: orderDetail.orderId,
2819
+ publicOrderId: result.publicOrderId,
2820
+ paymentUrl: "",
2821
+ amount: orderDetail.price || 0,
2822
+ coinId: orderDetail.coin || "",
2823
+ chainId: orderDetail.chain || "",
2824
+ status: orderDetail.orderStat,
2825
+ expiresAt: orderDetail.expireDt || "",
2826
+ redirectUrl: orderDetail.redirectUrl || null
2827
+ });
2828
+ } else {
2829
+ throw new Error("Order detail is null after retries");
2830
+ }
2831
+ } catch (err) {
2832
+ console.error("[PaymentButton] Failed to get valid order details:", err);
2833
+ if (createdOrder) {
2834
+ console.log("[PaymentButton] Using created order info as fallback");
2835
+ onSuccess({
2836
+ ...createdOrder,
2837
+ status: "completed"
2838
+ // 결제 완료 상태로 업데이트
2839
+ });
2840
+ } else {
2841
+ console.warn("[PaymentButton] No order info available, using minimal data");
2842
+ onSuccess({
2843
+ orderId: result.publicOrderId,
2844
+ publicOrderId: result.publicOrderId,
2845
+ paymentUrl: "",
2846
+ amount: 0,
2847
+ coinId: "",
2848
+ chainId: "",
2849
+ status: "completed",
2850
+ expiresAt: "",
2851
+ redirectUrl: null
2852
+ });
2853
+ }
2854
+ }
2855
+ };
2856
+ const handleModalError = (error) => {
2857
+ if (onError) {
2858
+ onError(new Error(error));
2859
+ }
2860
+ };
2861
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
2862
+ /* @__PURE__ */ jsx9(
2863
+ "button",
2864
+ {
2865
+ onClick: handleClick,
2866
+ disabled: disabled || isLoading || isCompleted,
2867
+ className,
2868
+ type: "button",
2869
+ children: isLoading ? "Processing..." : isCompleted ? "Completed" : children || "Pay Now"
2870
+ }
2871
+ ),
2872
+ publicOrderId && /* @__PURE__ */ jsx9(
2873
+ PaymentModal,
2874
+ {
2875
+ publicOrderId,
2876
+ isOpen: isModalOpen,
2877
+ onClose: () => setIsModalOpen(false),
2878
+ onSuccess: handleModalSuccess,
2879
+ onError: handleModalError
2880
+ }
2881
+ )
2882
+ ] });
2883
+ };
2884
+
2885
+ // src/components/WalletProvider.tsx
2886
+ import { useMemo as useMemo2 } from "react";
2887
+ import { WagmiProvider } from "wagmi";
2888
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2889
+
2890
+ // src/adapters/types.ts
2891
+ var WalletType = /* @__PURE__ */ ((WalletType2) => {
2892
+ WalletType2["EVM"] = "evm";
2893
+ WalletType2["TRON"] = "tron";
2894
+ return WalletType2;
2895
+ })(WalletType || {});
2896
+ var ChainType = /* @__PURE__ */ ((ChainType2) => {
2897
+ ChainType2["EVM"] = "evm";
2898
+ ChainType2["TRON"] = "tron";
2899
+ return ChainType2;
2900
+ })(ChainType || {});
2901
+
2902
+ // src/adapters/TronWalletAdapter.ts
2903
+ var TRON_NETWORKS = {
2904
+ mainnet: 728126428,
2905
+ shasta: 2494104990,
2906
+ // Testnet
2907
+ nile: 3448148188
2908
+ // Testnet
2909
+ };
2910
+ var TRON_NETWORK_NAMES = {
2911
+ 728126428: "mainnet",
2912
+ 2494104990: "shasta",
2913
+ 3448148188: "nile"
2914
+ };
2915
+ var TRC20_TRANSFER_ABI = {
2916
+ type: "Function",
2917
+ stateMutability: "Nonpayable",
2918
+ name: "transfer",
2919
+ inputs: [
2920
+ { type: "address", name: "_to" },
2921
+ { type: "uint256", name: "_value" }
2922
+ ],
2923
+ outputs: [{ type: "bool" }]
2924
+ };
2925
+ var TronWalletAdapter = class {
2926
+ constructor() {
2927
+ this.type = "tron";
2928
+ this.chainType = "tron";
2929
+ this.tronWeb = null;
2930
+ this.currentAddress = null;
2931
+ this.currentNetwork = null;
2932
+ this.initialized = false;
2933
+ this.eventListenerRegistered = false;
2934
+ this.handleTronLinkMessage = (event) => {
2935
+ if (event.data?.message && event.data.message.action === "setNode") {
2936
+ if (this.isTronWalletAvailable()) {
2937
+ this.initializeTronWeb();
2938
+ if (this.initialized) {
2939
+ this.removeEventListener();
2940
+ }
2941
+ }
2942
+ }
2943
+ };
2944
+ }
2945
+ /**
2946
+ * Trust Wallet 설치 확인
2947
+ */
2948
+ hasTrustWallet() {
2949
+ if (typeof window === "undefined") return false;
2950
+ const windowAny = window;
2951
+ return !!(windowAny.trustwallet || windowAny.trustWallet || windowAny.ethereum?.isTrust || windowAny.ethereum?.isTrustWallet);
2952
+ }
2953
+ /**
2954
+ * TronLink 전용 감지 (Trust Wallet보다 우선)
2955
+ * ⚠️ CRITICAL: 이 메서드는 connect() 시점에만 호출되어야 함
2956
+ */
2957
+ isTronLinkInstalled() {
2958
+ if (typeof window === "undefined") return false;
2959
+ return true;
2960
+ }
2961
+ /**
2962
+ * Tron 지갑 사용 가능 여부 확인
2963
+ * ⚠️ CRITICAL: 이 메서드는 connect() 시점에만 호출되어야 함
2964
+ */
2965
+ isTronWalletAvailable() {
2966
+ if (typeof window === "undefined") return false;
2967
+ return true;
2968
+ }
2969
+ /**
2970
+ * 현재 사용 중인 wallet 타입 반환
2971
+ */
2972
+ getWalletType() {
2973
+ if (this.isTronLinkInstalled()) return "TronLink";
2974
+ if (this.hasTrustWallet()) return "Trust Wallet";
2975
+ return "Unknown";
2976
+ }
2977
+ /**
2978
+ * 이벤트 리스너 등록 (connect 호출 시에만)
2979
+ */
2980
+ registerEventListener() {
2981
+ if (typeof window !== "undefined" && !this.eventListenerRegistered && !this.initialized) {
2982
+ window.addEventListener("message", this.handleTronLinkMessage);
2983
+ this.eventListenerRegistered = true;
2984
+ console.log("[TronWalletAdapter] Message event listener registered");
2985
+ }
2986
+ }
2987
+ /**
2988
+ * 이벤트 리스너 제거
2989
+ */
2990
+ removeEventListener() {
2991
+ if (typeof window !== "undefined" && this.eventListenerRegistered) {
2992
+ window.removeEventListener("message", this.handleTronLinkMessage);
2993
+ this.eventListenerRegistered = false;
2994
+ console.log("[TronWalletAdapter] Message event listener removed");
2995
+ }
2996
+ }
2997
+ // TronWeb에서 현재 네트워크 감지
2998
+ detectNetwork(tronWeb) {
2999
+ try {
3000
+ let fullNodeHost = "";
3001
+ if (tronWeb.fullNode?.host) {
3002
+ fullNodeHost = tronWeb.fullNode.host;
3003
+ } else if (tronWeb.fullHost) {
3004
+ fullNodeHost = tronWeb.fullHost;
3005
+ } else if (tronWeb.solidityNode?.host) {
3006
+ fullNodeHost = tronWeb.solidityNode.host;
3007
+ }
3008
+ console.log("[TronWalletAdapter] Detecting network from host:", fullNodeHost);
3009
+ const hostLower = fullNodeHost.toLowerCase();
3010
+ if (hostLower.includes("shasta")) {
3011
+ console.log("[TronWalletAdapter] Detected: Shasta Testnet");
3012
+ return TRON_NETWORKS.shasta;
3013
+ } else if (hostLower.includes("nile")) {
3014
+ console.log("[TronWalletAdapter] Detected: Nile Testnet");
3015
+ return TRON_NETWORKS.nile;
3016
+ } else {
3017
+ console.log("[TronWalletAdapter] Detected: Mainnet (default)");
3018
+ return TRON_NETWORKS.mainnet;
3019
+ }
3020
+ } catch (error) {
3021
+ console.warn("[TronWalletAdapter] Failed to detect network:", error);
3022
+ return TRON_NETWORKS.mainnet;
3023
+ }
3024
+ }
3025
+ initializeTronWeb() {
3026
+ if (this.initialized) return;
3027
+ if (typeof window === "undefined") return;
3028
+ if (!this.isTronWalletAvailable()) {
3029
+ return;
3030
+ }
3031
+ const windowAny = window;
3032
+ if (windowAny.tronLink?.tronWeb) {
3033
+ this.tronWeb = windowAny.tronLink.tronWeb;
3034
+ this.initialized = true;
3035
+ console.log(`[TronWalletAdapter] ${this.getWalletType()} initialized`);
3036
+ } else if (windowAny.tronWeb) {
3037
+ this.tronWeb = windowAny.tronWeb;
3038
+ this.initialized = true;
3039
+ console.log("[TronWalletAdapter] Using window.tronWeb");
3040
+ }
3041
+ }
3042
+ // 연결 상태
3043
+ isConnected() {
3044
+ return !!this.currentAddress && !!this.tronWeb;
3045
+ }
3046
+ getAddress() {
3047
+ return this.currentAddress;
3048
+ }
3049
+ getChainId() {
3050
+ if (this.tronWeb) {
3051
+ this.currentNetwork = this.detectNetwork(this.tronWeb);
3052
+ }
3053
+ return this.currentNetwork || TRON_NETWORKS.mainnet;
3054
+ }
3055
+ async getBalance() {
3056
+ if (!this.tronWeb || !this.currentAddress) return null;
3057
+ try {
3058
+ const balance = await this.tronWeb.trx.getBalance(this.currentAddress);
3059
+ return {
3060
+ value: BigInt(balance),
3061
+ decimals: 6,
3062
+ symbol: "TRX",
3063
+ formatted: (Number(balance) / 1e6).toFixed(6)
3064
+ };
3065
+ } catch (error) {
3066
+ console.error("[TronWalletAdapter] Failed to get balance:", error);
3067
+ return null;
3068
+ }
3069
+ }
3070
+ getConnectionInfo() {
3071
+ if (!this.isConnected() || !this.currentAddress) {
3072
+ return null;
3073
+ }
3074
+ return {
3075
+ address: this.currentAddress,
3076
+ chainId: this.getChainId() || TRON_NETWORKS.mainnet,
3077
+ chainType: this.chainType,
3078
+ isConnected: true,
3079
+ connector: {
3080
+ id: "tronlink",
3081
+ name: "TronLink",
3082
+ icon: "https://www.tronlink.org/favicon.ico"
3083
+ }
3084
+ };
3085
+ }
3086
+ // 연결 관리
3087
+ async connect(_connectorId) {
3088
+ if (typeof window === "undefined") {
3089
+ throw new Error("Window not available");
3090
+ }
3091
+ const windowAny = window;
3092
+ if (!windowAny.tronLink || typeof windowAny.tronLink.request !== "function") {
3093
+ throw new Error(
3094
+ "Tron wallet not installed. Please install TronLink extension."
3095
+ );
3096
+ }
3097
+ const isTronLinkProp = windowAny.tronLink?.isTronLink;
3098
+ const hasTrustWallet = this.hasTrustWallet();
3099
+ console.log("[TronWalletAdapter] Connecting with wallet:", {
3100
+ hasTronLink: !!windowAny.tronLink,
3101
+ isTronLinkProp,
3102
+ hasTrustWallet,
3103
+ walletType: isTronLinkProp === true ? "TronLink" : hasTrustWallet ? "Trust Wallet (Tron support)" : "Unknown"
3104
+ });
3105
+ if (!this.initialized) {
3106
+ this.registerEventListener();
3107
+ }
3108
+ try {
3109
+ console.log(`[TronWalletAdapter] Connecting to ${this.getWalletType()}...`);
3110
+ const result = await windowAny.tronLink.request({
3111
+ method: "tron_requestAccounts"
3112
+ });
3113
+ if (result.code === 200) {
3114
+ this.initializeTronWeb();
3115
+ if (!this.tronWeb) {
3116
+ throw new Error("TronWeb not initialized after connection");
3117
+ }
3118
+ await new Promise((resolve) => setTimeout(resolve, 100));
3119
+ if (windowAny.tronLink?.tronWeb) {
3120
+ this.tronWeb = windowAny.tronLink.tronWeb;
3121
+ this.currentAddress = this.tronWeb.defaultAddress?.base58 || null;
3122
+ this.currentNetwork = this.detectNetwork(this.tronWeb);
3123
+ } else if (windowAny.tronWeb) {
3124
+ this.tronWeb = windowAny.tronWeb;
3125
+ this.currentAddress = this.tronWeb.defaultAddress?.base58 || null;
3126
+ this.currentNetwork = this.detectNetwork(this.tronWeb);
3127
+ }
3128
+ if (!this.currentAddress) {
3129
+ throw new Error("Failed to get wallet address after connection");
3130
+ }
3131
+ console.log(
3132
+ "[TronWalletAdapter] Connected:",
3133
+ this.currentAddress,
3134
+ "Network:",
3135
+ this.currentNetwork ? TRON_NETWORK_NAMES[this.currentNetwork] : "unknown"
3136
+ );
3137
+ } else {
3138
+ throw new Error(result.message || "Connection rejected");
3139
+ }
3140
+ } catch (error) {
3141
+ console.error("[TronWalletAdapter] Connection failed:", error);
3142
+ throw error;
3143
+ }
3144
+ }
3145
+ async disconnect() {
3146
+ try {
3147
+ if (typeof window !== "undefined") {
3148
+ try {
3149
+ const windowAny = window;
3150
+ if (windowAny.tronLink?.request) {
3151
+ await windowAny.tronLink.request({
3152
+ method: "wallet_disconnect"
3153
+ });
3154
+ console.log("[TronWalletAdapter] TronLink disconnected via wallet_disconnect");
3155
+ }
3156
+ } catch (error) {
3157
+ console.log("[TronWalletAdapter] wallet_disconnect not supported, clearing state only");
3158
+ }
3159
+ }
3160
+ } catch (error) {
3161
+ console.warn("[TronWalletAdapter] Disconnect request failed:", error);
3162
+ }
3163
+ this.removeEventListener();
3164
+ this.currentAddress = null;
3165
+ this.currentNetwork = null;
3166
+ this.tronWeb = null;
3167
+ this.initialized = false;
3168
+ console.log("[TronWalletAdapter] Internal state cleared");
3169
+ }
3170
+ async switchChain(chainId) {
3171
+ const networkId = typeof chainId === "number" ? chainId : parseInt(chainId);
3172
+ const validNetworks = [TRON_NETWORKS.mainnet, TRON_NETWORKS.shasta, TRON_NETWORKS.nile];
3173
+ if (!validNetworks.includes(networkId)) {
3174
+ throw new Error(`Unsupported Tron network: ${chainId}`);
3175
+ }
3176
+ console.warn(
3177
+ "[TronWalletAdapter] Network switching must be done manually in TronLink"
3178
+ );
3179
+ this.currentNetwork = networkId;
3180
+ }
3181
+ // 트랜잭션
3182
+ async sendPayment(tx) {
3183
+ try {
3184
+ if (!this.tronWeb || !this.currentAddress) {
3185
+ throw new Error("Wallet not connected");
3186
+ }
3187
+ let hash;
3188
+ if (tx.tokenAddress) {
3189
+ const contract = await this.tronWeb.contract(
3190
+ [TRC20_TRANSFER_ABI],
3191
+ tx.tokenAddress
3192
+ );
3193
+ const result = await contract.transfer(tx.to, tx.value.toString()).send({
3194
+ from: this.currentAddress
3195
+ });
3196
+ hash = result;
3197
+ } else {
3198
+ const amountInSun = Number(tx.value);
3199
+ const transaction = await this.tronWeb.transactionBuilder.sendTrx(
3200
+ tx.to,
3201
+ amountInSun,
3202
+ this.currentAddress
3203
+ );
3204
+ const signedTx = await this.tronWeb.trx.sign(transaction);
3205
+ const broadcast = await this.tronWeb.trx.sendRawTransaction(signedTx);
3206
+ if (!broadcast.result) {
3207
+ throw new Error(
3208
+ broadcast.message || "Transaction broadcast failed"
3209
+ );
3210
+ }
3211
+ hash = broadcast.txid || signedTx.txID;
3212
+ }
3213
+ return { success: true, hash };
3214
+ } catch (error) {
3215
+ console.error("[TronWalletAdapter] Payment failed:", error);
3216
+ return {
3217
+ success: false,
3218
+ hash: "",
3219
+ error: error?.message ?? "Transaction failed"
3220
+ };
3221
+ }
3222
+ }
3223
+ // 지원 여부 확인
3224
+ isChainSupported(chainId) {
3225
+ const networkId = typeof chainId === "number" ? chainId : parseInt(chainId);
3226
+ const validNetworks = [TRON_NETWORKS.mainnet, TRON_NETWORKS.shasta, TRON_NETWORKS.nile];
3227
+ return validNetworks.includes(networkId);
3228
+ }
3229
+ getChainType(_chainId) {
3230
+ return this.chainType;
3231
+ }
3232
+ // 커넥터 정보
3233
+ getConnectors() {
3234
+ return [
3235
+ {
3236
+ id: "tronlink",
3237
+ name: "TronLink",
3238
+ icon: "https://www.tronlink.org/favicon.ico"
3239
+ }
3240
+ ];
3241
+ }
3242
+ checkWalletInstalled(connectorId) {
3243
+ if (typeof window === "undefined") return false;
3244
+ if (connectorId === "tronlink") {
3245
+ const hasTronLinkAPI = !!window.tronLink;
3246
+ const hasTronWeb = !!window.tronWeb;
3247
+ const isTronLinkProp = window.tronLink?.isTronLink;
3248
+ const hasTronLink = hasTronLinkAPI || hasTronWeb;
3249
+ console.log("[TronWalletAdapter] TronLink detection:", {
3250
+ hasTronLinkAPI,
3251
+ hasTronWeb,
3252
+ isTronLinkProp,
3253
+ hasTrustWallet: this.hasTrustWallet(),
3254
+ result: hasTronLink
3255
+ });
3256
+ return hasTronLink;
3257
+ }
3258
+ return false;
3259
+ }
3260
+ };
3261
+
3262
+ // src/adapters/WalletAdapterFactory.ts
3263
+ var WalletAdapterFactory = class {
3264
+ constructor() {
3265
+ this.evmAdapter = null;
3266
+ this.tronAdapter = null;
3267
+ }
3268
+ // EVM 체인 ID 확인 (숫자 또는 0x로 시작하는 문자열)
3269
+ isEvmChainId(chainId) {
3270
+ if (chainId === "evm") return true;
3271
+ if (typeof chainId === "number") return true;
3272
+ if (typeof chainId === "string") {
3273
+ if (chainId === "mainnet" || chainId === "shasta" || chainId === "nile" || chainId === "tron") {
3274
+ return false;
3275
+ }
3276
+ const numericChainId = Number(chainId);
3277
+ if (!isNaN(numericChainId) && numericChainId > 0) {
3278
+ return true;
3279
+ }
3280
+ }
3281
+ return false;
3282
+ }
3283
+ // Tron 네트워크 확인
3284
+ isTronNetwork(chainId) {
3285
+ if (chainId === "tron") return true;
3286
+ const tronNetworkIds = [728126428, 2494104990, 3448148188];
3287
+ const networkId = typeof chainId === "number" ? chainId : parseInt(chainId);
3288
+ if (tronNetworkIds.includes(networkId)) {
3289
+ return true;
3290
+ }
3291
+ return false;
3292
+ }
3293
+ // EVM 주소 형식 확인 (0x로 시작하는 42자)
3294
+ isEvmAddress(address) {
3295
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
3296
+ }
3297
+ // Tron 주소 형식 확인 (T로 시작하는 34자 Base58)
3298
+ isTronAddress(address) {
3299
+ return /^T[A-Za-z0-9]{33}$/.test(address);
3300
+ }
3301
+ /**
3302
+ * EVM 어댑터 초기화
3303
+ */
3304
+ initializeEvmAdapter(wagmiConfig) {
3305
+ this.evmAdapter = new EvmWalletAdapter(wagmiConfig);
3306
+ }
3307
+ /**
3308
+ * Tron 어댑터 초기화
3309
+ */
3310
+ initializeTronAdapter() {
3311
+ this.tronAdapter = new TronWalletAdapter();
3312
+ }
3313
+ /**
3314
+ * 어댑터 타입으로 어댑터 가져오기
3315
+ */
3316
+ getAdapter(type) {
3317
+ switch (type) {
3318
+ case "evm":
3319
+ return this.evmAdapter;
3320
+ case "tron":
3321
+ return this.tronAdapter;
3322
+ default:
3323
+ return null;
3324
+ }
3325
+ }
3326
+ /**
3327
+ * 체인 ID로 적절한 어댑터 가져오기
3328
+ */
3329
+ getAdapterForChain(chainId) {
3330
+ console.log("testtest get chainId", chainId);
3331
+ if (this.isEvmChainId(chainId)) {
3332
+ return this.evmAdapter;
3333
+ }
3334
+ if (this.isTronNetwork(chainId)) {
3335
+ return this.tronAdapter;
3336
+ }
3337
+ return null;
3338
+ }
3339
+ /**
3340
+ * 입금 주소 형식으로 적절한 어댑터 가져오기
3341
+ * - 0x로 시작 → EVM adapter
3342
+ * - T로 시작 → Tron adapter
3343
+ */
3344
+ getAdapterByAddress(address) {
3345
+ if (this.isEvmAddress(address)) {
3346
+ return this.evmAdapter;
3347
+ }
3348
+ if (this.isTronAddress(address)) {
3349
+ return this.tronAdapter;
3350
+ }
3351
+ console.warn(`[WalletAdapterFactory] Unknown address format: ${address}`);
3352
+ return null;
3353
+ }
3354
+ /**
3355
+ * 주소로부터 체인 타입 결정
3356
+ */
3357
+ getChainTypeByAddress(address) {
3358
+ if (this.isEvmAddress(address)) {
3359
+ return "evm";
3360
+ }
3361
+ if (this.isTronAddress(address)) {
3362
+ return "tron";
3363
+ }
3364
+ return null;
3365
+ }
3366
+ /**
3367
+ * 체인 타입 결정
3368
+ */
3369
+ getChainType(chainId) {
3370
+ if (this.isEvmChainId(chainId)) {
3371
+ return "evm";
3372
+ }
3373
+ if (this.isTronNetwork(chainId)) {
3374
+ return "tron";
3375
+ }
3376
+ throw new Error(`Unsupported chain ID: ${chainId}`);
3377
+ }
3378
+ /**
3379
+ * 모든 어댑터 가져오기
3380
+ */
3381
+ getAllAdapters() {
3382
+ const adapters = [];
3383
+ if (this.evmAdapter) adapters.push(this.evmAdapter);
3384
+ if (this.tronAdapter) adapters.push(this.tronAdapter);
3385
+ return adapters;
3386
+ }
3387
+ /**
3388
+ * 연결된 어댑터 가져오기
3389
+ */
3390
+ getConnectedAdapter() {
3391
+ if (this.evmAdapter?.isConnected()) {
3392
+ return this.evmAdapter;
3393
+ }
3394
+ if (this.tronAdapter?.isConnected()) {
3395
+ return this.tronAdapter;
3396
+ }
3397
+ return null;
3398
+ }
3399
+ };
3400
+
3401
+ // src/components/WalletProvider.tsx
3402
+ import { jsx as jsx10 } from "react/jsx-runtime";
3403
+ var defaultQueryClient = new QueryClient({
3404
+ defaultOptions: {
3405
+ queries: {
3406
+ refetchOnWindowFocus: false,
3407
+ retry: 3,
3408
+ staleTime: 1e3 * 60 * 5
3409
+ // 5 minutes
3410
+ }
3411
+ }
3412
+ });
3413
+ var WalletProvider = ({
3414
+ children,
3415
+ projectId,
3416
+ queryClient = defaultQueryClient
3417
+ }) => {
3418
+ const wagmiConfig = useMemo2(
3419
+ () => createWagmiConfig(projectId),
3420
+ [projectId]
3421
+ );
3422
+ const adapterFactory = useMemo2(() => {
3423
+ const factory = new WalletAdapterFactory();
3424
+ factory.initializeEvmAdapter(wagmiConfig);
3425
+ factory.initializeTronAdapter();
3426
+ return factory;
3427
+ }, [wagmiConfig]);
3428
+ return /* @__PURE__ */ jsx10(WagmiProvider, { config: wagmiConfig, children: /* @__PURE__ */ jsx10(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx10(WalletContextProvider, { factory: adapterFactory, children }) }) });
3429
+ };
3430
+
3431
+ // src/components/PaymentQRCode.tsx
3432
+ import { useState as useState9 } from "react";
3433
+ import { QRCodeSVG as QRCodeSVG2 } from "qrcode.react";
3434
+
3435
+ // src/utils/qrcode.ts
3436
+ function generatePaymentQRUrl(publicOrderId) {
3437
+ const sdkConfig = config.getConfig();
3438
+ const environment = sdkConfig.environment || "sandbox";
3439
+ const paymentDomain = PAYMENT_DOMAINS[environment];
3440
+ const domain = paymentDomain.endsWith("/") ? paymentDomain.slice(0, -1) : paymentDomain;
3441
+ return `${domain}/order/${publicOrderId}`;
3442
+ }
3443
+ function getPaymentDomain() {
3444
+ const sdkConfig = config.getConfig();
3445
+ const environment = sdkConfig.environment || "sandbox";
3446
+ return PAYMENT_DOMAINS[environment];
3447
+ }
3448
+
3449
+ // src/components/PaymentQRCode.tsx
3450
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3451
+ function PaymentQRCode({
3452
+ publicOrderId,
3453
+ size = 200,
3454
+ level = "H",
3455
+ includeMargin = true,
3456
+ className = "",
3457
+ showUrl = false,
3458
+ enableCopy = false,
3459
+ onCopy
3460
+ }) {
3461
+ const [copied, setCopied] = useState9(false);
3462
+ const paymentUrl = generatePaymentQRUrl(publicOrderId);
3463
+ const handleCopy = async () => {
3464
+ try {
3465
+ await navigator.clipboard.writeText(paymentUrl);
3466
+ setCopied(true);
3467
+ onCopy?.();
3468
+ setTimeout(() => setCopied(false), 2e3);
3469
+ } catch (error) {
3470
+ console.error("Failed to copy to clipboard:", error);
3471
+ }
3472
+ };
3473
+ return /* @__PURE__ */ jsxs8("div", { className: `payment-qr-code ${className}`, children: [
3474
+ /* @__PURE__ */ jsx11(
3475
+ "div",
3476
+ {
3477
+ style: {
3478
+ padding: "16px",
3479
+ backgroundColor: "white",
3480
+ borderRadius: "8px",
3481
+ display: "inline-block"
3482
+ },
3483
+ children: /* @__PURE__ */ jsx11(
3484
+ QRCodeSVG2,
3485
+ {
3486
+ value: paymentUrl,
3487
+ size,
3488
+ level,
3489
+ includeMargin
3490
+ }
3491
+ )
3492
+ }
3493
+ ),
3494
+ showUrl && /* @__PURE__ */ jsx11(
3495
+ "div",
3496
+ {
3497
+ style: {
3498
+ marginTop: "12px",
3499
+ fontSize: "12px",
3500
+ color: "#666",
3501
+ wordBreak: "break-all"
3502
+ },
3503
+ children: paymentUrl
3504
+ }
3505
+ ),
3506
+ enableCopy && /* @__PURE__ */ jsx11(
3507
+ "button",
3508
+ {
3509
+ onClick: handleCopy,
3510
+ style: {
3511
+ marginTop: "12px",
3512
+ padding: "8px 16px",
3513
+ backgroundColor: copied ? "#22c55e" : "#3b82f6",
3514
+ color: "white",
3515
+ border: "none",
3516
+ borderRadius: "6px",
3517
+ cursor: "pointer",
3518
+ fontSize: "14px",
3519
+ fontWeight: "500"
3520
+ },
3521
+ children: copied ? "Copied!" : "Copy Link"
3522
+ }
3523
+ )
3524
+ ] });
3525
+ }
3526
+
3527
+ // src/components/PaymentQRModal.tsx
3528
+ import { useState as useState10, useEffect as useEffect9 } from "react";
3529
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
3530
+ function PaymentQRModal({
3531
+ isOpen,
3532
+ onClose,
3533
+ productId,
3534
+ productName,
3535
+ qrSize = 200,
3536
+ className = ""
3537
+ }) {
3538
+ const { createOrder: createOrder2 } = usePayment();
3539
+ const [publicOrderId, setPublicOrderId] = useState10(null);
3540
+ const [isLoading, setIsLoading] = useState10(false);
3541
+ const [error, setError] = useState10(null);
3542
+ useEffect9(() => {
3543
+ if (isOpen && !publicOrderId) {
3544
+ const generateOrder = async () => {
3545
+ try {
3546
+ setIsLoading(true);
3547
+ setError(null);
3548
+ const order = await createOrder2({ productId });
3549
+ setPublicOrderId(order.publicOrderId);
3550
+ } catch (err) {
3551
+ setError(err.message || "Failed to create order");
3552
+ } finally {
3553
+ setIsLoading(false);
3554
+ }
3555
+ };
3556
+ generateOrder();
3557
+ }
3558
+ }, [isOpen, productId, publicOrderId, createOrder2]);
3559
+ const handleClose = () => {
3560
+ setPublicOrderId(null);
3561
+ setError(null);
3562
+ onClose();
3563
+ };
3564
+ if (!isOpen) return null;
3565
+ return /* @__PURE__ */ jsx12(
3566
+ "div",
3567
+ {
3568
+ style: {
3569
+ position: "fixed",
3570
+ inset: 0,
3571
+ zIndex: 9999,
3572
+ display: "flex",
3573
+ alignItems: "center",
3574
+ justifyContent: "center",
3575
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3576
+ padding: "16px"
3577
+ },
3578
+ onClick: onClose,
3579
+ children: /* @__PURE__ */ jsxs9(
3580
+ "div",
3581
+ {
3582
+ className: `payment-qr-modal ${className}`,
3583
+ style: {
3584
+ position: "relative",
3585
+ backgroundColor: "white",
3586
+ borderRadius: "12px",
3587
+ padding: "24px",
3588
+ maxWidth: "400px",
3589
+ width: "100%",
3590
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1)"
3591
+ },
3592
+ onClick: (e) => e.stopPropagation(),
3593
+ children: [
3594
+ /* @__PURE__ */ jsx12(
3595
+ "button",
3596
+ {
3597
+ onClick: handleClose,
3598
+ style: {
3599
+ position: "absolute",
3600
+ right: "16px",
3601
+ top: "16px",
3602
+ background: "none",
3603
+ border: "none",
3604
+ fontSize: "24px",
3605
+ cursor: "pointer",
3606
+ color: "#666",
3607
+ lineHeight: 1,
3608
+ padding: 0
3609
+ },
3610
+ children: "\u2715"
3611
+ }
3612
+ ),
3613
+ /* @__PURE__ */ jsx12(
3614
+ "h2",
3615
+ {
3616
+ style: {
3617
+ fontSize: "20px",
3618
+ fontWeight: "bold",
3619
+ marginBottom: "8px",
3620
+ marginTop: 0
3621
+ },
3622
+ children: "Payment QR Code"
3623
+ }
3624
+ ),
3625
+ /* @__PURE__ */ jsx12(
3626
+ "p",
3627
+ {
3628
+ style: {
3629
+ fontSize: "14px",
3630
+ color: "#666",
3631
+ marginBottom: "24px",
3632
+ marginTop: 0
3633
+ },
3634
+ children: productName ? `Scan this QR code to pay for ${productName}` : "Scan this QR code to complete your payment"
3635
+ }
3636
+ ),
3637
+ isLoading && /* @__PURE__ */ jsx12(
3638
+ "div",
3639
+ {
3640
+ style: {
3641
+ display: "flex",
3642
+ justifyContent: "center",
3643
+ padding: "40px"
3644
+ },
3645
+ children: /* @__PURE__ */ jsx12("p", { style: { color: "#666" }, children: "Creating order..." })
3646
+ }
3647
+ ),
3648
+ error && /* @__PURE__ */ jsx12(
3649
+ "div",
3650
+ {
3651
+ style: {
3652
+ backgroundColor: "#fee",
3653
+ color: "#c33",
3654
+ padding: "12px",
3655
+ borderRadius: "6px",
3656
+ marginBottom: "16px"
3657
+ },
3658
+ children: error
3659
+ }
3660
+ ),
3661
+ publicOrderId && !isLoading && !error && /* @__PURE__ */ jsx12("div", { style: { display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx12(
3662
+ PaymentQRCode,
3663
+ {
3664
+ publicOrderId,
3665
+ size: qrSize,
3666
+ level: "H",
3667
+ includeMargin: true,
3668
+ showUrl: true,
3669
+ enableCopy: true
3670
+ }
3671
+ ) })
3672
+ ]
3673
+ }
3674
+ )
3675
+ }
3676
+ );
3677
+ }
3678
+
3679
+ // src/hooks/useWallet.ts
3680
+ var useWallet = () => {
3681
+ const adapter = useWalletAdapter();
3682
+ const walletInfo = adapter.isConnected && adapter.address && typeof adapter.chainId === "number" ? {
3683
+ address: adapter.address,
3684
+ chainId: adapter.chainId,
3685
+ isConnected: adapter.isConnected,
3686
+ connector: adapter.wallet?.connector
3687
+ } : null;
3688
+ const sendPayment = async (tx) => {
3689
+ const result = await adapter.sendPayment({
3690
+ to: tx.to,
3691
+ value: tx.value,
3692
+ chainId: tx.chainId,
3693
+ coinId: tx.coinId,
3694
+ tokenAddress: tx.tokenAddress,
3695
+ decimals: tx.decimals
3696
+ });
3697
+ return {
3698
+ hash: result.hash,
3699
+ success: result.success,
3700
+ error: result.error
3701
+ };
3702
+ };
3703
+ const connectWallet = async (connectorId) => {
3704
+ if (adapter.isConnected) {
3705
+ await adapter.disconnect();
3706
+ }
3707
+ await adapter.connect("evm" /* EVM */, connectorId);
3708
+ };
3709
+ const evmAdapter = adapter.factory.getAdapter("evm" /* EVM */);
3710
+ const evmConnectors = evmAdapter?.getConnectors() || [];
3711
+ return {
3712
+ // Wallet info
3713
+ wallet: walletInfo,
3714
+ address: adapter.address,
3715
+ chainId: typeof adapter.chainId === "number" ? adapter.chainId : null,
3716
+ isConnected: adapter.isConnected,
3717
+ balance: adapter.balance,
3718
+ // Connection actions
3719
+ connect: connectWallet,
3720
+ disconnect: adapter.disconnect,
3721
+ connectors: evmConnectors,
3722
+ // EVM 커넥터만
3723
+ isConnecting: false,
3724
+ // TODO: track loading state
3725
+ // Chain switching
3726
+ switchChain: (chainId) => adapter.switchChain(chainId),
3727
+ // Transaction
3728
+ sendPayment,
3729
+ isSending: adapter.isSending,
3730
+ isConfirming: false,
3731
+ // TODO: track confirmation
3732
+ isConfirmed: false,
3733
+ // TODO: track confirmation
3734
+ txHash: adapter.txHash,
3735
+ // Utilities
3736
+ checkWalletInstalled: (connectorId) => adapter.checkWalletInstalled("evm" /* EVM */, connectorId)
3737
+ // EVM만 체크
3738
+ };
3739
+ };
3740
+ export {
3741
+ API_ENDPOINTS,
3742
+ ChainType as ChainTypes,
3743
+ DEFAULT_TIMEOUT,
3744
+ ENVIRONMENT_URLS,
3745
+ ERROR_CODES,
3746
+ EvmWalletAdapter,
3747
+ MIN_WITHDRAWAL_AMOUNT,
3748
+ ORDER_EXPIRY_MINUTES,
3749
+ OrderPayment,
3750
+ PAYMENT_DOMAINS,
3751
+ PayWithAddress,
3752
+ PayWithWallet,
3753
+ PaymentButton,
3754
+ PaymentContext,
3755
+ PaymentFlow,
3756
+ PaymentModal,
3757
+ PaymentProvider,
3758
+ PaymentQRCode,
3759
+ PaymentQRModal,
3760
+ SDK_VERSION,
3761
+ SUPPORTED_CHAINS,
3762
+ TRON_NETWORKS,
3763
+ TronWalletAdapter,
3764
+ WalletAdapterFactory,
3765
+ WalletProvider,
3766
+ WalletType as WalletTypes,
3767
+ coins_exports as coinsAPI,
3768
+ config,
3769
+ createWagmiConfig,
3770
+ detectChainType,
3771
+ generatePaymentQRUrl,
3772
+ getChainById,
3773
+ getErrorMessage,
3774
+ getEvmChainById,
3775
+ getPaymentDomain,
3776
+ handleAPIError,
3777
+ isEvmAddress,
3778
+ isTronAddress,
3779
+ isValidAddress,
3780
+ orders_exports as ordersAPI,
3781
+ supportedChains,
3782
+ supportedEvmChains,
3783
+ useOrder,
3784
+ usePayment,
3785
+ useWallet,
3786
+ useWalletAdapter,
3787
+ useWalletContext,
3788
+ validation_exports as validation
3789
+ };