Skip to content

Commit

Permalink
feat: refactor wallet pairing (#5817)
Browse files Browse the repository at this point in the history
* fix: mm things part 1

* wip: local things

* feat: no eslint-disable

* wip: wip

* feat: almost there

* feat: remove dangerous effect in other providers

* feat: freaking clojures, dis better fix it

* Revert "feat: freaking clojures, dis better fix it"

This reverts commit 846d3bac909c0939d6063a3e5471491ccaf93f6a.

* fix: hell yeah I did it

* feat: add TODO

* feat: i friggin did it, listeners actually properly removed now

* fix: missing event handlers on refresh

* feat: we did it bois

* feat: chainChanged event too

* feat: revert yarnrc

* feat: install alpha from npm

* feat: selectors

* feat: unsafe yarn update directive

* feat: console.error

* feat: bump to actual npm stable

* chore: re-run CI

* chore: trigger CI

* fix: hdwallet checksums

---------

Co-authored-by: Apotheosis <[email protected]>
Co-authored-by: Apotheosis <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2023
1 parent 94b178d commit a4a7106
Show file tree
Hide file tree
Showing 27 changed files with 502 additions and 321 deletions.
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,19 @@
"@shapeshiftoss/caip": "workspace:^",
"@shapeshiftoss/chain-adapters": "workspace:^",
"@shapeshiftoss/errors": "workspace:^",
"@shapeshiftoss/hdwallet-coinbase": "1.52.13",
"@shapeshiftoss/hdwallet-core": "1.52.13",
"@shapeshiftoss/hdwallet-keepkey": "1.52.13",
"@shapeshiftoss/hdwallet-keepkey-webusb": "1.52.13",
"@shapeshiftoss/hdwallet-keplr": "1.52.13",
"@shapeshiftoss/hdwallet-ledger": "1.52.13",
"@shapeshiftoss/hdwallet-ledger-webusb": "1.52.13",
"@shapeshiftoss/hdwallet-metamask": "1.52.13",
"@shapeshiftoss/hdwallet-native": "1.52.13",
"@shapeshiftoss/hdwallet-native-vault": "1.52.13",
"@shapeshiftoss/hdwallet-shapeshift-multichain": "1.52.13",
"@shapeshiftoss/hdwallet-walletconnectv2": "1.52.13",
"@shapeshiftoss/hdwallet-xdefi": "1.52.13",
"@shapeshiftoss/hdwallet-coinbase": "1.52.14",
"@shapeshiftoss/hdwallet-core": "1.52.14",
"@shapeshiftoss/hdwallet-keepkey": "1.52.14",
"@shapeshiftoss/hdwallet-keepkey-webusb": "1.52.14",
"@shapeshiftoss/hdwallet-keplr": "1.52.14",
"@shapeshiftoss/hdwallet-ledger": "1.52.14",
"@shapeshiftoss/hdwallet-ledger-webusb": "1.52.14",
"@shapeshiftoss/hdwallet-metamask": "1.52.14",
"@shapeshiftoss/hdwallet-native": "1.52.14",
"@shapeshiftoss/hdwallet-native-vault": "1.52.14",
"@shapeshiftoss/hdwallet-shapeshift-multichain": "1.52.14",
"@shapeshiftoss/hdwallet-walletconnectv2": "1.52.14",
"@shapeshiftoss/hdwallet-xdefi": "1.52.14",
"@shapeshiftoss/swapper": "workspace:^",
"@shapeshiftoss/types": "workspace:^",
"@shapeshiftoss/unchained-client": "workspace:^",
Expand Down
3 changes: 1 addition & 2 deletions src/components/Layout/Header/NavBar/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ export const UserMenu: React.FC<{ onClick?: () => void }> = memo(({ onClick }) =
const { isConnected, isDemoWallet, walletInfo, connectedType, isLocked, isLoadingLocalWallet } =
state

if (isLocked) disconnect()
const hasWallet = Boolean(walletInfo?.deviceId)
const handleConnect = useCallback(() => {
onClick && onClick()
Expand All @@ -173,7 +172,7 @@ export const UserMenu: React.FC<{ onClick?: () => void }> = memo(({ onClick }) =
<WalletButton
onConnect={handleConnect}
walletInfo={walletInfo}
isConnected={isConnected}
isConnected={isConnected && !isLocked}
isDemoWallet={isDemoWallet}
isLoadingLocalWallet={isLoadingLocalWallet}
data-test='navigation-wallet-dropdown-button'
Expand Down
23 changes: 14 additions & 9 deletions src/context/WalletProvider/Coinbase/components/Connect.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useCallback, useEffect, useState } from 'react'
import React, { useCallback, useState } from 'react'
import type { RouteComponentProps } from 'react-router-dom'
import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { setLocalWalletTypeAndDeviceId } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import type { LocationState } from '../../NativeWallet/types'
Expand All @@ -29,11 +30,7 @@ export const CoinbaseConnect = ({ history }: CoinbaseSetupProps) => {
setLoading(false)
}

useEffect(() => {
;(async () => {
await onProviderChange(KeyManager.Coinbase)
})()
}, [onProviderChange])
const localWallet = useLocalWallet()

const pairDevice = useCallback(async () => {
setError(null)
Expand All @@ -42,11 +39,19 @@ export const CoinbaseConnect = ({ history }: CoinbaseSetupProps) => {
const adapter = await getAdapter(KeyManager.Coinbase)
if (adapter) {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')

const wallet = await adapter.pairDevice()
if (!wallet) {
setErrorLoading('walletProvider.errors.walletNotFound')
throw new Error('Call to hdwallet-coinbase::pairDevice returned null or undefined')
}

await onProviderChange(KeyManager.Coinbase, wallet)

const { name, icon } = CoinbaseConfig
const deviceId = await wallet.getDeviceID()
const isLocked = await wallet.isLocked()
Expand All @@ -57,7 +62,7 @@ export const CoinbaseConnect = ({ history }: CoinbaseSetupProps) => {
})
dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: true })
dispatch({ type: WalletActions.SET_IS_LOCKED, payload: isLocked })
setLocalWalletTypeAndDeviceId(KeyManager.Coinbase, deviceId)
localWallet.setLocalWalletTypeAndDeviceId(KeyManager.Coinbase, deviceId)
dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false })
} catch (e: any) {
console.error(e, 'Coinbase Connect: There was an error initializing the wallet')
Expand All @@ -66,7 +71,7 @@ export const CoinbaseConnect = ({ history }: CoinbaseSetupProps) => {
}
}
setLoading(false)
}, [dispatch, getAdapter, history])
}, [dispatch, getAdapter, history, localWallet, onProviderChange])

return (
<ConnectModal
Expand Down
16 changes: 13 additions & 3 deletions src/context/WalletProvider/KeepKey/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { CircularProgress } from 'components/CircularProgress/CircularProgress'
import { Text } from 'components/Text'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { setLocalWalletTypeAndDeviceId } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { KeepKeyConfig } from '../config'
import { FailureType, MessageType } from '../KeepKeyTypes'
Expand All @@ -39,6 +40,7 @@ const translateError = (event: Event) => {

export const KeepKeyConnect = () => {
const { dispatch, getAdapter, state } = useWallet()
const localWallet = useLocalWallet()
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)

Expand All @@ -57,6 +59,11 @@ export const KeepKeyConnect = () => {

const wallet = await (async () => {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')

const sdk = await setupKeepKeySDK()

// There is no need to instantiate KkRestAdapter and attempt pairing if SDK is undefined
Expand Down Expand Up @@ -109,15 +116,18 @@ export const KeepKeyConnect = () => {
},
})
dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: true })
setLocalWalletTypeAndDeviceId(KeyManager.KeepKey, state.keyring.getAlias(deviceId))
localWallet.setLocalWalletTypeAndDeviceId(
KeyManager.KeepKey,
state.keyring.getAlias(deviceId),
)
dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false })
} catch (e) {
console.error(e)
setErrorLoading('walletProvider.keepKey.errors.unknown')
}

setLoading(false)
}, [dispatch, getAdapter, setErrorLoading, state.keyring])
}, [dispatch, getAdapter, localWallet, setErrorLoading, state.keyring])
return (
<>
<ModalHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useTranslate } from 'react-polyglot'
import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { getLocalWalletType } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import type { DeviceState, InitialState } from 'context/WalletProvider/WalletProvider'
import { usePoll } from 'hooks/usePoll/usePoll'

Expand All @@ -24,6 +24,7 @@ export const useKeepKeyEventHandler = (
modal,
deviceState: { disposition, isUpdatingPin },
} = state
const localWallet = useLocalWallet()

const toast = useToast()
const translate = useTranslate()
Expand All @@ -33,7 +34,7 @@ export const useKeepKeyEventHandler = (
// This effect should run and attach event handlers on KeepKey only
// Failure to check for the localWalletType will result in a bunch of random bugs on other wallets
// being mistakenly identified as KeepKey
const localWalletType = getLocalWalletType()
const { localWalletType } = localWallet
if (localWalletType !== KeyManager.KeepKey) return
const handleEvent = (e: [deviceId: string, message: Event]) => {
const [deviceId, event] = e
Expand Down Expand Up @@ -277,5 +278,6 @@ export const useKeepKeyEventHandler = (
poll,
state.connectedType,
state.modalType,
localWallet,
])
}
13 changes: 10 additions & 3 deletions src/context/WalletProvider/Keplr/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import type { RouteComponentProps } from 'react-router-dom'
import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { setLocalWalletTypeAndDeviceId } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import { KeplrConfig } from '../config'
Expand All @@ -19,6 +20,7 @@ export interface KeplrSetupProps

export const KeplrConnect = ({ history }: KeplrSetupProps) => {
const { dispatch, getAdapter } = useWallet()
const localWallet = useLocalWallet()
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)

Expand All @@ -30,6 +32,11 @@ export const KeplrConnect = ({ history }: KeplrSetupProps) => {
setLoading(true)
const adapter = await getAdapter(KeyManager.Keplr)
if (adapter) {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')

const wallet = await adapter.pairDevice()
if (!wallet) {
setErrorLoading('walletProvider.errors.walletNotFound')
Expand All @@ -52,7 +59,7 @@ export const KeplrConnect = ({ history }: KeplrSetupProps) => {
payload: { wallet, name, icon, deviceId, connectedType: KeyManager.Keplr },
})
dispatch({ type: WalletActions.SET_IS_CONNECTED, payload: true })
setLocalWalletTypeAndDeviceId(KeyManager.Keplr, deviceId)
localWallet.setLocalWalletTypeAndDeviceId(KeyManager.Keplr, deviceId)
dispatch({ type: WalletActions.SET_WALLET_MODAL, payload: false })

/** Reinitialize wallet when user changes accounts */
Expand All @@ -69,7 +76,7 @@ export const KeplrConnect = ({ history }: KeplrSetupProps) => {
}
}
setLoading(false)
}, [dispatch, getAdapter, history])
}, [dispatch, getAdapter, history, localWallet])

return (
<ConnectModal
Expand Down
13 changes: 10 additions & 3 deletions src/context/WalletProvider/Ledger/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import type { RouteComponentProps } from 'react-router-dom'
import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { setLocalWalletTypeAndDeviceId } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import { LedgerConfig } from '../config'
Expand All @@ -19,6 +20,7 @@ export interface LedgerSetupProps

export const LedgerConnect = ({ history }: LedgerSetupProps) => {
const { dispatch: walletDispatch, getAdapter } = useWallet()
const localWallet = useLocalWallet()
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)

Expand All @@ -34,6 +36,11 @@ export const LedgerConnect = ({ history }: LedgerSetupProps) => {
const adapter = await getAdapter(KeyManager.Ledger)
if (adapter) {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')

const wallet = await adapter.pairDevice()

if (!wallet) {
Expand All @@ -50,7 +57,7 @@ export const LedgerConnect = ({ history }: LedgerSetupProps) => {
payload: { wallet, name, icon, deviceId, connectedType: KeyManager.Ledger },
})
walletDispatch({ type: WalletActions.SET_IS_CONNECTED, payload: true })
setLocalWalletTypeAndDeviceId(KeyManager.Ledger, deviceId)
localWallet.setLocalWalletTypeAndDeviceId(KeyManager.Ledger, deviceId)
history.push('/ledger/chains')
} catch (e: any) {
console.error(e)
Expand All @@ -59,7 +66,7 @@ export const LedgerConnect = ({ history }: LedgerSetupProps) => {
}
}
setLoading(false)
}, [getAdapter, history, setErrorLoading, walletDispatch])
}, [getAdapter, history, localWallet, setErrorLoading, walletDispatch])

return (
<ConnectModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Dispatch } from 'react'
import { useEffect } from 'react'
import type { ActionTypes } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { getLocalWalletType } from 'context/WalletProvider/local-wallet'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import type { DeviceState, InitialState } from 'context/WalletProvider/WalletProvider'

export const useLedgerEventHandler = (
Expand All @@ -13,12 +13,13 @@ export const useLedgerEventHandler = (
setDeviceState: (deviceState: Partial<DeviceState>) => void,
) => {
const { keyring, modal } = state
const localWallet = useLocalWallet()

useEffect(() => {
// This effect should run and attach event handlers on Ledger only
// Failure to check for the localWalletType will result in a bunch of random bugs on other wallets
// being mistakenly identified as KeepKey
const localWalletType = getLocalWalletType()
const { localWalletType } = localWallet
if (localWalletType !== KeyManager.Ledger) return

const handleConnect = async (_deviceId: string) => {
Expand Down Expand Up @@ -50,5 +51,6 @@ export const useLedgerEventHandler = (
setDeviceState,
state.connectedType,
state.modalType,
localWallet,
])
}
Loading

0 comments on commit a4a7106

Please sign in to comment.