From 063194c97db0e5b265589fd626d4a9f03e92beb2 Mon Sep 17 00:00:00 2001 From: katspaugh Date: Tue, 1 Aug 2023 12:54:21 +0200 Subject: [PATCH 1/2] Fix: re-connecting a locked wallet --- src/hooks/wallets/useOnboard.ts | 12 +++---- src/utils/__tests__/wallet.test.ts | 53 ++++++++++++++++++++++++++++++ src/utils/wallets.ts | 8 ++--- 3 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 src/utils/__tests__/wallet.test.ts diff --git a/src/hooks/wallets/useOnboard.ts b/src/hooks/wallets/useOnboard.ts index d440c01c8c..e1d09199fe 100644 --- a/src/hooks/wallets/useOnboard.ts +++ b/src/hooks/wallets/useOnboard.ts @@ -179,17 +179,15 @@ export const useInitOnboard = () => { } // Connect to the last connected wallet - enableWallets().then(() => { + enableWallets().then(async () => { if (onboard.state.get().wallets.length > 0) return const label = lastWalletStorage.get() - if (!label) return + const isUnlocked = label && (await isWalletUnlocked(label)) + if (!isUnlocked) return - isWalletUnlocked(label).then((isUnlocked) => { - isUnlocked && - connectWallet(onboard, { - autoSelect: { label, disableModals: false }, - }) + connectWallet(onboard, { + autoSelect: { label, disableModals: true }, }) }) }, [chain, onboard]) diff --git a/src/utils/__tests__/wallet.test.ts b/src/utils/__tests__/wallet.test.ts new file mode 100644 index 0000000000..91370a8135 --- /dev/null +++ b/src/utils/__tests__/wallet.test.ts @@ -0,0 +1,53 @@ +import { isWalletUnlocked, WalletNames } from '../wallets' + +describe('utils/wallet', () => { + it('should check if MetaMask is unlocked and return false', async () => { + // mock window.ethereum + Object.defineProperty(window, 'ethereum', { + value: { + isMetaMask: true, + selectedAddress: '0x123', + isConnected: () => true, + _metamask: { + isUnlocked: () => Promise.resolve(false), + }, + }, + writable: true, + }) + const result = await isWalletUnlocked(WalletNames.METAMASK) + expect(result).toBe(false) + }) + + it('should check if MetaMask is unlocked and return true', async () => { + // mock window.ethereum + Object.defineProperty(window, 'ethereum', { + value: { + isMetaMask: true, + selectedAddress: '0x123', + isConnected: () => true, + _metamask: { + isUnlocked: () => Promise.resolve(true), + }, + }, + writable: true, + }) + const result = await isWalletUnlocked(WalletNames.METAMASK) + expect(result).toBe(true) + }) + + it('should check if WalletConnect is unlocked', async () => { + window.localStorage.setItem('walletconnect', 'true') + + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT)).toBe(true) + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT_V2)).toBe(true) + + window.localStorage.removeItem('walletconnect') + + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT)).toBe(false) + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT_V2)).toBe(false) + }) + + it('should return false for unhandled wallets', async () => { + expect(await isWalletUnlocked('PINEAPPLE')).toBe(false) + }) +}) diff --git a/src/utils/wallets.ts b/src/utils/wallets.ts index 969732049f..5fb3485355 100644 --- a/src/utils/wallets.ts +++ b/src/utils/wallets.ts @@ -32,17 +32,13 @@ export const WalletNames = { export const isWalletUnlocked = async (walletName: string): Promise => { if (typeof window === 'undefined') return false - if (window.ethereum?.isConnected?.()) { - return true - } - // Only MetaMask exposes a method to check if the wallet is unlocked if (walletName === WalletNames.METAMASK) { - return window.ethereum?._metamask?.isUnlocked?.() || false + return (await window.ethereum?._metamask?.isUnlocked?.()) || false } // Wallet connect creates a localStorage entry when connected and removes it when disconnected - if (walletName === WalletNames.WALLET_CONNECT) { + if (walletName === WalletNames.WALLET_CONNECT || walletName === WalletNames.WALLET_CONNECT_V2) { return window.localStorage.getItem('walletconnect') !== null } From 0f17711e9e6550e60d9aaa8490bf508c9cec2fcf Mon Sep 17 00:00:00 2001 From: katspaugh Date: Tue, 1 Aug 2023 13:08:26 +0200 Subject: [PATCH 2/2] Reconnect WC v2 --- src/utils/__tests__/wallet.test.ts | 12 ++++++++++-- src/utils/wallets.ts | 10 ++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/utils/__tests__/wallet.test.ts b/src/utils/__tests__/wallet.test.ts index 91370a8135..10b8451497 100644 --- a/src/utils/__tests__/wallet.test.ts +++ b/src/utils/__tests__/wallet.test.ts @@ -35,15 +35,23 @@ describe('utils/wallet', () => { expect(result).toBe(true) }) - it('should check if WalletConnect is unlocked', async () => { + it('should check if WalletConnect v1 is unlocked', async () => { window.localStorage.setItem('walletconnect', 'true') expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT)).toBe(true) - expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT_V2)).toBe(true) window.localStorage.removeItem('walletconnect') expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT)).toBe(false) + }) + + it('should check if WalletConnect v2 is unlocked', async () => { + window.localStorage.setItem('wc@2:client:0.3//session', '[{"topic":"123"}]') + + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT_V2)).toBe(true) + + window.localStorage.removeItem('wc@2:client:0.3//session') + expect(await isWalletUnlocked(WalletNames.WALLET_CONNECT_V2)).toBe(false) }) diff --git a/src/utils/wallets.ts b/src/utils/wallets.ts index 5fb3485355..c73abac5ac 100644 --- a/src/utils/wallets.ts +++ b/src/utils/wallets.ts @@ -37,8 +37,14 @@ export const isWalletUnlocked = async (walletName: string): Promise => return (await window.ethereum?._metamask?.isUnlocked?.()) || false } - // Wallet connect creates a localStorage entry when connected and removes it when disconnected - if (walletName === WalletNames.WALLET_CONNECT || walletName === WalletNames.WALLET_CONNECT_V2) { + // WalletConnect v2 + if (walletName === WalletNames.WALLET_CONNECT_V2) { + const wcSession = window.localStorage.getItem('wc@2:client:0.3//session') + return !!wcSession && wcSession !== '[]' + } + + // WalletConnect v1 creates a localStorage entry when connected and removes it when disconnected + if (walletName === WalletNames.WALLET_CONNECT) { return window.localStorage.getItem('walletconnect') !== null }