@blazium/ton-connect-mobile 1.2.1 → 1.2.4

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/src/index.ts CHANGED
@@ -13,6 +13,12 @@ import {
13
13
  SendTransactionRequest,
14
14
  StatusChangeCallback,
15
15
  PlatformAdapter,
16
+ Network,
17
+ TonConnectEventType,
18
+ TonConnectEventListener,
19
+ TransactionStatus,
20
+ TransactionStatusResponse,
21
+ BalanceResponse,
16
22
  } from './types';
17
23
  import {
18
24
  buildConnectionRequest,
@@ -106,8 +112,13 @@ export class TransactionInProgressError extends TonConnectError {
106
112
  */
107
113
  export class TonConnectMobile {
108
114
  private adapter: PlatformAdapter;
109
- private config: Required<Omit<TonConnectMobileConfig, 'preferredWallet'>> & { preferredWallet?: string };
115
+ private config: Required<Omit<TonConnectMobileConfig, 'preferredWallet' | 'network' | 'tonApiEndpoint'>> & {
116
+ preferredWallet?: string;
117
+ network: Network;
118
+ tonApiEndpoint?: string;
119
+ };
110
120
  private statusChangeCallbacks: Set<StatusChangeCallback> = new Set();
121
+ private eventListeners: Map<TonConnectEventType, Set<TonConnectEventListener>> = new Map();
111
122
  private currentStatus: ConnectionStatus = { connected: false, wallet: null };
112
123
  private urlUnsubscribe: (() => void) | null = null;
113
124
  private currentWallet!: WalletDefinition;
@@ -136,14 +147,32 @@ export class TonConnectMobile {
136
147
  throw new TonConnectError('scheme is required');
137
148
  }
138
149
 
150
+ // Validate network
151
+ const network = config.network || 'mainnet';
152
+ if (network !== 'mainnet' && network !== 'testnet') {
153
+ throw new TonConnectError('Network must be either "mainnet" or "testnet"');
154
+ }
155
+
156
+ // Set default TON API endpoint based on network
157
+ const defaultTonApiEndpoint =
158
+ network === 'testnet'
159
+ ? 'https://testnet.toncenter.com/api/v2'
160
+ : 'https://toncenter.com/api/v2';
161
+
139
162
  this.config = {
140
163
  storageKeyPrefix: 'tonconnect_',
141
164
  connectionTimeout: 300000, // 5 minutes
142
165
  transactionTimeout: 300000, // 5 minutes
143
166
  skipCanOpenURLCheck: true, // Skip canOpenURL check by default (Android issue)
144
167
  preferredWallet: config.preferredWallet,
168
+ network,
169
+ tonApiEndpoint: config.tonApiEndpoint || defaultTonApiEndpoint,
145
170
  ...config,
146
- } as Required<Omit<TonConnectMobileConfig, 'preferredWallet'>> & { preferredWallet?: string };
171
+ } as Required<Omit<TonConnectMobileConfig, 'preferredWallet' | 'network' | 'tonApiEndpoint'>> & {
172
+ preferredWallet?: string;
173
+ network: Network;
174
+ tonApiEndpoint?: string;
175
+ };
147
176
 
148
177
  // Determine which wallet to use
149
178
  if (this.config.preferredWallet) {
@@ -162,6 +191,7 @@ export class TonConnectMobile {
162
191
  console.log('[TON Connect] Initializing SDK with config:', {
163
192
  manifestUrl: this.config.manifestUrl,
164
193
  scheme: this.config.scheme,
194
+ network: this.config.network,
165
195
  wallet: this.currentWallet.name,
166
196
  universalLink: this.currentWallet.universalLink,
167
197
  });
@@ -347,6 +377,9 @@ export class TonConnectMobile {
347
377
  this.currentStatus = { connected: true, wallet };
348
378
  this.notifyStatusChange();
349
379
 
380
+ // Emit connect event
381
+ this.emit('connect', wallet);
382
+
350
383
  // Resolve connection promise
351
384
  // CRITICAL: Only resolve if promise still exists and hasn't timed out
352
385
  if (this.connectionPromise) {
@@ -372,6 +405,14 @@ export class TonConnectMobile {
372
405
  return;
373
406
  }
374
407
 
408
+ const transactionResult = {
409
+ boc: response.boc,
410
+ signature: response.signature,
411
+ };
412
+
413
+ // Emit transaction event
414
+ this.emit('transaction', transactionResult);
415
+
375
416
  // Resolve transaction promise
376
417
  // CRITICAL: Only resolve if promise still exists and hasn't timed out
377
418
  if (this.transactionPromise) {
@@ -384,10 +425,7 @@ export class TonConnectMobile {
384
425
  // Clear promise first to prevent race conditions
385
426
  this.transactionPromise = null;
386
427
  // Then resolve
387
- promise.resolve({
388
- boc: response.boc,
389
- signature: response.signature,
390
- });
428
+ promise.resolve(transactionResult);
391
429
  }
392
430
  }
393
431
 
@@ -395,6 +433,9 @@ export class TonConnectMobile {
395
433
  * Reject current promise with error
396
434
  */
397
435
  private rejectWithError(error: Error): void {
436
+ // Emit error event
437
+ this.emit('error', error);
438
+
398
439
  if (this.connectionPromise) {
399
440
  if (this.connectionPromise.timeout !== null) {
400
441
  clearTimeout(this.connectionPromise.timeout);
@@ -772,6 +813,9 @@ export class TonConnectMobile {
772
813
  // Update status
773
814
  this.currentStatus = { connected: false, wallet: null };
774
815
  this.notifyStatusChange();
816
+
817
+ // Emit disconnect event
818
+ this.emit('disconnect', null);
775
819
  }
776
820
 
777
821
  /**
@@ -876,6 +920,63 @@ export class TonConnectMobile {
876
920
  // Ignore errors in callbacks
877
921
  }
878
922
  });
923
+ // Emit statusChange event
924
+ this.emit('statusChange', status);
925
+ }
926
+
927
+ /**
928
+ * Emit event to all listeners
929
+ */
930
+ private emit<T>(event: TonConnectEventType, data: T): void {
931
+ const listeners = this.eventListeners.get(event);
932
+ if (listeners) {
933
+ listeners.forEach((listener) => {
934
+ try {
935
+ listener(data);
936
+ } catch (error) {
937
+ console.error(`[TON Connect] Error in event listener for ${event}:`, error);
938
+ }
939
+ });
940
+ }
941
+ }
942
+
943
+ /**
944
+ * Add event listener
945
+ */
946
+ on<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): () => void {
947
+ if (!this.eventListeners.has(event)) {
948
+ this.eventListeners.set(event, new Set());
949
+ }
950
+ this.eventListeners.get(event)!.add(listener);
951
+
952
+ // Return unsubscribe function
953
+ return () => {
954
+ const listeners = this.eventListeners.get(event);
955
+ if (listeners) {
956
+ listeners.delete(listener);
957
+ }
958
+ };
959
+ }
960
+
961
+ /**
962
+ * Remove event listener
963
+ */
964
+ off<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): void {
965
+ const listeners = this.eventListeners.get(event);
966
+ if (listeners) {
967
+ listeners.delete(listener);
968
+ }
969
+ }
970
+
971
+ /**
972
+ * Remove all listeners for an event
973
+ */
974
+ removeAllListeners(event?: TonConnectEventType): void {
975
+ if (event) {
976
+ this.eventListeners.delete(event);
977
+ } else {
978
+ this.eventListeners.clear();
979
+ }
879
980
  }
880
981
 
881
982
  /**
@@ -990,10 +1091,240 @@ export class TonConnectMobile {
990
1091
  }
991
1092
 
992
1093
  this.statusChangeCallbacks.clear();
1094
+ this.eventListeners.clear();
993
1095
  this.connectionPromise = null;
994
1096
  this.transactionPromise = null;
995
1097
  this.signDataPromise = null;
996
1098
  }
1099
+
1100
+ /**
1101
+ * Get current network
1102
+ */
1103
+ getNetwork(): Network {
1104
+ return this.config.network;
1105
+ }
1106
+
1107
+ /**
1108
+ * Set network (mainnet/testnet)
1109
+ */
1110
+ setNetwork(network: Network): void {
1111
+ if (network !== 'mainnet' && network !== 'testnet') {
1112
+ throw new TonConnectError('Network must be either "mainnet" or "testnet"');
1113
+ }
1114
+
1115
+ const oldNetwork = this.config.network;
1116
+
1117
+ // Warn if switching network while connected (wallet connection is network-specific)
1118
+ if (this.currentStatus.connected && oldNetwork !== network) {
1119
+ console.warn(
1120
+ '[TON Connect] Network changed while wallet is connected. ' +
1121
+ 'The wallet connection may be invalid for the new network. ' +
1122
+ 'Consider disconnecting and reconnecting after network change.'
1123
+ );
1124
+ }
1125
+
1126
+ this.config.network = network;
1127
+
1128
+ // Update TON API endpoint if not explicitly set
1129
+ if (!this.config.tonApiEndpoint || this.config.tonApiEndpoint.includes(oldNetwork)) {
1130
+ this.config.tonApiEndpoint =
1131
+ network === 'testnet'
1132
+ ? 'https://testnet.toncenter.com/api/v2'
1133
+ : 'https://toncenter.com/api/v2';
1134
+ }
1135
+
1136
+ console.log('[TON Connect] Network changed to:', network);
1137
+
1138
+ // Notify status change to update chain ID in React components
1139
+ this.notifyStatusChange();
1140
+ }
1141
+
1142
+ /**
1143
+ * Get wallet balance
1144
+ */
1145
+ async getBalance(address?: string): Promise<BalanceResponse> {
1146
+ const targetAddress = address || this.currentStatus.wallet?.address;
1147
+ if (!targetAddress) {
1148
+ throw new TonConnectError('Address is required. Either connect a wallet or provide an address.');
1149
+ }
1150
+
1151
+ // Validate address format
1152
+ if (!/^[0-9A-Za-z_-]{48}$/.test(targetAddress)) {
1153
+ throw new TonConnectError('Invalid TON address format');
1154
+ }
1155
+
1156
+ try {
1157
+ const apiEndpoint = this.config.tonApiEndpoint ||
1158
+ (this.config.network === 'testnet'
1159
+ ? 'https://testnet.toncenter.com/api/v2'
1160
+ : 'https://toncenter.com/api/v2');
1161
+
1162
+ const url = `${apiEndpoint}/getAddressInformation?address=${encodeURIComponent(targetAddress)}`;
1163
+
1164
+ const response = await fetch(url, {
1165
+ method: 'GET',
1166
+ headers: {
1167
+ 'Accept': 'application/json',
1168
+ },
1169
+ });
1170
+
1171
+ if (!response.ok) {
1172
+ throw new TonConnectError(`Failed to fetch balance: ${response.status} ${response.statusText}`);
1173
+ }
1174
+
1175
+ const data = await response.json();
1176
+
1177
+ if (data.ok === false) {
1178
+ throw new TonConnectError(data.error || 'Failed to fetch balance');
1179
+ }
1180
+
1181
+ // TON Center API returns balance in nanotons
1182
+ const balance = data.result?.balance || '0';
1183
+ const balanceTon = (BigInt(balance) / BigInt(1000000000)).toString() + '.' +
1184
+ (BigInt(balance) % BigInt(1000000000)).toString().padStart(9, '0').replace(/0+$/, '');
1185
+
1186
+ return {
1187
+ balance,
1188
+ balanceTon: balanceTon === '0.' ? '0' : balanceTon,
1189
+ network: this.config.network,
1190
+ };
1191
+ } catch (error: any) {
1192
+ if (error instanceof TonConnectError) {
1193
+ throw error;
1194
+ }
1195
+ throw new TonConnectError(`Failed to get balance: ${error?.message || String(error)}`);
1196
+ }
1197
+ }
1198
+
1199
+ /**
1200
+ * Get transaction status
1201
+ */
1202
+ async getTransactionStatus(boc: string, maxAttempts: number = 10, intervalMs: number = 2000): Promise<TransactionStatusResponse> {
1203
+ if (!boc || typeof boc !== 'string' || boc.length === 0) {
1204
+ throw new TonConnectError('Transaction BOC is required');
1205
+ }
1206
+
1207
+ // Extract transaction hash from BOC (simplified - in production, you'd parse the BOC properly)
1208
+ // For now, we'll use a polling approach with TON Center API
1209
+ try {
1210
+ const apiEndpoint = this.config.tonApiEndpoint ||
1211
+ (this.config.network === 'testnet'
1212
+ ? 'https://testnet.toncenter.com/api/v2'
1213
+ : 'https://toncenter.com/api/v2');
1214
+
1215
+ // Try to get transaction info
1216
+ // Note: This is a simplified implementation. In production, you'd need to:
1217
+ // 1. Parse the BOC to extract transaction hash
1218
+ // 2. Query the blockchain for transaction status
1219
+ // 3. Handle different confirmation states
1220
+
1221
+ // For now, we'll return a basic status
1222
+ // In a real implementation, you'd query the blockchain API
1223
+ let attempts = 0;
1224
+ let lastError: Error | null = null;
1225
+
1226
+ while (attempts < maxAttempts) {
1227
+ try {
1228
+ // This is a placeholder - you'd need to implement actual transaction lookup
1229
+ // For now, we'll simulate checking
1230
+ await new Promise<void>((resolve) => setTimeout(() => resolve(), intervalMs));
1231
+
1232
+ // In production, you would:
1233
+ // 1. Parse BOC to get transaction hash
1234
+ // 2. Query TON API: GET /getTransactions?address=...&limit=1
1235
+ // 3. Check if transaction exists and is confirmed
1236
+
1237
+ // For now, return unknown status (as we can't parse BOC without additional libraries)
1238
+ return {
1239
+ status: 'unknown',
1240
+ error: 'Transaction status checking requires BOC parsing. Please use a TON library to parse the BOC and extract the transaction hash.',
1241
+ };
1242
+ } catch (error: any) {
1243
+ lastError = error;
1244
+ attempts++;
1245
+ if (attempts < maxAttempts) {
1246
+ await new Promise<void>((resolve) => setTimeout(() => resolve(), intervalMs));
1247
+ }
1248
+ }
1249
+ }
1250
+
1251
+ return {
1252
+ status: 'failed',
1253
+ error: lastError?.message || 'Failed to check transaction status',
1254
+ };
1255
+ } catch (error: any) {
1256
+ throw new TonConnectError(`Failed to get transaction status: ${error?.message || String(error)}`);
1257
+ }
1258
+ }
1259
+
1260
+ /**
1261
+ * Get transaction status by hash (more reliable than BOC)
1262
+ */
1263
+ async getTransactionStatusByHash(txHash: string, address: string): Promise<TransactionStatusResponse> {
1264
+ if (!txHash || typeof txHash !== 'string' || txHash.length === 0) {
1265
+ throw new TonConnectError('Transaction hash is required');
1266
+ }
1267
+ if (!address || typeof address !== 'string' || address.length === 0) {
1268
+ throw new TonConnectError('Address is required');
1269
+ }
1270
+
1271
+ try {
1272
+ const apiEndpoint = this.config.tonApiEndpoint ||
1273
+ (this.config.network === 'testnet'
1274
+ ? 'https://testnet.toncenter.com/api/v2'
1275
+ : 'https://toncenter.com/api/v2');
1276
+
1277
+ // Query transactions for the address
1278
+ const url = `${apiEndpoint}/getTransactions?address=${encodeURIComponent(address)}&limit=100`;
1279
+
1280
+ const response = await fetch(url, {
1281
+ method: 'GET',
1282
+ headers: {
1283
+ 'Accept': 'application/json',
1284
+ },
1285
+ });
1286
+
1287
+ if (!response.ok) {
1288
+ throw new TonConnectError(`Failed to fetch transactions: ${response.status} ${response.statusText}`);
1289
+ }
1290
+
1291
+ const data = await response.json();
1292
+
1293
+ if (data.ok === false) {
1294
+ throw new TonConnectError(data.error || 'Failed to fetch transactions');
1295
+ }
1296
+
1297
+ // Search for transaction with matching hash
1298
+ const transactions = data.result || [];
1299
+ const transaction = transactions.find((tx: any) =>
1300
+ tx.transaction_id?.hash === txHash ||
1301
+ tx.transaction_id?.lt === txHash ||
1302
+ JSON.stringify(tx.transaction_id).includes(txHash)
1303
+ );
1304
+
1305
+ if (transaction) {
1306
+ return {
1307
+ status: 'confirmed',
1308
+ hash: transaction.transaction_id?.hash || txHash,
1309
+ blockNumber: transaction.transaction_id?.lt,
1310
+ };
1311
+ }
1312
+
1313
+ // Transaction not found - could be pending or failed
1314
+ return {
1315
+ status: 'pending',
1316
+ hash: txHash,
1317
+ };
1318
+ } catch (error: any) {
1319
+ if (error instanceof TonConnectError) {
1320
+ throw error;
1321
+ }
1322
+ return {
1323
+ status: 'failed',
1324
+ error: error?.message || 'Failed to check transaction status',
1325
+ };
1326
+ }
1327
+ }
997
1328
  }
998
1329
 
999
1330
  // Export types
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
7
- import { TonConnectMobile, ConnectionStatus, WalletInfo, SendTransactionRequest } from '../index';
8
- import type { TonConnectMobileConfig } from '../types';
7
+ import { TonConnectMobile, ConnectionStatus, WalletInfo, SendTransactionRequest, WalletDefinition, Network, BalanceResponse, TransactionStatusResponse } from '../index';
8
+ import type { TonConnectMobileConfig, TonConnectEventType, TonConnectEventListener } from '../types';
9
9
  import { WalletSelectionModal } from './WalletSelectionModal';
10
10
 
11
11
  /**
@@ -54,6 +54,7 @@ export interface SignDataResponse {
54
54
 
55
55
  /**
56
56
  * TonConnect UI instance interface (compatible with @tonconnect/ui-react)
57
+ * Includes all features from @tonconnect/ui-react for full compatibility
57
58
  */
58
59
  export interface TonConnectUI {
59
60
  /** Open connection modal */
@@ -68,6 +69,24 @@ export interface TonConnectUI {
68
69
  sendTransaction: (transaction: SendTransactionRequest) => Promise<TransactionResponse>;
69
70
  /** Sign data */
70
71
  signData: (request: SignDataRequest) => Promise<SignDataResponse>;
72
+ /** Restore connection from stored session */
73
+ restoreConnection: () => Promise<void>;
74
+ /** Set wallet list (customize available wallets) */
75
+ setWalletList: (wallets: WalletDefinition[]) => void;
76
+ /** Get current network */
77
+ getNetwork: () => Network;
78
+ /** Set network (mainnet/testnet) */
79
+ setNetwork: (network: Network) => void;
80
+ /** Get wallet balance */
81
+ getBalance: (address?: string) => Promise<BalanceResponse>;
82
+ /** Get transaction status */
83
+ getTransactionStatus: (boc: string, maxAttempts?: number, intervalMs?: number) => Promise<TransactionStatusResponse>;
84
+ /** Get transaction status by hash */
85
+ getTransactionStatusByHash: (txHash: string, address: string) => Promise<TransactionStatusResponse>;
86
+ /** Add event listener */
87
+ on: <T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>) => () => void;
88
+ /** Remove event listener */
89
+ off: <T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>) => void;
71
90
  /** Current wallet state */
72
91
  wallet: WalletState | null;
73
92
  /** Modal open state */
@@ -124,14 +143,23 @@ export function TonConnectUIProvider({
124
143
  const [walletState, setWalletState] = useState<WalletState | null>(null);
125
144
  const [modalOpen, setModalOpen] = useState(false);
126
145
  const [isConnecting, setIsConnecting] = useState(false);
146
+ const [customWalletList, setCustomWalletList] = useState<WalletDefinition[] | null>(null);
147
+
148
+ // Get chain ID based on network
149
+ const getChainId = useCallback((network: Network): number => {
150
+ // TON mainnet chain ID: -239
151
+ // TON testnet chain ID: -3
152
+ return network === 'testnet' ? -3 : -239;
153
+ }, []);
127
154
 
128
155
  // Update wallet state from SDK status
129
156
  const updateWalletState = useCallback((status: ConnectionStatus) => {
130
157
  if (status.connected && status.wallet) {
158
+ const network = sdk.getNetwork();
131
159
  setWalletState({
132
160
  account: {
133
161
  address: status.wallet.address,
134
- chain: -239, // TON mainnet chain ID
162
+ chain: getChainId(network),
135
163
  publicKey: status.wallet.publicKey,
136
164
  },
137
165
  wallet: status.wallet,
@@ -144,7 +172,7 @@ export function TonConnectUIProvider({
144
172
  connected: false,
145
173
  });
146
174
  }
147
- }, []);
175
+ }, [sdk, getChainId]);
148
176
 
149
177
  // Subscribe to SDK status changes
150
178
  useEffect(() => {
@@ -257,6 +285,73 @@ export function TonConnectUIProvider({
257
285
  [sdk]
258
286
  );
259
287
 
288
+ // Restore connection from stored session
289
+ const restoreConnection = useCallback(async (): Promise<void> => {
290
+ try {
291
+ // SDK automatically loads session on initialization
292
+ // This method triggers a re-check of the stored session
293
+ const status = sdk.getStatus();
294
+ if (status.connected && status.wallet) {
295
+ updateWalletState(status);
296
+ }
297
+ } catch (error) {
298
+ console.error('[TonConnectUIProvider] Restore connection error:', error);
299
+ throw error;
300
+ }
301
+ }, [sdk, updateWalletState]);
302
+
303
+ // Set wallet list (customize available wallets)
304
+ const setWalletList = useCallback((wallets: WalletDefinition[]): void => {
305
+ if (!wallets || !Array.isArray(wallets)) {
306
+ throw new Error('Wallet list must be an array');
307
+ }
308
+ setCustomWalletList(wallets);
309
+ }, []);
310
+
311
+ // Get network
312
+ const getNetwork = useCallback((): Network => {
313
+ return sdk.getNetwork();
314
+ }, [sdk]);
315
+
316
+ // Set network
317
+ const setNetwork = useCallback((network: Network): void => {
318
+ sdk.setNetwork(network);
319
+ // Update wallet state to reflect new chain ID
320
+ const status = sdk.getStatus();
321
+ updateWalletState(status);
322
+ }, [sdk, updateWalletState]);
323
+
324
+ // Get balance
325
+ const getBalance = useCallback(async (address?: string): Promise<BalanceResponse> => {
326
+ return await sdk.getBalance(address);
327
+ }, [sdk]);
328
+
329
+ // Get transaction status
330
+ const getTransactionStatus = useCallback(async (
331
+ boc: string,
332
+ maxAttempts: number = 10,
333
+ intervalMs: number = 2000
334
+ ): Promise<TransactionStatusResponse> => {
335
+ return await sdk.getTransactionStatus(boc, maxAttempts, intervalMs);
336
+ }, [sdk]);
337
+
338
+ // Get transaction status by hash
339
+ const getTransactionStatusByHash = useCallback(async (
340
+ txHash: string,
341
+ address: string
342
+ ): Promise<TransactionStatusResponse> => {
343
+ return await sdk.getTransactionStatusByHash(txHash, address);
344
+ }, [sdk]);
345
+
346
+ // Event listeners
347
+ const on = useCallback(<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): (() => void) => {
348
+ return sdk.on(event, listener);
349
+ }, [sdk]);
350
+
351
+ const off = useCallback(<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): void => {
352
+ sdk.off(event, listener);
353
+ }, [sdk]);
354
+
260
355
  // Create TonConnectUI instance
261
356
  const tonConnectUI: TonConnectUI = {
262
357
  openModal,
@@ -265,6 +360,15 @@ export function TonConnectUIProvider({
265
360
  disconnect,
266
361
  sendTransaction,
267
362
  signData,
363
+ restoreConnection,
364
+ setWalletList,
365
+ getNetwork,
366
+ setNetwork,
367
+ getBalance,
368
+ getTransactionStatus,
369
+ getTransactionStatusByHash,
370
+ on,
371
+ off,
268
372
  wallet: walletState,
269
373
  modalState: {
270
374
  open: modalOpen,
@@ -284,6 +388,7 @@ export function TonConnectUIProvider({
284
388
  <WalletSelectionModal
285
389
  visible={modalOpen && !walletState?.connected}
286
390
  onClose={closeModal}
391
+ wallets={customWalletList || undefined}
287
392
  />
288
393
  </TonConnectUIContext.Provider>
289
394
  );