Commit 839d4ac8 authored by cartcrom's avatar cartcrom Committed by GitHub

refactor: adding safe getter for ChainInfo (#4110)

* replaced CHAIN_INFO access with a function call
* updated CTACard tests to work with getChainInfo
* updated typechecking, removed console.log
parent 29fdcb80
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { CHAIN_INFO, L2ChainInfo } from 'constants/chainInfo'
import { getChainInfoOrDefault, L2ChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { AlertOctagon } from 'react-feather'
import styled from 'styled-components/macro'
......@@ -46,7 +46,7 @@ const Wrapper = styled.div`
export function ChainConnectivityWarning() {
const { chainId } = useWeb3React()
const info = CHAIN_INFO[chainId ?? SupportedChainId.MAINNET]
const info = getChainInfoOrDefault(chainId)
const label = info?.label
return (
......
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { getConnection } from 'connection/utils'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfo } from 'constants/chainInfo'
import { CHAIN_IDS_TO_NAMES, SupportedChainId } from 'constants/chains'
import useParsedQueryString from 'hooks/useParsedQueryString'
import usePrevious from 'hooks/usePrevious'
......@@ -195,7 +195,7 @@ function Row({
return null
}
const active = chainId === targetChain
const { helpCenterUrl, explorer, bridge, label, logoUrl } = CHAIN_INFO[targetChain]
const { helpCenterUrl, explorer, bridge, label, logoUrl } = getChainInfo(targetChain)
const rowContent = (
<FlyoutRow onClick={() => onSelectChain(targetChain)} active={active}>
......@@ -285,10 +285,10 @@ export default function NetworkSelector() {
const toggleModal = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
const history = useHistory()
const info = chainId ? CHAIN_INFO[chainId] : undefined
const info = getChainInfo(chainId)
const onSelectChain = useCallback(
async (targetChain: number, skipClose?: boolean) => {
async (targetChain: SupportedChainId, skipClose?: boolean) => {
if (!connector) return
const connectionType = getConnection(connector).type
......
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { RowFixed } from 'components/Row'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfo } from 'constants/chainInfo'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useGasPrice from 'hooks/useGasPrice'
import useMachineTimeMs from 'hooks/useMachineTime'
......@@ -112,7 +112,7 @@ export default function Polling() {
const priceGwei = ethGasPrice ? JSBI.divide(ethGasPrice, JSBI.BigInt(1000000000)) : undefined
const waitMsBeforeWarning =
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
(chainId ? getChainInfo(chainId)?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
......
import { Trans } from '@lingui/macro'
import useScrollPosition from '@react-hook/window-scroll'
import { useWeb3React } from '@web3-react/core'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfoOrDefault } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import useTheme from 'hooks/useTheme'
import { darken } from 'polished'
......@@ -13,7 +13,6 @@ import { useNativeCurrencyBalances } from 'state/connection/hooks'
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
import { useDarkModeManager } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { isChainAllowed } from 'utils/switchChain'
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
import { ExternalLink, ThemedText } from '../../theme'
......@@ -247,9 +246,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
`
export default function Header() {
const { account, chainId, connector } = useWeb3React()
const chainAllowed = chainId && isChainAllowed(connector, chainId)
const { account, chainId } = useWeb3React()
const userEthBalance = useNativeCurrencyBalances(account ? [account] : [])?.[account ?? '']
const [darkMode] = useDarkModeManager()
......@@ -268,7 +265,7 @@ export default function Header() {
const {
infoLink,
nativeCurrency: { symbol: nativeCurrencySymbol },
} = CHAIN_INFO[!chainId || !chainAllowed ? SupportedChainId.MAINNET : chainId]
} = getChainInfoOrDefault(chainId)
return (
<HeaderFrame showBackground={scrollY > 45}>
......
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { ArrowUpRight } from 'react-feather'
import { useDarkModeManager } from 'state/user/hooks'
......@@ -159,7 +159,7 @@ export function NetworkAlert() {
return null
}
const { label, logoUrl, bridge } = CHAIN_INFO[chainId]
const { label, logoUrl, bridge } = getChainInfo(chainId)
const textColor = TEXT_COLORS[chainId]
return bridge ? (
......
import { Trans } from '@lingui/macro'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { useContext } from 'react'
import { AlertCircle } from 'react-feather'
......@@ -14,7 +14,7 @@ const RowNoFlex = styled(AutoRow)`
`
export default function FailedNetworkSwitchPopup({ chainId }: { chainId: SupportedChainId }) {
const chainInfo = CHAIN_INFO[chainId]
const chainInfo = getChainInfo(chainId)
const theme = useContext(ThemeContext)
return (
......
......@@ -2,14 +2,15 @@ import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import Badge from 'components/Badge'
import { CHAIN_INFO } from 'constants/chainInfo'
import { L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedL2ChainId } from 'constants/chains'
import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs'
import { ReactNode, useCallback, useContext, useState } from 'react'
import { AlertCircle, AlertTriangle, ArrowUpCircle, CheckCircle } from 'react-feather'
import { Text } from 'rebass'
import { useIsTransactionConfirmed, useTransaction } from 'state/transactions/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import { isL2ChainId } from 'utils/chains'
import Circle from '../../assets/images/blue-loader.svg'
import { ExternalLink } from '../../theme'
......@@ -232,7 +233,7 @@ function L2Content({
}: {
onDismiss: () => void
hash: string | undefined
chainId: number
chainId: SupportedL2ChainId
currencyToAdd?: Currency | undefined
pendingText: ReactNode
inline?: boolean // not in modal
......@@ -248,7 +249,7 @@ function L2Content({
? (transaction.confirmedTime - transaction.addedTime) / 1000
: undefined
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const info = getChainInfo(chainId)
return (
<Wrapper>
......@@ -344,14 +345,12 @@ export default function TransactionConfirmationModal({
}: ConfirmationModalProps) {
const { chainId } = useWeb3React()
const isL2 = Boolean(chainId && L2_CHAIN_IDS.includes(chainId))
if (!chainId) return null
// confirmation screen
return (
<Modal isOpen={isOpen} onDismiss={onDismiss} maxHeight={90}>
{isL2 && (hash || attemptingTxn) ? (
{isL2ChainId(chainId) && (hash || attemptingTxn) ? (
<L2Content chainId={chainId} hash={hash} onDismiss={onDismiss} pendingText={pendingText} />
) : attemptingTxn ? (
<ConfirmationPendingContent onDismiss={onDismiss} pendingText={pendingText} />
......
......@@ -46,7 +46,7 @@ export type ChainInfoMap = { readonly [chainId: number]: L1ChainInfo | L2ChainIn
readonly [chainId in SupportedL2ChainId]: L2ChainInfo
} & { readonly [chainId in SupportedL1ChainId]: L1ChainInfo }
export const CHAIN_INFO: ChainInfoMap = {
const CHAIN_INFO: ChainInfoMap = {
[SupportedChainId.MAINNET]: {
networkType: NetworkType.L1,
docs: 'https://docs.uniswap.org/',
......@@ -193,3 +193,30 @@ export const CHAIN_INFO: ChainInfoMap = {
defaultListUrl: CELO_LIST,
},
}
export function getChainInfo(chainId: SupportedL1ChainId): L1ChainInfo
export function getChainInfo(chainId: SupportedL2ChainId): L2ChainInfo
export function getChainInfo(chainId: SupportedChainId): L1ChainInfo | L2ChainInfo
export function getChainInfo(
chainId: SupportedChainId | SupportedL1ChainId | SupportedL2ChainId | number | undefined
): L1ChainInfo | L2ChainInfo | undefined
/**
* Overloaded method for returning ChainInfo given a chainID
* Return type varies depending on input type:
* number | undefined -> returns chaininfo | undefined
* SupportedChainId -> returns L1ChainInfo | L2ChainInfo
* SupportedL1ChainId -> returns L1ChainInfo
* SupportedL2ChainId -> returns L2ChainInfo
*/
export function getChainInfo(chainId: any): any {
if (chainId) {
return CHAIN_INFO[chainId] ?? undefined
}
return undefined
}
export const MAINNET_INFO = CHAIN_INFO[SupportedChainId.MAINNET]
export function getChainInfoOrDefault(chainId: number | undefined) {
return getChainInfo(chainId) ?? MAINNET_INFO
}
import { Currency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { CHAIN_INFO } from 'constants/chainInfo'
import { L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { useCurrencyFromMap, useTokenFromMapOrNetwork } from 'lib/hooks/useCurrency'
import { getTokenFilter } from 'lib/hooks/useTokenList/filtering'
import { useMemo } from 'react'
import { isL2ChainId } from 'utils/chains'
import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks'
import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
......@@ -70,7 +71,7 @@ export function useUnsupportedTokens(): { [address: string]: Token } {
// checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
if (!chainId || !L2_CHAIN_IDS.includes(chainId)) {
if (!chainId || !isL2ChainId(chainId)) {
return {}
}
......@@ -78,7 +79,8 @@ export function useUnsupportedTokens(): { [address: string]: Token } {
return {}
}
const listUrl = CHAIN_INFO[chainId as SupportedL2ChainId].defaultListUrl
const listUrl = getChainInfo(chainId).defaultListUrl
const { current: list } = listsByUrl[listUrl]
if (!list) {
return {}
......
import * as useV3Positions from 'hooks/useV3Positions'
import { BrowserRouter as Router } from 'react-router-dom'
import { render, screen } from 'test-utils'
import * as switchChain from 'utils/switchChain'
import CTACards from './CTACards'
......@@ -10,14 +9,13 @@ jest.mock('@web3-react/core', () => {
return {
...web3React,
useWeb3React: () => ({
chainId: 10,
chainId: 99999,
}),
}
})
describe('CTAcard links', () => {
it('renders mainnet link when chain is not supported', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(false)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
......@@ -29,18 +27,4 @@ describe('CTAcard links', () => {
)
expect(screen.getByTestId('cta-infolink')).toHaveAttribute('href', 'https://info.uniswap.org/#/pools')
})
it('renders specific link when chain is supported', () => {
jest.spyOn(switchChain, 'isChainAllowed').mockReturnValue(true)
jest.spyOn(useV3Positions, 'useV3Positions').mockImplementation(() => {
return { loading: false, positions: undefined }
})
render(
<Router>
<CTACards />
</Router>
)
expect(screen.getByTestId('cta-infolink')).toHaveAttribute('href', 'https://info.uniswap.org/#/optimism/pools')
})
})
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { AutoColumn } from 'components/Column'
import { CHAIN_INFO } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { getChainInfoOrDefault } from 'constants/chainInfo'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import { isChainAllowed } from 'utils/switchChain'
import { ExternalLink } from '../../theme'
......@@ -94,8 +92,8 @@ const ResponsiveColumn = styled(AutoColumn)`
`
export default function CTACards() {
const { chainId, connector } = useWeb3React()
const { infoLink } = CHAIN_INFO[chainId && isChainAllowed(connector, chainId) ? chainId : SupportedChainId.MAINNET]
const { chainId } = useWeb3React()
const { infoLink } = getChainInfoOrDefault(chainId)
return (
<CTASection>
......
import { CHAIN_INFO, NetworkType } from 'constants/chainInfo'
import { getChainInfo, NetworkType } from 'constants/chainInfo'
import { SupportedL1ChainId, SupportedL2ChainId } from 'constants/chains'
export function isL1ChainId(chainId: number | undefined): chainId is SupportedL1ChainId {
return typeof chainId === 'number' && CHAIN_INFO[chainId].networkType === NetworkType.L1
const chainInfo = getChainInfo(chainId)
return chainInfo?.networkType === NetworkType.L1
}
export function isL2ChainId(chainId: number | undefined): chainId is SupportedL2ChainId {
return typeof chainId === 'number' && CHAIN_INFO[chainId].networkType === NetworkType.L2
const chainInfo = getChainInfo(chainId)
return chainInfo?.networkType === NetworkType.L2
}
......@@ -7,7 +7,7 @@ import {
networkConnection,
walletConnectConnection,
} from 'connection'
import { CHAIN_INFO } from 'constants/chainInfo'
import { getChainInfo } from 'constants/chainInfo'
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { RPC_URLS } from 'constants/networks'
......@@ -56,13 +56,13 @@ export function isChainAllowed(connector: Connector, chainId: number) {
}
}
export const switchChain = async (connector: Connector, chainId: number) => {
export const switchChain = async (connector: Connector, chainId: SupportedChainId) => {
if (!isChainAllowed(connector, chainId)) {
throw new Error(`Chain ${chainId} not supported for connector (${typeof connector})`)
} else if (connector === walletConnectConnection.connector || connector === networkConnection.connector) {
await connector.activate(chainId)
} else {
const info = CHAIN_INFO[chainId]
const info = getChainInfo(chainId)
const addChainParameter = {
chainId,
chainName: info.label,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment