@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/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * TON Connect Mobile SDK
3
3
  * Production-ready implementation for React Native and Expo
4
4
  */
5
- import { TonConnectMobileConfig, ConnectionStatus, WalletInfo, SendTransactionRequest, StatusChangeCallback } from './types';
5
+ import { TonConnectMobileConfig, ConnectionStatus, WalletInfo, SendTransactionRequest, StatusChangeCallback, Network, TonConnectEventType, TonConnectEventListener, TransactionStatusResponse, BalanceResponse } from './types';
6
6
  import { type WalletDefinition } from './core/wallets';
7
7
  /**
8
8
  * Custom error classes
@@ -34,6 +34,7 @@ export declare class TonConnectMobile {
34
34
  private adapter;
35
35
  private config;
36
36
  private statusChangeCallbacks;
37
+ private eventListeners;
37
38
  private currentStatus;
38
39
  private urlUnsubscribe;
39
40
  private currentWallet;
@@ -103,6 +104,8 @@ export declare class TonConnectMobile {
103
104
  /**
104
105
  * Check if a wallet is available on the current platform
105
106
  * Note: This is a best-effort check and may not be 100% accurate
107
+ * CRITICAL FIX: On web, if wallet has universalLink, it's considered available
108
+ * because universal links can open in new tabs/windows
106
109
  */
107
110
  isWalletAvailable(walletName?: string): Promise<boolean>;
108
111
  /**
@@ -117,6 +120,22 @@ export declare class TonConnectMobile {
117
120
  * Notify all status change callbacks
118
121
  */
119
122
  private notifyStatusChange;
123
+ /**
124
+ * Emit event to all listeners
125
+ */
126
+ private emit;
127
+ /**
128
+ * Add event listener
129
+ */
130
+ on<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): () => void;
131
+ /**
132
+ * Remove event listener
133
+ */
134
+ off<T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>): void;
135
+ /**
136
+ * Remove all listeners for an event
137
+ */
138
+ removeAllListeners(event?: TonConnectEventType): void;
120
139
  /**
121
140
  * Validate session ID format
122
141
  */
@@ -137,6 +156,26 @@ export declare class TonConnectMobile {
137
156
  * Cleanup resources
138
157
  */
139
158
  destroy(): void;
159
+ /**
160
+ * Get current network
161
+ */
162
+ getNetwork(): Network;
163
+ /**
164
+ * Set network (mainnet/testnet)
165
+ */
166
+ setNetwork(network: Network): void;
167
+ /**
168
+ * Get wallet balance
169
+ */
170
+ getBalance(address?: string): Promise<BalanceResponse>;
171
+ /**
172
+ * Get transaction status
173
+ */
174
+ getTransactionStatus(boc: string, maxAttempts?: number, intervalMs?: number): Promise<TransactionStatusResponse>;
175
+ /**
176
+ * Get transaction status by hash (more reliable than BOC)
177
+ */
178
+ getTransactionStatusByHash(txHash: string, address: string): Promise<TransactionStatusResponse>;
140
179
  }
141
180
  export * from './types';
142
181
  export type { WalletDefinition } from './core/wallets';
package/dist/index.js CHANGED
@@ -60,14 +60,14 @@ class UserRejectedError extends TonConnectError {
60
60
  exports.UserRejectedError = UserRejectedError;
61
61
  class ConnectionInProgressError extends TonConnectError {
62
62
  constructor() {
63
- super('Connection request already in progress', 'CONNECTION_IN_PROGRESS');
63
+ super('Connection request already in progress', 'CONNECTION_IN_PROGRESS', 'Please wait for the current connection attempt to complete before trying again.');
64
64
  this.name = 'ConnectionInProgressError';
65
65
  }
66
66
  }
67
67
  exports.ConnectionInProgressError = ConnectionInProgressError;
68
68
  class TransactionInProgressError extends TonConnectError {
69
69
  constructor() {
70
- super('Transaction request already in progress', 'TRANSACTION_IN_PROGRESS');
70
+ super('Transaction request already in progress', 'TRANSACTION_IN_PROGRESS', 'Please wait for the current transaction to complete before sending another one.');
71
71
  this.name = 'TransactionInProgressError';
72
72
  }
73
73
  }
@@ -78,6 +78,7 @@ exports.TransactionInProgressError = TransactionInProgressError;
78
78
  class TonConnectMobile {
79
79
  constructor(config) {
80
80
  this.statusChangeCallbacks = new Set();
81
+ this.eventListeners = new Map();
81
82
  this.currentStatus = { connected: false, wallet: null };
82
83
  this.urlUnsubscribe = null;
83
84
  this.connectionPromise = null;
@@ -90,12 +91,23 @@ class TonConnectMobile {
90
91
  if (!config.scheme) {
91
92
  throw new TonConnectError('scheme is required');
92
93
  }
94
+ // Validate network
95
+ const network = config.network || 'mainnet';
96
+ if (network !== 'mainnet' && network !== 'testnet') {
97
+ throw new TonConnectError('Network must be either "mainnet" or "testnet"');
98
+ }
99
+ // Set default TON API endpoint based on network
100
+ const defaultTonApiEndpoint = network === 'testnet'
101
+ ? 'https://testnet.toncenter.com/api/v2'
102
+ : 'https://toncenter.com/api/v2';
93
103
  this.config = {
94
104
  storageKeyPrefix: 'tonconnect_',
95
105
  connectionTimeout: 300000, // 5 minutes
96
106
  transactionTimeout: 300000, // 5 minutes
97
107
  skipCanOpenURLCheck: true, // Skip canOpenURL check by default (Android issue)
98
108
  preferredWallet: config.preferredWallet,
109
+ network,
110
+ tonApiEndpoint: config.tonApiEndpoint || defaultTonApiEndpoint,
99
111
  ...config,
100
112
  };
101
113
  // Determine which wallet to use
@@ -116,6 +128,7 @@ class TonConnectMobile {
116
128
  console.log('[TON Connect] Initializing SDK with config:', {
117
129
  manifestUrl: this.config.manifestUrl,
118
130
  scheme: this.config.scheme,
131
+ network: this.config.network,
119
132
  wallet: this.currentWallet.name,
120
133
  universalLink: this.currentWallet.universalLink,
121
134
  });
@@ -198,8 +211,9 @@ class TonConnectMobile {
198
211
  const parsed = (0, protocol_1.parseCallbackURL)(url, this.config.scheme);
199
212
  console.log('[TON Connect] Parsed callback:', parsed.type, parsed.data ? 'has data' : 'no data');
200
213
  // CRITICAL FIX: Check for sign data response first (before other handlers)
201
- if (this.signDataPromise && !this.signDataPromise.timeout) {
202
- // Sign data request is pending
214
+ // Note: We check if promise exists and hasn't timed out (timeout !== null means not timed out yet)
215
+ if (this.signDataPromise && this.signDataPromise.timeout !== null) {
216
+ // Sign data request is pending and hasn't timed out
203
217
  if (parsed.type === 'error' && parsed.data) {
204
218
  const errorData = parsed.data;
205
219
  if (errorData?.error) {
@@ -283,13 +297,21 @@ class TonConnectMobile {
283
297
  // Update status
284
298
  this.currentStatus = { connected: true, wallet };
285
299
  this.notifyStatusChange();
300
+ // Emit connect event
301
+ this.emit('connect', wallet);
286
302
  // Resolve connection promise
303
+ // CRITICAL: Only resolve if promise still exists and hasn't timed out
287
304
  if (this.connectionPromise) {
305
+ // Clear timeout if it exists
288
306
  if (this.connectionPromise.timeout !== null) {
289
307
  clearTimeout(this.connectionPromise.timeout);
290
308
  }
291
- this.connectionPromise.resolve(wallet);
309
+ // Store reference before clearing to prevent race conditions
310
+ const promise = this.connectionPromise;
311
+ // Clear promise first
292
312
  this.connectionPromise = null;
313
+ // Then resolve
314
+ promise.resolve(wallet);
293
315
  }
294
316
  }
295
317
  /**
@@ -300,22 +322,33 @@ class TonConnectMobile {
300
322
  this.rejectWithError(new TonConnectError('Invalid transaction response'));
301
323
  return;
302
324
  }
325
+ const transactionResult = {
326
+ boc: response.boc,
327
+ signature: response.signature,
328
+ };
329
+ // Emit transaction event
330
+ this.emit('transaction', transactionResult);
303
331
  // Resolve transaction promise
332
+ // CRITICAL: Only resolve if promise still exists and hasn't timed out
304
333
  if (this.transactionPromise) {
334
+ // Clear timeout if it exists
305
335
  if (this.transactionPromise.timeout !== null) {
306
336
  clearTimeout(this.transactionPromise.timeout);
307
337
  }
308
- this.transactionPromise.resolve({
309
- boc: response.boc,
310
- signature: response.signature,
311
- });
338
+ // Store reference before clearing
339
+ const promise = this.transactionPromise;
340
+ // Clear promise first to prevent race conditions
312
341
  this.transactionPromise = null;
342
+ // Then resolve
343
+ promise.resolve(transactionResult);
313
344
  }
314
345
  }
315
346
  /**
316
347
  * Reject current promise with error
317
348
  */
318
349
  rejectWithError(error) {
350
+ // Emit error event
351
+ this.emit('error', error);
319
352
  if (this.connectionPromise) {
320
353
  if (this.connectionPromise.timeout !== null) {
321
354
  clearTimeout(this.connectionPromise.timeout);
@@ -330,6 +363,14 @@ class TonConnectMobile {
330
363
  this.transactionPromise.reject(error);
331
364
  this.transactionPromise = null;
332
365
  }
366
+ // CRITICAL FIX: Also clear signDataPromise to prevent memory leaks
367
+ if (this.signDataPromise) {
368
+ if (this.signDataPromise.timeout !== null) {
369
+ clearTimeout(this.signDataPromise.timeout);
370
+ }
371
+ this.signDataPromise.reject(error);
372
+ this.signDataPromise = null;
373
+ }
333
374
  }
334
375
  /**
335
376
  * Connect to wallet
@@ -627,6 +668,8 @@ class TonConnectMobile {
627
668
  // Update status
628
669
  this.currentStatus = { connected: false, wallet: null };
629
670
  this.notifyStatusChange();
671
+ // Emit disconnect event
672
+ this.emit('disconnect', null);
630
673
  }
631
674
  /**
632
675
  * Get current connection status
@@ -649,16 +692,21 @@ class TonConnectMobile {
649
692
  /**
650
693
  * Check if a wallet is available on the current platform
651
694
  * Note: This is a best-effort check and may not be 100% accurate
695
+ * CRITICAL FIX: On web, if wallet has universalLink, it's considered available
696
+ * because universal links can open in new tabs/windows
652
697
  */
653
698
  async isWalletAvailable(walletName) {
654
699
  const wallet = walletName ? (0, wallets_1.getWalletByName)(walletName) : this.currentWallet;
655
700
  if (!wallet) {
656
701
  return false;
657
702
  }
658
- // On web, check if wallet supports web platform
659
- // eslint-disable-next-line no-undef
660
- if (typeof globalThis !== 'undefined' && globalThis.window) {
661
- return wallet.platforms.includes('web');
703
+ // CRITICAL FIX: Check adapter type to reliably detect web platform
704
+ // WebAdapter is only used on web, so this is the most reliable check
705
+ const isWeb = this.adapter.constructor.name === 'WebAdapter';
706
+ if (isWeb) {
707
+ // On web, if wallet has universalLink or supports web platform, it's available
708
+ // Universal links can open in a new tab on web
709
+ return wallet.platforms.includes('web') || !!wallet.universalLink;
662
710
  }
663
711
  // On mobile, we can't reliably check if wallet is installed
664
712
  // Return true if wallet supports the current platform
@@ -712,6 +760,60 @@ class TonConnectMobile {
712
760
  // Ignore errors in callbacks
713
761
  }
714
762
  });
763
+ // Emit statusChange event
764
+ this.emit('statusChange', status);
765
+ }
766
+ /**
767
+ * Emit event to all listeners
768
+ */
769
+ emit(event, data) {
770
+ const listeners = this.eventListeners.get(event);
771
+ if (listeners) {
772
+ listeners.forEach((listener) => {
773
+ try {
774
+ listener(data);
775
+ }
776
+ catch (error) {
777
+ console.error(`[TON Connect] Error in event listener for ${event}:`, error);
778
+ }
779
+ });
780
+ }
781
+ }
782
+ /**
783
+ * Add event listener
784
+ */
785
+ on(event, listener) {
786
+ if (!this.eventListeners.has(event)) {
787
+ this.eventListeners.set(event, new Set());
788
+ }
789
+ this.eventListeners.get(event).add(listener);
790
+ // Return unsubscribe function
791
+ return () => {
792
+ const listeners = this.eventListeners.get(event);
793
+ if (listeners) {
794
+ listeners.delete(listener);
795
+ }
796
+ };
797
+ }
798
+ /**
799
+ * Remove event listener
800
+ */
801
+ off(event, listener) {
802
+ const listeners = this.eventListeners.get(event);
803
+ if (listeners) {
804
+ listeners.delete(listener);
805
+ }
806
+ }
807
+ /**
808
+ * Remove all listeners for an event
809
+ */
810
+ removeAllListeners(event) {
811
+ if (event) {
812
+ this.eventListeners.delete(event);
813
+ }
814
+ else {
815
+ this.eventListeners.clear();
816
+ }
715
817
  }
716
818
  /**
717
819
  * Validate session ID format
@@ -815,10 +917,204 @@ class TonConnectMobile {
815
917
  this.adapter.destroy();
816
918
  }
817
919
  this.statusChangeCallbacks.clear();
920
+ this.eventListeners.clear();
818
921
  this.connectionPromise = null;
819
922
  this.transactionPromise = null;
820
923
  this.signDataPromise = null;
821
924
  }
925
+ /**
926
+ * Get current network
927
+ */
928
+ getNetwork() {
929
+ return this.config.network;
930
+ }
931
+ /**
932
+ * Set network (mainnet/testnet)
933
+ */
934
+ setNetwork(network) {
935
+ if (network !== 'mainnet' && network !== 'testnet') {
936
+ throw new TonConnectError('Network must be either "mainnet" or "testnet"');
937
+ }
938
+ const oldNetwork = this.config.network;
939
+ // Warn if switching network while connected (wallet connection is network-specific)
940
+ if (this.currentStatus.connected && oldNetwork !== network) {
941
+ console.warn('[TON Connect] Network changed while wallet is connected. ' +
942
+ 'The wallet connection may be invalid for the new network. ' +
943
+ 'Consider disconnecting and reconnecting after network change.');
944
+ }
945
+ this.config.network = network;
946
+ // Update TON API endpoint if not explicitly set
947
+ if (!this.config.tonApiEndpoint || this.config.tonApiEndpoint.includes(oldNetwork)) {
948
+ this.config.tonApiEndpoint =
949
+ network === 'testnet'
950
+ ? 'https://testnet.toncenter.com/api/v2'
951
+ : 'https://toncenter.com/api/v2';
952
+ }
953
+ console.log('[TON Connect] Network changed to:', network);
954
+ // Notify status change to update chain ID in React components
955
+ this.notifyStatusChange();
956
+ }
957
+ /**
958
+ * Get wallet balance
959
+ */
960
+ async getBalance(address) {
961
+ const targetAddress = address || this.currentStatus.wallet?.address;
962
+ if (!targetAddress) {
963
+ throw new TonConnectError('Address is required. Either connect a wallet or provide an address.');
964
+ }
965
+ // Validate address format
966
+ if (!/^[0-9A-Za-z_-]{48}$/.test(targetAddress)) {
967
+ throw new TonConnectError('Invalid TON address format');
968
+ }
969
+ try {
970
+ const apiEndpoint = this.config.tonApiEndpoint ||
971
+ (this.config.network === 'testnet'
972
+ ? 'https://testnet.toncenter.com/api/v2'
973
+ : 'https://toncenter.com/api/v2');
974
+ const url = `${apiEndpoint}/getAddressInformation?address=${encodeURIComponent(targetAddress)}`;
975
+ const response = await fetch(url, {
976
+ method: 'GET',
977
+ headers: {
978
+ 'Accept': 'application/json',
979
+ },
980
+ });
981
+ if (!response.ok) {
982
+ throw new TonConnectError(`Failed to fetch balance: ${response.status} ${response.statusText}`);
983
+ }
984
+ const data = await response.json();
985
+ if (data.ok === false) {
986
+ throw new TonConnectError(data.error || 'Failed to fetch balance');
987
+ }
988
+ // TON Center API returns balance in nanotons
989
+ const balance = data.result?.balance || '0';
990
+ const balanceTon = (BigInt(balance) / BigInt(1000000000)).toString() + '.' +
991
+ (BigInt(balance) % BigInt(1000000000)).toString().padStart(9, '0').replace(/0+$/, '');
992
+ return {
993
+ balance,
994
+ balanceTon: balanceTon === '0.' ? '0' : balanceTon,
995
+ network: this.config.network,
996
+ };
997
+ }
998
+ catch (error) {
999
+ if (error instanceof TonConnectError) {
1000
+ throw error;
1001
+ }
1002
+ throw new TonConnectError(`Failed to get balance: ${error?.message || String(error)}`);
1003
+ }
1004
+ }
1005
+ /**
1006
+ * Get transaction status
1007
+ */
1008
+ async getTransactionStatus(boc, maxAttempts = 10, intervalMs = 2000) {
1009
+ if (!boc || typeof boc !== 'string' || boc.length === 0) {
1010
+ throw new TonConnectError('Transaction BOC is required');
1011
+ }
1012
+ // Extract transaction hash from BOC (simplified - in production, you'd parse the BOC properly)
1013
+ // For now, we'll use a polling approach with TON Center API
1014
+ try {
1015
+ const apiEndpoint = this.config.tonApiEndpoint ||
1016
+ (this.config.network === 'testnet'
1017
+ ? 'https://testnet.toncenter.com/api/v2'
1018
+ : 'https://toncenter.com/api/v2');
1019
+ // Try to get transaction info
1020
+ // Note: This is a simplified implementation. In production, you'd need to:
1021
+ // 1. Parse the BOC to extract transaction hash
1022
+ // 2. Query the blockchain for transaction status
1023
+ // 3. Handle different confirmation states
1024
+ // For now, we'll return a basic status
1025
+ // In a real implementation, you'd query the blockchain API
1026
+ let attempts = 0;
1027
+ let lastError = null;
1028
+ while (attempts < maxAttempts) {
1029
+ try {
1030
+ // This is a placeholder - you'd need to implement actual transaction lookup
1031
+ // For now, we'll simulate checking
1032
+ await new Promise((resolve) => setTimeout(() => resolve(), intervalMs));
1033
+ // In production, you would:
1034
+ // 1. Parse BOC to get transaction hash
1035
+ // 2. Query TON API: GET /getTransactions?address=...&limit=1
1036
+ // 3. Check if transaction exists and is confirmed
1037
+ // For now, return unknown status (as we can't parse BOC without additional libraries)
1038
+ return {
1039
+ status: 'unknown',
1040
+ error: 'Transaction status checking requires BOC parsing. Please use a TON library to parse the BOC and extract the transaction hash.',
1041
+ };
1042
+ }
1043
+ catch (error) {
1044
+ lastError = error;
1045
+ attempts++;
1046
+ if (attempts < maxAttempts) {
1047
+ await new Promise((resolve) => setTimeout(() => resolve(), intervalMs));
1048
+ }
1049
+ }
1050
+ }
1051
+ return {
1052
+ status: 'failed',
1053
+ error: lastError?.message || 'Failed to check transaction status',
1054
+ };
1055
+ }
1056
+ catch (error) {
1057
+ throw new TonConnectError(`Failed to get transaction status: ${error?.message || String(error)}`);
1058
+ }
1059
+ }
1060
+ /**
1061
+ * Get transaction status by hash (more reliable than BOC)
1062
+ */
1063
+ async getTransactionStatusByHash(txHash, address) {
1064
+ if (!txHash || typeof txHash !== 'string' || txHash.length === 0) {
1065
+ throw new TonConnectError('Transaction hash is required');
1066
+ }
1067
+ if (!address || typeof address !== 'string' || address.length === 0) {
1068
+ throw new TonConnectError('Address is required');
1069
+ }
1070
+ try {
1071
+ const apiEndpoint = this.config.tonApiEndpoint ||
1072
+ (this.config.network === 'testnet'
1073
+ ? 'https://testnet.toncenter.com/api/v2'
1074
+ : 'https://toncenter.com/api/v2');
1075
+ // Query transactions for the address
1076
+ const url = `${apiEndpoint}/getTransactions?address=${encodeURIComponent(address)}&limit=100`;
1077
+ const response = await fetch(url, {
1078
+ method: 'GET',
1079
+ headers: {
1080
+ 'Accept': 'application/json',
1081
+ },
1082
+ });
1083
+ if (!response.ok) {
1084
+ throw new TonConnectError(`Failed to fetch transactions: ${response.status} ${response.statusText}`);
1085
+ }
1086
+ const data = await response.json();
1087
+ if (data.ok === false) {
1088
+ throw new TonConnectError(data.error || 'Failed to fetch transactions');
1089
+ }
1090
+ // Search for transaction with matching hash
1091
+ const transactions = data.result || [];
1092
+ const transaction = transactions.find((tx) => tx.transaction_id?.hash === txHash ||
1093
+ tx.transaction_id?.lt === txHash ||
1094
+ JSON.stringify(tx.transaction_id).includes(txHash));
1095
+ if (transaction) {
1096
+ return {
1097
+ status: 'confirmed',
1098
+ hash: transaction.transaction_id?.hash || txHash,
1099
+ blockNumber: transaction.transaction_id?.lt,
1100
+ };
1101
+ }
1102
+ // Transaction not found - could be pending or failed
1103
+ return {
1104
+ status: 'pending',
1105
+ hash: txHash,
1106
+ };
1107
+ }
1108
+ catch (error) {
1109
+ if (error instanceof TonConnectError) {
1110
+ throw error;
1111
+ }
1112
+ return {
1113
+ status: 'failed',
1114
+ error: error?.message || 'Failed to check transaction status',
1115
+ };
1116
+ }
1117
+ }
822
1118
  }
823
1119
  exports.TonConnectMobile = TonConnectMobile;
824
1120
  // Export types
@@ -3,8 +3,8 @@
3
3
  * Provides TonConnectUIProvider, hooks, and components compatible with @tonconnect/ui-react API
4
4
  */
5
5
  import { ReactNode } from 'react';
6
- import { TonConnectMobile, WalletInfo, SendTransactionRequest } from '../index';
7
- import type { TonConnectMobileConfig } from '../types';
6
+ import { TonConnectMobile, WalletInfo, SendTransactionRequest, WalletDefinition, Network, BalanceResponse, TransactionStatusResponse } from '../index';
7
+ import type { TonConnectMobileConfig, TonConnectEventType, TonConnectEventListener } from '../types';
8
8
  /**
9
9
  * Account information (compatible with @tonconnect/ui-react)
10
10
  */
@@ -46,6 +46,7 @@ export interface SignDataResponse {
46
46
  }
47
47
  /**
48
48
  * TonConnect UI instance interface (compatible with @tonconnect/ui-react)
49
+ * Includes all features from @tonconnect/ui-react for full compatibility
49
50
  */
50
51
  export interface TonConnectUI {
51
52
  /** Open connection modal */
@@ -60,6 +61,24 @@ export interface TonConnectUI {
60
61
  sendTransaction: (transaction: SendTransactionRequest) => Promise<TransactionResponse>;
61
62
  /** Sign data */
62
63
  signData: (request: SignDataRequest) => Promise<SignDataResponse>;
64
+ /** Restore connection from stored session */
65
+ restoreConnection: () => Promise<void>;
66
+ /** Set wallet list (customize available wallets) */
67
+ setWalletList: (wallets: WalletDefinition[]) => void;
68
+ /** Get current network */
69
+ getNetwork: () => Network;
70
+ /** Set network (mainnet/testnet) */
71
+ setNetwork: (network: Network) => void;
72
+ /** Get wallet balance */
73
+ getBalance: (address?: string) => Promise<BalanceResponse>;
74
+ /** Get transaction status */
75
+ getTransactionStatus: (boc: string, maxAttempts?: number, intervalMs?: number) => Promise<TransactionStatusResponse>;
76
+ /** Get transaction status by hash */
77
+ getTransactionStatusByHash: (txHash: string, address: string) => Promise<TransactionStatusResponse>;
78
+ /** Add event listener */
79
+ on: <T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>) => () => void;
80
+ /** Remove event listener */
81
+ off: <T = any>(event: TonConnectEventType, listener: TonConnectEventListener<T>) => void;
63
82
  /** Current wallet state */
64
83
  wallet: WalletState | null;
65
84
  /** Modal open state */