Commit d1627a6c authored by Jordan Frankfurt's avatar Jordan Frankfurt Committed by GitHub

fix(L2): remove redux from chain connectivity (#2781)

* remove redux from chain connectivity

* useMachineTimeMs instead of Date.now to force updates, useCurrentBlockTimestamp

* use useInterval
parent 55c97189
import { CHAIN_INFO } from 'constants/chains'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useMachineTimeMs from 'hooks/useMachineTime'
import { useActiveWeb3React } from 'hooks/web3'
import ms from 'ms.macro'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useAppSelector } from 'state/hooks' import { useBlockNumber } from 'state/application/hooks'
import styled, { keyframes } from 'styled-components/macro' import styled, { keyframes } from 'styled-components/macro'
import { ExternalLink, TYPE } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import { useActiveWeb3React } from '../../hooks/web3'
import { useBlockNumber } from '../../state/application/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ChainConnectivityWarning } from './ChainConnectivityWarning' import { ChainConnectivityWarning } from './ChainConnectivityWarning'
const StyledPolling = styled.div<{ warning: boolean }>` const StyledPolling = styled.div<{ warning: boolean }>`
...@@ -68,12 +71,21 @@ const Spinner = styled.div<{ warning: boolean }>` ...@@ -68,12 +71,21 @@ const Spinner = styled.div<{ warning: boolean }>`
top: -3px; top: -3px;
` `
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
const NETWORK_HEALTH_CHECK_MS = ms`10s`
export default function Polling() { export default function Polling() {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const blockNumber = useBlockNumber() const blockNumber = useBlockNumber()
const [isMounting, setIsMounting] = useState(false) const [isMounting, setIsMounting] = useState(false)
const [isHover, setIsHover] = useState(false) const [isHover, setIsHover] = useState(false)
const chainConnectivityWarning = useAppSelector((state) => state.application.chainConnectivityWarning) const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
const blockTime = useCurrentBlockTimestamp()
const waitMsBeforeWarning =
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
useEffect( useEffect(
() => { () => {
...@@ -98,20 +110,14 @@ export default function Polling() { ...@@ -98,20 +110,14 @@ export default function Polling() {
<ExternalLink <ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''} href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
> >
<StyledPolling <StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} warning={warning}>
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
warning={chainConnectivityWarning}
>
<StyledPollingNumber breathe={isMounting} hovering={isHover}> <StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}&ensp; {blockNumber}&ensp;
</StyledPollingNumber> </StyledPollingNumber>
<StyledPollingDot warning={chainConnectivityWarning}> <StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
{isMounting && <Spinner warning={chainConnectivityWarning} />}
</StyledPollingDot>{' '}
</StyledPolling> </StyledPolling>
</ExternalLink> </ExternalLink>
{chainConnectivityWarning && <ChainConnectivityWarning />} {warning && <ChainConnectivityWarning />}
</> </>
) )
} }
...@@ -133,7 +133,7 @@ export const CHAIN_INFO: ChainInfo = { ...@@ -133,7 +133,7 @@ export const CHAIN_INFO: ChainInfo = {
nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 }, nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 },
}, },
[SupportedChainId.OPTIMISM]: { [SupportedChainId.OPTIMISM]: {
blockWaitMsBeforeWarning: ms`10m`, blockWaitMsBeforeWarning: ms`15m`,
bridge: 'https://gateway.optimism.io/', bridge: 'https://gateway.optimism.io/',
docs: 'https://optimism.io/', docs: 'https://optimism.io/',
explorer: 'https://optimistic.etherscan.io/', explorer: 'https://optimistic.etherscan.io/',
...@@ -144,7 +144,7 @@ export const CHAIN_INFO: ChainInfo = { ...@@ -144,7 +144,7 @@ export const CHAIN_INFO: ChainInfo = {
rpcUrls: ['https://mainnet.optimism.io'], rpcUrls: ['https://mainnet.optimism.io'],
}, },
[SupportedChainId.OPTIMISTIC_KOVAN]: { [SupportedChainId.OPTIMISTIC_KOVAN]: {
blockWaitMsBeforeWarning: ms`10m`, blockWaitMsBeforeWarning: ms`15m`,
bridge: 'https://gateway.optimism.io/', bridge: 'https://gateway.optimism.io/',
docs: 'https://optimism.io/', docs: 'https://optimism.io/',
explorer: 'https://optimistic.etherscan.io/', explorer: 'https://optimistic.etherscan.io/',
......
import { useState } from 'react'
import useInterval from './useInterval'
const useMachineTimeMs = (updateInterval: number): number => {
const [now, setNow] = useState(Date.now())
useInterval(() => {
setNow(Date.now())
}, updateInterval)
return now
}
export default useMachineTimeMs
...@@ -19,7 +19,6 @@ describe('application reducer', () => { ...@@ -19,7 +19,6 @@ describe('application reducer', () => {
[1]: 3, [1]: 3,
}, },
chainId: null, chainId: null,
chainConnectivityWarning: false,
implements3085: false, implements3085: false,
openModal: null, openModal: null,
popupList: [], popupList: [],
......
...@@ -25,7 +25,6 @@ type PopupList = Array<{ key: string; show: boolean; content: PopupContent; remo ...@@ -25,7 +25,6 @@ type PopupList = Array<{ key: string; show: boolean; content: PopupContent; remo
export interface ApplicationState { export interface ApplicationState {
readonly blockNumber: { readonly [chainId: number]: number } readonly blockNumber: { readonly [chainId: number]: number }
readonly chainConnectivityWarning: boolean
readonly chainId: number | null readonly chainId: number | null
readonly implements3085: boolean readonly implements3085: boolean
readonly openModal: ApplicationModal | null readonly openModal: ApplicationModal | null
...@@ -34,7 +33,6 @@ export interface ApplicationState { ...@@ -34,7 +33,6 @@ export interface ApplicationState {
const initialState: ApplicationState = { const initialState: ApplicationState = {
blockNumber: {}, blockNumber: {},
chainConnectivityWarning: false,
chainId: null, chainId: null,
implements3085: false, implements3085: false,
openModal: null, openModal: null,
...@@ -80,19 +78,9 @@ const applicationSlice = createSlice({ ...@@ -80,19 +78,9 @@ const applicationSlice = createSlice({
setImplements3085(state, { payload: { implements3085 } }) { setImplements3085(state, { payload: { implements3085 } }) {
state.implements3085 = implements3085 state.implements3085 = implements3085
}, },
setChainConnectivityWarning(state, { payload: { warn } }) {
state.chainConnectivityWarning = warn
},
}, },
}) })
export const { export const { updateChainId, updateBlockNumber, setOpenModal, addPopup, removePopup, setImplements3085 } =
updateChainId, applicationSlice.actions
updateBlockNumber,
setOpenModal,
addPopup,
removePopup,
setImplements3085,
setChainConnectivityWarning,
} = applicationSlice.actions
export default applicationSlice.reducer export default applicationSlice.reducer
import { CHAIN_INFO } from 'constants/chains'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useDebounce from 'hooks/useDebounce' import useDebounce from 'hooks/useDebounce'
import useIsWindowVisible from 'hooks/useIsWindowVisible' import useIsWindowVisible from 'hooks/useIsWindowVisible'
import { useActiveWeb3React } from 'hooks/web3' import { useActiveWeb3React } from 'hooks/web3'
import ms from 'ms.macro' import { useCallback, useEffect, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { api, CHAIN_TAG } from 'state/data/enhanced' import { api, CHAIN_TAG } from 'state/data/enhanced'
import { useAppDispatch, useAppSelector } from 'state/hooks' import { useAppDispatch, useAppSelector } from 'state/hooks'
import { supportedChainId } from 'utils/supportedChainId' import { supportedChainId } from 'utils/supportedChainId'
import { switchToNetwork } from 'utils/switchToNetwork' import { switchToNetwork } from 'utils/switchToNetwork'
import { setChainConnectivityWarning, setImplements3085, updateBlockNumber, updateChainId } from './reducer' import { setImplements3085, updateBlockNumber, updateChainId } from './reducer'
function useQueryCacheInvalidator() { function useQueryCacheInvalidator() {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
...@@ -25,61 +22,6 @@ function useQueryCacheInvalidator() { ...@@ -25,61 +22,6 @@ function useQueryCacheInvalidator() {
}, [chainId, dispatch]) }, [chainId, dispatch])
} }
const NETWORK_HEALTH_CHECK_MS = ms`15s`
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
function useBlockWarningTimer() {
const { chainId } = useActiveWeb3React()
const dispatch = useAppDispatch()
const chainConnectivityWarningActive = useAppSelector((state) => state.application.chainConnectivityWarning)
const timeout = useRef<NodeJS.Timeout>()
const isWindowVisible = useIsWindowVisible()
const [msSinceLastBlock, setMsSinceLastBlock] = useState(0)
const blockTimestamp = useCurrentBlockTimestamp()
const waitMsBeforeWarning =
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
useEffect(() => {
if (blockTimestamp && chainId) {
if (Math.floor(Date.now() - blockTimestamp.mul(1000).toNumber()) > waitMsBeforeWarning) {
if (!chainConnectivityWarningActive) {
dispatch(setChainConnectivityWarning({ warn: true }))
}
} else {
if (chainConnectivityWarningActive) {
dispatch(setChainConnectivityWarning({ warn: false }))
}
}
}
}, [blockTimestamp, chainId, chainConnectivityWarningActive, dispatch, waitMsBeforeWarning])
useEffect(() => {
timeout.current = setTimeout(() => {
setMsSinceLastBlock(NETWORK_HEALTH_CHECK_MS + msSinceLastBlock)
if (msSinceLastBlock > waitMsBeforeWarning && isWindowVisible) {
dispatch(setChainConnectivityWarning({ warn: true }))
} else if (chainConnectivityWarningActive) {
dispatch(setChainConnectivityWarning({ warn: false }))
}
}, NETWORK_HEALTH_CHECK_MS)
return function cleanup() {
if (timeout.current) {
clearTimeout(timeout.current)
}
}
}, [
chainId,
chainConnectivityWarningActive,
dispatch,
isWindowVisible,
msSinceLastBlock,
setMsSinceLastBlock,
waitMsBeforeWarning,
])
}
export default function Updater(): null { export default function Updater(): null {
const { account, chainId, library } = useActiveWeb3React() const { account, chainId, library } = useActiveWeb3React()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
...@@ -90,7 +32,6 @@ export default function Updater(): null { ...@@ -90,7 +32,6 @@ export default function Updater(): null {
blockNumber: null, blockNumber: null,
}) })
useBlockWarningTimer()
useQueryCacheInvalidator() useQueryCacheInvalidator()
const blockNumberCallback = useCallback( const blockNumberCallback = useCallback(
......
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