import { ReactNode, useEffect, useMemo, useReducer, useState } from 'react' import { providers } from 'ethers' import { useConfig } from '../../../hooks' import { Providers } from './model' import { ReadonlyNetworksContext } from './context' import { BaseProviderFactory, ChainId, NodeUrls } from '../../../constants' import { fromEntries } from '../../../helpers/fromEntries' import { networkStatesReducer } from './reducer' import { useWindow } from '../../window' const { Provider, StaticJsonRpcProvider } = providers type BaseProvider = providers.BaseProvider interface NetworkProviderProps { providerOverrides?: Providers children?: ReactNode } const getProviderFromConfig = (urlOrProviderOrProviderFunction: string | BaseProvider | BaseProviderFactory) => { if (Provider.isProvider(urlOrProviderOrProviderFunction)) { return urlOrProviderOrProviderFunction } if (typeof urlOrProviderOrProviderFunction === 'function') { return urlOrProviderOrProviderFunction() } return new StaticJsonRpcProvider(urlOrProviderOrProviderFunction) } export const getProvidersFromConfig = (readOnlyUrls: NodeUrls) => fromEntries( Object.entries(readOnlyUrls).map(([chainId, urlOrProviderOrProviderFunction]) => [ chainId, getProviderFromConfig(urlOrProviderOrProviderFunction), ]) ) export function ReadonlyNetworksProvider({ providerOverrides = {}, children }: NetworkProviderProps) { const { readOnlyUrls = {} } = useConfig() const { isActive } = useWindow() const [providers, setProviders] = useState(() => ({ ...getProvidersFromConfig(readOnlyUrls), ...providerOverrides, })) const [networkStates, dispatchNetworkState] = useReducer(networkStatesReducer, { ...fromEntries( Object.keys({ ...readOnlyUrls, ...providerOverrides }).map((chainId) => [chainId, { nonStaticCalls: 0 }]) ), }) useEffect(() => { setProviders({ ...getProvidersFromConfig(readOnlyUrls), ...providerOverrides }) }, Object.entries(readOnlyUrls).flat()) useEffect(() => { for (const [chainId, { nonStaticCalls }] of Object.entries(networkStates)) { const provider = providers[(chainId as unknown) as ChainId] if (provider) { provider.polling = isActive && nonStaticCalls > 0 } } }, [networkStates, isActive]) const networks = useMemo( () => ({ providers, updateNetworkState: dispatchNetworkState, }), [providers, dispatchNetworkState] ) return {children} }