From 4e462ddbef4b79aa3c5842c4ed3c145e3f2ad029 Mon Sep 17 00:00:00 2001 From: Vignesh Mohankumar Date: Thu, 7 Jul 2022 09:17:49 -1000 Subject: [PATCH] refactor: extract Web3Provider hooks, create internal Connection representation (#4040) * refactor: separate hooks file for Web3Provider * move utils * rename + comments * rename Wallet enum to ConnectionType * more wallet -> connectiontype * more wallet -> connectiontype * move hooks * use Connection everywhere * connector -> connection * generic getConnection * rename injected -> injectedConnection * check connectionType * rm unused --- src/components/AccountDetails/index.tsx | 53 ++---- src/components/CurrencyInputPanel/index.tsx | 2 +- src/components/Header/NetworkSelector.tsx | 10 +- src/components/Header/index.tsx | 2 +- src/components/Identicon/StatusIcon.tsx | 48 ++++-- src/components/PositionCard/V2.tsx | 2 +- src/components/PositionCard/index.tsx | 2 +- .../SearchModal/CurrencyList/index.test.tsx | 2 +- .../SearchModal/CurrencyList/index.tsx | 2 +- src/components/SearchModal/CurrencySearch.tsx | 2 +- src/components/WalletModal/index.tsx | 23 +-- src/components/Web3Provider/index.tsx | 43 +---- src/components/Web3Status/index.tsx | 26 +-- src/components/vote/DelegateModal.tsx | 2 +- src/connection/index.ts | 100 ++++++++++++ src/connection/utils.ts | 44 +++++ src/connectors/index.ts | 151 ------------------ src/constants/wallet.ts | 30 ++-- src/hooks/useConnectors.ts | 34 ++++ src/hooks/useEagerlyConnect.ts | 42 +++++ src/hooks/useSocksBalance.ts | 2 +- src/hooks/useWrapCallback.tsx | 2 +- src/pages/Earn/Manage.tsx | 2 +- src/pages/MigrateV2/MigrateV2Pair.tsx | 2 +- src/pages/MigrateV2/index.tsx | 2 +- src/pages/Pool/v2.tsx | 2 +- src/pages/PoolFinder/index.tsx | 2 +- src/pages/Vote/Landing.tsx | 2 +- src/pages/Vote/VotePage.tsx | 2 +- src/state/burn/hooks.tsx | 2 +- src/state/connection/constants.ts | 7 + src/state/{wallet => connection}/hooks.ts | 0 src/state/connection/reducer.ts | 33 ++++ src/state/index.ts | 4 +- src/state/mint/hooks.tsx | 2 +- src/state/mint/v3/hooks.tsx | 2 +- src/state/swap/hooks.tsx | 2 +- src/state/user/reducer.ts | 4 +- src/state/wallet/reducer.ts | 33 ---- src/utils/switchChain.ts | 23 ++- 40 files changed, 389 insertions(+), 361 deletions(-) create mode 100644 src/connection/index.ts create mode 100644 src/connection/utils.ts delete mode 100644 src/connectors/index.ts create mode 100644 src/hooks/useConnectors.ts create mode 100644 src/hooks/useEagerlyConnect.ts create mode 100644 src/state/connection/constants.ts rename src/state/{wallet => connection}/hooks.ts (100%) create mode 100644 src/state/connection/reducer.ts delete mode 100644 src/state/wallet/reducer.ts diff --git a/src/components/AccountDetails/index.tsx b/src/components/AccountDetails/index.tsx index c2f1768be1..9a09647194 100644 --- a/src/components/AccountDetails/index.tsx +++ b/src/components/AccountDetails/index.tsx @@ -1,7 +1,8 @@ import { Trans } from '@lingui/macro' import { useWeb3React } from '@web3-react/core' -import { Connector } from '@web3-react/types' import CopyHelper from 'components/AccountDetails/Copy' +import { coinbaseWalletConnection, injectedConnection } from 'connection' +import { getConnection } from 'connection/utils' import { useCallback, useContext } from 'react' import { ExternalLink as LinkIcon } from 'react-feather' import { useAppDispatch } from 'state/hooks' @@ -10,7 +11,6 @@ import styled, { ThemeContext } from 'styled-components/macro' import { isMobile } from 'utils/userAgent' import { ReactComponent as Close } from '../../assets/images/x.svg' -import { coinbaseWallet, injected } from '../../connectors' import { SUPPORTED_WALLETS } from '../../constants/wallet' import { clearAllTransactions } from '../../state/transactions/reducer' import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme' @@ -163,29 +163,6 @@ const WalletName = styled.div` color: ${({ theme }) => theme.text3}; ` -const IconWrapper = styled.div<{ size?: number }>` - ${({ theme }) => theme.flexColumnNoWrap}; - align-items: center; - justify-content: center; - margin-right: 8px; - & > img, - span { - height: ${({ size }) => (size ? size + 'px' : '32px')}; - width: ${({ size }) => (size ? size + 'px' : '32px')}; - } - ${({ theme }) => theme.mediaWidth.upToMedium` - align-items: flex-end; - `}; -` - -function WrappedStatusIcon({ connector }: { connector: Connector }) { - return ( - - - - ) -} - const TransactionListWrapper = styled.div` ${({ theme }) => theme.flexColumnNoWrap}; ` @@ -228,6 +205,8 @@ export default function AccountDetails({ openOptions, }: AccountDetailsProps) { const { chainId, account, connector } = useWeb3React() + const connectionType = getConnection(connector).type + const theme = useContext(ThemeContext) const dispatch = useAppDispatch() @@ -241,7 +220,8 @@ export default function AccountDetails({ const name = Object.keys(SUPPORTED_WALLETS) .filter( (k) => - SUPPORTED_WALLETS[k].connector === connector && (connector !== injected || isMetaMask === (k === 'METAMASK')) + SUPPORTED_WALLETS[k].connector === connector && + (connector !== injectedConnection.connector || isMetaMask === (k === 'METAMASK')) ) .map((k) => SUPPORTED_WALLETS[k].name)[0] return ( @@ -281,7 +261,7 @@ export default function AccountDetails({ // Coinbase Wallet SDK does not emit a disconnect event to the provider, // which is what web3-react uses to reset state. As a workaround we manually // reset state. - if (connector === coinbaseWallet) { + if (connector === coinbaseWalletConnection.connector) { connector.resetState() } } else { @@ -308,21 +288,10 @@ export default function AccountDetails({ - {ENSName ? ( - <> -
- {connector && } -

{ENSName}

-
- - ) : ( - <> -
- {connector && } -

{account && shortenAddress(account)}

-
- - )} +
+ +

{ENSName ? ENSName : account && shortenAddress(account)}

+
diff --git a/src/components/CurrencyInputPanel/index.tsx b/src/components/CurrencyInputPanel/index.tsx index 9b6f6fb7df..6c7a35be69 100644 --- a/src/components/CurrencyInputPanel/index.tsx +++ b/src/components/CurrencyInputPanel/index.tsx @@ -12,7 +12,7 @@ import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg' import useTheme from '../../hooks/useTheme' -import { useCurrencyBalance } from '../../state/wallet/hooks' +import { useCurrencyBalance } from '../../state/connection/hooks' import { ThemedText } from '../../theme' import { ButtonGray } from '../Button' import CurrencyLogo from '../CurrencyLogo' diff --git a/src/components/Header/NetworkSelector.tsx b/src/components/Header/NetworkSelector.tsx index 7354027e90..082936d237 100644 --- a/src/components/Header/NetworkSelector.tsx +++ b/src/components/Header/NetworkSelector.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/macro' import { useWeb3React } from '@web3-react/core' -import { getWalletForConnector } from 'connectors' +import { getConnection } from 'connection/utils' import { CHAIN_INFO } from 'constants/chainInfo' import { CHAIN_IDS_TO_NAMES, SupportedChainId } from 'constants/chains' import { useOnClickOutside } from 'hooks/useOnClickOutside' @@ -12,8 +12,8 @@ import { ArrowDownCircle, ChevronDown } from 'react-feather' import { useHistory } from 'react-router-dom' import { useModalOpen, useToggleModal } from 'state/application/hooks' import { addPopup, ApplicationModal } from 'state/application/reducer' +import { updateConnectionError } from 'state/connection/reducer' import { useAppDispatch } from 'state/hooks' -import { updateWalletError } from 'state/wallet/reducer' import styled from 'styled-components/macro' import { ExternalLink, MEDIA_WIDTHS } from 'theme' import { replaceURLParam } from 'utils/routes' @@ -285,15 +285,15 @@ export default function NetworkSelector() { async (targetChain: number, skipToggle?: boolean) => { if (!connector) return - const wallet = getWalletForConnector(connector) + const connectionType = getConnection(connector).type try { - dispatch(updateWalletError({ wallet, error: undefined })) + dispatch(updateConnectionError({ connectionType, error: undefined })) await switchChain(connector, targetChain) } catch (error) { console.error('Failed to switch networks', error) - dispatch(updateWalletError({ wallet, error: error.message })) + dispatch(updateConnectionError({ connectionType, error: error.message })) dispatch(addPopup({ content: { failedSwitchNetwork: targetChain }, key: `failed-network-switch` })) } diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index f4f542a337..73cd16d666 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -9,9 +9,9 @@ import { NavLink } from 'react-router-dom' import { Text } from 'rebass' import { useShowClaimPopup, useToggleSelfClaimModal } from 'state/application/hooks' import { useUserHasAvailableClaim } from 'state/claim/hooks' +import { useNativeCurrencyBalances } from 'state/connection/hooks' import { useUserHasSubmittedClaim } from 'state/transactions/hooks' import { useDarkModeManager } from 'state/user/hooks' -import { useNativeCurrencyBalances } from 'state/wallet/hooks' import styled from 'styled-components/macro' import { isChainAllowed } from 'utils/switchChain' diff --git a/src/components/Identicon/StatusIcon.tsx b/src/components/Identicon/StatusIcon.tsx index f51e3ccdb2..a843f3a701 100644 --- a/src/components/Identicon/StatusIcon.tsx +++ b/src/components/Identicon/StatusIcon.tsx @@ -1,22 +1,42 @@ -import { Connector } from '@web3-react/types' +import { ConnectionType } from 'connection' +import styled from 'styled-components/macro' import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg' import FortmaticIcon from '../../assets/images/fortmaticIcon.png' import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg' -import { coinbaseWallet, fortmatic, injected, walletConnect } from '../../connectors' import Identicon from '../Identicon' -export default function StatusIcon({ connector }: { connector: Connector }) { - switch (connector) { - case injected: - return - case walletConnect: - return WalletConnect - case coinbaseWallet: - return Coinbase Wallet - case fortmatic: - return Fortmatic - default: - return null +const IconWrapper = styled.div<{ size?: number }>` + ${({ theme }) => theme.flexColumnNoWrap}; + align-items: center; + justify-content: center; + margin-right: 8px; + & > img, + span { + height: ${({ size }) => (size ? size + 'px' : '32px')}; + width: ${({ size }) => (size ? size + 'px' : '32px')}; } + ${({ theme }) => theme.mediaWidth.upToMedium` + align-items: flex-end; + `}; +` + +export default function StatusIcon({ connectionType }: { connectionType: ConnectionType }) { + let image + switch (connectionType) { + case ConnectionType.INJECTED: + image = + break + case ConnectionType.WALLET_CONNECT: + image = WalletConnect + break + case ConnectionType.COINBASE_WALLET: + image = Coinbase Wallet + break + case ConnectionType.FORTMATIC: + image = Fortmatic + break + } + + return {image} } diff --git a/src/components/PositionCard/V2.tsx b/src/components/PositionCard/V2.tsx index f337bcc295..4c27ca5db1 100644 --- a/src/components/PositionCard/V2.tsx +++ b/src/components/PositionCard/V2.tsx @@ -13,7 +13,7 @@ import styled from 'styled-components/macro' import { BIG_INT_ZERO } from '../../constants/misc' import { useColor } from '../../hooks/useColor' import { useTotalSupply } from '../../hooks/useTotalSupply' -import { useTokenBalance } from '../../state/wallet/hooks' +import { useTokenBalance } from '../../state/connection/hooks' import { currencyId } from '../../utils/currencyId' import { unwrappedToken } from '../../utils/unwrappedToken' import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button' diff --git a/src/components/PositionCard/index.tsx b/src/components/PositionCard/index.tsx index 2adbbdc8a0..b74e2da5a5 100644 --- a/src/components/PositionCard/index.tsx +++ b/src/components/PositionCard/index.tsx @@ -13,7 +13,7 @@ import styled from 'styled-components/macro' import { BIG_INT_ZERO } from '../../constants/misc' import { useColor } from '../../hooks/useColor' import { useTotalSupply } from '../../hooks/useTotalSupply' -import { useTokenBalance } from '../../state/wallet/hooks' +import { useTokenBalance } from '../../state/connection/hooks' import { ExternalLink, ThemedText } from '../../theme' import { currencyId } from '../../utils/currencyId' import { unwrappedToken } from '../../utils/unwrappedToken' diff --git a/src/components/SearchModal/CurrencyList/index.test.tsx b/src/components/SearchModal/CurrencyList/index.test.tsx index 1a936081be..2a1c7ab406 100644 --- a/src/components/SearchModal/CurrencyList/index.test.tsx +++ b/src/components/SearchModal/CurrencyList/index.test.tsx @@ -33,7 +33,7 @@ jest.mock('@web3-react/core', () => { } }) -jest.mock('../../../state/wallet/hooks', () => { +jest.mock('../../../state/connection/hooks', () => { return { useCurrencyBalance: (currency: Currency) => { return mockCurrencyAmt[(currency as mockToken)?.address] diff --git a/src/components/SearchModal/CurrencyList/index.tsx b/src/components/SearchModal/CurrencyList/index.tsx index 9ce530641e..db651633a3 100644 --- a/src/components/SearchModal/CurrencyList/index.tsx +++ b/src/components/SearchModal/CurrencyList/index.tsx @@ -11,9 +11,9 @@ import styled from 'styled-components/macro' import TokenListLogo from '../../../assets/svg/tokenlist.svg' import { useIsUserAddedToken } from '../../../hooks/Tokens' +import { useCurrencyBalance } from '../../../state/connection/hooks' import { useCombinedActiveList } from '../../../state/lists/hooks' import { WrappedTokenInfo } from '../../../state/lists/wrappedTokenInfo' -import { useCurrencyBalance } from '../../../state/wallet/hooks' import { ThemedText } from '../../../theme' import { isTokenOnList } from '../../../utils' import Column from '../../Column' diff --git a/src/components/SearchModal/CurrencySearch.tsx b/src/components/SearchModal/CurrencySearch.tsx index 7cbcfbd1b3..4b6290b668 100644 --- a/src/components/SearchModal/CurrencySearch.tsx +++ b/src/components/SearchModal/CurrencySearch.tsx @@ -15,7 +15,7 @@ import { Edit } from 'react-feather' import AutoSizer from 'react-virtualized-auto-sizer' import { FixedSizeList } from 'react-window' import { Text } from 'rebass' -import { useAllTokenBalances } from 'state/wallet/hooks' +import { useAllTokenBalances } from 'state/connection/hooks' import styled from 'styled-components/macro' import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens' diff --git a/src/components/WalletModal/index.tsx b/src/components/WalletModal/index.tsx index f2765060dc..f17ddd5870 100644 --- a/src/components/WalletModal/index.tsx +++ b/src/components/WalletModal/index.tsx @@ -4,16 +4,17 @@ import { Connector } from '@web3-react/types' import { sendEvent } from 'components/analytics' import { AutoColumn } from 'components/Column' import { AutoRow } from 'components/Row' +import { ConnectionType, injectedConnection } from 'connection' +import { getConnection } from 'connection/utils' import { useCallback, useEffect, useState } from 'react' import { ArrowLeft } from 'react-feather' +import { updateConnectionError } from 'state/connection/reducer' import { useAppDispatch, useAppSelector } from 'state/hooks' import { updateSelectedWallet } from 'state/user/reducer' -import { updateWalletError } from 'state/wallet/reducer' import styled from 'styled-components/macro' import MetamaskIcon from '../../assets/images/metamask.png' import { ReactComponent as Close } from '../../assets/images/x.svg' -import { fortmatic, getWalletForConnector, injected } from '../../connectors' import { SUPPORTED_WALLETS } from '../../constants/wallet' import { useModalOpen, useWalletModalToggle } from '../../state/application/hooks' import { ApplicationModal } from '../../state/application/reducer' @@ -125,7 +126,7 @@ export default function WalletModal({ const [pendingConnector, setPendingConnector] = useState() const pendingError = useAppSelector((state) => - pendingConnector ? state.wallet.errorByWallet[getWalletForConnector(pendingConnector)] : undefined + pendingConnector ? state.connection.errorByConnectionType[getConnection(pendingConnector).type] : undefined ) const walletModalOpen = useModalOpen(ApplicationModal.WALLET) @@ -143,39 +144,39 @@ export default function WalletModal({ useEffect(() => { if (pendingConnector && walletView !== WALLET_VIEWS.PENDING) { - updateWalletError({ wallet: getWalletForConnector(pendingConnector), error: undefined }) + updateConnectionError({ connectionType: getConnection(pendingConnector).type, error: undefined }) setPendingConnector(undefined) } }, [pendingConnector, walletView]) const tryActivation = useCallback( async (connector: Connector) => { - const wallet = getWalletForConnector(connector) + const connectionType = getConnection(connector).type // log selected wallet sendEvent({ category: 'Wallet', action: 'Change Wallet', - label: wallet, + label: connectionType, }) try { // Fortmatic opens it's own modal on activation to log in. This modal has a tabIndex // collision into the WalletModal, so we special case by closing the modal. - if (connector === fortmatic) { + if (connectionType === ConnectionType.FORTMATIC) { toggleWalletModal() } setPendingConnector(connector) setWalletView(WALLET_VIEWS.PENDING) - dispatch(updateWalletError({ wallet, error: undefined })) + dispatch(updateConnectionError({ connectionType, error: undefined })) await connector.activate() - dispatch(updateSelectedWallet({ wallet })) + dispatch(updateSelectedWallet({ wallet: connectionType })) } catch (error) { console.debug(`web3-react connection error: ${error}`) - dispatch(updateWalletError({ wallet, error: error.message })) + dispatch(updateConnectionError({ connectionType, error: error.message })) } }, [dispatch, toggleWalletModal] @@ -221,7 +222,7 @@ export default function WalletModal({ } // overwrite injected when needed - if (option.connector === injected) { + if (option.connector === injectedConnection.connector) { // don't show injected if there's no injected provider if (!(window.web3 || window.ethereum)) { if (option.name === 'MetaMask') { diff --git a/src/components/Web3Provider/index.tsx b/src/components/Web3Provider/index.tsx index 00b81abf9d..817d380909 100644 --- a/src/components/Web3Provider/index.tsx +++ b/src/components/Web3Provider/index.tsx @@ -1,44 +1,11 @@ import { Web3ReactProvider } from '@web3-react/core' -import { Connector } from '@web3-react/types' -import { BACKFILLABLE_WALLETS, getConnectorForWallet, gnosisSafe, injected, network, useConnectors } from 'connectors' -import { ReactNode, useEffect } from 'react' -import { useAppSelector } from 'state/hooks' - -import { isMobile } from '../../utils/userAgent' - -const connect = async (connector: Connector) => { - try { - if (connector.connectEagerly) { - await connector.connectEagerly() - } else { - await connector.activate() - } - } catch (error) { - console.debug(`web3-react eager connection error: ${error}`) - } -} +import useConnectors from 'hooks/useConnectors' +import useEagerlyConnect from 'hooks/useEagerlyConnect' +import { ReactNode } from 'react' export default function Web3Provider({ children }: { children: ReactNode }) { - const selectedWalletBackfilled = useAppSelector((state) => state.user.selectedWalletBackfilled) - const selectedWallet = useAppSelector((state) => state.user.selectedWallet) - - const connectors = useConnectors(selectedWallet) - - const isMetaMask = !!window.ethereum?.isMetaMask - - useEffect(() => { - connect(gnosisSafe) - connect(network) - - if (isMobile && isMetaMask) { - injected.activate() - } else if (selectedWallet) { - connect(getConnectorForWallet(selectedWallet)) - } else if (!selectedWalletBackfilled) { - BACKFILLABLE_WALLETS.map(getConnectorForWallet).forEach(connect) - } - // The dependency list is empty so this is only run once on mount - }, []) // eslint-disable-line react-hooks/exhaustive-deps + useEagerlyConnect() + const connectors = useConnectors() return {children} } diff --git a/src/components/Web3Status/index.tsx b/src/components/Web3Status/index.tsx index b2fcf522dd..5d447b6ff6 100644 --- a/src/components/Web3Status/index.tsx +++ b/src/components/Web3Status/index.tsx @@ -1,8 +1,7 @@ // eslint-disable-next-line no-restricted-imports import { t, Trans } from '@lingui/macro' import { useWeb3React } from '@web3-react/core' -import { Connector } from '@web3-react/types' -import { getWalletForConnector } from 'connectors' +import { getConnection } from 'connection/utils' import { darken } from 'polished' import { useMemo } from 'react' import { Activity } from 'react-feather' @@ -21,16 +20,6 @@ import Loader from '../Loader' import { RowBetween } from '../Row' import WalletModal from '../WalletModal' -const IconWrapper = styled.div<{ size?: number }>` - ${({ theme }) => theme.flexColumnNoWrap}; - align-items: center; - justify-content: center; - & > * { - height: ${({ size }) => (size ? size + 'px' : '32px')}; - width: ${({ size }) => (size ? size + 'px' : '32px')}; - } -` - const Web3StatusGeneric = styled(ButtonSecondary)` ${({ theme }) => theme.flexRowNoWrap} width: 100%; @@ -131,18 +120,11 @@ function Sock() { ) } -function WrappedStatusIcon({ connector }: { connector: Connector }) { - return ( - - - - ) -} - function Web3StatusInner() { const { account, connector, chainId, ENSName } = useWeb3React() + const connectionType = getConnection(connector).type - const error = useAppSelector((state) => state.wallet.errorByWallet[getWalletForConnector(connector)]) + const error = useAppSelector((state) => state.connection.errorByConnectionType[getConnection(connector).type]) const chainAllowed = chainId && isChainAllowed(connector, chainId) @@ -199,7 +181,7 @@ function Web3StatusInner() { {ENSName || shortenAddress(account)} )} - {!hasPendingTransactions && connector && } + {!hasPendingTransactions && } ) } else { diff --git a/src/components/vote/DelegateModal.tsx b/src/components/vote/DelegateModal.tsx index 9bf9e87c39..a7fd7823c6 100644 --- a/src/components/vote/DelegateModal.tsx +++ b/src/components/vote/DelegateModal.tsx @@ -8,8 +8,8 @@ import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' import { UNI } from '../../constants/tokens' import useENS from '../../hooks/useENS' +import { useTokenBalance } from '../../state/connection/hooks' import { useDelegateCallback } from '../../state/governance/hooks' -import { useTokenBalance } from '../../state/wallet/hooks' import { ThemedText } from '../../theme' import AddressInputPanel from '../AddressInputPanel' import { ButtonPrimary } from '../Button' diff --git a/src/connection/index.ts b/src/connection/index.ts new file mode 100644 index 0000000000..601779da8f --- /dev/null +++ b/src/connection/index.ts @@ -0,0 +1,100 @@ +import { CoinbaseWallet } from '@web3-react/coinbase-wallet' +import { initializeConnector, Web3ReactHooks } from '@web3-react/core' +import { EIP1193 } from '@web3-react/eip1193' +import { GnosisSafe } from '@web3-react/gnosis-safe' +import { MetaMask } from '@web3-react/metamask' +import { Network } from '@web3-react/network' +import { Connector } from '@web3-react/types' +import { WalletConnect } from '@web3-react/walletconnect' +import { SupportedChainId } from 'constants/chains' +import { INFURA_NETWORK_URLS } from 'constants/infura' +import Fortmatic from 'fortmatic' + +import UNISWAP_LOGO_URL from '../assets/svg/logo.svg' + +export enum ConnectionType { + INJECTED = 'INJECTED', + COINBASE_WALLET = 'COINBASE_WALLET', + WALLET_CONNECT = 'WALLET_CONNECT', + FORTMATIC = 'FORTMATIC', + NETWORK = 'NETWORK', + GNOSIS_SAFE = 'GNOSIS_SAFE', +} + +export interface Connection { + connector: Connector + hooks: Web3ReactHooks + type: ConnectionType +} + +function onError(error: Error) { + console.debug(`web3-react error: ${error}`) +} + +const [web3Network, web3NetworkHooks] = initializeConnector( + (actions) => new Network({ actions, urlMap: INFURA_NETWORK_URLS, defaultChainId: 1 }) +) +export const networkConnection: Connection = { + connector: web3Network, + hooks: web3NetworkHooks, + type: ConnectionType.NETWORK, +} + +const [web3Injected, web3InjectedHooks] = initializeConnector((actions) => new MetaMask({ actions, onError })) +export const injectedConnection: Connection = { + connector: web3Injected, + hooks: web3InjectedHooks, + type: ConnectionType.INJECTED, +} + +const [web3GnosisSafe, web3GnosisSafeHooks] = initializeConnector((actions) => new GnosisSafe({ actions })) +export const gnosisSafeConnection: Connection = { + connector: web3GnosisSafe, + hooks: web3GnosisSafeHooks, + type: ConnectionType.GNOSIS_SAFE, +} + +const [web3WalletConnect, web3WalletConnectHooks] = initializeConnector( + (actions) => + new WalletConnect({ + actions, + options: { + rpc: INFURA_NETWORK_URLS, + qrcode: true, + }, + onError, + }) +) +export const walletConnectConnection: Connection = { + connector: web3WalletConnect, + hooks: web3WalletConnectHooks, + type: ConnectionType.WALLET_CONNECT, +} + +const [web3Fortmatic, web3FortmaticHooks] = initializeConnector( + (actions) => new EIP1193({ actions, provider: new Fortmatic(process.env.REACT_APP_FORTMATIC_KEY).getProvider() }) +) +export const fortmaticConnection: Connection = { + connector: web3Fortmatic, + hooks: web3FortmaticHooks, + type: ConnectionType.FORTMATIC, +} + +const [web3CoinbaseWallet, web3CoinbaseWalletHooks] = initializeConnector( + (actions) => + new CoinbaseWallet({ + actions, + options: { + url: INFURA_NETWORK_URLS[SupportedChainId.MAINNET], + appName: 'Uniswap', + appLogoUrl: UNISWAP_LOGO_URL, + reloadOnDisconnect: false, + }, + onError, + }) +) +export const coinbaseWalletConnection: Connection = { + connector: web3CoinbaseWallet, + hooks: web3CoinbaseWalletHooks, + type: ConnectionType.COINBASE_WALLET, +} diff --git a/src/connection/utils.ts b/src/connection/utils.ts new file mode 100644 index 0000000000..7c5e930c23 --- /dev/null +++ b/src/connection/utils.ts @@ -0,0 +1,44 @@ +import { Connector } from '@web3-react/types' +import { + coinbaseWalletConnection, + ConnectionType, + fortmaticConnection, + gnosisSafeConnection, + injectedConnection, + networkConnection, + walletConnectConnection, +} from 'connection' + +const CONNECTIONS = [ + coinbaseWalletConnection, + fortmaticConnection, + injectedConnection, + networkConnection, + walletConnectConnection, + gnosisSafeConnection, +] + +export function getConnection(c: Connector | ConnectionType) { + if (c instanceof Connector) { + const connection = CONNECTIONS.find((connection) => connection.connector === c) + if (!connection) { + throw Error('unsupported connector') + } + return connection + } else { + switch (c) { + case ConnectionType.INJECTED: + return injectedConnection + case ConnectionType.COINBASE_WALLET: + return coinbaseWalletConnection + case ConnectionType.WALLET_CONNECT: + return walletConnectConnection + case ConnectionType.FORTMATIC: + return fortmaticConnection + case ConnectionType.NETWORK: + return networkConnection + case ConnectionType.GNOSIS_SAFE: + return gnosisSafeConnection + } + } +} diff --git a/src/connectors/index.ts b/src/connectors/index.ts deleted file mode 100644 index 9e2d13d26f..0000000000 --- a/src/connectors/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { CoinbaseWallet } from '@web3-react/coinbase-wallet' -import { initializeConnector, Web3ReactHooks } from '@web3-react/core' -import { EIP1193 } from '@web3-react/eip1193' -import { GnosisSafe } from '@web3-react/gnosis-safe' -import { MetaMask } from '@web3-react/metamask' -import { Network } from '@web3-react/network' -import { Connector } from '@web3-react/types' -import { WalletConnect } from '@web3-react/walletconnect' -import { SupportedChainId } from 'constants/chains' -import { INFURA_NETWORK_URLS } from 'constants/infura' -import Fortmatic from 'fortmatic' -import { useMemo } from 'react' - -import UNISWAP_LOGO_URL from '../assets/svg/logo.svg' - -export enum Wallet { - INJECTED = 'INJECTED', - COINBASE_WALLET = 'COINBASE_WALLET', - WALLET_CONNECT = 'WALLET_CONNECT', - FORTMATIC = 'FORTMATIC', - NETWORK = 'NETWORK', - GNOSIS_SAFE = 'GNOSIS_SAFE', -} - -export const BACKFILLABLE_WALLETS = [Wallet.COINBASE_WALLET, Wallet.WALLET_CONNECT, Wallet.INJECTED] -export const SELECTABLE_WALLETS = [...BACKFILLABLE_WALLETS, Wallet.FORTMATIC] - -function onError(error: Error) { - console.debug(`web3-react error: ${error}`) -} - -export function getWalletForConnector(connector: Connector) { - switch (connector) { - case injected: - return Wallet.INJECTED - case coinbaseWallet: - return Wallet.COINBASE_WALLET - case walletConnect: - return Wallet.WALLET_CONNECT - case fortmatic: - return Wallet.FORTMATIC - case network: - return Wallet.NETWORK - case gnosisSafe: - return Wallet.GNOSIS_SAFE - default: - throw Error('unsupported connector') - } -} - -export function getConnectorForWallet(wallet: Wallet) { - switch (wallet) { - case Wallet.INJECTED: - return injected - case Wallet.COINBASE_WALLET: - return coinbaseWallet - case Wallet.WALLET_CONNECT: - return walletConnect - case Wallet.FORTMATIC: - return fortmatic - case Wallet.NETWORK: - return network - case Wallet.GNOSIS_SAFE: - return gnosisSafe - } -} - -function getHooksForWallet(wallet: Wallet) { - switch (wallet) { - case Wallet.INJECTED: - return injectedHooks - case Wallet.COINBASE_WALLET: - return coinbaseWalletHooks - case Wallet.WALLET_CONNECT: - return walletConnectHooks - case Wallet.FORTMATIC: - return fortmaticHooks - case Wallet.NETWORK: - return networkHooks - case Wallet.GNOSIS_SAFE: - return gnosisSafeHooks - } -} - -export const [network, networkHooks] = initializeConnector( - (actions) => new Network({ actions, urlMap: INFURA_NETWORK_URLS, defaultChainId: 1 }) -) - -export const [injected, injectedHooks] = initializeConnector((actions) => new MetaMask({ actions, onError })) - -export const [gnosisSafe, gnosisSafeHooks] = initializeConnector((actions) => new GnosisSafe({ actions })) - -export const [walletConnect, walletConnectHooks] = initializeConnector( - (actions) => - new WalletConnect({ - actions, - options: { - rpc: INFURA_NETWORK_URLS, - qrcode: true, - }, - onError, - }) -) - -export const [fortmatic, fortmaticHooks] = initializeConnector( - (actions) => new EIP1193({ actions, provider: new Fortmatic(process.env.REACT_APP_FORTMATIC_KEY).getProvider() }) -) - -export const [coinbaseWallet, coinbaseWalletHooks] = initializeConnector( - (actions) => - new CoinbaseWallet({ - actions, - options: { - url: INFURA_NETWORK_URLS[SupportedChainId.MAINNET], - appName: 'Uniswap', - appLogoUrl: UNISWAP_LOGO_URL, - reloadOnDisconnect: false, - }, - onError, - }) -) - -interface ConnectorListItem { - connector: Connector - hooks: Web3ReactHooks -} - -function getConnectorListItemForWallet(wallet: Wallet) { - return { - connector: getConnectorForWallet(wallet), - hooks: getHooksForWallet(wallet), - } -} - -export function useConnectors(selectedWallet: Wallet | undefined) { - return useMemo(() => { - const connectors: ConnectorListItem[] = [{ connector: gnosisSafe, hooks: gnosisSafeHooks }] - if (selectedWallet) { - connectors.push(getConnectorListItemForWallet(selectedWallet)) - } - connectors.push( - ...SELECTABLE_WALLETS.filter((wallet) => wallet !== selectedWallet).map(getConnectorListItemForWallet) - ) - connectors.push({ connector: network, hooks: networkHooks }) - const web3ReactConnectors: [Connector, Web3ReactHooks][] = connectors.map(({ connector, hooks }) => [ - connector, - hooks, - ]) - return web3ReactConnectors - }, [selectedWallet]) -} diff --git a/src/constants/wallet.ts b/src/constants/wallet.ts index 7adb0b8fa4..cd8662c409 100644 --- a/src/constants/wallet.ts +++ b/src/constants/wallet.ts @@ -1,15 +1,21 @@ import { Connector } from '@web3-react/types' +import { + coinbaseWalletConnection, + ConnectionType, + fortmaticConnection, + injectedConnection, + walletConnectConnection, +} from 'connection' import INJECTED_ICON_URL from '../assets/images/arrow-right.svg' import COINBASE_ICON_URL from '../assets/images/coinbaseWalletIcon.svg' import FORTMATIC_ICON_URL from '../assets/images/fortmaticIcon.png' import METAMASK_ICON_URL from '../assets/images/metamask.png' import WALLETCONNECT_ICON_URL from '../assets/images/walletConnectIcon.svg' -import { coinbaseWallet, fortmatic, injected, Wallet, walletConnect } from '../connectors' interface WalletInfo { connector?: Connector - wallet?: Wallet + connectionType?: ConnectionType name: string iconURL: string description: string @@ -22,8 +28,8 @@ interface WalletInfo { export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = { INJECTED: { - connector: injected, - wallet: Wallet.INJECTED, + connector: injectedConnection.connector, + connectionType: ConnectionType.INJECTED, name: 'Injected', iconURL: INJECTED_ICON_URL, description: 'Injected web3 provider.', @@ -32,8 +38,8 @@ export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = { primary: true, }, METAMASK: { - connector: injected, - wallet: Wallet.INJECTED, + connector: injectedConnection.connector, + connectionType: ConnectionType.INJECTED, name: 'MetaMask', iconURL: METAMASK_ICON_URL, description: 'Easy-to-use browser extension.', @@ -41,8 +47,8 @@ export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = { color: '#E8831D', }, WALLET_CONNECT: { - connector: walletConnect, - wallet: Wallet.WALLET_CONNECT, + connector: walletConnectConnection.connector, + connectionType: ConnectionType.WALLET_CONNECT, name: 'WalletConnect', iconURL: WALLETCONNECT_ICON_URL, description: 'Connect to Trust Wallet, Rainbow Wallet and more...', @@ -51,8 +57,8 @@ export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = { mobile: true, }, COINBASE_WALLET: { - connector: coinbaseWallet, - wallet: Wallet.COINBASE_WALLET, + connector: coinbaseWalletConnection.connector, + connectionType: ConnectionType.COINBASE_WALLET, name: 'Coinbase Wallet', iconURL: COINBASE_ICON_URL, description: 'Use Coinbase Wallet app on mobile device', @@ -69,8 +75,8 @@ export const SUPPORTED_WALLETS: { [key: string]: WalletInfo } = { mobileOnly: true, }, FORTMATIC: { - connector: fortmatic, - wallet: Wallet.FORTMATIC, + connector: fortmaticConnection.connector, + connectionType: ConnectionType.FORTMATIC, name: 'Fortmatic', iconURL: FORTMATIC_ICON_URL, description: 'Login using Fortmatic hosted wallet', diff --git a/src/hooks/useConnectors.ts b/src/hooks/useConnectors.ts new file mode 100644 index 0000000000..665f745307 --- /dev/null +++ b/src/hooks/useConnectors.ts @@ -0,0 +1,34 @@ +import { Web3ReactHooks } from '@web3-react/core' +import { Connector } from '@web3-react/types' +import { ConnectionType } from 'connection' +import { getConnection } from 'connection/utils' +import { useMemo } from 'react' +import { BACKFILLABLE_WALLETS } from 'state/connection/constants' +import { useAppSelector } from 'state/hooks' + +const SELECTABLE_WALLETS = [...BACKFILLABLE_WALLETS, ConnectionType.FORTMATIC] + +export default function useConnectors() { + const selectedWallet = useAppSelector((state) => state.user.selectedWallet) + return useMemo(() => { + const orderedConnectionTypes: ConnectionType[] = [] + + // Always attempt to use to Gnosis Safe first, as we can't know if we're in a SafeContext. + orderedConnectionTypes.push(ConnectionType.GNOSIS_SAFE) + + // Add the `selectedWallet` to the top so it's prioritized, then add the other selectable wallets. + if (selectedWallet) { + orderedConnectionTypes.push(selectedWallet) + } + orderedConnectionTypes.push(...SELECTABLE_WALLETS.filter((wallet) => wallet !== selectedWallet)) + + // Add network connection last as it should be the fallback. + orderedConnectionTypes.push(ConnectionType.NETWORK) + + // Convert to web3-react's representation of connectors. + const web3Connectors: [Connector, Web3ReactHooks][] = orderedConnectionTypes + .map(getConnection) + .map(({ connector, hooks }) => [connector, hooks]) + return web3Connectors + }, [selectedWallet]) +} diff --git a/src/hooks/useEagerlyConnect.ts b/src/hooks/useEagerlyConnect.ts new file mode 100644 index 0000000000..263b2d7950 --- /dev/null +++ b/src/hooks/useEagerlyConnect.ts @@ -0,0 +1,42 @@ +import { Connector } from '@web3-react/types' +import { gnosisSafeConnection, injectedConnection, networkConnection } from 'connection' +import { getConnection } from 'connection/utils' +import { useEffect } from 'react' +import { BACKFILLABLE_WALLETS } from 'state/connection/constants' +import { useAppSelector } from 'state/hooks' +import { isMobile } from 'utils/userAgent' + +async function connect(connector: Connector) { + try { + if (connector.connectEagerly) { + await connector.connectEagerly() + } else { + await connector.activate() + } + } catch (error) { + console.debug(`web3-react eager connection error: ${error}`) + } +} + +export default function useEagerlyConnect() { + const selectedWalletBackfilled = useAppSelector((state) => state.user.selectedWalletBackfilled) + const selectedWallet = useAppSelector((state) => state.user.selectedWallet) + + const isMetaMask = !!window.ethereum?.isMetaMask + + useEffect(() => { + connect(gnosisSafeConnection.connector) + connect(networkConnection.connector) + + if (isMobile && isMetaMask) { + injectedConnection.connector.activate() + } else if (selectedWallet) { + connect(getConnection(selectedWallet).connector) + } else if (!selectedWalletBackfilled) { + BACKFILLABLE_WALLETS.map(getConnection) + .map((connection) => connection.connector) + .forEach(connect) + } + // The dependency list is empty so this is only run once on mount + }, []) // eslint-disable-line react-hooks/exhaustive-deps +} diff --git a/src/hooks/useSocksBalance.ts b/src/hooks/useSocksBalance.ts index 3d93e2e642..bbf8c687d7 100644 --- a/src/hooks/useSocksBalance.ts +++ b/src/hooks/useSocksBalance.ts @@ -3,7 +3,7 @@ import { useWeb3React } from '@web3-react/core' import { SOCKS_CONTROLLER_ADDRESSES } from 'constants/addresses' import { SupportedChainId } from 'constants/chains' import { useMemo } from 'react' -import { useTokenBalance } from 'state/wallet/hooks' +import { useTokenBalance } from 'state/connection/hooks' // technically a 721, not an ERC20, but suffices for our purposes const SOCKS = new Token(SupportedChainId.MAINNET, SOCKS_CONTROLLER_ADDRESSES[SupportedChainId.MAINNET], 0) diff --git a/src/hooks/useWrapCallback.tsx b/src/hooks/useWrapCallback.tsx index ad34d2d5ee..968edecbc9 100644 --- a/src/hooks/useWrapCallback.tsx +++ b/src/hooks/useWrapCallback.tsx @@ -6,9 +6,9 @@ import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useMemo } from 'react' import { WRAPPED_NATIVE_CURRENCY } from '../constants/tokens' +import { useCurrencyBalance } from '../state/connection/hooks' import { useTransactionAdder } from '../state/transactions/hooks' import { TransactionType } from '../state/transactions/types' -import { useCurrencyBalance } from '../state/wallet/hooks' import { useWETHContract } from './useContract' export enum WrapType { diff --git a/src/pages/Earn/Manage.tsx b/src/pages/Earn/Manage.tsx index 197b15350b..218d16e36f 100644 --- a/src/pages/Earn/Manage.tsx +++ b/src/pages/Earn/Manage.tsx @@ -24,8 +24,8 @@ import { useTotalSupply } from '../../hooks/useTotalSupply' import useUSDCPrice from '../../hooks/useUSDCPrice' import { useV2Pair } from '../../hooks/useV2Pairs' import { useWalletModalToggle } from '../../state/application/hooks' +import { useTokenBalance } from '../../state/connection/hooks' import { useStakingInfo } from '../../state/stake/hooks' -import { useTokenBalance } from '../../state/wallet/hooks' import { ThemedText } from '../../theme' import { currencyId } from '../../utils/currencyId' diff --git a/src/pages/MigrateV2/MigrateV2Pair.tsx b/src/pages/MigrateV2/MigrateV2Pair.tsx index 56344bca82..b4b6591554 100644 --- a/src/pages/MigrateV2/MigrateV2Pair.tsx +++ b/src/pages/MigrateV2/MigrateV2Pair.tsx @@ -44,8 +44,8 @@ import { useToken } from '../../hooks/Tokens' import { usePairContract, useV2MigratorContract } from '../../hooks/useContract' import useIsArgentWallet from '../../hooks/useIsArgentWallet' import { useTotalSupply } from '../../hooks/useTotalSupply' +import { useTokenBalance } from '../../state/connection/hooks' import { TransactionType } from '../../state/transactions/types' -import { useTokenBalance } from '../../state/wallet/hooks' import { BackArrow, ExternalLink, ThemedText } from '../../theme' import { isAddress } from '../../utils' import { calculateGasMargin } from '../../utils/calculateGasMargin' diff --git a/src/pages/MigrateV2/index.tsx b/src/pages/MigrateV2/index.tsx index 984874c6e9..6ec708e40e 100644 --- a/src/pages/MigrateV2/index.tsx +++ b/src/pages/MigrateV2/index.tsx @@ -18,8 +18,8 @@ import QuestionHelper from '../../components/QuestionHelper' import { AutoRow } from '../../components/Row' import { Dots } from '../../components/swap/styleds' import { V2_FACTORY_ADDRESSES } from '../../constants/addresses' +import { useTokenBalancesWithLoadingIndicator } from '../../state/connection/hooks' import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks' -import { useTokenBalancesWithLoadingIndicator } from '../../state/wallet/hooks' import { BackArrow, StyledInternalLink, ThemedText } from '../../theme' import { BodyWrapper } from '../AppBody' diff --git a/src/pages/Pool/v2.tsx b/src/pages/Pool/v2.tsx index 7eed26bdb4..54bcff2cd8 100644 --- a/src/pages/Pool/v2.tsx +++ b/src/pages/Pool/v2.tsx @@ -20,9 +20,9 @@ import { Dots } from '../../components/swap/styleds' import { SwitchLocaleLink } from '../../components/SwitchLocaleLink' import { BIG_INT_ZERO } from '../../constants/misc' import { useV2Pairs } from '../../hooks/useV2Pairs' +import { useTokenBalancesWithLoadingIndicator } from '../../state/connection/hooks' import { useStakingInfo } from '../../state/stake/hooks' import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks' -import { useTokenBalancesWithLoadingIndicator } from '../../state/wallet/hooks' import { ExternalLink, HideSmall, ThemedText } from '../../theme' const PageWrapper = styled(AutoColumn)` diff --git a/src/pages/PoolFinder/index.tsx b/src/pages/PoolFinder/index.tsx index 13d5b76f6e..120bd812fc 100644 --- a/src/pages/PoolFinder/index.tsx +++ b/src/pages/PoolFinder/index.tsx @@ -19,8 +19,8 @@ import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModa import { SwitchLocaleLink } from '../../components/SwitchLocaleLink' import { nativeOnChain } from '../../constants/tokens' import { PairState, useV2Pair } from '../../hooks/useV2Pairs' +import { useTokenBalance } from '../../state/connection/hooks' import { usePairAdder } from '../../state/user/hooks' -import { useTokenBalance } from '../../state/wallet/hooks' import { StyledInternalLink } from '../../theme' import { ThemedText } from '../../theme' import { currencyId } from '../../utils/currencyId' diff --git a/src/pages/Vote/Landing.tsx b/src/pages/Vote/Landing.tsx index 3f4838dae7..c699515896 100644 --- a/src/pages/Vote/Landing.tsx +++ b/src/pages/Vote/Landing.tsx @@ -18,9 +18,9 @@ import { Link } from 'react-router-dom' import { Button } from 'rebass/styled-components' import { useModalOpen, useToggleDelegateModal } from 'state/application/hooks' import { ApplicationModal } from 'state/application/reducer' +import { useTokenBalance } from 'state/connection/hooks' import { ProposalData, ProposalState } from 'state/governance/hooks' import { useAllProposalData, useUserDelegatee, useUserVotes } from 'state/governance/hooks' -import { useTokenBalance } from 'state/wallet/hooks' import styled from 'styled-components/macro' import { ExternalLink, ThemedText } from 'theme' import { shortenAddress } from 'utils' diff --git a/src/pages/Vote/VotePage.tsx b/src/pages/Vote/VotePage.tsx index 7465560ce4..7a6c17fb0a 100644 --- a/src/pages/Vote/VotePage.tsx +++ b/src/pages/Vote/VotePage.tsx @@ -38,6 +38,7 @@ import { useToggleVoteModal, } from '../../state/application/hooks' import { ApplicationModal } from '../../state/application/reducer' +import { useTokenBalance } from '../../state/connection/hooks' import { ProposalData, ProposalState, @@ -47,7 +48,6 @@ import { useUserVotesAsOfBlock, } from '../../state/governance/hooks' import { VoteOption } from '../../state/governance/types' -import { useTokenBalance } from '../../state/wallet/hooks' import { ExternalLink, StyledInternalLink, ThemedText } from '../../theme' import { isAddress } from '../../utils' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' diff --git a/src/state/burn/hooks.tsx b/src/state/burn/hooks.tsx index 45e3a5e9cf..a8910c5c26 100644 --- a/src/state/burn/hooks.tsx +++ b/src/state/burn/hooks.tsx @@ -9,8 +9,8 @@ import { useAppDispatch, useAppSelector } from 'state/hooks' import { useTotalSupply } from '../../hooks/useTotalSupply' import { useV2Pair } from '../../hooks/useV2Pairs' +import { useTokenBalances } from '../connection/hooks' import { AppState } from '../index' -import { useTokenBalances } from '../wallet/hooks' import { Field, typeInput } from './actions' export function useBurnState(): AppState['burn'] { diff --git a/src/state/connection/constants.ts b/src/state/connection/constants.ts new file mode 100644 index 0000000000..2cd26750a1 --- /dev/null +++ b/src/state/connection/constants.ts @@ -0,0 +1,7 @@ +import { ConnectionType } from 'connection' + +export const BACKFILLABLE_WALLETS = [ + ConnectionType.COINBASE_WALLET, + ConnectionType.WALLET_CONNECT, + ConnectionType.INJECTED, +] diff --git a/src/state/wallet/hooks.ts b/src/state/connection/hooks.ts similarity index 100% rename from src/state/wallet/hooks.ts rename to src/state/connection/hooks.ts diff --git a/src/state/connection/reducer.ts b/src/state/connection/reducer.ts new file mode 100644 index 0000000000..422496d3fa --- /dev/null +++ b/src/state/connection/reducer.ts @@ -0,0 +1,33 @@ +import { createSlice } from '@reduxjs/toolkit' +import { ConnectionType } from 'connection' + +export interface ConnectionState { + errorByConnectionType: Record +} + +export const initialState: ConnectionState = { + errorByConnectionType: { + [ConnectionType.INJECTED]: undefined, + [ConnectionType.FORTMATIC]: undefined, + [ConnectionType.WALLET_CONNECT]: undefined, + [ConnectionType.COINBASE_WALLET]: undefined, + [ConnectionType.NETWORK]: undefined, + [ConnectionType.GNOSIS_SAFE]: undefined, + }, +} + +const connectionSlice = createSlice({ + name: 'connection', + initialState, + reducers: { + updateConnectionError( + state, + { payload: { connectionType, error } }: { payload: { connectionType: ConnectionType; error: string | undefined } } + ) { + state.errorByConnectionType[connectionType] = error + }, + }, +}) + +export const { updateConnectionError } = connectionSlice.actions +export default connectionSlice.reducer diff --git a/src/state/index.ts b/src/state/index.ts index d4df428332..b7d199473e 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -6,6 +6,7 @@ import { load, save } from 'redux-localstorage-simple' import application from './application/reducer' import burn from './burn/reducer' import burnV3 from './burn/v3/reducer' +import connection from './connection/reducer' import { api as dataApi } from './data/slice' import { updateVersion } from './global/actions' import lists from './lists/reducer' @@ -16,7 +17,6 @@ import { routingApi } from './routing/slice' import swap from './swap/reducer' import transactions from './transactions/reducer' import user from './user/reducer' -import wallet from './wallet/reducer' const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists'] @@ -24,7 +24,7 @@ const store = configureStore({ reducer: { application, user, - wallet, + connection, transactions, swap, mint, diff --git a/src/state/mint/hooks.tsx b/src/state/mint/hooks.tsx index 2790d91846..3e50423d29 100644 --- a/src/state/mint/hooks.tsx +++ b/src/state/mint/hooks.tsx @@ -9,8 +9,8 @@ import { useAppDispatch, useAppSelector } from 'state/hooks' import { useTotalSupply } from '../../hooks/useTotalSupply' import { PairState, useV2Pair } from '../../hooks/useV2Pairs' +import { useCurrencyBalances } from '../connection/hooks' import { AppState } from '../index' -import { useCurrencyBalances } from '../wallet/hooks' import { Field, typeInput } from './actions' const ZERO = JSBI.BigInt(0) diff --git a/src/state/mint/v3/hooks.tsx b/src/state/mint/v3/hooks.tsx index c4b4111988..afa03b3127 100644 --- a/src/state/mint/v3/hooks.tsx +++ b/src/state/mint/v3/hooks.tsx @@ -23,8 +23,8 @@ import { replaceURLParam } from 'utils/routes' import { BIG_INT_ZERO } from '../../../constants/misc' import { PoolState } from '../../../hooks/usePools' +import { useCurrencyBalances } from '../../connection/hooks' import { AppState } from '../../index' -import { useCurrencyBalances } from '../../wallet/hooks' import { Bound, Field, diff --git a/src/state/swap/hooks.tsx b/src/state/swap/hooks.tsx index e7fd1bfa03..883815c723 100644 --- a/src/state/swap/hooks.tsx +++ b/src/state/swap/hooks.tsx @@ -15,8 +15,8 @@ import { useCurrency } from '../../hooks/Tokens' import useENS from '../../hooks/useENS' import useParsedQueryString from '../../hooks/useParsedQueryString' import { isAddress } from '../../utils' +import { useCurrencyBalances } from '../connection/hooks' import { AppState } from '../index' -import { useCurrencyBalances } from '../wallet/hooks' import { Field, replaceSwapState, selectCurrency, setRecipient, switchCurrencies, typeInput } from './actions' import { SwapState } from './reducer' diff --git a/src/state/user/reducer.ts b/src/state/user/reducer.ts index a3cf1485ff..304f806cda 100644 --- a/src/state/user/reducer.ts +++ b/src/state/user/reducer.ts @@ -1,5 +1,5 @@ import { createSlice } from '@reduxjs/toolkit' -import { Wallet } from 'connectors' +import { ConnectionType } from 'connection' import { SupportedLocale } from 'constants/locales' import { DEFAULT_DEADLINE_FROM_NOW } from '../../constants/misc' @@ -14,7 +14,7 @@ export interface UserState { // we want to handle that case by backfilling them manually. Once we backfill, we set the backfilled field to `true`. // After some period of time, our active users will have this property set so we can likely remove the backfilling logic. selectedWalletBackfilled: boolean - selectedWallet?: Wallet + selectedWallet?: ConnectionType // the timestamp of the last updateVersion action lastUpdateVersionTimestamp?: number diff --git a/src/state/wallet/reducer.ts b/src/state/wallet/reducer.ts deleted file mode 100644 index 865aa4d505..0000000000 --- a/src/state/wallet/reducer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit' -import { Wallet } from 'connectors' - -export interface WalletState { - errorByWallet: Record -} - -export const initialState: WalletState = { - errorByWallet: { - [Wallet.INJECTED]: undefined, - [Wallet.FORTMATIC]: undefined, - [Wallet.WALLET_CONNECT]: undefined, - [Wallet.COINBASE_WALLET]: undefined, - [Wallet.NETWORK]: undefined, - [Wallet.GNOSIS_SAFE]: undefined, - }, -} - -const walletSlice = createSlice({ - name: 'wallet', - initialState, - reducers: { - updateWalletError( - state, - { payload: { wallet, error } }: { payload: { wallet: Wallet; error: string | undefined } } - ) { - state.errorByWallet[wallet] = error - }, - }, -}) - -export const { updateWalletError } = walletSlice.actions -export default walletSlice.reducer diff --git a/src/utils/switchChain.ts b/src/utils/switchChain.ts index 43b6fedee5..e631c48ef9 100644 --- a/src/utils/switchChain.ts +++ b/src/utils/switchChain.ts @@ -1,5 +1,12 @@ import { Connector } from '@web3-react/types' -import { coinbaseWallet, fortmatic, gnosisSafe, injected, network, walletConnect } from 'connectors' +import { + coinbaseWalletConnection, + fortmaticConnection, + gnosisSafeConnection, + injectedConnection, + networkConnection, + walletConnectConnection, +} from 'connection' import { CHAIN_INFO } from 'constants/chainInfo' import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains' import { INFURA_NETWORK_URLS } from 'constants/infura' @@ -32,13 +39,13 @@ function getRpcUrls(chainId: SupportedChainId): [string] { export function isChainAllowed(connector: Connector, chainId: number) { switch (connector) { - case fortmatic: + case fortmaticConnection.connector: return chainId === SupportedChainId.MAINNET - case injected: - case coinbaseWallet: - case walletConnect: - case network: - case gnosisSafe: + case injectedConnection.connector: + case coinbaseWalletConnection.connector: + case walletConnectConnection.connector: + case networkConnection.connector: + case gnosisSafeConnection.connector: return ALL_SUPPORTED_CHAIN_IDS.includes(chainId) default: return false @@ -48,7 +55,7 @@ export function isChainAllowed(connector: Connector, chainId: number) { export const switchChain = async (connector: Connector, chainId: number) => { if (!isChainAllowed(connector, chainId)) { throw new Error(`Chain ${chainId} not supported for connector (${typeof connector})`) - } else if (connector === walletConnect || connector === network) { + } else if (connector === walletConnectConnection.connector || connector === networkConnection.connector) { await connector.activate(chainId) } else { const info = CHAIN_INFO[chainId]