@blazium/ton-connect-mobile 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -144,7 +144,6 @@ Access the TonConnectUI instance with all methods and features.
144
144
  ```typescript
145
145
  const tonConnectUI = useTonConnectUI();
146
146
 
147
- <<<<<<< HEAD
148
147
  // Connection methods:
149
148
  await tonConnectUI.connectWallet();
150
149
  await tonConnectUI.disconnect();
@@ -241,7 +240,6 @@ new TonConnectMobile(config: TonConnectMobileConfig)
241
240
  - `manifestUrl` (required): URL to your TonConnect manifest file
242
241
  - `scheme` (required): Your app's deep link scheme
243
242
  - `storageKeyPrefix` (optional): Prefix for storage keys (default: `'tonconnect_'`)
244
- <<<<<<< HEAD
245
243
  - `connectionTimeout` (optional): Connection timeout in ms (default: `300000` = 5 minutes)
246
244
  - `transactionTimeout` (optional): Transaction timeout in ms (default: `300000` = 5 minutes)
247
245
  - `skipCanOpenURLCheck` (optional): Skip canOpenURL check (default: `true` for Android compatibility)
@@ -325,7 +323,6 @@ const unsubscribe = ton.onStatusChange((status) => {
325
323
  });
326
324
  ```
327
325
 
328
- <<<<<<< HEAD
329
326
  ##### `getNetwork(): Network`
330
327
 
331
328
  Get current network (mainnet or testnet).
@@ -445,20 +442,6 @@ ton.removeAllListeners(); // Remove all listeners
445
442
  - iOS device or simulator
446
443
  - Web browsers (for wallets with web support like Tonkeeper Web)
447
444
 
448
- ## Platform Support
449
-
450
- - ✅ **Android**: Full support via Expo or React Native CLI
451
- - ✅ **iOS**: Full support via Expo or React Native CLI
452
- - ⚠️ **Web**: Deep links are not supported. The SDK will throw a clear error message if you try to use it in a web browser.
453
-
454
- **Why?** The `tonconnect://` protocol is a custom URI scheme that requires a mobile app handler. Web browsers cannot handle these custom protocols.
455
-
456
- **Testing**: To test wallet connections, use:
457
- - Android device or emulator
458
- - iOS device or simulator
459
- - Not web browsers
460
- >>>>>>> af0bd46f78c13fb8e9799027e48d4fa228a49e3c
461
-
462
445
  ## Configuration
463
446
 
464
447
  ### Expo Setup
@@ -526,13 +509,13 @@ The manifest URL must be accessible via HTTPS.
526
509
 
527
510
  ## Supported Wallets
528
511
 
529
- <<<<<<< HEAD
530
512
  - **Tonkeeper** - Full support (iOS, Android, Web)
531
513
  - **MyTonWallet** - Full support (iOS, Android, Web)
532
514
  - **Tonhub** - Full support (iOS, Android)
533
515
  - **Wallet in Telegram** - Full support (iOS, Android)
534
516
 
535
517
  **Note**: Wallet icons are automatically loaded from official sources. If an icon fails to load, a placeholder with the wallet's initial is shown.
518
+
536
519
  ## Migration from @tonconnect/ui-react
537
520
 
538
521
  This SDK is a drop-in replacement for `@tonconnect/ui-react` in React Native/Expo environments.
@@ -613,7 +596,6 @@ MIT
613
596
  For issues and questions:
614
597
  - GitHub Issues: [https://github.com/blaziumdev/ton-connect-mobile/issues](https://github.com/blaziumdev/ton-connect-mobile/issues)
615
598
 
616
- <<<<<<< HEAD
617
599
  ## New Features in v1.2.3
618
600
 
619
601
  ### 🌐 Network Switching
@@ -847,6 +829,11 @@ try {
847
829
 
848
830
  ## Changelog
849
831
 
832
+ ### v1.2.5
833
+ - ✅ **FIXED**: Connection response validation - `appName` and `version` fields are now optional, improving compatibility with wallets that don't send these fields
834
+ - ✅ **FIXED**: ReactNativeAdapter URL listener error handling - Added try-catch block to prevent app crashes if URL listeners throw errors
835
+ - ✅ **IMPROVED**: Enhanced error handling robustness across the SDK
836
+
850
837
  ### v1.2.3
851
838
  - ✅ **NEW**: Network switching - Switch between mainnet and testnet dynamically
852
839
  - ✅ **NEW**: Event emitters - Listen to connect, disconnect, transaction, and error events
@@ -863,6 +850,7 @@ try {
863
850
  - ✅ **IMPROVED**: Chain ID automatically updates when network changes
864
851
  - ✅ **FIXED**: Tonkeeper now correctly shows as available on web
865
852
 
853
+
866
854
  ### v1.2.0
867
855
  - ✅ **NEW**: Beautiful wallet selection modal component
868
856
  - ✅ **NEW**: Transaction builder utilities (`buildTransferTransaction`, `tonToNano`, etc.)
@@ -873,7 +861,6 @@ try {
873
861
  - ✅ Enhanced logging and debugging
874
862
  - ✅ Better TypeScript types
875
863
 
876
-
877
864
  ### v1.1.5
878
865
  - ✅ Full `@tonconnect/ui-react` compatibility
879
866
  - ✅ React integration layer with hooks and components
@@ -34,7 +34,14 @@ class ReactNativeAdapter {
34
34
  }
35
35
  // Listen for deep links when app is already open
36
36
  this.subscription = Linking.addEventListener('url', (event) => {
37
- this.urlListeners.forEach((listener) => listener(event.url));
37
+ this.urlListeners.forEach((listener) => {
38
+ try {
39
+ listener(event.url);
40
+ }
41
+ catch (error) {
42
+ console.error('[ReactNativeAdapter] Error in URL listener:', error);
43
+ }
44
+ });
38
45
  });
39
46
  }
40
47
  async openURL(url, skipCanOpenURLCheck = true) {
@@ -0,0 +1,61 @@
1
+ /**
2
+ * TON Connect v2 Bridge Gateway
3
+ * Handles SSE connection for receiving wallet responses and POST for sending messages
4
+ */
5
+ /**
6
+ * Bridge message received from wallet
7
+ */
8
+ export interface BridgeIncomingMessage {
9
+ from: string;
10
+ message: string;
11
+ }
12
+ /**
13
+ * Bridge Gateway for TON Connect v2 HTTP Bridge
14
+ */
15
+ export declare class BridgeGateway {
16
+ private xhr;
17
+ private lastEventId;
18
+ private active;
19
+ private reconnectTimer;
20
+ private bridgeUrl;
21
+ private clientId;
22
+ private onMessageCallback;
23
+ private onErrorCallback;
24
+ /**
25
+ * Connect to the bridge SSE endpoint
26
+ * Listens for incoming messages from the wallet
27
+ */
28
+ connect(bridgeUrl: string, clientId: string, onMessage: (msg: BridgeIncomingMessage) => void, onError?: (error: Error) => void): void;
29
+ /**
30
+ * Open SSE connection using XMLHttpRequest (works in React Native)
31
+ */
32
+ private openSSE;
33
+ /**
34
+ * Fallback: poll bridge with fetch (for environments without XMLHttpRequest streaming)
35
+ */
36
+ private pollWithFetch;
37
+ /**
38
+ * Handle a single SSE event data
39
+ */
40
+ private handleEventData;
41
+ /**
42
+ * Schedule reconnection after a delay
43
+ */
44
+ private scheduleReconnect;
45
+ /**
46
+ * Send an encrypted message via the bridge
47
+ */
48
+ send(bridgeUrl: string, fromClientId: string, toClientId: string, encryptedMessage: Uint8Array, ttl?: number): Promise<void>;
49
+ /**
50
+ * Close the bridge connection
51
+ */
52
+ close(): void;
53
+ /**
54
+ * Check if bridge is currently connected/active
55
+ */
56
+ get isConnected(): boolean;
57
+ /**
58
+ * Parse SSE text into events
59
+ */
60
+ private parseSSE;
61
+ }
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /**
3
+ * TON Connect v2 Bridge Gateway
4
+ * Handles SSE connection for receiving wallet responses and POST for sending messages
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BridgeGateway = void 0;
8
+ const session_1 = require("./session");
9
+ /**
10
+ * Bridge Gateway for TON Connect v2 HTTP Bridge
11
+ */
12
+ class BridgeGateway {
13
+ constructor() {
14
+ this.xhr = null;
15
+ this.lastEventId = '';
16
+ this.active = false;
17
+ this.reconnectTimer = null;
18
+ this.bridgeUrl = '';
19
+ this.clientId = '';
20
+ this.onMessageCallback = null;
21
+ this.onErrorCallback = null;
22
+ }
23
+ /**
24
+ * Connect to the bridge SSE endpoint
25
+ * Listens for incoming messages from the wallet
26
+ */
27
+ connect(bridgeUrl, clientId, onMessage, onError) {
28
+ this.bridgeUrl = bridgeUrl;
29
+ this.clientId = clientId;
30
+ this.onMessageCallback = onMessage;
31
+ this.onErrorCallback = onError || null;
32
+ this.active = true;
33
+ this.openSSE();
34
+ }
35
+ /**
36
+ * Open SSE connection using XMLHttpRequest (works in React Native)
37
+ */
38
+ openSSE() {
39
+ if (!this.active)
40
+ return;
41
+ // Build URL
42
+ let url = `${this.bridgeUrl}/events?client_id=${this.clientId}`;
43
+ if (this.lastEventId) {
44
+ url += `&last_event_id=${this.lastEventId}`;
45
+ }
46
+ console.log('[Bridge] Opening SSE connection:', url);
47
+ // Use XMLHttpRequest for SSE (available in React Native)
48
+ if (typeof XMLHttpRequest === 'undefined') {
49
+ // Fallback: use fetch-based polling
50
+ this.pollWithFetch(url);
51
+ return;
52
+ }
53
+ const xhr = new XMLHttpRequest();
54
+ this.xhr = xhr;
55
+ let processedLength = 0;
56
+ let buffer = '';
57
+ xhr.onreadystatechange = () => {
58
+ // LOADING (3) or DONE (4) — process incoming data
59
+ if (xhr.readyState >= 3) {
60
+ try {
61
+ const newData = xhr.responseText.substring(processedLength);
62
+ processedLength = xhr.responseText.length;
63
+ if (newData) {
64
+ buffer += newData;
65
+ const parsed = this.parseSSE(buffer);
66
+ buffer = parsed.remaining;
67
+ for (const event of parsed.events) {
68
+ if (event.id) {
69
+ this.lastEventId = event.id;
70
+ }
71
+ if (event.data) {
72
+ this.handleEventData(event.data);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ catch (e) {
78
+ // Ignore parse errors, continue listening
79
+ console.warn('[Bridge] SSE parse error:', e);
80
+ }
81
+ }
82
+ // Connection closed (readyState 4) — reconnect if still active
83
+ if (xhr.readyState === 4 && this.active) {
84
+ console.log('[Bridge] SSE connection closed, reconnecting...');
85
+ this.scheduleReconnect();
86
+ }
87
+ };
88
+ xhr.onerror = () => {
89
+ console.error('[Bridge] SSE connection error');
90
+ if (this.active) {
91
+ this.scheduleReconnect();
92
+ }
93
+ };
94
+ xhr.open('GET', url, true);
95
+ xhr.setRequestHeader('Accept', 'text/event-stream');
96
+ xhr.send();
97
+ }
98
+ /**
99
+ * Fallback: poll bridge with fetch (for environments without XMLHttpRequest streaming)
100
+ */
101
+ async pollWithFetch(url) {
102
+ while (this.active) {
103
+ try {
104
+ let pollUrl = `${this.bridgeUrl}/events?client_id=${this.clientId}`;
105
+ if (this.lastEventId) {
106
+ pollUrl += `&last_event_id=${this.lastEventId}`;
107
+ }
108
+ const controller = new AbortController();
109
+ const timeoutId = setTimeout(() => controller.abort(), 25000);
110
+ const response = await fetch(pollUrl, {
111
+ headers: { 'Accept': 'text/event-stream' },
112
+ signal: controller.signal,
113
+ });
114
+ clearTimeout(timeoutId);
115
+ const text = await response.text();
116
+ const parsed = this.parseSSE(text);
117
+ for (const event of parsed.events) {
118
+ if (event.id) {
119
+ this.lastEventId = event.id;
120
+ }
121
+ if (event.data) {
122
+ this.handleEventData(event.data);
123
+ }
124
+ }
125
+ }
126
+ catch (error) {
127
+ if (error?.name === 'AbortError') {
128
+ // Timeout — reconnect
129
+ continue;
130
+ }
131
+ console.error('[Bridge] Fetch poll error:', error);
132
+ // Wait before retrying
133
+ await new Promise((resolve) => setTimeout(() => resolve(), 2000));
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * Handle a single SSE event data
139
+ */
140
+ handleEventData(data) {
141
+ try {
142
+ const parsed = JSON.parse(data);
143
+ if (parsed.from && parsed.message) {
144
+ console.log('[Bridge] Received message from:', parsed.from.substring(0, 16) + '...');
145
+ if (this.onMessageCallback) {
146
+ this.onMessageCallback(parsed);
147
+ }
148
+ }
149
+ }
150
+ catch (e) {
151
+ // Might be a heartbeat or other non-JSON data — ignore
152
+ console.log('[Bridge] Non-message event:', data.substring(0, 50));
153
+ }
154
+ }
155
+ /**
156
+ * Schedule reconnection after a delay
157
+ */
158
+ scheduleReconnect() {
159
+ if (this.reconnectTimer) {
160
+ clearTimeout(this.reconnectTimer);
161
+ }
162
+ this.reconnectTimer = setTimeout(() => {
163
+ if (this.active) {
164
+ this.openSSE();
165
+ }
166
+ }, 1500);
167
+ }
168
+ /**
169
+ * Send an encrypted message via the bridge
170
+ */
171
+ async send(bridgeUrl, fromClientId, toClientId, encryptedMessage, ttl = 300) {
172
+ const base64Message = (0, session_1.bytesToBase64)(encryptedMessage);
173
+ const url = `${bridgeUrl}/message?client_id=${fromClientId}&to=${toClientId}&ttl=${ttl}`;
174
+ console.log('[Bridge] Sending message to:', toClientId.substring(0, 16) + '...');
175
+ const response = await fetch(url, {
176
+ method: 'POST',
177
+ body: base64Message,
178
+ headers: {
179
+ 'Content-Type': 'text/plain',
180
+ },
181
+ });
182
+ if (!response.ok) {
183
+ throw new Error(`Bridge send failed: ${response.status} ${response.statusText}`);
184
+ }
185
+ console.log('[Bridge] Message sent successfully');
186
+ }
187
+ /**
188
+ * Close the bridge connection
189
+ */
190
+ close() {
191
+ console.log('[Bridge] Closing connection');
192
+ this.active = false;
193
+ if (this.xhr) {
194
+ this.xhr.abort();
195
+ this.xhr = null;
196
+ }
197
+ if (this.reconnectTimer) {
198
+ clearTimeout(this.reconnectTimer);
199
+ this.reconnectTimer = null;
200
+ }
201
+ this.onMessageCallback = null;
202
+ this.onErrorCallback = null;
203
+ }
204
+ /**
205
+ * Check if bridge is currently connected/active
206
+ */
207
+ get isConnected() {
208
+ return this.active;
209
+ }
210
+ /**
211
+ * Parse SSE text into events
212
+ */
213
+ parseSSE(text) {
214
+ const events = [];
215
+ const parts = text.split('\n\n');
216
+ const remaining = parts.pop() || '';
217
+ for (const part of parts) {
218
+ if (!part.trim())
219
+ continue;
220
+ const event = {};
221
+ const lines = part.split('\n');
222
+ for (const line of lines) {
223
+ if (line.startsWith('id:')) {
224
+ event.id = line.substring(3).trim();
225
+ }
226
+ else if (line.startsWith('data:')) {
227
+ event.data = (event.data || '') + line.substring(5).trim();
228
+ }
229
+ }
230
+ if (event.data || event.id) {
231
+ events.push(event);
232
+ }
233
+ }
234
+ return { events, remaining };
235
+ }
236
+ }
237
+ exports.BridgeGateway = BridgeGateway;
@@ -1,28 +1,17 @@
1
1
  /**
2
2
  * Cryptographic utilities for TonConnect
3
- * Uses tweetnacl for signature verification
3
+ * Legacy module primary crypto is now in session.ts
4
+ * This module provides helper functions that may be used externally
4
5
  */
5
- import { ConnectionResponsePayload } from '../types';
6
6
  /**
7
- * Verify connection proof signature
8
- * The proof is signed by the wallet to verify authenticity
7
+ * Convert hex string to Uint8Array
9
8
  */
10
- export declare function verifyConnectionProof(response: ConnectionResponsePayload, manifestUrl: string): boolean;
11
- /**
12
- * Verify transaction signature
13
- *
14
- * WARNING: This function only performs basic format validation.
15
- * Full signature verification requires parsing the BOC (Bag of Cells) and
16
- * verifying the signature against the transaction hash, which requires
17
- * TON library integration (@ton/core or @ton/crypto).
18
- *
19
- * For production use, transaction signatures should be verified server-side
20
- * using proper TON libraries.
21
- *
22
- * @returns false - Always returns false to be safe until proper implementation
23
- */
24
- export declare function verifyTransactionSignature(boc: string, signature: string, publicKey: string): boolean;
9
+ export declare function hexToBytes(hex: string): Uint8Array;
25
10
  /**
26
11
  * Generate random session ID
27
12
  */
28
13
  export declare function generateSessionId(): string;
14
+ /**
15
+ * Verify Ed25519 signature
16
+ */
17
+ export declare function verifySignature(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;
@@ -1,153 +1,20 @@
1
1
  "use strict";
2
2
  /**
3
3
  * Cryptographic utilities for TonConnect
4
- * Uses tweetnacl for signature verification
4
+ * Legacy module primary crypto is now in session.ts
5
+ * This module provides helper functions that may be used externally
5
6
  */
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.verifyConnectionProof = verifyConnectionProof;
8
- exports.verifyTransactionSignature = verifyTransactionSignature;
8
+ exports.hexToBytes = hexToBytes;
9
9
  exports.generateSessionId = generateSessionId;
10
+ exports.verifySignature = verifySignature;
10
11
  // eslint-disable-next-line @typescript-eslint/no-var-requires
11
12
  const nacl = require('tweetnacl');
12
- /**
13
- * Decode base64 string to Uint8Array
14
- */
15
- function decodeBase64(base64) {
16
- // Remove padding and convert URL-safe to standard base64
17
- const cleanBase64 = base64.replace(/-/g, '+').replace(/_/g, '/');
18
- const padded = cleanBase64 + '='.repeat((4 - (cleanBase64.length % 4)) % 4);
19
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
20
- const bytes = [];
21
- let buffer = 0;
22
- let bitsCollected = 0;
23
- for (let i = 0; i < padded.length; i++) {
24
- const ch = padded[i];
25
- if (ch === '=')
26
- break;
27
- const index = chars.indexOf(ch);
28
- if (index === -1)
29
- continue;
30
- buffer = (buffer << 6) | index;
31
- bitsCollected += 6;
32
- if (bitsCollected >= 8) {
33
- bitsCollected -= 8;
34
- bytes.push((buffer >> bitsCollected) & 0xff);
35
- buffer &= (1 << bitsCollected) - 1;
36
- }
37
- }
38
- return new Uint8Array(bytes);
39
- }
40
- /**
41
- * Get TextEncoder with fallback
42
- */
43
- function getTextEncoder() {
44
- if (typeof TextEncoder !== 'undefined') {
45
- return new TextEncoder();
46
- }
47
- // Fallback implementation for older React Native
48
- throw new Error('TextEncoder is not available. Please use React Native 0.59+ or add a polyfill.');
49
- }
50
- /**
51
- * Verify connection proof signature
52
- * The proof is signed by the wallet to verify authenticity
53
- */
54
- function verifyConnectionProof(response, manifestUrl) {
55
- // HIGH FIX: Log warning if proof is missing but allow for compatibility
56
- if (!response.proof) {
57
- console.warn('TON Connect: Connection proof missing - wallet may not support proof verification');
58
- // Allow connection for compatibility, but log warning
59
- return true;
60
- }
61
- try {
62
- const { timestamp, domain, signature } = response.proof;
63
- // Validate proof structure
64
- if (typeof timestamp !== 'number' || !domain || typeof domain.lengthBytes !== 'number' || typeof domain.value !== 'string' || typeof signature !== 'string') {
65
- return false;
66
- }
67
- // Build the message that was signed
68
- // Format: <timestamp>.<domain_length>.<domain_value>.<address>.<publicKey>
69
- const domainLength = domain.lengthBytes;
70
- const message = `${timestamp}.${domainLength}.${domain.value}.${response.address}.${response.publicKey}`;
71
- // Convert public key from hex to Uint8Array
72
- const publicKeyBytes = hexToBytes(response.publicKey);
73
- if (publicKeyBytes.length !== 32) {
74
- return false;
75
- }
76
- // Convert signature from base64 to Uint8Array
77
- const signatureBytes = decodeBase64(signature);
78
- if (signatureBytes.length !== 64) {
79
- return false;
80
- }
81
- // Verify signature using nacl
82
- const encoder = getTextEncoder();
83
- const messageBytes = encoder.encode(message);
84
- return nacl.sign.detached.verify(messageBytes, signatureBytes, publicKeyBytes);
85
- }
86
- catch (error) {
87
- // If verification fails, return false
88
- console.error('TON Connect: Proof verification error:', error);
89
- return false;
90
- }
91
- }
92
- /**
93
- * Verify transaction signature
94
- *
95
- * WARNING: This function only performs basic format validation.
96
- * Full signature verification requires parsing the BOC (Bag of Cells) and
97
- * verifying the signature against the transaction hash, which requires
98
- * TON library integration (@ton/core or @ton/crypto).
99
- *
100
- * For production use, transaction signatures should be verified server-side
101
- * using proper TON libraries.
102
- *
103
- * @returns false - Always returns false to be safe until proper implementation
104
- */
105
- function verifyTransactionSignature(boc, signature, publicKey) {
106
- // CRITICAL FIX: This function does not actually verify signatures
107
- // It only checks format. For security, we return false until proper implementation.
108
- try {
109
- // Basic format validation
110
- if (!boc || typeof boc !== 'string' || boc.length === 0) {
111
- return false;
112
- }
113
- if (!signature || typeof signature !== 'string' || signature.length === 0) {
114
- return false;
115
- }
116
- if (!publicKey || typeof publicKey !== 'string' || publicKey.length === 0) {
117
- return false;
118
- }
119
- // Convert public key from hex to Uint8Array
120
- const publicKeyBytes = hexToBytes(publicKey);
121
- if (publicKeyBytes.length !== 32) {
122
- return false;
123
- }
124
- // Convert signature from base64 to Uint8Array
125
- const signatureBytes = decodeBase64(signature);
126
- if (signatureBytes.length !== 64) {
127
- return false;
128
- }
129
- // Convert BOC from base64 to Uint8Array
130
- const bocBytes = decodeBase64(boc);
131
- if (bocBytes.length === 0) {
132
- return false;
133
- }
134
- // CRITICAL: Return false - actual signature verification requires TON library
135
- // TODO: Integrate @ton/core or @ton/crypto for proper BOC parsing and signature verification
136
- console.warn('TON Connect: Transaction signature verification not fully implemented. Signature format is valid but not cryptographically verified. Verify server-side using @ton/core.');
137
- return false; // Fail-safe: reject until properly implemented
138
- }
139
- catch (error) {
140
- console.error('TON Connect: Transaction signature verification error:', error);
141
- return false;
142
- }
143
- }
144
13
  /**
145
14
  * Convert hex string to Uint8Array
146
15
  */
147
16
  function hexToBytes(hex) {
148
- // Remove 0x prefix if present
149
17
  const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
150
- // Handle odd-length hex strings
151
18
  const paddedHex = cleanHex.length % 2 === 0 ? cleanHex : '0' + cleanHex;
152
19
  const bytes = new Uint8Array(paddedHex.length / 2);
153
20
  for (let i = 0; i < paddedHex.length; i += 2) {
@@ -160,13 +27,11 @@ function hexToBytes(hex) {
160
27
  */
161
28
  function getSecureRandomBytes(length) {
162
29
  const bytes = new Uint8Array(length);
163
- // Try to use crypto.getRandomValues (available in React Native with polyfill)
164
30
  // eslint-disable-next-line no-undef
165
31
  if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.getRandomValues) {
166
32
  globalThis.crypto.getRandomValues(bytes);
167
33
  return bytes;
168
34
  }
169
- // HIGH FIX: Throw error instead of using insecure Math.random()
170
35
  throw new Error('Cryptographically secure random number generation not available. ' +
171
36
  'Please install react-native-get-random-values or use React Native 0.59+');
172
37
  }
@@ -174,10 +39,19 @@ function getSecureRandomBytes(length) {
174
39
  * Generate random session ID
175
40
  */
176
41
  function generateSessionId() {
177
- // HIGH FIX: Use secure random bytes
178
42
  const bytes = getSecureRandomBytes(32);
179
- // Convert to hex string
180
43
  return Array.from(bytes)
181
44
  .map((b) => b.toString(16).padStart(2, '0'))
182
45
  .join('');
183
46
  }
47
+ /**
48
+ * Verify Ed25519 signature
49
+ */
50
+ function verifySignature(message, signature, publicKey) {
51
+ try {
52
+ return nacl.sign.detached.verify(message, signature, publicKey);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Core protocol exports
2
+ * Core module exports
3
3
  */
4
- export * from './protocol';
5
- export * from './crypto';
4
+ export { SessionCrypto } from './session';
5
+ export { BridgeGateway } from './bridge';
6
+ export { buildConnectUniversalLink, buildReturnUniversalLink, buildSendTransactionRpcRequest, buildDisconnectRpcRequest, parseConnectResponse, parseRpcResponse, extractWalletInfoFromEvent, validateTransactionRequest, } from './protocol';
7
+ export { SUPPORTED_WALLETS, getWalletByName, getDefaultWallet, getWalletsForPlatform } from './wallets';