@tomo-inc/wallet-connect-protocol 0.0.5 → 0.0.7

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.cjs ADDED
@@ -0,0 +1,1245 @@
1
+ 'use strict';
2
+
3
+ var SignClient = require('@walletconnect/sign-client');
4
+ var QRCode = require('qrcode');
5
+ var react = require('react');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var SignClient__default = /*#__PURE__*/_interopDefault(SignClient);
11
+ var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
12
+
13
+ // src/client.ts
14
+ var WalletConnectClient = class {
15
+ signClient = null;
16
+ config;
17
+ eventHandlers = /* @__PURE__ */ new Map();
18
+ initialized = false;
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ /**
23
+ * initialize WalletConnect client
24
+ */
25
+ async initialize() {
26
+ if (this.initialized) {
27
+ return;
28
+ }
29
+ try {
30
+ this.signClient = await SignClient__default.default.init({
31
+ projectId: this.config.projectId,
32
+ metadata: this.config.metadata,
33
+ relayUrl: this.config.relayUrl
34
+ });
35
+ this.setupEventListeners();
36
+ this.initialized = true;
37
+ } catch (error) {
38
+ throw error;
39
+ }
40
+ }
41
+ /**
42
+ * set event listeners
43
+ */
44
+ setupEventListeners() {
45
+ if (!this.signClient) return;
46
+ this.signClient.on("session_proposal", (proposal) => {
47
+ this.emit("session_proposal", proposal);
48
+ });
49
+ this.signClient.on("session_request", (request) => {
50
+ this.emit("session_request", request);
51
+ });
52
+ this.signClient.on("session_delete", (data) => {
53
+ this.emit("session_delete", data);
54
+ });
55
+ this.signClient.on("session_update", (data) => {
56
+ this.emit("session_update", data);
57
+ });
58
+ }
59
+ /**
60
+ * create pairing connection and generate URI
61
+ * @param params connection parameters
62
+ * @returns WalletConnect URI
63
+ */
64
+ async connect(params) {
65
+ if (!this.signClient) {
66
+ throw new Error("WalletConnect client not initialized. Call initialize() first.");
67
+ }
68
+ try {
69
+ const defaultNamespaces = {
70
+ eip155: {
71
+ methods: [
72
+ "eth_sendTransaction",
73
+ "eth_signTransaction",
74
+ "eth_sign",
75
+ "personal_sign",
76
+ "eth_signTypedData",
77
+ "eth_signTypedData_v4"
78
+ ],
79
+ chains: ["eip155:1"],
80
+ // Ethereum Mainnet
81
+ events: ["chainChanged", "accountsChanged"]
82
+ }
83
+ };
84
+ const defaultOptionalNamespaces = {
85
+ eip155: {
86
+ methods: [
87
+ "eth_sendTransaction",
88
+ "eth_signTransaction",
89
+ "eth_sign",
90
+ "personal_sign",
91
+ "eth_signTypedData",
92
+ "eth_signTypedData_v4"
93
+ ],
94
+ chains: [
95
+ "eip155:137",
96
+ // Polygon Mainnet
97
+ "eip155:56",
98
+ // BSC Mainnet
99
+ "eip155:42161",
100
+ // Arbitrum Mainnet
101
+ "eip155:10",
102
+ // Optimism Mainnet
103
+ "eip155:43114"
104
+ // Avalanche Mainnet
105
+ ],
106
+ events: ["chainChanged", "accountsChanged"]
107
+ },
108
+ solana: {
109
+ methods: ["solana_signTransaction", "solana_signMessage"],
110
+ chains: ["solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ"],
111
+ events: ["accountsChanged"]
112
+ }
113
+ };
114
+ const { uri, approval } = await this.signClient.connect({
115
+ requiredNamespaces: params?.requiredNamespaces || defaultNamespaces,
116
+ optionalNamespaces: params?.optionalNamespaces || defaultOptionalNamespaces
117
+ });
118
+ if (!uri) {
119
+ throw new Error("Failed to generate WalletConnect URI");
120
+ }
121
+ this.emit("display_uri", { uri });
122
+ approval().then((session) => {
123
+ this.emit("session_update", session);
124
+ }).catch((error) => {
125
+ });
126
+ return uri;
127
+ } catch (error) {
128
+ throw error;
129
+ }
130
+ }
131
+ /**
132
+ * generate QR code (Base64 format)
133
+ * @param uri WalletConnect URI
134
+ * @param options QR code options
135
+ * @returns Base64 formatted QR code image
136
+ */
137
+ async generateQRCode(uri, options) {
138
+ try {
139
+ const qrOptions = {
140
+ width: options?.width || 300,
141
+ margin: options?.margin || 4,
142
+ errorCorrectionLevel: options?.errorCorrectionLevel || "M",
143
+ color: {
144
+ dark: options?.color?.dark || "#000000",
145
+ light: options?.color?.light || "#ffffff"
146
+ }
147
+ };
148
+ const qrCodeDataUrl = await QRCode__default.default.toDataURL(uri, qrOptions);
149
+ return qrCodeDataUrl;
150
+ } catch (error) {
151
+ throw error;
152
+ }
153
+ }
154
+ /**
155
+ * generate QR code (Canvas format)
156
+ * @param canvas Canvas element
157
+ * @param uri WalletConnect URI
158
+ * @param options QR code options
159
+ */
160
+ async generateQRCodeToCanvas(canvas, uri, options) {
161
+ try {
162
+ const qrOptions = {
163
+ width: options?.width || 300,
164
+ margin: options?.margin || 4,
165
+ errorCorrectionLevel: options?.errorCorrectionLevel || "M",
166
+ color: {
167
+ dark: options?.color?.dark || "#000000",
168
+ light: options?.color?.light || "#ffffff"
169
+ }
170
+ };
171
+ await QRCode__default.default.toCanvas(canvas, uri, qrOptions);
172
+ } catch (error) {
173
+ throw error;
174
+ }
175
+ }
176
+ /**
177
+ * get all active sessions
178
+ * @returns session information array
179
+ */
180
+ getActiveSessions() {
181
+ if (!this.signClient) {
182
+ return [];
183
+ }
184
+ const sessions = this.signClient.session.getAll();
185
+ return sessions.map((session) => ({
186
+ topic: session.topic,
187
+ peer: session.peer,
188
+ namespaces: session.namespaces,
189
+ expiry: session.expiry
190
+ }));
191
+ }
192
+ /**
193
+ * disconnect specified session
194
+ * @param topic session topic/ID
195
+ */
196
+ async disconnectSession(topic) {
197
+ if (!this.signClient) {
198
+ throw new Error("WalletConnect client not initialized");
199
+ }
200
+ try {
201
+ await this.signClient.disconnect({
202
+ topic,
203
+ reason: {
204
+ code: 6e3,
205
+ message: "User disconnected"
206
+ }
207
+ });
208
+ } catch (error) {
209
+ throw error;
210
+ }
211
+ }
212
+ /**
213
+ * listen to events
214
+ * @param event event name
215
+ * @param handler event handler
216
+ */
217
+ on(event, handler) {
218
+ if (!this.eventHandlers.has(event)) {
219
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
220
+ }
221
+ this.eventHandlers.get(event)?.add(handler);
222
+ }
223
+ /**
224
+ * remove event listener
225
+ * @param event event name
226
+ * @param handler event handler
227
+ */
228
+ off(event, handler) {
229
+ this.eventHandlers.get(event)?.delete(handler);
230
+ }
231
+ /**
232
+ * trigger event
233
+ * @param event event name
234
+ * @param data event data
235
+ */
236
+ emit(event, data) {
237
+ const handlers = this.eventHandlers.get(event);
238
+ if (handlers) {
239
+ handlers.forEach((handler) => {
240
+ try {
241
+ handler(data);
242
+ } catch (error) {
243
+ }
244
+ });
245
+ }
246
+ }
247
+ /**
248
+ * send JSON-RPC request to wallet
249
+ * @param params request parameters
250
+ * @returns request result
251
+ */
252
+ async sendRequest(params) {
253
+ if (!this.signClient) {
254
+ throw new Error("WalletConnect client not initialized");
255
+ }
256
+ try {
257
+ const result = await this.signClient.request({
258
+ topic: params.topic,
259
+ chainId: params.chainId,
260
+ request: params.request
261
+ });
262
+ return result;
263
+ } catch (error) {
264
+ throw error;
265
+ }
266
+ }
267
+ /**
268
+ * destroy client
269
+ */
270
+ async destroy() {
271
+ if (this.signClient) {
272
+ this.eventHandlers.clear();
273
+ this.signClient = null;
274
+ this.initialized = false;
275
+ }
276
+ }
277
+ /**
278
+ * get if client is initialized
279
+ */
280
+ isInitialized() {
281
+ return this.initialized;
282
+ }
283
+ /**
284
+ * get configuration information
285
+ */
286
+ getConfig() {
287
+ return { ...this.config };
288
+ }
289
+ };
290
+ var WalletConnectContext = react.createContext(void 0);
291
+ function WalletConnectProvider({ config, children, autoInit = true }) {
292
+ const [client, setClient] = react.useState(null);
293
+ const [initialized, setInitialized] = react.useState(false);
294
+ const [connecting, setConnecting] = react.useState(false);
295
+ const [uri, setUri] = react.useState(null);
296
+ const [sessions, setSessions] = react.useState([]);
297
+ const refreshSessions = react.useCallback(() => {
298
+ if (client) {
299
+ const activeSessions = client.getActiveSessions();
300
+ setSessions(activeSessions);
301
+ }
302
+ }, [client]);
303
+ const initialize = react.useCallback(async () => {
304
+ if (initialized) {
305
+ return;
306
+ }
307
+ try {
308
+ const newClient = new WalletConnectClient(config);
309
+ newClient.on("display_uri", ({ uri: uri2 }) => {
310
+ setUri(uri2);
311
+ });
312
+ const handleSessionUpdate = () => {
313
+ const activeSessions2 = newClient.getActiveSessions();
314
+ setSessions(activeSessions2);
315
+ };
316
+ newClient.on("session_proposal", handleSessionUpdate);
317
+ newClient.on("session_update", handleSessionUpdate);
318
+ newClient.on("session_delete", handleSessionUpdate);
319
+ await newClient.initialize();
320
+ setClient(newClient);
321
+ setInitialized(true);
322
+ const activeSessions = newClient.getActiveSessions();
323
+ setSessions(activeSessions);
324
+ } catch (error) {
325
+ throw error;
326
+ }
327
+ }, [config, initialized]);
328
+ const connect = react.useCallback(async () => {
329
+ if (!client) {
330
+ throw new Error("WalletConnect client not initialized");
331
+ }
332
+ setConnecting(true);
333
+ try {
334
+ const connectionUri = await client.connect();
335
+ setUri(connectionUri);
336
+ return connectionUri;
337
+ } catch (error) {
338
+ throw error;
339
+ } finally {
340
+ setConnecting(false);
341
+ }
342
+ }, [client]);
343
+ const generateQRCode = react.useCallback(
344
+ async (uri2, options) => {
345
+ if (!client) {
346
+ throw new Error("WalletConnect client not initialized");
347
+ }
348
+ return client.generateQRCode(uri2, options);
349
+ },
350
+ [client]
351
+ );
352
+ const disconnect = react.useCallback(
353
+ async (topic) => {
354
+ if (!client) {
355
+ throw new Error("WalletConnect client not initialized");
356
+ }
357
+ await client.disconnectSession(topic);
358
+ refreshSessions();
359
+ },
360
+ [client]
361
+ );
362
+ react.useEffect(() => {
363
+ if (!client || !initialized) return;
364
+ const interval = setInterval(() => {
365
+ refreshSessions();
366
+ }, 2e3);
367
+ return () => clearInterval(interval);
368
+ }, [client, initialized, refreshSessions]);
369
+ react.useEffect(() => {
370
+ if (autoInit && !initialized) {
371
+ initialize().catch(console.error);
372
+ }
373
+ }, [autoInit, initialized, initialize]);
374
+ react.useEffect(() => {
375
+ return () => {
376
+ if (client) {
377
+ client.destroy().catch(console.error);
378
+ }
379
+ };
380
+ }, [client]);
381
+ const value = {
382
+ client,
383
+ initialized,
384
+ connecting,
385
+ uri,
386
+ sessions,
387
+ initialize,
388
+ connect,
389
+ generateQRCode,
390
+ disconnect,
391
+ refreshSessions
392
+ };
393
+ return /* @__PURE__ */ jsxRuntime.jsx(WalletConnectContext.Provider, { value, children });
394
+ }
395
+ function useWalletConnect() {
396
+ const context = react.useContext(WalletConnectContext);
397
+ if (!context) {
398
+ throw new Error("useWalletConnect must be used within WalletConnectProvider");
399
+ }
400
+ return context;
401
+ }
402
+ function useQRCode(uri, options) {
403
+ const { generateQRCode } = useWalletConnect();
404
+ const [qrCode, setQrCode] = react.useState(null);
405
+ const [loading, setLoading] = react.useState(false);
406
+ const [error, setError] = react.useState(null);
407
+ const generate = react.useCallback(
408
+ async (targetUri) => {
409
+ const uriToUse = targetUri || uri;
410
+ if (!uriToUse) {
411
+ setError(new Error("No URI provided"));
412
+ return;
413
+ }
414
+ setLoading(true);
415
+ setError(null);
416
+ try {
417
+ const qr = await generateQRCode(uriToUse, options);
418
+ setQrCode(qr);
419
+ } catch (err) {
420
+ setError(err);
421
+ setQrCode(null);
422
+ } finally {
423
+ setLoading(false);
424
+ }
425
+ },
426
+ [uri, options, generateQRCode]
427
+ );
428
+ react.useEffect(() => {
429
+ if (uri) {
430
+ generate(uri);
431
+ }
432
+ }, [uri, generate]);
433
+ return {
434
+ qrCode,
435
+ loading,
436
+ error,
437
+ generate
438
+ };
439
+ }
440
+
441
+ // src/utils.ts
442
+ function isValidWalletConnectUri(uri) {
443
+ return uri.startsWith("wc:") || uri.startsWith("wc://");
444
+ }
445
+ function parseWalletConnectUri(uri) {
446
+ try {
447
+ const cleanUri = uri.replace(/^wc:\/?\/?/, "");
448
+ const [topicVersion, paramsString] = cleanUri.split("?");
449
+ const [topic, version] = topicVersion.split("@");
450
+ const params = new URLSearchParams(paramsString);
451
+ return {
452
+ topic,
453
+ version,
454
+ symKey: params.get("symKey") || void 0,
455
+ relay: params.get("relay-protocol") ? {
456
+ protocol: params.get("relay-protocol"),
457
+ data: params.get("relay-data") || void 0
458
+ } : void 0
459
+ };
460
+ } catch {
461
+ return null;
462
+ }
463
+ }
464
+ function formatAddress(address, startLength = 6, endLength = 4) {
465
+ if (!address || address.length < startLength + endLength) {
466
+ return address;
467
+ }
468
+ return `${address.slice(0, startLength)}...${address.slice(-endLength)}`;
469
+ }
470
+ function extractAddressFromAccount(account) {
471
+ const parts = account.split(":");
472
+ return parts.length > 1 ? parts[parts.length - 1] : account;
473
+ }
474
+ function extractChainIdFromAccount(account) {
475
+ const parts = account.split(":");
476
+ return parts.length > 2 ? `${parts[0]}:${parts[1]}` : "";
477
+ }
478
+ function isSessionExpired(expiry) {
479
+ return Date.now() / 1e3 > expiry;
480
+ }
481
+ function getSessionTimeRemaining(expiry) {
482
+ const remaining = expiry - Date.now() / 1e3;
483
+ return Math.max(0, remaining);
484
+ }
485
+ function formatTimestamp(timestamp) {
486
+ const date = new Date(timestamp * 1e3);
487
+ return date.toLocaleString();
488
+ }
489
+ function isMobile() {
490
+ if (typeof window === "undefined") return false;
491
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
492
+ }
493
+ function generateDeepLink(uri, walletName) {
494
+ const encodedUri = encodeURIComponent(uri);
495
+ if (walletName) {
496
+ switch (walletName.toLowerCase()) {
497
+ case "metamask":
498
+ return `https://metamask.app.link/wc?uri=${encodedUri}`;
499
+ case "trust":
500
+ return `https://link.trustwallet.com/wc?uri=${encodedUri}`;
501
+ case "rainbow":
502
+ return `https://rnbwapp.com/wc?uri=${encodedUri}`;
503
+ default:
504
+ return `wc://wc?uri=${encodedUri}`;
505
+ }
506
+ }
507
+ return `wc://wc?uri=${encodedUri}`;
508
+ }
509
+ async function copyToClipboard(text) {
510
+ try {
511
+ if (navigator.clipboard) {
512
+ await navigator.clipboard.writeText(text);
513
+ return true;
514
+ } else {
515
+ const textarea = document.createElement("textarea");
516
+ textarea.value = text;
517
+ textarea.style.position = "fixed";
518
+ textarea.style.opacity = "0";
519
+ document.body.appendChild(textarea);
520
+ textarea.select();
521
+ const success = document.execCommand("copy");
522
+ document.body.removeChild(textarea);
523
+ return success;
524
+ }
525
+ } catch {
526
+ return false;
527
+ }
528
+ }
529
+ function formatError(error) {
530
+ if (typeof error === "string") return error;
531
+ if (error?.message) return error.message;
532
+ if (error?.error?.message) return error.error.message;
533
+ return "Unknown error occurred";
534
+ }
535
+ function isValidChainId(chainId) {
536
+ return /^[a-z]+:\d+$/.test(chainId);
537
+ }
538
+ function parseChainId(chainId) {
539
+ if (!isValidChainId(chainId)) return null;
540
+ const [namespace, reference] = chainId.split(":");
541
+ return { namespace, reference };
542
+ }
543
+
544
+ // src/hooks/useSession.ts
545
+ function useSession(topic) {
546
+ const { sessions, disconnect, refreshSessions, client } = useWalletConnect();
547
+ const [currentSession, setCurrentSession] = react.useState(null);
548
+ react.useEffect(() => {
549
+ if (topic) {
550
+ const session = sessions.find((s) => s.topic === topic);
551
+ setCurrentSession(session || null);
552
+ } else {
553
+ setCurrentSession(sessions[0] || null);
554
+ }
555
+ }, [topic, sessions]);
556
+ const disconnectSession = react.useCallback(
557
+ async (sessionTopic) => {
558
+ const topicToDisconnect = sessionTopic || topic || currentSession?.topic;
559
+ if (!topicToDisconnect) {
560
+ throw new Error("No session to disconnect");
561
+ }
562
+ await disconnect(topicToDisconnect);
563
+ },
564
+ [topic, currentSession, disconnect]
565
+ );
566
+ const checkExpired = react.useCallback((session) => {
567
+ return isSessionExpired(session.expiry);
568
+ }, []);
569
+ const getAccounts = react.useCallback(
570
+ (session) => {
571
+ const targetSession = session || currentSession;
572
+ if (!targetSession) return [];
573
+ const allAccounts = [];
574
+ Object.values(targetSession.namespaces).forEach((namespace) => {
575
+ if (namespace.accounts) {
576
+ allAccounts.push(...namespace.accounts);
577
+ }
578
+ });
579
+ return allAccounts;
580
+ },
581
+ [currentSession]
582
+ );
583
+ const getChains = react.useCallback(
584
+ (session) => {
585
+ const targetSession = session || currentSession;
586
+ if (!targetSession) return [];
587
+ const allChains = [];
588
+ Object.values(targetSession.namespaces).forEach((namespace) => {
589
+ if (namespace.chains) {
590
+ allChains.push(...namespace.chains);
591
+ }
592
+ });
593
+ return allChains;
594
+ },
595
+ [currentSession]
596
+ );
597
+ return {
598
+ session: currentSession,
599
+ allSessions: sessions,
600
+ disconnect: disconnectSession,
601
+ refresh: refreshSessions,
602
+ isExpired: currentSession ? checkExpired(currentSession) : false,
603
+ getAccounts,
604
+ getChains,
605
+ hasSession: !!currentSession
606
+ };
607
+ }
608
+ function useConnect(options) {
609
+ const { connect, generateQRCode, connecting } = useWalletConnect();
610
+ const [uri, setUri] = react.useState(null);
611
+ const [qrCode, setQrCode] = react.useState(null);
612
+ const [error, setError] = react.useState(null);
613
+ const handleConnect = react.useCallback(async () => {
614
+ setError(null);
615
+ try {
616
+ const connectionUri = await connect();
617
+ setUri(connectionUri);
618
+ if (options?.onConnect) {
619
+ options.onConnect(connectionUri);
620
+ }
621
+ if (options?.autoGenerateQRCode !== false) {
622
+ const qr = await generateQRCode(connectionUri, options?.qrCodeOptions);
623
+ setQrCode(qr);
624
+ }
625
+ return connectionUri;
626
+ } catch (err) {
627
+ const error2 = err;
628
+ setError(error2);
629
+ options?.onError?.(error2);
630
+ throw error2;
631
+ }
632
+ }, [connect, generateQRCode, options]);
633
+ const reset = react.useCallback(() => {
634
+ setUri(null);
635
+ setQrCode(null);
636
+ setError(null);
637
+ }, []);
638
+ return {
639
+ connect: handleConnect,
640
+ uri,
641
+ qrCode,
642
+ connecting,
643
+ error,
644
+ reset
645
+ };
646
+ }
647
+
648
+ // src/siwe.ts
649
+ async function getChecksumAddress(address) {
650
+ try {
651
+ const ethers = await import('ethers');
652
+ return ethers.getAddress(address);
653
+ } catch {
654
+ return address;
655
+ }
656
+ }
657
+ async function createSiweMessage(config, address) {
658
+ const siweModule = await import('siwe');
659
+ const SiweMessage = siweModule.SiweMessage || siweModule.default?.SiweMessage;
660
+ const checksumAddress = await getChecksumAddress(address);
661
+ const siweMessage = new SiweMessage({
662
+ domain: config.domain,
663
+ address: checksumAddress,
664
+ statement: config.statement || "Sign in with Ethereum to the app.",
665
+ uri: config.uri,
666
+ version: config.version || "1",
667
+ chainId: config.chainId,
668
+ nonce: config.nonce || generateNonce(),
669
+ issuedAt: config.issuedAt || (/* @__PURE__ */ new Date()).toISOString(),
670
+ expirationTime: config.expirationTime,
671
+ notBefore: config.notBefore,
672
+ requestId: config.requestId,
673
+ resources: config.resources
674
+ });
675
+ return siweMessage.prepareMessage();
676
+ }
677
+ async function parseSiweMessage(message) {
678
+ const siweModule = await import('siwe');
679
+ const SiweMessage = siweModule.SiweMessage || siweModule.default?.SiweMessage;
680
+ return new SiweMessage(message);
681
+ }
682
+ async function verifySiweSignature(params) {
683
+ try {
684
+ const siweModule = await import('siwe');
685
+ const SiweMessage = siweModule.SiweMessage || siweModule.default?.SiweMessage;
686
+ const siweMessage = new SiweMessage(params.message);
687
+ const result = await siweMessage.verify(
688
+ {
689
+ signature: params.signature,
690
+ nonce: params.nonce,
691
+ domain: params.domain,
692
+ time: params.time
693
+ },
694
+ {
695
+ suppressExceptions: true
696
+ // Suppress exceptions to get error details
697
+ }
698
+ );
699
+ if (result.success) {
700
+ return {
701
+ success: true,
702
+ data: result.data
703
+ };
704
+ } else {
705
+ return {
706
+ success: false,
707
+ error: result.error?.type || "Verification failed"
708
+ };
709
+ }
710
+ } catch (error) {
711
+ return {
712
+ success: false,
713
+ error: error.type || error.message || "Unknown verification error"
714
+ };
715
+ }
716
+ }
717
+ function generateNonce(length = 16) {
718
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
719
+ let nonce = "";
720
+ const randomValues = new Uint8Array(length);
721
+ if (typeof window !== "undefined" && window.crypto) {
722
+ window.crypto.getRandomValues(randomValues);
723
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
724
+ globalThis.crypto.getRandomValues(randomValues);
725
+ } else {
726
+ for (let i = 0; i < length; i++) {
727
+ randomValues[i] = Math.floor(Math.random() * 256);
728
+ }
729
+ }
730
+ for (let i = 0; i < length; i++) {
731
+ nonce += chars[randomValues[i] % chars.length];
732
+ }
733
+ return nonce;
734
+ }
735
+ function extractChainIdNumber(account) {
736
+ const parts = account.split(":");
737
+ if (parts.length > 2) {
738
+ return parseInt(parts[1], 10);
739
+ }
740
+ return 1;
741
+ }
742
+ function createSiweConfigFromSession(params) {
743
+ return {
744
+ domain: params.domain,
745
+ uri: params.uri,
746
+ chainId: params.chainId,
747
+ statement: params.statement || "Sign in with Ethereum to authenticate your wallet.",
748
+ version: "1",
749
+ nonce: generateNonce(),
750
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
751
+ expirationTime: new Date(Date.now() + 5 * 60 * 1e3).toISOString(),
752
+ // 5 minutes
753
+ resources: params.resources
754
+ };
755
+ }
756
+ var SiweAuth = class {
757
+ config;
758
+ constructor(config) {
759
+ this.config = {
760
+ ...config,
761
+ nonce: generateNonce(),
762
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
763
+ };
764
+ }
765
+ /**
766
+ * Create the message to sign
767
+ */
768
+ async createMessage(address) {
769
+ return createSiweMessage(this.config, address);
770
+ }
771
+ /**
772
+ * Verify the signature
773
+ */
774
+ async verify(message, signature) {
775
+ return verifySiweSignature({
776
+ message,
777
+ signature,
778
+ nonce: this.config.nonce,
779
+ domain: this.config.domain
780
+ });
781
+ }
782
+ /**
783
+ * Get the nonce
784
+ */
785
+ getNonce() {
786
+ return this.config.nonce || "";
787
+ }
788
+ /**
789
+ * Refresh nonce (for new sign-in attempts)
790
+ */
791
+ refreshNonce() {
792
+ this.config.nonce = generateNonce();
793
+ this.config.issuedAt = (/* @__PURE__ */ new Date()).toISOString();
794
+ }
795
+ };
796
+
797
+ // src/hooks/useSiwe.ts
798
+ function useSiwe(config) {
799
+ const { client } = useWalletConnect();
800
+ const [isAuthenticating, setIsAuthenticating] = react.useState(false);
801
+ const [authResult, setAuthResult] = react.useState(null);
802
+ const signIn = react.useCallback(
803
+ async (sessionTopic) => {
804
+ if (!client) {
805
+ throw new Error("WalletConnect client not initialized");
806
+ }
807
+ const sessions = client.getActiveSessions();
808
+ if (sessions.length === 0) {
809
+ throw new Error("No active sessions. Connect wallet first.");
810
+ }
811
+ setIsAuthenticating(true);
812
+ setAuthResult(null);
813
+ try {
814
+ const session = sessionTopic ? sessions.find((s) => s.topic === sessionTopic) : sessions[0];
815
+ if (!session) {
816
+ throw new Error("Session not found");
817
+ }
818
+ const accounts = Object.values(session.namespaces).flatMap((ns) => ns.accounts || []);
819
+ const primaryAccount = accounts[0];
820
+ if (!primaryAccount) {
821
+ throw new Error("No accounts found in session");
822
+ }
823
+ const address = extractAddressFromAccount(primaryAccount);
824
+ const chainIdStr = extractChainIdFromAccount(primaryAccount);
825
+ const chainId = extractChainIdNumber(primaryAccount);
826
+ const siweConfig = createSiweConfigFromSession({
827
+ domain: config?.domain || window.location.host,
828
+ uri: config?.uri || window.location.origin,
829
+ chainId,
830
+ statement: config?.statement,
831
+ resources: config?.resources
832
+ });
833
+ const siweAuth = new SiweAuth(siweConfig);
834
+ const message = await siweAuth.createMessage(address);
835
+ if (!client.signClient) {
836
+ throw new Error("SignClient not initialized");
837
+ }
838
+ const signature = await client.signClient.request({
839
+ topic: session.topic,
840
+ chainId: chainIdStr,
841
+ request: {
842
+ method: "personal_sign",
843
+ params: [message, address]
844
+ }
845
+ });
846
+ const verifyResult = await siweAuth.verify(message, signature);
847
+ if (verifyResult.success) {
848
+ setAuthResult({
849
+ success: true,
850
+ address,
851
+ message,
852
+ signature
853
+ });
854
+ return {
855
+ success: true,
856
+ address,
857
+ message,
858
+ signature,
859
+ siweMessage: verifyResult.data
860
+ };
861
+ } else {
862
+ throw new Error(verifyResult.error || "Signature verification failed");
863
+ }
864
+ } catch (error) {
865
+ const errorMsg = error.message || "Authentication failed";
866
+ setAuthResult({
867
+ success: false,
868
+ error: errorMsg
869
+ });
870
+ throw error;
871
+ } finally {
872
+ setIsAuthenticating(false);
873
+ }
874
+ },
875
+ [client, config]
876
+ );
877
+ const signOut = react.useCallback(() => {
878
+ setAuthResult(null);
879
+ }, []);
880
+ return {
881
+ signIn,
882
+ signOut,
883
+ isAuthenticating,
884
+ authResult,
885
+ isAuthenticated: authResult?.success || false
886
+ };
887
+ }
888
+
889
+ // src/chains.ts
890
+ var EIP155_NAMESPACE = {
891
+ chains: ["eip155:1"],
892
+ // Ethereum Mainnet
893
+ methods: [
894
+ "eth_sendTransaction",
895
+ "eth_signTransaction",
896
+ "eth_sign",
897
+ "personal_sign",
898
+ "eth_signTypedData",
899
+ "eth_signTypedData_v4",
900
+ "wallet_switchEthereumChain",
901
+ "wallet_addEthereumChain"
902
+ ],
903
+ events: ["chainChanged", "accountsChanged"]
904
+ };
905
+ var SOLANA_NAMESPACE = {
906
+ chains: ["solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ"],
907
+ // Solana Mainnet
908
+ methods: ["solana_signTransaction", "solana_signMessage", "solana_signAndSendTransaction"],
909
+ events: ["accountsChanged", "chainChanged"]
910
+ };
911
+ var APTOS_NAMESPACE = {
912
+ chains: ["aptos:1"],
913
+ // Aptos Mainnet
914
+ methods: ["aptos_signTransaction", "aptos_signMessage", "aptos_signAndSubmitTransaction"],
915
+ events: ["accountChanged", "networkChanged"]
916
+ };
917
+ var COSMOS_NAMESPACE = {
918
+ chains: ["cosmos:cosmoshub-4"],
919
+ // Cosmos Hub
920
+ methods: ["cosmos_signDirect", "cosmos_signAmino", "cosmos_getAccounts"],
921
+ events: ["chainChanged", "accountsChanged"]
922
+ };
923
+ var POLKADOT_NAMESPACE = {
924
+ chains: ["polkadot:91b171bb158e2d3848fa23a9f1c25182"],
925
+ // Polkadot Mainnet
926
+ methods: ["polkadot_signTransaction", "polkadot_signMessage"],
927
+ events: ["accountsChanged"]
928
+ };
929
+ var NEAR_NAMESPACE = {
930
+ chains: ["near:mainnet"],
931
+ methods: ["near_signTransaction", "near_signMessage"],
932
+ events: ["accountsChanged"]
933
+ };
934
+ var EVM_CHAINS = {
935
+ // Ethereum
936
+ ETHEREUM_MAINNET: "eip155:1",
937
+ ETHEREUM_GOERLI: "eip155:5",
938
+ ETHEREUM_SEPOLIA: "eip155:11155111",
939
+ // Layer 2 (L2)
940
+ POLYGON: "eip155:137",
941
+ POLYGON_MUMBAI: "eip155:80001",
942
+ ARBITRUM: "eip155:42161",
943
+ ARBITRUM_GOERLI: "eip155:421613",
944
+ OPTIMISM: "eip155:10",
945
+ OPTIMISM_GOERLI: "eip155:420",
946
+ // other EVM chains
947
+ BSC: "eip155:56",
948
+ BSC_TESTNET: "eip155:97",
949
+ AVALANCHE: "eip155:43114",
950
+ AVALANCHE_FUJI: "eip155:43113",
951
+ FANTOM: "eip155:250",
952
+ CRONOS: "eip155:25",
953
+ GNOSIS: "eip155:100",
954
+ BASE: "eip155:8453",
955
+ ZKSYNC: "eip155:324",
956
+ LINEA: "eip155:59144",
957
+ SCROLL: "eip155:534352"
958
+ };
959
+ var SOLANA_CHAINS = {
960
+ MAINNET: "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ",
961
+ DEVNET: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
962
+ TESTNET: "solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K"
963
+ };
964
+ var APTOS_CHAINS = {
965
+ MAINNET: "aptos:1",
966
+ TESTNET: "aptos:2",
967
+ DEVNET: "aptos:3"
968
+ };
969
+ function getChainName(chainId) {
970
+ const chainNames = {
971
+ // Ethereum
972
+ "eip155:1": "Ethereum Mainnet",
973
+ "eip155:5": "Goerli Testnet",
974
+ "eip155:11155111": "Sepolia Testnet",
975
+ // Layer 2
976
+ "eip155:137": "Polygon",
977
+ "eip155:80001": "Polygon Mumbai",
978
+ "eip155:42161": "Arbitrum One",
979
+ "eip155:421613": "Arbitrum Goerli",
980
+ "eip155:10": "Optimism",
981
+ "eip155:420": "Optimism Goerli",
982
+ // other EVM chains
983
+ "eip155:56": "BNB Smart Chain",
984
+ "eip155:97": "BSC Testnet",
985
+ "eip155:43114": "Avalanche C-Chain",
986
+ "eip155:43113": "Avalanche Fuji",
987
+ "eip155:250": "Fantom Opera",
988
+ "eip155:25": "Cronos",
989
+ "eip155:100": "Gnosis Chain",
990
+ "eip155:8453": "Base",
991
+ "eip155:324": "zkSync Era",
992
+ "eip155:59144": "Linea",
993
+ "eip155:534352": "Scroll",
994
+ // Solana
995
+ "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ": "Solana Mainnet",
996
+ "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "Solana Devnet",
997
+ "solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K": "Solana Testnet",
998
+ // Aptos
999
+ "aptos:1": "Aptos Mainnet",
1000
+ "aptos:2": "Aptos Testnet",
1001
+ "aptos:3": "Aptos Devnet",
1002
+ // Cosmos
1003
+ "cosmos:cosmoshub-4": "Cosmos Hub",
1004
+ "cosmos:osmosis-1": "Osmosis",
1005
+ // Polkadot
1006
+ "polkadot:91b171bb158e2d3848fa23a9f1c25182": "Polkadot",
1007
+ // Near
1008
+ "near:mainnet": "Near Mainnet"
1009
+ };
1010
+ return chainNames[chainId] || chainId;
1011
+ }
1012
+ function createMultiChainNamespaces(chains) {
1013
+ const namespaces = {};
1014
+ const evmChains = chains.filter((chain) => chain.startsWith("eip155:"));
1015
+ if (evmChains.length > 0) {
1016
+ namespaces.eip155 = {
1017
+ ...EIP155_NAMESPACE,
1018
+ chains: evmChains
1019
+ };
1020
+ }
1021
+ const solanaChains = chains.filter((chain) => chain.startsWith("solana:"));
1022
+ if (solanaChains.length > 0) {
1023
+ namespaces.solana = {
1024
+ ...SOLANA_NAMESPACE,
1025
+ chains: solanaChains
1026
+ };
1027
+ }
1028
+ const aptosChains = chains.filter((chain) => chain.startsWith("aptos:"));
1029
+ if (aptosChains.length > 0) {
1030
+ namespaces.aptos = {
1031
+ ...APTOS_NAMESPACE,
1032
+ chains: aptosChains
1033
+ };
1034
+ }
1035
+ const cosmosChains = chains.filter((chain) => chain.startsWith("cosmos:"));
1036
+ if (cosmosChains.length > 0) {
1037
+ namespaces.cosmos = {
1038
+ ...COSMOS_NAMESPACE,
1039
+ chains: cosmosChains
1040
+ };
1041
+ }
1042
+ return namespaces;
1043
+ }
1044
+ function getChainType(chainId) {
1045
+ if (chainId.startsWith("eip155:")) return "EVM";
1046
+ if (chainId.startsWith("solana:")) return "Solana";
1047
+ if (chainId.startsWith("aptos:")) return "Aptos";
1048
+ if (chainId.startsWith("cosmos:")) return "Cosmos";
1049
+ if (chainId.startsWith("polkadot:")) return "Polkadot";
1050
+ if (chainId.startsWith("near:")) return "Near";
1051
+ return "Unknown";
1052
+ }
1053
+
1054
+ // src/wallets.ts
1055
+ var EXPLORER_API_URL = "https://explorer-api.walletconnect.com";
1056
+ async function getWalletConnectWallets(options = {}) {
1057
+ const { projectId, entries = 100, page = 1, search, chains, include, exclude, recommendedIds } = options;
1058
+ const params = new URLSearchParams();
1059
+ if (projectId) {
1060
+ params.append("projectId", projectId);
1061
+ }
1062
+ params.append("entries", entries.toString());
1063
+ params.append("page", page.toString());
1064
+ if (search) {
1065
+ params.append("search", search);
1066
+ }
1067
+ if (chains) {
1068
+ params.append("chains", chains);
1069
+ }
1070
+ if (include) {
1071
+ params.append("include", include);
1072
+ }
1073
+ if (exclude) {
1074
+ params.append("exclude", exclude);
1075
+ }
1076
+ if (recommendedIds) {
1077
+ params.append("recommendedIds", recommendedIds);
1078
+ }
1079
+ const url = `${EXPLORER_API_URL}/v3/wallets?${params.toString()}`;
1080
+ try {
1081
+ const response = await fetch(url);
1082
+ if (!response.ok) {
1083
+ throw new Error(`Failed to fetch wallets: ${response.statusText}`);
1084
+ }
1085
+ const data = await response.json();
1086
+ return data;
1087
+ } catch (error) {
1088
+ throw error;
1089
+ }
1090
+ }
1091
+ async function getAllWallets(options = {}) {
1092
+ const allWallets = [];
1093
+ let page = 1;
1094
+ let hasMore = true;
1095
+ while (hasMore) {
1096
+ const response = await getWalletConnectWallets({
1097
+ ...options,
1098
+ page,
1099
+ entries: 100
1100
+ });
1101
+ allWallets.push(...response.data);
1102
+ hasMore = response.data.length === 100;
1103
+ page++;
1104
+ }
1105
+ return allWallets;
1106
+ }
1107
+ async function getWalletById(walletId, projectId) {
1108
+ const params = new URLSearchParams();
1109
+ if (projectId) {
1110
+ params.append("projectId", projectId);
1111
+ }
1112
+ const url = `${EXPLORER_API_URL}/v3/wallets/${walletId}?${params.toString()}`;
1113
+ try {
1114
+ const response = await fetch(url);
1115
+ if (!response.ok) {
1116
+ if (response.status === 404) {
1117
+ return null;
1118
+ }
1119
+ throw new Error(`Failed to fetch wallet: ${response.statusText}`);
1120
+ }
1121
+ return await response.json();
1122
+ } catch (error) {
1123
+ return null;
1124
+ }
1125
+ }
1126
+ async function searchWallets(query, options = {}) {
1127
+ const response = await getWalletConnectWallets({
1128
+ ...options,
1129
+ search: query
1130
+ });
1131
+ return response.data;
1132
+ }
1133
+ async function getWalletsByChain(chainId, options = {}) {
1134
+ const response = await getWalletConnectWallets({
1135
+ ...options,
1136
+ chains: chainId
1137
+ });
1138
+ return response.data;
1139
+ }
1140
+ async function getRecommendedWallets(walletIds, options = {}) {
1141
+ const response = await getWalletConnectWallets({
1142
+ ...options,
1143
+ recommendedIds: walletIds.join(",")
1144
+ });
1145
+ return response.data;
1146
+ }
1147
+ async function getMobileWallets(options = {}) {
1148
+ const response = await getWalletConnectWallets(options);
1149
+ return response.data.filter((wallet) => wallet.mobile || wallet.app?.ios || wallet.app?.android);
1150
+ }
1151
+ async function getDesktopWallets(options = {}) {
1152
+ const response = await getWalletConnectWallets(options);
1153
+ return response.data.filter(
1154
+ (wallet) => wallet.desktop || wallet.app?.mac || wallet.app?.windows || wallet.app?.linux
1155
+ );
1156
+ }
1157
+ async function getBrowserWallets(options = {}) {
1158
+ const response = await getWalletConnectWallets(options);
1159
+ return response.data.filter(
1160
+ (wallet) => wallet.app?.chrome || wallet.app?.firefox || wallet.app?.safari || wallet.app?.edge
1161
+ );
1162
+ }
1163
+ var POPULAR_WALLET_IDS = {
1164
+ METAMASK: "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96",
1165
+ TRUST: "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0",
1166
+ RAINBOW: "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369",
1167
+ COINBASE: "fd20dc426fb37566d803205b19bbc1d4096b248ac04548e3cfb6b3a38bd033aa",
1168
+ SAFE: "225affb176778569276e484e1b92637ad061b01e13a048b35a9d280c3b58970f",
1169
+ ARGENT: "bc949c5d968ae81310268bf9193f9c9fb7bb4e1283e1284af8f2bd4992535fd6",
1170
+ ZERION: "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18",
1171
+ IMTOKEN: "ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef",
1172
+ OKX: "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709",
1173
+ PHANTOM: "a797aa35c0fadbfc1a53e7f675162ed5226968b44a19ee3d24385c64d1d3c393",
1174
+ TOKENPOCKET: "20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66",
1175
+ BITGET: "7674bb4e353bf52886768a3ddc2a4562ce2f4191c80831291218ebd90f5f5e26"
1176
+ };
1177
+
1178
+ // src/types.ts
1179
+ var ChainType = /* @__PURE__ */ ((ChainType2) => {
1180
+ ChainType2["EIP155"] = "eip155";
1181
+ ChainType2["SOLANA"] = "solana";
1182
+ ChainType2["APTOS"] = "aptos";
1183
+ ChainType2["COSMOS"] = "cosmos";
1184
+ ChainType2["POLKADOT"] = "polkadot";
1185
+ ChainType2["NEAR"] = "near";
1186
+ return ChainType2;
1187
+ })(ChainType || {});
1188
+ var AuthMethod = /* @__PURE__ */ ((AuthMethod2) => {
1189
+ AuthMethod2["STANDARD"] = "standard";
1190
+ AuthMethod2["SIWE"] = "siwe";
1191
+ return AuthMethod2;
1192
+ })(AuthMethod || {});
1193
+
1194
+ exports.APTOS_CHAINS = APTOS_CHAINS;
1195
+ exports.APTOS_NAMESPACE = APTOS_NAMESPACE;
1196
+ exports.AuthMethod = AuthMethod;
1197
+ exports.COSMOS_NAMESPACE = COSMOS_NAMESPACE;
1198
+ exports.ChainType = ChainType;
1199
+ exports.EIP155_NAMESPACE = EIP155_NAMESPACE;
1200
+ exports.EVM_CHAINS = EVM_CHAINS;
1201
+ exports.NEAR_NAMESPACE = NEAR_NAMESPACE;
1202
+ exports.POLKADOT_NAMESPACE = POLKADOT_NAMESPACE;
1203
+ exports.POPULAR_WALLET_IDS = POPULAR_WALLET_IDS;
1204
+ exports.SOLANA_CHAINS = SOLANA_CHAINS;
1205
+ exports.SOLANA_NAMESPACE = SOLANA_NAMESPACE;
1206
+ exports.SiweAuth = SiweAuth;
1207
+ exports.WalletConnectClient = WalletConnectClient;
1208
+ exports.WalletConnectProvider = WalletConnectProvider;
1209
+ exports.copyToClipboard = copyToClipboard;
1210
+ exports.createMultiChainNamespaces = createMultiChainNamespaces;
1211
+ exports.createSiweConfigFromSession = createSiweConfigFromSession;
1212
+ exports.createSiweMessage = createSiweMessage;
1213
+ exports.extractAddressFromAccount = extractAddressFromAccount;
1214
+ exports.extractChainIdFromAccount = extractChainIdFromAccount;
1215
+ exports.extractChainIdNumber = extractChainIdNumber;
1216
+ exports.formatAddress = formatAddress;
1217
+ exports.formatError = formatError;
1218
+ exports.formatTimestamp = formatTimestamp;
1219
+ exports.generateDeepLink = generateDeepLink;
1220
+ exports.generateNonce = generateNonce;
1221
+ exports.getAllWallets = getAllWallets;
1222
+ exports.getBrowserWallets = getBrowserWallets;
1223
+ exports.getChainName = getChainName;
1224
+ exports.getChainType = getChainType;
1225
+ exports.getDesktopWallets = getDesktopWallets;
1226
+ exports.getMobileWallets = getMobileWallets;
1227
+ exports.getRecommendedWallets = getRecommendedWallets;
1228
+ exports.getSessionTimeRemaining = getSessionTimeRemaining;
1229
+ exports.getWalletById = getWalletById;
1230
+ exports.getWalletConnectWallets = getWalletConnectWallets;
1231
+ exports.getWalletsByChain = getWalletsByChain;
1232
+ exports.isMobile = isMobile;
1233
+ exports.isSessionExpired = isSessionExpired;
1234
+ exports.isValidChainId = isValidChainId;
1235
+ exports.isValidWalletConnectUri = isValidWalletConnectUri;
1236
+ exports.parseChainId = parseChainId;
1237
+ exports.parseSiweMessage = parseSiweMessage;
1238
+ exports.parseWalletConnectUri = parseWalletConnectUri;
1239
+ exports.searchWallets = searchWallets;
1240
+ exports.useConnect = useConnect;
1241
+ exports.useQRCode = useQRCode;
1242
+ exports.useSession = useSession;
1243
+ exports.useSiwe = useSiwe;
1244
+ exports.useWalletConnect = useWalletConnect;
1245
+ exports.verifySiweSignature = verifySiweSignature;