Commit 984c742d authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: use context for block number (#3708)

* fix: use context for block number

* fix: check for valid BlockNumberContext
parent 00b151d7
......@@ -3,7 +3,7 @@ import 'inter-ui'
import 'polyfills'
import 'components/analytics'
import { BlockUpdater } from 'lib/hooks/useBlockNumber'
import { BlockNumberProvider } from 'lib/hooks/useBlockNumber'
import { MulticallUpdater } from 'lib/state/multicall'
import { StrictMode } from 'react'
import ReactDOM from 'react-dom'
......@@ -40,7 +40,6 @@ function Updaters() {
<UserUpdater />
<ApplicationUpdater />
<TransactionUpdater />
<BlockUpdater />
<MulticallUpdater />
<LogsUpdater />
</>
......@@ -55,11 +54,13 @@ ReactDOM.render(
<Web3ReactProvider getLibrary={getLibrary}>
<Web3ProviderNetwork getLibrary={getLibrary}>
<Blocklist>
<Updaters />
<ThemeProvider>
<ThemedGlobalStyle />
<App />
</ThemeProvider>
<BlockNumberProvider>
<Updaters />
<ThemeProvider>
<ThemedGlobalStyle />
<App />
</ThemeProvider>
</BlockNumberProvider>
</Blocklist>
</Web3ProviderNetwork>
</Web3ReactProvider>
......
......@@ -4,7 +4,7 @@ import { DEFAULT_LOCALE, SUPPORTED_LOCALES, SupportedLocale } from 'constants/lo
import { Provider as AtomProvider } from 'jotai'
import { TransactionsUpdater } from 'lib/hooks/transactions'
import { ActiveWeb3Provider } from 'lib/hooks/useActiveWeb3React'
import { BlockUpdater } from 'lib/hooks/useBlockNumber'
import { BlockNumberProvider } from 'lib/hooks/useBlockNumber'
import { Provider as I18nProvider } from 'lib/i18n'
import { MulticallUpdater, store as multicallStore } from 'lib/state/multicall'
import styled, { keyframes, Theme, ThemeProvider } from 'lib/theme'
......@@ -83,7 +83,6 @@ const DialogWrapper = styled.div`
function Updaters() {
return (
<>
<BlockUpdater />
<MulticallUpdater />
<TransactionsUpdater />
</>
......@@ -130,8 +129,10 @@ export default function Widget(props: PropsWithChildren<WidgetProps>) {
<ReduxProvider store={multicallStore}>
<AtomProvider>
<ActiveWeb3Provider provider={provider} jsonRpcEndpoint={jsonRpcEndpoint}>
<Updaters />
{children}
<BlockNumberProvider>
<Updaters />
{children}
</BlockNumberProvider>
</ActiveWeb3Provider>
</AtomProvider>
</ReduxProvider>
......
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useIsWindowVisible from 'hooks/useIsWindowVisible'
import { atom } from 'jotai'
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { useCallback, useEffect } from 'react'
import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react'
interface ChainBlock {
chainId?: number
block?: number
const MISSING_PROVIDER = Symbol()
const BlockNumberContext = createContext<
| {
value?: number
fastForward(block: number): void
}
| typeof MISSING_PROVIDER
>(MISSING_PROVIDER)
function useBlockNumberContext() {
const blockNumber = useContext(BlockNumberContext)
if (blockNumber === MISSING_PROVIDER) {
throw new Error('BlockNumber hooks must be wrapped in a <BlockNumberProvider>')
}
return blockNumber
}
const chainBlockAtom = atom<ChainBlock>({})
function useUpdateChainBlock() {
const { chainId, library } = useActiveWeb3React()
const windowVisible = useIsWindowVisible()
const setChainBlock = useUpdateAtom(chainBlockAtom)
/** Requires that BlockUpdater be installed in the DOM tree. */
export default function useBlockNumber(): number | undefined {
return useBlockNumberContext().value
}
export function useFastForwardBlockNumber(): (block: number) => void {
return useBlockNumberContext().fastForward
}
export function BlockNumberProvider({ children }: { children: ReactNode }) {
const { chainId: activeChainId, library } = useActiveWeb3React()
const [{ chainId, block }, setChainBlock] = useState<{ chainId?: number; block?: number }>({ chainId: activeChainId })
const onBlock = useCallback(
(block: number) => {
setChainBlock((chainBlock) => {
if (chainBlock.chainId === chainId) {
if (chainBlock.chainId === activeChainId) {
if (!chainBlock.block || chainBlock.block < block) {
return { chainId, block }
return { chainId: activeChainId, block }
}
}
return chainBlock
})
},
[chainId, setChainBlock]
[activeChainId, setChainBlock]
)
const windowVisible = useIsWindowVisible()
useEffect(() => {
if (library && chainId && windowVisible) {
if (library && activeChainId && windowVisible) {
// If chainId hasn't changed, don't clear the block. This prevents re-fetching still valid data.
setChainBlock((chainBlock) => (chainBlock.chainId === chainId ? chainBlock : { chainId }))
setChainBlock((chainBlock) => (chainBlock.chainId === activeChainId ? chainBlock : { chainId: activeChainId }))
library
.getBlockNumber()
.then(onBlock)
.catch((error) => {
console.error(`Failed to get block number for chainId ${chainId}`, error)
console.error(`Failed to get block number for chainId ${activeChainId}`, error)
})
library.on('block', onBlock)
......@@ -47,23 +65,14 @@ function useUpdateChainBlock() {
}
}
return undefined
}, [chainId, library, onBlock, setChainBlock, windowVisible])
}
export function BlockUpdater() {
useUpdateChainBlock()
return null
}
/** Requires that BlockUpdater be installed in the DOM tree. */
export default function useBlockNumber(): number | undefined {
const { chainId: activeChainId } = useActiveWeb3React()
const { chainId, block } = useAtomValue(chainBlockAtom)
return activeChainId === chainId ? block : undefined
}
}, [activeChainId, library, onBlock, setChainBlock, windowVisible])
export function useFastForwardBlockNumber(): (block: number) => void {
const { chainId } = useActiveWeb3React()
const setChainBlock = useUpdateAtom(chainBlockAtom)
return useCallback((block: number) => setChainBlock({ chainId, block }), [chainId, setChainBlock])
const value = useMemo(
() => ({
value: chainId === activeChainId ? block : undefined,
fastForward: (block: number) => setChainBlock({ chainId: activeChainId, block }),
}),
[activeChainId, block, chainId]
)
return <BlockNumberContext.Provider value={value}>{children}</BlockNumberContext.Provider>
}
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