@blazium/ton-connect-mobile 1.2.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +316 -18
- package/dist/adapters/expo.js +3 -3
- package/dist/adapters/react-native.js +3 -3
- package/dist/core/protocol.d.ts +1 -0
- package/dist/core/protocol.js +69 -9
- package/dist/core/wallets.js +5 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +309 -13
- package/dist/react/TonConnectUIProvider.d.ts +21 -2
- package/dist/react/TonConnectUIProvider.js +118 -14
- package/dist/react/WalletSelectionModal.d.ts +1 -0
- package/dist/react/WalletSelectionModal.js +153 -80
- package/dist/react/index.d.ts +1 -0
- package/dist/types/index.d.ts +46 -0
- package/dist/utils/transactionBuilder.js +50 -7
- package/package.json +1 -1
- package/src/adapters/expo.ts +3 -3
- package/src/adapters/react-native.ts +3 -3
- package/src/core/protocol.ts +76 -9
- package/src/core/wallets.ts +5 -1
- package/src/index.ts +381 -15
- package/src/react/TonConnectUIProvider.tsx +154 -15
- package/src/react/WalletSelectionModal.tsx +180 -90
- package/src/react/index.ts +1 -0
- package/src/types/index.ts +52 -0
- package/src/utils/transactionBuilder.ts +56 -7
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@ Production-ready TON Connect Mobile SDK for React Native and Expo. Implements th
|
|
|
9
9
|
- ✅ **Full `@tonconnect/ui-react` Compatibility** - Drop-in replacement
|
|
10
10
|
- ✅ **React Native & Expo Support** - Works with both Expo and React Native CLI
|
|
11
11
|
- ✅ **Android & iOS Support** - Full deep linking support
|
|
12
|
-
- ✅ **Multiple Wallet Support** - Tonkeeper, Tonhub, MyTonWallet, Telegram Wallet
|
|
13
|
-
- ✅ **Beautiful Wallet Selection Modal** -
|
|
12
|
+
- ✅ **Multiple Wallet Support** - Tonkeeper (including Web), Tonhub, MyTonWallet, Telegram Wallet
|
|
13
|
+
- ✅ **Beautiful Wallet Selection Modal** - Grid layout matching @tonconnect/ui-react design
|
|
14
14
|
- ✅ **Transaction Signing** - Send transactions with wallet approval
|
|
15
15
|
- ✅ **Data Signing** - Sign arbitrary data for authentication
|
|
16
16
|
- ✅ **Transaction Builder Utilities** - Helper functions for building transactions
|
|
@@ -18,6 +18,10 @@ Production-ready TON Connect Mobile SDK for React Native and Expo. Implements th
|
|
|
18
18
|
- ✅ **Enhanced Error Messages** - Clear error messages with recovery suggestions
|
|
19
19
|
- ✅ **Wallet Availability Checking** - Check if wallets are available
|
|
20
20
|
- ✅ **Session Persistence** - Maintains connection across app restarts
|
|
21
|
+
- ✅ **Network Switching** - Switch between mainnet and testnet dynamically
|
|
22
|
+
- ✅ **Event Emitters** - Listen to connect, disconnect, transaction, and error events
|
|
23
|
+
- ✅ **Wallet Balance Checking** - Get wallet balance via TON Center API
|
|
24
|
+
- ✅ **Transaction Status Tracking** - Track transaction status with polling
|
|
21
25
|
- ✅ **TypeScript** - Full type safety
|
|
22
26
|
- ✅ **Production Ready** - Battle-tested implementation
|
|
23
27
|
|
|
@@ -135,18 +139,50 @@ Pre-built button component for connecting/disconnecting wallets.
|
|
|
135
139
|
|
|
136
140
|
#### `useTonConnectUI()`
|
|
137
141
|
|
|
138
|
-
Access the TonConnectUI instance with all methods.
|
|
142
|
+
Access the TonConnectUI instance with all methods and features.
|
|
139
143
|
|
|
140
144
|
```typescript
|
|
141
145
|
const tonConnectUI = useTonConnectUI();
|
|
142
146
|
|
|
143
|
-
//
|
|
147
|
+
// Connection methods:
|
|
144
148
|
await tonConnectUI.connectWallet();
|
|
145
149
|
await tonConnectUI.disconnect();
|
|
150
|
+
await tonConnectUI.restoreConnection(); // Restore from stored session
|
|
151
|
+
|
|
152
|
+
// Transaction methods:
|
|
146
153
|
await tonConnectUI.sendTransaction({ ... });
|
|
147
154
|
await tonConnectUI.signData({ data: '...', version: '1.0' });
|
|
155
|
+
|
|
156
|
+
// Modal methods:
|
|
148
157
|
await tonConnectUI.openModal();
|
|
149
158
|
tonConnectUI.closeModal();
|
|
159
|
+
|
|
160
|
+
// Wallet customization:
|
|
161
|
+
tonConnectUI.setWalletList([...]); // Customize available wallets
|
|
162
|
+
|
|
163
|
+
// Network management:
|
|
164
|
+
const network = tonConnectUI.getNetwork(); // Get current network
|
|
165
|
+
tonConnectUI.setNetwork('testnet'); // Switch to testnet
|
|
166
|
+
|
|
167
|
+
// Balance checking:
|
|
168
|
+
const balance = await tonConnectUI.getBalance(); // Get connected wallet balance
|
|
169
|
+
const balance2 = await tonConnectUI.getBalance(address); // Get specific address balance
|
|
170
|
+
|
|
171
|
+
// Transaction status:
|
|
172
|
+
const status = await tonConnectUI.getTransactionStatusByHash(txHash, address);
|
|
173
|
+
|
|
174
|
+
// Event listeners:
|
|
175
|
+
const unsubscribe = tonConnectUI.on('connect', (wallet) => {
|
|
176
|
+
console.log('Connected:', wallet);
|
|
177
|
+
});
|
|
178
|
+
tonConnectUI.on('disconnect', () => console.log('Disconnected'));
|
|
179
|
+
tonConnectUI.on('transaction', (tx) => console.log('Transaction:', tx));
|
|
180
|
+
tonConnectUI.on('error', (error) => console.error('Error:', error));
|
|
181
|
+
|
|
182
|
+
// State access:
|
|
183
|
+
tonConnectUI.wallet; // Current wallet state
|
|
184
|
+
tonConnectUI.modalState.open; // Modal open state
|
|
185
|
+
tonConnectUI.uiVersion; // UI kit version
|
|
150
186
|
```
|
|
151
187
|
|
|
152
188
|
#### `useTonWallet()`
|
|
@@ -204,10 +240,12 @@ new TonConnectMobile(config: TonConnectMobileConfig)
|
|
|
204
240
|
- `manifestUrl` (required): URL to your TonConnect manifest file
|
|
205
241
|
- `scheme` (required): Your app's deep link scheme
|
|
206
242
|
- `storageKeyPrefix` (optional): Prefix for storage keys (default: `'tonconnect_'`)
|
|
207
|
-
- `connectionTimeout` (optional): Connection timeout in ms (default: `
|
|
208
|
-
- `transactionTimeout` (optional): Transaction timeout in ms (default: `300000`)
|
|
243
|
+
- `connectionTimeout` (optional): Connection timeout in ms (default: `300000` = 5 minutes)
|
|
244
|
+
- `transactionTimeout` (optional): Transaction timeout in ms (default: `300000` = 5 minutes)
|
|
209
245
|
- `skipCanOpenURLCheck` (optional): Skip canOpenURL check (default: `true` for Android compatibility)
|
|
210
246
|
- `preferredWallet` (optional): Default wallet name
|
|
247
|
+
- `network` (optional): Network to use - `'mainnet'` or `'testnet'` (default: `'mainnet'`)
|
|
248
|
+
- `tonApiEndpoint` (optional): Custom TON API endpoint (default: auto-selected based on network)
|
|
211
249
|
|
|
212
250
|
#### Methods
|
|
213
251
|
|
|
@@ -286,20 +324,124 @@ const unsubscribe = ton.onStatusChange((status) => {
|
|
|
286
324
|
});
|
|
287
325
|
```
|
|
288
326
|
|
|
289
|
-
|
|
327
|
+
##### `getNetwork(): Network`
|
|
328
|
+
|
|
329
|
+
Get current network (mainnet or testnet).
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const network = ton.getNetwork(); // 'mainnet' or 'testnet'
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
##### `setNetwork(network: Network): void`
|
|
336
|
+
|
|
337
|
+
Switch between mainnet and testnet.
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
ton.setNetwork('testnet'); // Switch to testnet
|
|
341
|
+
// Note: Warning is logged if switching while wallet is connected
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
##### `getBalance(address?: string): Promise<BalanceResponse>`
|
|
345
|
+
|
|
346
|
+
Get wallet balance from TON Center API.
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// Get balance of connected wallet
|
|
350
|
+
const balance = await ton.getBalance();
|
|
351
|
+
|
|
352
|
+
// Get balance of specific address
|
|
353
|
+
const balance = await ton.getBalance('EQD0vdSA_NedR9uvbgN9EikRX-suesDxGeFg69XQMavfLqIo');
|
|
354
|
+
|
|
355
|
+
// Response:
|
|
356
|
+
// {
|
|
357
|
+
// balance: "1000000000", // in nanotons
|
|
358
|
+
// balanceTon: "1.0", // formatted TON
|
|
359
|
+
// network: "mainnet"
|
|
360
|
+
// }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
##### `getTransactionStatusByHash(txHash: string, address: string): Promise<TransactionStatusResponse>`
|
|
364
|
+
|
|
365
|
+
Get transaction status by hash (recommended method).
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
const status = await ton.getTransactionStatusByHash(txHash, address);
|
|
369
|
+
|
|
370
|
+
// Response:
|
|
371
|
+
// {
|
|
372
|
+
// status: "confirmed" | "pending" | "failed" | "unknown",
|
|
373
|
+
// hash?: string,
|
|
374
|
+
// blockNumber?: number,
|
|
375
|
+
// error?: string
|
|
376
|
+
// }
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
##### `getTransactionStatus(boc: string, maxAttempts?: number, intervalMs?: number): Promise<TransactionStatusResponse>`
|
|
380
|
+
|
|
381
|
+
Get transaction status from BOC (requires BOC parsing library).
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
// Note: This method requires BOC parsing. Use getTransactionStatusByHash() instead.
|
|
385
|
+
const status = await ton.getTransactionStatus(boc, 10, 2000);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
##### `on<T>(event: TonConnectEventType, listener: TonConnectEventListener<T>): () => void`
|
|
389
|
+
|
|
390
|
+
Add event listener.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// Listen to connection events
|
|
394
|
+
const unsubscribe = ton.on('connect', (wallet) => {
|
|
395
|
+
console.log('Connected to:', wallet.name);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Listen to transaction events
|
|
399
|
+
ton.on('transaction', (tx) => {
|
|
400
|
+
console.log('Transaction sent:', tx.boc);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Listen to errors
|
|
404
|
+
ton.on('error', (error) => {
|
|
405
|
+
console.error('SDK error:', error);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Cleanup
|
|
409
|
+
unsubscribe();
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
##### `off<T>(event: TonConnectEventType, listener: TonConnectEventListener<T>): void`
|
|
413
|
+
|
|
414
|
+
Remove event listener.
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
ton.off('connect', listener);
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
##### `removeAllListeners(event?: TonConnectEventType): void`
|
|
290
421
|
|
|
291
|
-
|
|
422
|
+
Remove all listeners for an event, or all events.
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
ton.removeAllListeners('connect'); // Remove all connect listeners
|
|
426
|
+
ton.removeAllListeners(); // Remove all listeners
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Platform Support
|
|
292
430
|
|
|
293
431
|
- ✅ **Android**: Full support via Expo or React Native CLI
|
|
294
432
|
- ✅ **iOS**: Full support via Expo or React Native CLI
|
|
295
|
-
-
|
|
433
|
+
- ✅ **Web**: Universal links supported (opens wallet in new tab/window)
|
|
296
434
|
|
|
297
|
-
**
|
|
435
|
+
**Web Platform Notes:**
|
|
436
|
+
- On web, wallets with universal links (like Tonkeeper Web, MyTonWallet) can be opened in a new browser tab
|
|
437
|
+
- The SDK automatically detects web platform and shows all available wallets
|
|
438
|
+
- Wallet availability is checked based on universal link support
|
|
439
|
+
- Deep links (`tonconnect://`) are not supported in web browsers, but universal links work perfectly
|
|
298
440
|
|
|
299
|
-
**Testing**:
|
|
441
|
+
**Testing**:
|
|
300
442
|
- Android device or emulator
|
|
301
443
|
- iOS device or simulator
|
|
302
|
-
-
|
|
444
|
+
- Web browsers (for wallets with web support like Tonkeeper Web)
|
|
303
445
|
|
|
304
446
|
## Configuration
|
|
305
447
|
|
|
@@ -368,10 +510,12 @@ The manifest URL must be accessible via HTTPS.
|
|
|
368
510
|
|
|
369
511
|
## Supported Wallets
|
|
370
512
|
|
|
371
|
-
- **Tonkeeper** - Full support
|
|
372
|
-
- **
|
|
373
|
-
- **
|
|
374
|
-
- **Wallet in Telegram** - Full support
|
|
513
|
+
- **Tonkeeper** - Full support (iOS, Android, Web)
|
|
514
|
+
- **MyTonWallet** - Full support (iOS, Android, Web)
|
|
515
|
+
- **Tonhub** - Full support (iOS, Android)
|
|
516
|
+
- **Wallet in Telegram** - Full support (iOS, Android)
|
|
517
|
+
|
|
518
|
+
**Note**: Wallet icons are automatically loaded from official sources. If an icon fails to load, a placeholder with the wallet's initial is shown.
|
|
375
519
|
|
|
376
520
|
## Migration from @tonconnect/ui-react
|
|
377
521
|
|
|
@@ -453,10 +597,133 @@ MIT
|
|
|
453
597
|
For issues and questions:
|
|
454
598
|
- GitHub Issues: [https://github.com/blaziumdev/ton-connect-mobile/issues](https://github.com/blaziumdev/ton-connect-mobile/issues)
|
|
455
599
|
|
|
456
|
-
## New Features in v1.2.
|
|
600
|
+
## New Features in v1.2.3
|
|
601
|
+
|
|
602
|
+
### 🌐 Network Switching
|
|
603
|
+
Switch between mainnet and testnet dynamically:
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
// Initialize with network
|
|
607
|
+
const ton = new TonConnectMobile({
|
|
608
|
+
network: 'testnet', // or 'mainnet' (default)
|
|
609
|
+
// ... other config
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// Or switch at runtime
|
|
613
|
+
ton.setNetwork('testnet');
|
|
614
|
+
tonConnectUI.setNetwork('testnet');
|
|
615
|
+
|
|
616
|
+
// Get current network
|
|
617
|
+
const network = ton.getNetwork(); // 'mainnet' or 'testnet'
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
**Features:**
|
|
621
|
+
- Chain ID automatically updates (-239 for mainnet, -3 for testnet)
|
|
622
|
+
- TON API endpoint automatically switches based on network
|
|
623
|
+
- Warning logged if switching network while wallet is connected
|
|
624
|
+
- React components automatically update chain ID
|
|
625
|
+
|
|
626
|
+
### 📡 Event Emitters
|
|
627
|
+
Listen to SDK events for reactive programming:
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
// Add event listeners
|
|
631
|
+
tonConnectUI.on('connect', (wallet) => {
|
|
632
|
+
console.log('Connected to:', wallet.name);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
tonConnectUI.on('disconnect', () => {
|
|
636
|
+
console.log('Disconnected');
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
tonConnectUI.on('transaction', (tx) => {
|
|
640
|
+
console.log('Transaction sent:', tx.boc);
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
tonConnectUI.on('error', (error) => {
|
|
644
|
+
console.error('SDK error:', error);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
// Remove listener
|
|
648
|
+
const unsubscribe = tonConnectUI.on('connect', listener);
|
|
649
|
+
unsubscribe(); // or
|
|
650
|
+
tonConnectUI.off('connect', listener);
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Available Events:**
|
|
654
|
+
- `connect` - Fired when wallet connects
|
|
655
|
+
- `disconnect` - Fired when wallet disconnects
|
|
656
|
+
- `transaction` - Fired when transaction is sent
|
|
657
|
+
- `error` - Fired when an error occurs
|
|
658
|
+
- `statusChange` - Fired when connection status changes
|
|
659
|
+
|
|
660
|
+
### 💰 Wallet Balance Checking
|
|
661
|
+
Get wallet balance from TON Center API:
|
|
662
|
+
|
|
663
|
+
```typescript
|
|
664
|
+
// Get balance of connected wallet
|
|
665
|
+
const balance = await tonConnectUI.getBalance();
|
|
666
|
+
|
|
667
|
+
// Get balance of specific address
|
|
668
|
+
const balance = await tonConnectUI.getBalance('EQD0vdSA_NedR9uvbgN9EikRX-suesDxGeFg69XQMavfLqIo');
|
|
669
|
+
|
|
670
|
+
// Response:
|
|
671
|
+
// {
|
|
672
|
+
// balance: "1000000000", // in nanotons
|
|
673
|
+
// balanceTon: "1.0", // formatted TON
|
|
674
|
+
// network: "mainnet"
|
|
675
|
+
// }
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
**Features:**
|
|
679
|
+
- Automatically uses correct API endpoint based on network
|
|
680
|
+
- Returns balance in both nanotons and formatted TON
|
|
681
|
+
- Validates address format before API call
|
|
682
|
+
- Handles API errors gracefully
|
|
683
|
+
|
|
684
|
+
### 📊 Transaction Status Tracking
|
|
685
|
+
Track transaction status after sending:
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
// Using transaction hash (recommended)
|
|
689
|
+
const status = await tonConnectUI.getTransactionStatusByHash(txHash, address);
|
|
690
|
+
|
|
691
|
+
// Response:
|
|
692
|
+
// {
|
|
693
|
+
// status: "confirmed" | "pending" | "failed" | "unknown",
|
|
694
|
+
// hash: "transaction_hash",
|
|
695
|
+
// blockNumber: 12345,
|
|
696
|
+
// error?: "error message"
|
|
697
|
+
// }
|
|
698
|
+
|
|
699
|
+
// Using BOC (requires BOC parsing library)
|
|
700
|
+
const status = await tonConnectUI.getTransactionStatus(boc, maxAttempts, intervalMs);
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**Features:**
|
|
704
|
+
- Polling mechanism with configurable attempts and intervals
|
|
705
|
+
- Network-specific API endpoint selection
|
|
706
|
+
- Returns detailed status information
|
|
707
|
+
- Handles API errors gracefully
|
|
708
|
+
|
|
709
|
+
### 🎯 Complete TonConnectUI API
|
|
710
|
+
All features from `@tonconnect/ui-react` are now available:
|
|
711
|
+
|
|
712
|
+
```typescript
|
|
713
|
+
const tonConnectUI = useTonConnectUI();
|
|
714
|
+
|
|
715
|
+
// Restore connection from stored session
|
|
716
|
+
await tonConnectUI.restoreConnection();
|
|
717
|
+
|
|
718
|
+
// Customize available wallets
|
|
719
|
+
tonConnectUI.setWalletList([
|
|
720
|
+
{ name: 'Tonkeeper', universalLink: '...', platforms: ['ios', 'android', 'web'] },
|
|
721
|
+
{ name: 'MyTonWallet', universalLink: '...', platforms: ['ios', 'android', 'web'] },
|
|
722
|
+
]);
|
|
723
|
+
```
|
|
457
724
|
|
|
458
725
|
### 🎨 Wallet Selection Modal
|
|
459
|
-
Beautiful, built-in wallet selection modal
|
|
726
|
+
Beautiful, built-in wallet selection modal with grid layout matching @tonconnect/ui-react design. Automatically appears when you call `openModal()`:
|
|
460
727
|
|
|
461
728
|
```typescript
|
|
462
729
|
import { WalletSelectionModal } from '@blazium/ton-connect-mobile/react';
|
|
@@ -469,6 +736,14 @@ import { WalletSelectionModal } from '@blazium/ton-connect-mobile/react';
|
|
|
469
736
|
/>
|
|
470
737
|
```
|
|
471
738
|
|
|
739
|
+
**Features:**
|
|
740
|
+
- Grid layout (4 columns) matching @tonconnect/ui-react design
|
|
741
|
+
- Real wallet icons loaded from official sources
|
|
742
|
+
- Availability status for each wallet
|
|
743
|
+
- Automatic wallet filtering by platform
|
|
744
|
+
- Smooth animations and loading states
|
|
745
|
+
- Custom wallet list support via `setWalletList()`
|
|
746
|
+
|
|
472
747
|
### 🛠️ Transaction Builder Utilities
|
|
473
748
|
Helper functions for building transactions easily:
|
|
474
749
|
|
|
@@ -533,6 +808,12 @@ if (isAvailable) {
|
|
|
533
808
|
}
|
|
534
809
|
```
|
|
535
810
|
|
|
811
|
+
**Platform Detection:**
|
|
812
|
+
- On web: Checks if wallet has universal link support (can open in new tab)
|
|
813
|
+
- On mobile: Checks if wallet supports the current platform (iOS/Android)
|
|
814
|
+
- Uses adapter type for reliable platform detection
|
|
815
|
+
- All wallets with universal links are considered available on web
|
|
816
|
+
|
|
536
817
|
### 💬 Enhanced Error Messages
|
|
537
818
|
All errors now include helpful recovery suggestions:
|
|
538
819
|
|
|
@@ -549,6 +830,23 @@ try {
|
|
|
549
830
|
|
|
550
831
|
## Changelog
|
|
551
832
|
|
|
833
|
+
### v1.2.3
|
|
834
|
+
- ✅ **NEW**: Network switching - Switch between mainnet and testnet dynamically
|
|
835
|
+
- ✅ **NEW**: Event emitters - Listen to connect, disconnect, transaction, and error events
|
|
836
|
+
- ✅ **NEW**: Wallet balance checking - Get wallet balance via TON Center API integration
|
|
837
|
+
- ✅ **NEW**: Transaction status tracking - Track transaction status with polling mechanism
|
|
838
|
+
- ✅ **NEW**: Complete TonConnectUI API implementation - all features from @tonconnect/ui-react
|
|
839
|
+
- ✅ **NEW**: `restoreConnection()` method - restore connection from stored session
|
|
840
|
+
- ✅ **NEW**: `setWalletList()` method - customize available wallets in modal
|
|
841
|
+
- ✅ **NEW**: Wallet selection modal with grid layout matching @tonconnect/ui-react design
|
|
842
|
+
- ✅ **NEW**: Real wallet icons loaded from official sources
|
|
843
|
+
- ✅ **NEW**: Improved web platform support (Tonkeeper Web, MyTonWallet Web)
|
|
844
|
+
- ✅ **IMPROVED**: Wallet availability detection using adapter type (more reliable)
|
|
845
|
+
- ✅ **IMPROVED**: All wallets shown on web platform (with availability status)
|
|
846
|
+
- ✅ **IMPROVED**: Chain ID automatically updates when network changes
|
|
847
|
+
- ✅ **FIXED**: Tonkeeper now correctly shows as available on web
|
|
848
|
+
- ✅ **FIXED**: All Turkish comments translated to English
|
|
849
|
+
|
|
552
850
|
### v1.2.0
|
|
553
851
|
- ✅ **NEW**: Beautiful wallet selection modal component
|
|
554
852
|
- ✅ **NEW**: Transaction builder utilities (`buildTransferTransaction`, `tonToNano`, etc.)
|
package/dist/adapters/expo.js
CHANGED
|
@@ -67,15 +67,15 @@ class ExpoAdapter {
|
|
|
67
67
|
else {
|
|
68
68
|
console.log('[ExpoAdapter] Skipping canOpenURL check (Android compatibility)');
|
|
69
69
|
}
|
|
70
|
-
// CRITICAL FIX: Android
|
|
71
|
-
//
|
|
70
|
+
// CRITICAL FIX: On Android, canOpenURL() may not recognize tonconnect:// protocol
|
|
71
|
+
// So we call openURL() directly. If it fails, it will throw an error.
|
|
72
72
|
await Linking.openURL(url);
|
|
73
73
|
console.log('[ExpoAdapter] URL opened successfully');
|
|
74
74
|
return true;
|
|
75
75
|
}
|
|
76
76
|
catch (error) {
|
|
77
77
|
console.error('[ExpoAdapter] Error in openURL:', error);
|
|
78
|
-
// Android
|
|
78
|
+
// On Android, if tonconnect:// protocol is not recognized or wallet is not installed, it will throw an error
|
|
79
79
|
const errorMessage = error?.message || String(error);
|
|
80
80
|
if (errorMessage.includes('No Activity found') || errorMessage.includes('No app found') || errorMessage.includes('Cannot open URL')) {
|
|
81
81
|
throw new Error('No TON wallet app found. Please install Tonkeeper or another TON Connect compatible wallet from Google Play Store.');
|
|
@@ -55,15 +55,15 @@ class ReactNativeAdapter {
|
|
|
55
55
|
else {
|
|
56
56
|
console.log('[ReactNativeAdapter] Skipping canOpenURL check (Android compatibility)');
|
|
57
57
|
}
|
|
58
|
-
// CRITICAL FIX: Android
|
|
59
|
-
//
|
|
58
|
+
// CRITICAL FIX: On Android, canOpenURL() may not recognize tonconnect:// protocol
|
|
59
|
+
// So we call openURL() directly. If it fails, it will throw an error.
|
|
60
60
|
await Linking.openURL(url);
|
|
61
61
|
console.log('[ReactNativeAdapter] URL opened successfully');
|
|
62
62
|
return true;
|
|
63
63
|
}
|
|
64
64
|
catch (error) {
|
|
65
65
|
console.error('[ReactNativeAdapter] Error in openURL:', error);
|
|
66
|
-
// Android
|
|
66
|
+
// On Android, if tonconnect:// protocol is not recognized or wallet is not installed, it will throw an error
|
|
67
67
|
const errorMessage = error?.message || String(error);
|
|
68
68
|
if (errorMessage.includes('No Activity found') || errorMessage.includes('No app found') || errorMessage.includes('Cannot open URL')) {
|
|
69
69
|
throw new Error('No TON wallet app found. Please install Tonkeeper or another TON Connect compatible wallet from Google Play Store.');
|
package/dist/core/protocol.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export declare function parseCallbackURL(url: string, scheme: string): {
|
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
37
|
* Extract wallet info from connection response
|
|
38
|
+
* CRITICAL: This function assumes response has been validated by validateConnectionResponse
|
|
38
39
|
*/
|
|
39
40
|
export declare function extractWalletInfo(response: ConnectionResponsePayload): WalletInfo;
|
|
40
41
|
/**
|
package/dist/core/protocol.js
CHANGED
|
@@ -195,12 +195,21 @@ function parseCallbackURL(url, scheme) {
|
|
|
195
195
|
return { type: 'unknown', data: null };
|
|
196
196
|
}
|
|
197
197
|
// Extract encoded payload
|
|
198
|
-
|
|
198
|
+
let encoded = url.substring(expectedPrefix.length);
|
|
199
|
+
// CRITICAL FIX: Decode URL encoding first (wallet may URL-encode the payload)
|
|
200
|
+
try {
|
|
201
|
+
encoded = decodeURIComponent(encoded);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
// If decodeURIComponent fails, try using the original encoded string
|
|
205
|
+
// Some wallets may not URL-encode the payload
|
|
206
|
+
console.log('[TON Connect] Payload not URL-encoded, using as-is');
|
|
207
|
+
}
|
|
199
208
|
// CRITICAL FIX: Validate base64 payload size (prevent DoS)
|
|
200
209
|
if (encoded.length === 0 || encoded.length > 5000) {
|
|
201
210
|
return { type: 'unknown', data: null };
|
|
202
211
|
}
|
|
203
|
-
// CRITICAL FIX: Validate base64 characters only
|
|
212
|
+
// CRITICAL FIX: Validate base64 characters only (after URL decoding)
|
|
204
213
|
if (!/^[A-Za-z0-9_-]+$/.test(encoded)) {
|
|
205
214
|
return { type: 'unknown', data: null };
|
|
206
215
|
}
|
|
@@ -241,12 +250,17 @@ function parseCallbackURL(url, scheme) {
|
|
|
241
250
|
}
|
|
242
251
|
/**
|
|
243
252
|
* Extract wallet info from connection response
|
|
253
|
+
* CRITICAL: This function assumes response has been validated by validateConnectionResponse
|
|
244
254
|
*/
|
|
245
255
|
function extractWalletInfo(response) {
|
|
256
|
+
// CRITICAL FIX: Add null checks to prevent runtime errors
|
|
257
|
+
if (!response || !response.name || !response.address || !response.publicKey) {
|
|
258
|
+
throw new Error('Invalid connection response: missing required fields');
|
|
259
|
+
}
|
|
246
260
|
return {
|
|
247
261
|
name: response.name,
|
|
248
|
-
appName: response.appName,
|
|
249
|
-
version: response.version,
|
|
262
|
+
appName: response.appName || response.name,
|
|
263
|
+
version: response.version || 'unknown',
|
|
250
264
|
platform: response.platform || 'unknown',
|
|
251
265
|
address: response.address,
|
|
252
266
|
publicKey: response.publicKey,
|
|
@@ -280,13 +294,59 @@ function validateTransactionRequest(request) {
|
|
|
280
294
|
if (!request.messages || request.messages.length === 0) {
|
|
281
295
|
return { valid: false, error: 'Transaction must have at least one message' };
|
|
282
296
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
297
|
+
// CRITICAL: Validate each message
|
|
298
|
+
for (let i = 0; i < request.messages.length; i++) {
|
|
299
|
+
const msg = request.messages[i];
|
|
300
|
+
// Validate address
|
|
301
|
+
if (!msg.address || typeof msg.address !== 'string') {
|
|
302
|
+
return { valid: false, error: `Message ${i + 1}: Address is required and must be a string` };
|
|
303
|
+
}
|
|
304
|
+
// CRITICAL: Validate TON address format (EQ... or 0Q...)
|
|
305
|
+
if (!/^(EQ|0Q)[A-Za-z0-9_-]{46}$/.test(msg.address)) {
|
|
306
|
+
return { valid: false, error: `Message ${i + 1}: Invalid TON address format. Address must start with EQ or 0Q and be 48 characters long.` };
|
|
307
|
+
}
|
|
308
|
+
// Validate amount
|
|
309
|
+
if (!msg.amount || typeof msg.amount !== 'string') {
|
|
310
|
+
return { valid: false, error: `Message ${i + 1}: Amount is required and must be a string (nanotons)` };
|
|
311
|
+
}
|
|
312
|
+
// CRITICAL: Validate amount is a valid positive number (nanotons)
|
|
313
|
+
try {
|
|
314
|
+
const amount = BigInt(msg.amount);
|
|
315
|
+
if (amount <= 0n) {
|
|
316
|
+
return { valid: false, error: `Message ${i + 1}: Amount must be greater than 0` };
|
|
317
|
+
}
|
|
318
|
+
// Check for reasonable maximum (prevent overflow)
|
|
319
|
+
if (amount > BigInt('1000000000000000000')) { // 1 billion TON
|
|
320
|
+
return { valid: false, error: `Message ${i + 1}: Amount exceeds maximum allowed (1 billion TON)` };
|
|
321
|
+
}
|
|
286
322
|
}
|
|
287
|
-
|
|
288
|
-
return { valid: false, error:
|
|
323
|
+
catch (error) {
|
|
324
|
+
return { valid: false, error: `Message ${i + 1}: Amount must be a valid number string (nanotons)` };
|
|
289
325
|
}
|
|
326
|
+
// Validate payload if provided (must be base64)
|
|
327
|
+
if (msg.payload !== undefined && msg.payload !== null) {
|
|
328
|
+
if (typeof msg.payload !== 'string') {
|
|
329
|
+
return { valid: false, error: `Message ${i + 1}: Payload must be a base64 string` };
|
|
330
|
+
}
|
|
331
|
+
// Basic base64 validation
|
|
332
|
+
if (msg.payload.length > 0 && !/^[A-Za-z0-9+/=]+$/.test(msg.payload)) {
|
|
333
|
+
return { valid: false, error: `Message ${i + 1}: Payload must be valid base64 encoded` };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Validate stateInit if provided (must be base64)
|
|
337
|
+
if (msg.stateInit !== undefined && msg.stateInit !== null) {
|
|
338
|
+
if (typeof msg.stateInit !== 'string') {
|
|
339
|
+
return { valid: false, error: `Message ${i + 1}: StateInit must be a base64 string` };
|
|
340
|
+
}
|
|
341
|
+
// Basic base64 validation
|
|
342
|
+
if (msg.stateInit.length > 0 && !/^[A-Za-z0-9+/=]+$/.test(msg.stateInit)) {
|
|
343
|
+
return { valid: false, error: `Message ${i + 1}: StateInit must be valid base64 encoded` };
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// CRITICAL: Limit maximum number of messages (prevent DoS)
|
|
348
|
+
if (request.messages.length > 255) {
|
|
349
|
+
return { valid: false, error: 'Transaction cannot have more than 255 messages' };
|
|
290
350
|
}
|
|
291
351
|
return { valid: true };
|
|
292
352
|
}
|
package/dist/core/wallets.js
CHANGED
|
@@ -17,7 +17,8 @@ exports.SUPPORTED_WALLETS = [
|
|
|
17
17
|
appName: 'Tonkeeper',
|
|
18
18
|
universalLink: 'https://app.tonkeeper.com/ton-connect',
|
|
19
19
|
deepLink: 'tonkeeper://',
|
|
20
|
-
|
|
20
|
+
iconUrl: 'https://tonkeeper.com/assets/tonconnect-icon.png',
|
|
21
|
+
platforms: ['ios', 'android', 'web'], // CRITICAL FIX: Tonkeeper Web is supported
|
|
21
22
|
preferredReturnStrategy: 'post_redirect', // CRITICAL FIX: 'back' strategy may not send callback properly, use 'post_redirect'
|
|
22
23
|
requiresReturnScheme: true, // CRITICAL FIX: Mobile apps need returnScheme for proper callback handling
|
|
23
24
|
},
|
|
@@ -26,6 +27,7 @@ exports.SUPPORTED_WALLETS = [
|
|
|
26
27
|
appName: 'MyTonWallet',
|
|
27
28
|
universalLink: 'https://connect.mytonwallet.org',
|
|
28
29
|
deepLink: 'mytonwallet://',
|
|
30
|
+
iconUrl: 'https://static.mytonwallet.io/icon-256.png',
|
|
29
31
|
platforms: ['ios', 'android', 'web'],
|
|
30
32
|
preferredReturnStrategy: 'post_redirect',
|
|
31
33
|
requiresReturnScheme: true, // MyTonWallet requires explicit returnScheme
|
|
@@ -35,6 +37,7 @@ exports.SUPPORTED_WALLETS = [
|
|
|
35
37
|
appName: 'Wallet',
|
|
36
38
|
universalLink: 'https://wallet.tonapi.io/ton-connect',
|
|
37
39
|
deepLink: 'tg://',
|
|
40
|
+
iconUrl: 'https://wallet.tonapi.io/icon.png',
|
|
38
41
|
platforms: ['ios', 'android'],
|
|
39
42
|
preferredReturnStrategy: 'post_redirect',
|
|
40
43
|
requiresReturnScheme: true, // Telegram Wallet requires explicit returnScheme
|
|
@@ -44,6 +47,7 @@ exports.SUPPORTED_WALLETS = [
|
|
|
44
47
|
appName: 'Tonhub',
|
|
45
48
|
universalLink: 'https://tonhub.com/ton-connect',
|
|
46
49
|
deepLink: 'tonhub://',
|
|
50
|
+
iconUrl: 'https://tonhub.com/tonconnect_logo.png',
|
|
47
51
|
platforms: ['ios', 'android'],
|
|
48
52
|
preferredReturnStrategy: 'post_redirect',
|
|
49
53
|
requiresReturnScheme: true, // Tonhub requires explicit returnScheme for proper callback
|