diff --git a/src/context/WalletProvider/WalletProvider.tsx b/src/context/WalletProvider/WalletProvider.tsx index 2235841d614..83997e88df2 100644 --- a/src/context/WalletProvider/WalletProvider.tsx +++ b/src/context/WalletProvider/WalletProvider.tsx @@ -674,32 +674,46 @@ export const WalletProvider = ({ children }: { children: React.ReactNode }): JSX }) } - const localMetaMaskWallet = await metamaskAdapter?.pairDevice() - if (localMetaMaskWallet) { - const { name, icon } = SUPPORTED_WALLETS[KeyManager.MetaMask] - try { + try { + const localMetaMaskWallet = await metamaskAdapter?.pairDevice() + if (localMetaMaskWallet) { + const { name, icon } = SUPPORTED_WALLETS[KeyManager.MetaMask] await localMetaMaskWallet.initialize() const deviceId = await localMetaMaskWallet.getDeviceID() - dispatch({ - type: WalletActions.SET_WALLET, - payload: { - wallet: localMetaMaskWallet, - name, - icon, - deviceId, - connectedType: KeyManager.MetaMask, - }, - }) - dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) - dispatch({ - type: WalletActions.SET_IS_CONNECTED, - payload: true, - }) - } catch (e) { + + // Check if wallet is actually unlocked by verifying ethAddress is available + // If ethAddress is empty, the wallet is locked - don't claim it's connected + const ethAddress = (localMetaMaskWallet as MetaMaskMultiChainHDWallet).ethAddress + + if (!ethAddress) { + // Wallet is locked - set locked state and disconnect + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) + } else { + dispatch({ + type: WalletActions.SET_WALLET, + payload: { + wallet: localMetaMaskWallet, + name, + icon, + deviceId, + connectedType: KeyManager.MetaMask, + }, + }) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) + dispatch({ + type: WalletActions.SET_IS_CONNECTED, + payload: true, + }) + } + } else { disconnect() } - } else { - disconnect() + } catch (e) { + // pairDevice/initialize/getDeviceID failed - wallet is likely locked or disconnected + console.error('MetaMask: Failed to reconnect wallet on app load:', e) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) } dispatch({ type: WalletActions.SET_LOCAL_WALLET_LOADING, payload: false }) break @@ -717,32 +731,42 @@ export const WalletProvider = ({ children }: { children: React.ReactNode }): JSX }) } - const localPhantomWallet = await phantomAdapter?.pairDevice() - if (localPhantomWallet) { - const { name, icon } = SUPPORTED_WALLETS[KeyManager.Phantom] - try { + try { + const localPhantomWallet = await phantomAdapter?.pairDevice() + if (localPhantomWallet) { + const { name, icon } = SUPPORTED_WALLETS[KeyManager.Phantom] await localPhantomWallet.initialize() const deviceId = await localPhantomWallet.getDeviceID() - dispatch({ - type: WalletActions.SET_WALLET, - payload: { - wallet: localPhantomWallet, - name, - icon, - deviceId, - connectedType: KeyManager.Phantom, - }, - }) - dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) - dispatch({ - type: WalletActions.SET_IS_CONNECTED, - payload: true, - }) - } catch (e) { + + if (!deviceId) { + // Wallet is locked - set locked state + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) + } else { + dispatch({ + type: WalletActions.SET_WALLET, + payload: { + wallet: localPhantomWallet, + name, + icon, + deviceId, + connectedType: KeyManager.Phantom, + }, + }) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) + dispatch({ + type: WalletActions.SET_IS_CONNECTED, + payload: true, + }) + } + } else { disconnect() } - } else { - disconnect() + } catch (e) { + // pairDevice/initialize/getDeviceID failed - wallet is likely locked or disconnected + console.error('Phantom: Failed to reconnect wallet on app load:', e) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) } dispatch({ type: WalletActions.SET_LOCAL_WALLET_LOADING, payload: false }) break @@ -760,32 +784,42 @@ export const WalletProvider = ({ children }: { children: React.ReactNode }): JSX }) } - const localCoinbaseWallet = await coinbaseAdapter?.pairDevice() - if (localCoinbaseWallet) { - const { name, icon } = SUPPORTED_WALLETS[KeyManager.Coinbase] - try { + try { + const localCoinbaseWallet = await coinbaseAdapter?.pairDevice() + if (localCoinbaseWallet) { + const { name, icon } = SUPPORTED_WALLETS[KeyManager.Coinbase] await localCoinbaseWallet.initialize() const deviceId = await localCoinbaseWallet.getDeviceID() - dispatch({ - type: WalletActions.SET_WALLET, - payload: { - wallet: localCoinbaseWallet, - name, - icon, - deviceId, - connectedType: KeyManager.Coinbase, - }, - }) - dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) - dispatch({ - type: WalletActions.SET_IS_CONNECTED, - payload: true, - }) - } catch (e) { + + if (!deviceId) { + // Wallet is locked - set locked state + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) + } else { + dispatch({ + type: WalletActions.SET_WALLET, + payload: { + wallet: localCoinbaseWallet, + name, + icon, + deviceId, + connectedType: KeyManager.Coinbase, + }, + }) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) + dispatch({ + type: WalletActions.SET_IS_CONNECTED, + payload: true, + }) + } + } else { disconnect() } - } else { - disconnect() + } catch (e) { + // pairDevice/initialize/getDeviceID failed - wallet is likely locked or disconnected + console.error('Coinbase: Failed to reconnect wallet on app load:', e) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) } dispatch({ type: WalletActions.SET_LOCAL_WALLET_LOADING, payload: false }) break diff --git a/src/context/WalletProvider/useEip1993EventHandler.ts b/src/context/WalletProvider/useEip1993EventHandler.ts index af68d09d4fa..b69e89ea612 100644 --- a/src/context/WalletProvider/useEip1993EventHandler.ts +++ b/src/context/WalletProvider/useEip1993EventHandler.ts @@ -63,38 +63,50 @@ export const useEip1993EventHandler = ({ const _isLocked = Array.isArray(accountsOrChains) && accountsOrChains.length === 0 if (_isLocked) { + // Wallet is locked - set both locked state AND disconnected state + // This prevents the wallet drawer overlay from blocking interaction dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) - } else { - // Either a chain change or a wallet unlock - ensure we set isLocked to false before continuing to avoid bad states - dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) + // Return early - don't try to re-pair when wallet is locked + return } + // Either a chain change or a wallet unlock - ensure we set isLocked to false before continuing to avoid bad states + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: false }) + const adapter = (await getAdapter(localWalletType)) as MetaMaskAdapter | PhantomAdapter | null // Re-pair - which in case of accounts changed means the user will be prompted to connect their current account if they didn't do so // Note, this isn't guaranteed to work, not all wallets are the same, some (i.e MM) have this weird flow where connecting to an unconnected account // from a connected account can only be done from the wallet itself and not programmatically - const localWallet = await adapter?.pairDevice() - - if (!localWallet) return - - await localWallet.initialize() - const deviceId = await localWallet?.getDeviceID() - - if (!deviceId) return - - const { icon, name } = SUPPORTED_WALLETS[localWalletType] - - dispatch({ - type: WalletActions.SET_WALLET, - payload: { - wallet: localWallet, - name, - icon, - deviceId, - connectedType: localWalletType, - }, - }) + try { + const localWallet = await adapter?.pairDevice() + + if (!localWallet) return + + await localWallet.initialize() + const deviceId = await localWallet?.getDeviceID() + + if (!deviceId) return + + const { icon, name } = SUPPORTED_WALLETS[localWalletType] + + dispatch({ + type: WalletActions.SET_WALLET, + payload: { + wallet: localWallet, + name, + icon, + deviceId, + connectedType: localWalletType, + }, + }) + } catch (e) { + // If pairDevice/initialize/getDeviceID fails, wallet is likely locked or disconnected + console.error('Failed to re-pair wallet after account/chain change:', e) + dispatch({ type: WalletActions.SET_IS_LOCKED, payload: true }) + dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: false }) + } }, [dispatch, getAdapter, localWalletType, state.adapters], )