tiwiflix-wallet-connector 1.5.5 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -7530,7 +7530,7 @@ const defaultStyles = {
7530
7530
  fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
7531
7531
  boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
7532
7532
  }};
7533
- const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
7533
+ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet Now', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
7534
7534
  // Provide a default fetchBalance if not passed
7535
7535
  const fetchBalance = fetchBalanceProp || (async (account) => {
7536
7536
  // Default: return zero balance with symbol based on chain
@@ -7662,12 +7662,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7662
7662
  });
7663
7663
  // Stable USD value updater - only updates if value changes significantly
7664
7664
  const setUsdValueStable = useCallback((newValue) => {
7665
- // Set USD value immediately - only skip if value is the same
7666
7665
  setUsdValue((prevValue) => {
7667
7666
  // If new value is null/undefined and we have a previous value, keep it
7668
7667
  if ((newValue === null || newValue === undefined) && prevValue !== null) {
7669
7668
  return prevValue;
7670
7669
  }
7670
+ // Only update if value actually changed
7671
+ if (prevValue === newValue) {
7672
+ return prevValue;
7673
+ }
7671
7674
  // Otherwise set the new value
7672
7675
  return newValue;
7673
7676
  });
@@ -7832,6 +7835,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7832
7835
  });
7833
7836
  // eslint-disable-next-line react-hooks/exhaustive-deps
7834
7837
  }, [account?.address, fetchTransactions, cacheTimeout]);
7838
+ // Fallback guard to avoid getting stuck in a loading state (e.g., after page refresh)
7839
+ useEffect(() => {
7840
+ // Only run when we are actually in a loading state
7841
+ if (!isInitializing && !balanceLoading && !isConnecting)
7842
+ return;
7843
+ const timeout = setTimeout(() => {
7844
+ setIsInitializing(false);
7845
+ setBalanceLoading(false);
7846
+ setIsConnecting(false);
7847
+ }, 4000); // force-resolve after 4s
7848
+ return () => clearTimeout(timeout);
7849
+ }, [isInitializing, balanceLoading, isConnecting]);
7835
7850
  // Check chain ID and validate network
7836
7851
  useEffect(() => {
7837
7852
  const checkChain = async () => {
@@ -7881,9 +7896,29 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7881
7896
  const walletsRef = useRef(null);
7882
7897
  // Initialize and subscribe to events
7883
7898
  useEffect(() => {
7899
+ let isMounted = true;
7884
7900
  // Get initial state
7885
7901
  const initialState = connector.getState();
7886
7902
  setStatus(initialState.status);
7903
+ // Immediate hydration from cached state/localStorage to avoid loading flashes on page changes
7904
+ if (initialState.account) {
7905
+ setAccount(initialState.account);
7906
+ // Prefer fresh TWC state, otherwise restore from localStorage cache
7907
+ if (initialState.twcBalance && initialState.twcBalance !== '0' && initialState.twcBalance !== '0.00') {
7908
+ setTwcBalance(initialState.twcBalance);
7909
+ setUsdValueStable(initialState.usdValue ?? null);
7910
+ }
7911
+ else {
7912
+ const cached = loadTWCBalanceFromCache(initialState.account.address);
7913
+ if (cached?.balance) {
7914
+ setTwcBalance(cached.balance);
7915
+ setUsdValueStable(cached.usdValue);
7916
+ }
7917
+ }
7918
+ // Since we have hydrated from cache, avoid showing the loading state
7919
+ setIsInitializing(false);
7920
+ setBalanceLoading(false);
7921
+ }
7887
7922
  // Safety: Clear isConnecting on mount (in case it was stuck from previous session)
7888
7923
  setIsConnecting(false);
7889
7924
  // Only set wallets once to prevent re-renders
@@ -7902,6 +7937,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7902
7937
  setBalanceLoading(false);
7903
7938
  }, 2000);
7904
7939
  connector.getAccount().then(async (acc) => {
7940
+ if (!isMounted)
7941
+ return;
7905
7942
  setAccount(acc);
7906
7943
  // Load balance when account is available
7907
7944
  if (acc && acc.chainType === 'ton') {
@@ -7912,10 +7949,14 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7912
7949
  fetchTONBalance(acc),
7913
7950
  fetchTONNFTs(acc)
7914
7951
  ]);
7952
+ if (!isMounted)
7953
+ return;
7915
7954
  clearTimeout(safetyTimeout);
7916
7955
  setIsInitializing(false);
7917
7956
  }
7918
7957
  catch (err) {
7958
+ if (!isMounted)
7959
+ return;
7919
7960
  clearTimeout(safetyTimeout);
7920
7961
  setIsInitializing(false);
7921
7962
  }
@@ -7924,6 +7965,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7924
7965
  try {
7925
7966
  setBalanceLoading(true);
7926
7967
  const hasRealBalance = await loadBalance();
7968
+ if (!isMounted)
7969
+ return;
7927
7970
  // Always stop loading state after balance fetch
7928
7971
  setBalanceLoading(false);
7929
7972
  clearTimeout(safetyTimeout);
@@ -7931,6 +7974,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7931
7974
  setIsInitializing(false);
7932
7975
  }
7933
7976
  catch (err) {
7977
+ if (!isMounted)
7978
+ return;
7934
7979
  setBalanceLoading(false);
7935
7980
  clearTimeout(safetyTimeout);
7936
7981
  // Always stop initializing on error
@@ -7942,6 +7987,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7942
7987
  const state = connector.getState();
7943
7988
  const stateTwcBalance = state.twcBalance;
7944
7989
  if (acc && stateTwcBalance && stateTwcBalance !== '0' && stateTwcBalance !== '0.00') {
7990
+ if (!isMounted)
7991
+ return;
7945
7992
  setTwcBalance(stateTwcBalance);
7946
7993
  setUsdValueStable(state.usdValue ?? null);
7947
7994
  // Save to cache
@@ -7955,6 +8002,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7955
8002
  // Try to load from cache as fallback
7956
8003
  const cached = loadTWCBalanceFromCache(acc.address);
7957
8004
  if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00') {
8005
+ if (!isMounted)
8006
+ return;
7958
8007
  setTwcBalance(cached.balance);
7959
8008
  setUsdValueStable(cached.usdValue);
7960
8009
  clearTimeout(safetyTimeout);
@@ -7964,6 +8013,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7964
8013
  // No real balance yet, but for EVM wallets, proactively fetch with retries
7965
8014
  if (acc.chainType === 'evm') {
7966
8015
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8016
+ if (!isMounted)
8017
+ return;
7967
8018
  if (result) {
7968
8019
  setTwcBalance(result.balance);
7969
8020
  setUsdValueStable(result.usdValue);
@@ -7980,6 +8031,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7980
8031
  setIsInitializing(false);
7981
8032
  }
7982
8033
  }).catch((error) => {
8034
+ if (!isMounted)
8035
+ return;
7983
8036
  // On error - show connected button with 0 balance
7984
8037
  setTwcBalance('0');
7985
8038
  clearTimeout(safetyTimeout);
@@ -7995,9 +8048,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7995
8048
  fetchTONBalance(acc),
7996
8049
  fetchTONNFTs(acc)
7997
8050
  ]).then(() => {
8051
+ if (!isMounted)
8052
+ return;
7998
8053
  clearTimeout(safetyTimeout);
7999
8054
  setIsInitializing(false);
8000
8055
  }).catch((err) => {
8056
+ if (!isMounted)
8057
+ return;
8001
8058
  clearTimeout(safetyTimeout);
8002
8059
  setIsInitializing(false);
8003
8060
  });
@@ -8005,6 +8062,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8005
8062
  else if (fetchBalance) {
8006
8063
  // For other non-EVM chains: If fetchBalance is provided, load balance and then stop initializing
8007
8064
  fetchTWCBalanceWithRetry(1, 100).then((result) => {
8065
+ if (!isMounted)
8066
+ return;
8008
8067
  if (result) {
8009
8068
  setTwcBalance(result.balance);
8010
8069
  setUsdValueStable(result.usdValue);
@@ -8016,12 +8075,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8016
8075
  clearTimeout(safetyTimeout);
8017
8076
  setIsInitializing(false);
8018
8077
  }).catch(() => {
8078
+ if (!isMounted)
8079
+ return;
8019
8080
  // Stop initializing even on error
8020
8081
  clearTimeout(safetyTimeout);
8021
8082
  setIsInitializing(false);
8022
8083
  });
8023
8084
  }
8024
8085
  else {
8086
+ if (!isMounted)
8087
+ return;
8025
8088
  // No fetchBalance and no cached balance - stop initializing with 0 balance
8026
8089
  setTwcBalance('0');
8027
8090
  clearTimeout(safetyTimeout);
@@ -8032,6 +8095,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8032
8095
  }
8033
8096
  }
8034
8097
  }).catch((err) => {
8098
+ if (!isMounted)
8099
+ return;
8035
8100
  clearTimeout(safetyTimeout);
8036
8101
  setIsInitializing(false);
8037
8102
  // If we can't get account even though status is connected, disconnect
@@ -8044,9 +8109,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8044
8109
  setIsInitializing(true);
8045
8110
  // Set a shorter timeout to prevent stuck loading state
8046
8111
  initTimeout = setTimeout(() => {
8112
+ if (!isMounted)
8113
+ return;
8047
8114
  setIsInitializing(false);
8048
8115
  // If still no account after timeout, ensure we show connect button
8049
8116
  connector.getAccount().then((acc) => {
8117
+ if (!isMounted)
8118
+ return;
8050
8119
  if (!acc) {
8051
8120
  setAccount(null);
8052
8121
  // If status is disconnected and no account, ensure we're fully disconnected
@@ -8058,11 +8127,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8058
8127
  }
8059
8128
  }
8060
8129
  }).catch((err) => {
8130
+ if (!isMounted)
8131
+ return;
8061
8132
  setAccount(null);
8062
8133
  setStatus(ConnectionStatus.DISCONNECTED);
8063
8134
  });
8064
8135
  }, 1500); // Reduced to 1.5 second timeout to prevent stuck loading
8065
8136
  connector.getAccount().then((acc) => {
8137
+ if (!isMounted)
8138
+ return;
8066
8139
  if (initTimeout)
8067
8140
  clearTimeout(initTimeout);
8068
8141
  setAccount(acc);
@@ -8077,6 +8150,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8077
8150
  }
8078
8151
  }
8079
8152
  }).catch((err) => {
8153
+ if (!isMounted)
8154
+ return;
8080
8155
  if (initTimeout)
8081
8156
  clearTimeout(initTimeout);
8082
8157
  setIsInitializing(false);
@@ -8090,6 +8165,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8090
8165
  }
8091
8166
  // Subscribe to events
8092
8167
  const unsubscribeAccount = connector.on(WalletEvent.ACCOUNT_CHANGED, async (acc) => {
8168
+ if (!isMounted)
8169
+ return;
8093
8170
  setAccount(acc);
8094
8171
  // Clear isConnecting when account changes (connection succeeded)
8095
8172
  setIsConnecting(false);
@@ -8110,9 +8187,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8110
8187
  fetchTONBalance(acc),
8111
8188
  fetchTONNFTs(acc)
8112
8189
  ]);
8190
+ if (!isMounted)
8191
+ return;
8113
8192
  setIsInitializing(false);
8114
8193
  }
8115
8194
  catch (err) {
8195
+ if (!isMounted)
8196
+ return;
8116
8197
  setIsInitializing(false);
8117
8198
  }
8118
8199
  }
@@ -8120,9 +8201,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8120
8201
  setBalanceLoading(true);
8121
8202
  try {
8122
8203
  await loadBalance();
8204
+ if (!isMounted)
8205
+ return;
8123
8206
  setIsInitializing(false);
8124
8207
  }
8125
8208
  catch (err) {
8209
+ if (!isMounted)
8210
+ return;
8126
8211
  setIsInitializing(false);
8127
8212
  setBalanceLoading(false);
8128
8213
  }
@@ -8245,6 +8330,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8245
8330
  }
8246
8331
  });
8247
8332
  return () => {
8333
+ isMounted = false;
8248
8334
  clearTimeout(initTimeout);
8249
8335
  unsubscribeAccount();
8250
8336
  unsubscribeStatus();
@@ -8390,16 +8476,23 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8390
8476
  }, [connector]);
8391
8477
  // Load balance when account changes
8392
8478
  useEffect(() => {
8479
+ let isActive = true;
8393
8480
  if (account && fetchBalance) {
8394
8481
  setBalanceLoading(true);
8395
8482
  loadBalance()
8396
8483
  .then(() => {
8484
+ if (!isActive)
8485
+ return;
8397
8486
  // Always stop initializing once balance request completes
8398
8487
  })
8399
8488
  .catch(() => {
8489
+ if (!isActive)
8490
+ return;
8400
8491
  // Ignore errors, we still clear loading states
8401
8492
  })
8402
8493
  .finally(() => {
8494
+ if (!isActive)
8495
+ return;
8403
8496
  setBalanceLoading(false);
8404
8497
  setIsInitializing(false);
8405
8498
  });
@@ -8432,6 +8525,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8432
8525
  // Only fetch if we don't have a balance yet
8433
8526
  if (!hasBalance) {
8434
8527
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8528
+ if (!isActive)
8529
+ return;
8435
8530
  if (result) {
8436
8531
  setTwcBalance(result.balance);
8437
8532
  setUsdValueStable(result.usdValue);
@@ -8447,6 +8542,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8447
8542
  setIsInitializing(false);
8448
8543
  }
8449
8544
  }).catch(() => {
8545
+ if (!isActive)
8546
+ return;
8450
8547
  setIsInitializing(false);
8451
8548
  });
8452
8549
  }
@@ -8467,22 +8564,33 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8467
8564
  }
8468
8565
  }
8469
8566
  }
8567
+ return () => {
8568
+ isActive = false;
8569
+ };
8470
8570
  // eslint-disable-next-line react-hooks/exhaustive-deps
8471
8571
  }, [account?.address, fetchBalance]);
8472
8572
  // Polling mechanism as fallback to ensure TWC balance is always fetched
8473
8573
  useEffect(() => {
8474
- if (!account || account.chainType !== 'evm' || isInitializing) {
8574
+ if (!account || account.chainType !== 'evm') {
8475
8575
  return;
8476
8576
  }
8477
- // If we don't have a balance yet, start polling
8478
- const hasBalance = twcBalance && twcBalance !== '0' && twcBalance !== '0.00';
8479
- if (!hasBalance) {
8577
+ // Check if we already have a balance
8578
+ const currentBalance = twcBalance;
8579
+ const hasBalance = currentBalance && currentBalance !== '0' && currentBalance !== '0.00';
8580
+ if (!hasBalance && !isInitializing) {
8480
8581
  // Poll every 2 seconds, up to 3 times (6 seconds total) - faster polling
8481
8582
  let pollCount = 0;
8482
8583
  const maxPolls = 3;
8584
+ let isActive = true;
8483
8585
  const pollInterval = setInterval(() => {
8586
+ if (!isActive) {
8587
+ clearInterval(pollInterval);
8588
+ return;
8589
+ }
8484
8590
  pollCount++;
8485
8591
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8592
+ if (!isActive)
8593
+ return;
8486
8594
  if (result) {
8487
8595
  setTwcBalance(result.balance);
8488
8596
  setUsdValueStable(result.usdValue);
@@ -8495,17 +8603,22 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8495
8603
  clearInterval(pollInterval);
8496
8604
  }
8497
8605
  }).catch((error) => {
8606
+ if (!isActive)
8607
+ return;
8498
8608
  if (pollCount >= maxPolls) {
8499
8609
  clearInterval(pollInterval);
8500
8610
  }
8501
8611
  });
8502
8612
  }, 2000); // Poll every 2 seconds (faster)
8503
8613
  return () => {
8614
+ isActive = false;
8504
8615
  clearInterval(pollInterval);
8505
8616
  };
8506
8617
  }
8618
+ return undefined;
8619
+ // Only depend on account address - check balance inside effect
8507
8620
  // eslint-disable-next-line react-hooks/exhaustive-deps
8508
- }, [account?.address, twcBalance, isInitializing]);
8621
+ }, [account?.address]);
8509
8622
  // Load transactions when details modal opens
8510
8623
  useEffect(() => {
8511
8624
  if (showDetailsModal && account) {
package/dist/index.js CHANGED
@@ -7532,7 +7532,7 @@ const defaultStyles = {
7532
7532
  fontFamily: 'Lexend, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
7533
7533
  boxShadow: '0 4px 14px 0 rgba(51, 150, 255, 0.39)',
7534
7534
  }};
7535
- const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
7535
+ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className, style, showBalance = false, modalPosition = 'center', theme = 'auto', buttonText = 'Connect Wallet Now', fetchTransactions, getExplorerUrl, fetchBalance: fetchBalanceProp, }) => {
7536
7536
  // Provide a default fetchBalance if not passed
7537
7537
  const fetchBalance = fetchBalanceProp || (async (account) => {
7538
7538
  // Default: return zero balance with symbol based on chain
@@ -7664,12 +7664,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7664
7664
  });
7665
7665
  // Stable USD value updater - only updates if value changes significantly
7666
7666
  const setUsdValueStable = React.useCallback((newValue) => {
7667
- // Set USD value immediately - only skip if value is the same
7668
7667
  setUsdValue((prevValue) => {
7669
7668
  // If new value is null/undefined and we have a previous value, keep it
7670
7669
  if ((newValue === null || newValue === undefined) && prevValue !== null) {
7671
7670
  return prevValue;
7672
7671
  }
7672
+ // Only update if value actually changed
7673
+ if (prevValue === newValue) {
7674
+ return prevValue;
7675
+ }
7673
7676
  // Otherwise set the new value
7674
7677
  return newValue;
7675
7678
  });
@@ -7834,6 +7837,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7834
7837
  });
7835
7838
  // eslint-disable-next-line react-hooks/exhaustive-deps
7836
7839
  }, [account?.address, fetchTransactions, cacheTimeout]);
7840
+ // Fallback guard to avoid getting stuck in a loading state (e.g., after page refresh)
7841
+ React.useEffect(() => {
7842
+ // Only run when we are actually in a loading state
7843
+ if (!isInitializing && !balanceLoading && !isConnecting)
7844
+ return;
7845
+ const timeout = setTimeout(() => {
7846
+ setIsInitializing(false);
7847
+ setBalanceLoading(false);
7848
+ setIsConnecting(false);
7849
+ }, 4000); // force-resolve after 4s
7850
+ return () => clearTimeout(timeout);
7851
+ }, [isInitializing, balanceLoading, isConnecting]);
7837
7852
  // Check chain ID and validate network
7838
7853
  React.useEffect(() => {
7839
7854
  const checkChain = async () => {
@@ -7883,9 +7898,29 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7883
7898
  const walletsRef = React.useRef(null);
7884
7899
  // Initialize and subscribe to events
7885
7900
  React.useEffect(() => {
7901
+ let isMounted = true;
7886
7902
  // Get initial state
7887
7903
  const initialState = connector.getState();
7888
7904
  setStatus(initialState.status);
7905
+ // Immediate hydration from cached state/localStorage to avoid loading flashes on page changes
7906
+ if (initialState.account) {
7907
+ setAccount(initialState.account);
7908
+ // Prefer fresh TWC state, otherwise restore from localStorage cache
7909
+ if (initialState.twcBalance && initialState.twcBalance !== '0' && initialState.twcBalance !== '0.00') {
7910
+ setTwcBalance(initialState.twcBalance);
7911
+ setUsdValueStable(initialState.usdValue ?? null);
7912
+ }
7913
+ else {
7914
+ const cached = loadTWCBalanceFromCache(initialState.account.address);
7915
+ if (cached?.balance) {
7916
+ setTwcBalance(cached.balance);
7917
+ setUsdValueStable(cached.usdValue);
7918
+ }
7919
+ }
7920
+ // Since we have hydrated from cache, avoid showing the loading state
7921
+ setIsInitializing(false);
7922
+ setBalanceLoading(false);
7923
+ }
7889
7924
  // Safety: Clear isConnecting on mount (in case it was stuck from previous session)
7890
7925
  setIsConnecting(false);
7891
7926
  // Only set wallets once to prevent re-renders
@@ -7904,6 +7939,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7904
7939
  setBalanceLoading(false);
7905
7940
  }, 2000);
7906
7941
  connector.getAccount().then(async (acc) => {
7942
+ if (!isMounted)
7943
+ return;
7907
7944
  setAccount(acc);
7908
7945
  // Load balance when account is available
7909
7946
  if (acc && acc.chainType === 'ton') {
@@ -7914,10 +7951,14 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7914
7951
  fetchTONBalance(acc),
7915
7952
  fetchTONNFTs(acc)
7916
7953
  ]);
7954
+ if (!isMounted)
7955
+ return;
7917
7956
  clearTimeout(safetyTimeout);
7918
7957
  setIsInitializing(false);
7919
7958
  }
7920
7959
  catch (err) {
7960
+ if (!isMounted)
7961
+ return;
7921
7962
  clearTimeout(safetyTimeout);
7922
7963
  setIsInitializing(false);
7923
7964
  }
@@ -7926,6 +7967,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7926
7967
  try {
7927
7968
  setBalanceLoading(true);
7928
7969
  const hasRealBalance = await loadBalance();
7970
+ if (!isMounted)
7971
+ return;
7929
7972
  // Always stop loading state after balance fetch
7930
7973
  setBalanceLoading(false);
7931
7974
  clearTimeout(safetyTimeout);
@@ -7933,6 +7976,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7933
7976
  setIsInitializing(false);
7934
7977
  }
7935
7978
  catch (err) {
7979
+ if (!isMounted)
7980
+ return;
7936
7981
  setBalanceLoading(false);
7937
7982
  clearTimeout(safetyTimeout);
7938
7983
  // Always stop initializing on error
@@ -7944,6 +7989,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7944
7989
  const state = connector.getState();
7945
7990
  const stateTwcBalance = state.twcBalance;
7946
7991
  if (acc && stateTwcBalance && stateTwcBalance !== '0' && stateTwcBalance !== '0.00') {
7992
+ if (!isMounted)
7993
+ return;
7947
7994
  setTwcBalance(stateTwcBalance);
7948
7995
  setUsdValueStable(state.usdValue ?? null);
7949
7996
  // Save to cache
@@ -7957,6 +8004,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7957
8004
  // Try to load from cache as fallback
7958
8005
  const cached = loadTWCBalanceFromCache(acc.address);
7959
8006
  if (cached?.balance && cached.balance !== '0' && cached.balance !== '0.00') {
8007
+ if (!isMounted)
8008
+ return;
7960
8009
  setTwcBalance(cached.balance);
7961
8010
  setUsdValueStable(cached.usdValue);
7962
8011
  clearTimeout(safetyTimeout);
@@ -7966,6 +8015,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7966
8015
  // No real balance yet, but for EVM wallets, proactively fetch with retries
7967
8016
  if (acc.chainType === 'evm') {
7968
8017
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8018
+ if (!isMounted)
8019
+ return;
7969
8020
  if (result) {
7970
8021
  setTwcBalance(result.balance);
7971
8022
  setUsdValueStable(result.usdValue);
@@ -7982,6 +8033,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7982
8033
  setIsInitializing(false);
7983
8034
  }
7984
8035
  }).catch((error) => {
8036
+ if (!isMounted)
8037
+ return;
7985
8038
  // On error - show connected button with 0 balance
7986
8039
  setTwcBalance('0');
7987
8040
  clearTimeout(safetyTimeout);
@@ -7997,9 +8050,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7997
8050
  fetchTONBalance(acc),
7998
8051
  fetchTONNFTs(acc)
7999
8052
  ]).then(() => {
8053
+ if (!isMounted)
8054
+ return;
8000
8055
  clearTimeout(safetyTimeout);
8001
8056
  setIsInitializing(false);
8002
8057
  }).catch((err) => {
8058
+ if (!isMounted)
8059
+ return;
8003
8060
  clearTimeout(safetyTimeout);
8004
8061
  setIsInitializing(false);
8005
8062
  });
@@ -8007,6 +8064,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8007
8064
  else if (fetchBalance) {
8008
8065
  // For other non-EVM chains: If fetchBalance is provided, load balance and then stop initializing
8009
8066
  fetchTWCBalanceWithRetry(1, 100).then((result) => {
8067
+ if (!isMounted)
8068
+ return;
8010
8069
  if (result) {
8011
8070
  setTwcBalance(result.balance);
8012
8071
  setUsdValueStable(result.usdValue);
@@ -8018,12 +8077,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8018
8077
  clearTimeout(safetyTimeout);
8019
8078
  setIsInitializing(false);
8020
8079
  }).catch(() => {
8080
+ if (!isMounted)
8081
+ return;
8021
8082
  // Stop initializing even on error
8022
8083
  clearTimeout(safetyTimeout);
8023
8084
  setIsInitializing(false);
8024
8085
  });
8025
8086
  }
8026
8087
  else {
8088
+ if (!isMounted)
8089
+ return;
8027
8090
  // No fetchBalance and no cached balance - stop initializing with 0 balance
8028
8091
  setTwcBalance('0');
8029
8092
  clearTimeout(safetyTimeout);
@@ -8034,6 +8097,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8034
8097
  }
8035
8098
  }
8036
8099
  }).catch((err) => {
8100
+ if (!isMounted)
8101
+ return;
8037
8102
  clearTimeout(safetyTimeout);
8038
8103
  setIsInitializing(false);
8039
8104
  // If we can't get account even though status is connected, disconnect
@@ -8046,9 +8111,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8046
8111
  setIsInitializing(true);
8047
8112
  // Set a shorter timeout to prevent stuck loading state
8048
8113
  initTimeout = setTimeout(() => {
8114
+ if (!isMounted)
8115
+ return;
8049
8116
  setIsInitializing(false);
8050
8117
  // If still no account after timeout, ensure we show connect button
8051
8118
  connector.getAccount().then((acc) => {
8119
+ if (!isMounted)
8120
+ return;
8052
8121
  if (!acc) {
8053
8122
  setAccount(null);
8054
8123
  // If status is disconnected and no account, ensure we're fully disconnected
@@ -8060,11 +8129,15 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8060
8129
  }
8061
8130
  }
8062
8131
  }).catch((err) => {
8132
+ if (!isMounted)
8133
+ return;
8063
8134
  setAccount(null);
8064
8135
  setStatus(exports.ConnectionStatus.DISCONNECTED);
8065
8136
  });
8066
8137
  }, 1500); // Reduced to 1.5 second timeout to prevent stuck loading
8067
8138
  connector.getAccount().then((acc) => {
8139
+ if (!isMounted)
8140
+ return;
8068
8141
  if (initTimeout)
8069
8142
  clearTimeout(initTimeout);
8070
8143
  setAccount(acc);
@@ -8079,6 +8152,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8079
8152
  }
8080
8153
  }
8081
8154
  }).catch((err) => {
8155
+ if (!isMounted)
8156
+ return;
8082
8157
  if (initTimeout)
8083
8158
  clearTimeout(initTimeout);
8084
8159
  setIsInitializing(false);
@@ -8092,6 +8167,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8092
8167
  }
8093
8168
  // Subscribe to events
8094
8169
  const unsubscribeAccount = connector.on(exports.WalletEvent.ACCOUNT_CHANGED, async (acc) => {
8170
+ if (!isMounted)
8171
+ return;
8095
8172
  setAccount(acc);
8096
8173
  // Clear isConnecting when account changes (connection succeeded)
8097
8174
  setIsConnecting(false);
@@ -8112,9 +8189,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8112
8189
  fetchTONBalance(acc),
8113
8190
  fetchTONNFTs(acc)
8114
8191
  ]);
8192
+ if (!isMounted)
8193
+ return;
8115
8194
  setIsInitializing(false);
8116
8195
  }
8117
8196
  catch (err) {
8197
+ if (!isMounted)
8198
+ return;
8118
8199
  setIsInitializing(false);
8119
8200
  }
8120
8201
  }
@@ -8122,9 +8203,13 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8122
8203
  setBalanceLoading(true);
8123
8204
  try {
8124
8205
  await loadBalance();
8206
+ if (!isMounted)
8207
+ return;
8125
8208
  setIsInitializing(false);
8126
8209
  }
8127
8210
  catch (err) {
8211
+ if (!isMounted)
8212
+ return;
8128
8213
  setIsInitializing(false);
8129
8214
  setBalanceLoading(false);
8130
8215
  }
@@ -8247,6 +8332,7 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8247
8332
  }
8248
8333
  });
8249
8334
  return () => {
8335
+ isMounted = false;
8250
8336
  clearTimeout(initTimeout);
8251
8337
  unsubscribeAccount();
8252
8338
  unsubscribeStatus();
@@ -8392,16 +8478,23 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8392
8478
  }, [connector]);
8393
8479
  // Load balance when account changes
8394
8480
  React.useEffect(() => {
8481
+ let isActive = true;
8395
8482
  if (account && fetchBalance) {
8396
8483
  setBalanceLoading(true);
8397
8484
  loadBalance()
8398
8485
  .then(() => {
8486
+ if (!isActive)
8487
+ return;
8399
8488
  // Always stop initializing once balance request completes
8400
8489
  })
8401
8490
  .catch(() => {
8491
+ if (!isActive)
8492
+ return;
8402
8493
  // Ignore errors, we still clear loading states
8403
8494
  })
8404
8495
  .finally(() => {
8496
+ if (!isActive)
8497
+ return;
8405
8498
  setBalanceLoading(false);
8406
8499
  setIsInitializing(false);
8407
8500
  });
@@ -8434,6 +8527,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8434
8527
  // Only fetch if we don't have a balance yet
8435
8528
  if (!hasBalance) {
8436
8529
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8530
+ if (!isActive)
8531
+ return;
8437
8532
  if (result) {
8438
8533
  setTwcBalance(result.balance);
8439
8534
  setUsdValueStable(result.usdValue);
@@ -8449,6 +8544,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8449
8544
  setIsInitializing(false);
8450
8545
  }
8451
8546
  }).catch(() => {
8547
+ if (!isActive)
8548
+ return;
8452
8549
  setIsInitializing(false);
8453
8550
  });
8454
8551
  }
@@ -8469,22 +8566,33 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8469
8566
  }
8470
8567
  }
8471
8568
  }
8569
+ return () => {
8570
+ isActive = false;
8571
+ };
8472
8572
  // eslint-disable-next-line react-hooks/exhaustive-deps
8473
8573
  }, [account?.address, fetchBalance]);
8474
8574
  // Polling mechanism as fallback to ensure TWC balance is always fetched
8475
8575
  React.useEffect(() => {
8476
- if (!account || account.chainType !== 'evm' || isInitializing) {
8576
+ if (!account || account.chainType !== 'evm') {
8477
8577
  return;
8478
8578
  }
8479
- // If we don't have a balance yet, start polling
8480
- const hasBalance = twcBalance && twcBalance !== '0' && twcBalance !== '0.00';
8481
- if (!hasBalance) {
8579
+ // Check if we already have a balance
8580
+ const currentBalance = twcBalance;
8581
+ const hasBalance = currentBalance && currentBalance !== '0' && currentBalance !== '0.00';
8582
+ if (!hasBalance && !isInitializing) {
8482
8583
  // Poll every 2 seconds, up to 3 times (6 seconds total) - faster polling
8483
8584
  let pollCount = 0;
8484
8585
  const maxPolls = 3;
8586
+ let isActive = true;
8485
8587
  const pollInterval = setInterval(() => {
8588
+ if (!isActive) {
8589
+ clearInterval(pollInterval);
8590
+ return;
8591
+ }
8486
8592
  pollCount++;
8487
8593
  fetchTWCBalanceWithRetry(2, 200).then((result) => {
8594
+ if (!isActive)
8595
+ return;
8488
8596
  if (result) {
8489
8597
  setTwcBalance(result.balance);
8490
8598
  setUsdValueStable(result.usdValue);
@@ -8497,17 +8605,22 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8497
8605
  clearInterval(pollInterval);
8498
8606
  }
8499
8607
  }).catch((error) => {
8608
+ if (!isActive)
8609
+ return;
8500
8610
  if (pollCount >= maxPolls) {
8501
8611
  clearInterval(pollInterval);
8502
8612
  }
8503
8613
  });
8504
8614
  }, 2000); // Poll every 2 seconds (faster)
8505
8615
  return () => {
8616
+ isActive = false;
8506
8617
  clearInterval(pollInterval);
8507
8618
  };
8508
8619
  }
8620
+ return undefined;
8621
+ // Only depend on account address - check balance inside effect
8509
8622
  // eslint-disable-next-line react-hooks/exhaustive-deps
8510
- }, [account?.address, twcBalance, isInitializing]);
8623
+ }, [account?.address]);
8511
8624
  // Load transactions when details modal opens
8512
8625
  React.useEffect(() => {
8513
8626
  if (showDetailsModal && account) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiwiflix-wallet-connector",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "Multi-chain wallet connector for Tiwiflix supporting EVM, TON, Solana, and Tron wallets",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",