fix: convert token list to context (#3712)
* fix: convert token list to context * fix: cosmos
This commit is contained in:
parent
984c742d0e
commit
6294915be6
@ -1,4 +1,3 @@
|
||||
import { tokens } from '@uniswap/default-token-list'
|
||||
import { DAI, USDC_MAINNET } from 'constants/tokens'
|
||||
import { useUpdateAtom } from 'jotai/utils'
|
||||
import { useEffect } from 'react'
|
||||
@ -65,7 +64,6 @@ function Fixture() {
|
||||
defaultInputAmount={defaultInputAmount}
|
||||
defaultOutputTokenAddress={optionsToAddressMap[defaultOutputToken]}
|
||||
defaultOutputAmount={defaultOutputAmount}
|
||||
tokenList={tokens}
|
||||
onConnectWallet={() => console.log('onConnectWallet')} // this handler is included as a test of functionality, but only logs
|
||||
/>
|
||||
)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { TokenInfo } from '@uniswap/token-lists'
|
||||
import { useAtom } from 'jotai'
|
||||
import { SwapInfoProvider } from 'lib/hooks/swap/useSwapInfo'
|
||||
import useSyncConvenienceFee, { FeeOptions } from 'lib/hooks/swap/useSyncConvenienceFee'
|
||||
@ -8,7 +7,6 @@ import { usePendingTransactions } from 'lib/hooks/transactions'
|
||||
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
|
||||
import useHasFocus from 'lib/hooks/useHasFocus'
|
||||
import useOnSupportedNetwork from 'lib/hooks/useOnSupportedNetwork'
|
||||
import { useIsTokenListLoaded, useSyncTokenList } from 'lib/hooks/useTokenList'
|
||||
import { displayTxHashAtom } from 'lib/state/swap'
|
||||
import { SwapTransactionInfo, Transaction, TransactionType, WrapTransactionInfo } from 'lib/state/transactions'
|
||||
import { useState } from 'react'
|
||||
@ -43,18 +41,13 @@ function getTransactionFromMap(
|
||||
}
|
||||
|
||||
export interface SwapProps extends TokenDefaults, FeeOptions {
|
||||
tokenList?: string | TokenInfo[]
|
||||
onConnectWallet?: () => void
|
||||
}
|
||||
|
||||
function Updaters(props: SwapProps) {
|
||||
useSyncTokenDefaults(props)
|
||||
useSyncConvenienceFee(props)
|
||||
return null
|
||||
}
|
||||
|
||||
export default function Swap(props: SwapProps) {
|
||||
useValidate(props)
|
||||
useSyncConvenienceFee(props)
|
||||
useSyncTokenDefaults(props)
|
||||
|
||||
const { active, account } = useActiveWeb3React()
|
||||
const [wrapper, setWrapper] = useState<HTMLDivElement | null>(null)
|
||||
@ -66,14 +59,10 @@ export default function Swap(props: SwapProps) {
|
||||
const onSupportedNetwork = useOnSupportedNetwork()
|
||||
const isDisabled = !(active && onSupportedNetwork)
|
||||
|
||||
useSyncTokenList(props.tokenList)
|
||||
const isTokenListLoaded = useIsTokenListLoaded()
|
||||
|
||||
const focused = useHasFocus(wrapper)
|
||||
|
||||
return (
|
||||
<>
|
||||
{isTokenListLoaded && <Updaters {...props} />}
|
||||
<Header title={<Trans>Swap</Trans>}>
|
||||
{active && <Wallet disabled={!account} onClick={props.onConnectWallet} />}
|
||||
<Settings disabled={isDisabled} />
|
||||
|
@ -1,15 +1,15 @@
|
||||
import DEFAULT_TOKEN_LIST from '@uniswap/default-token-list'
|
||||
import { useSyncTokenList } from 'lib/hooks/useTokenList'
|
||||
import { TokenListProvider } from 'lib/hooks/useTokenList'
|
||||
|
||||
import { Modal } from './Dialog'
|
||||
import { TokenSelectDialog } from './TokenSelect'
|
||||
|
||||
export default function Fixture() {
|
||||
useSyncTokenList(DEFAULT_TOKEN_LIST.tokens)
|
||||
|
||||
return (
|
||||
<Modal color="module">
|
||||
<TokenSelectDialog onSelect={() => void 0} />
|
||||
<TokenListProvider list={DEFAULT_TOKEN_LIST.tokens}>
|
||||
<TokenSelectDialog onSelect={() => void 0} />
|
||||
</TokenListProvider>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ const SearchInput = styled(StringInput)`
|
||||
function usePrefetchBalances() {
|
||||
const { account } = useActiveWeb3React()
|
||||
const tokenList = useTokenList()
|
||||
const [prefetchedTokenList, setPrefetchedTokenList] = useState(tokenList)
|
||||
useEffect(() => setPrefetchedTokenList(tokenList), [tokenList])
|
||||
useCurrencyBalances(account, tokenList !== prefetchedTokenList ? tokenList : undefined)
|
||||
const prefetchedTokenList = useRef<typeof tokenList>()
|
||||
useCurrencyBalances(account, tokenList !== prefetchedTokenList.current ? tokenList : undefined)
|
||||
prefetchedTokenList.current = tokenList
|
||||
}
|
||||
|
||||
function useAreBalancesLoaded(): boolean {
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { JsonRpcProvider } from '@ethersproject/providers'
|
||||
import { TokenInfo } from '@uniswap/token-lists'
|
||||
import { Provider as Eip1193Provider } from '@web3-react/types'
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
|
||||
import { Provider as AtomProvider } from 'jotai'
|
||||
import { TransactionsUpdater } from 'lib/hooks/transactions'
|
||||
import { ActiveWeb3Provider } from 'lib/hooks/useActiveWeb3React'
|
||||
import { BlockNumberProvider } from 'lib/hooks/useBlockNumber'
|
||||
import { TokenListProvider } from 'lib/hooks/useTokenList'
|
||||
import { Provider as I18nProvider } from 'lib/i18n'
|
||||
import { MulticallUpdater, store as multicallStore } from 'lib/state/multicall'
|
||||
import styled, { keyframes, Theme, ThemeProvider } from 'lib/theme'
|
||||
@ -80,20 +82,12 @@ const DialogWrapper = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
function Updaters() {
|
||||
return (
|
||||
<>
|
||||
<MulticallUpdater />
|
||||
<TransactionsUpdater />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export type WidgetProps = {
|
||||
theme?: Theme
|
||||
locale?: SupportedLocale
|
||||
provider?: Eip1193Provider | JsonRpcProvider
|
||||
jsonRpcEndpoint?: string | JsonRpcProvider
|
||||
tokenList?: string | TokenInfo[]
|
||||
width?: string | number
|
||||
dialog?: HTMLElement | null
|
||||
className?: string
|
||||
@ -130,8 +124,9 @@ export default function Widget(props: PropsWithChildren<WidgetProps>) {
|
||||
<AtomProvider>
|
||||
<ActiveWeb3Provider provider={provider} jsonRpcEndpoint={jsonRpcEndpoint}>
|
||||
<BlockNumberProvider>
|
||||
<Updaters />
|
||||
{children}
|
||||
<MulticallUpdater />
|
||||
<TransactionsUpdater />
|
||||
<TokenListProvider list={props.tokenList}>{children}</TokenListProvider>
|
||||
</BlockNumberProvider>
|
||||
</ActiveWeb3Provider>
|
||||
</AtomProvider>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { tokens } from '@uniswap/default-token-list'
|
||||
import { initializeConnector } from '@web3-react/core'
|
||||
import { MetaMask } from '@web3-react/metamask'
|
||||
import { Connector } from '@web3-react/types'
|
||||
@ -75,6 +76,7 @@ export default function Wrapper({ children }: { children: ReactNode }) {
|
||||
locale={locale}
|
||||
jsonRpcEndpoint={jsonRpcEndpoint === NO_JSON_RPC ? undefined : jsonRpcEndpoint}
|
||||
provider={connector?.provider}
|
||||
tokenList={tokens}
|
||||
>
|
||||
{children}
|
||||
</Widget>
|
||||
|
@ -5,9 +5,10 @@ import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
|
||||
import { useToken } from 'lib/hooks/useCurrency'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
import { Field, Swap, swapAtom } from 'lib/state/swap'
|
||||
import { useCallback, useLayoutEffect, useRef } from 'react'
|
||||
import { useCallback, useRef } from 'react'
|
||||
|
||||
import useOnSupportedNetwork from '../useOnSupportedNetwork'
|
||||
import { useIsTokenListLoaded } from '../useTokenList'
|
||||
|
||||
export type DefaultAddress = string | { [chainId: number]: string | 'NATIVE' } | 'NATIVE'
|
||||
|
||||
@ -72,10 +73,9 @@ export default function useSyncTokenDefaults({
|
||||
}, [defaultInputAmount, defaultInputToken, defaultOutputAmount, defaultOutputToken, updateSwap])
|
||||
|
||||
const lastChainId = useRef<number | undefined>(undefined)
|
||||
useLayoutEffect(() => {
|
||||
if (chainId && chainId !== lastChainId.current) {
|
||||
setToDefaults()
|
||||
}
|
||||
const shouldSync = useIsTokenListLoaded() && chainId && chainId !== lastChainId.current
|
||||
if (shouldSync) {
|
||||
setToDefaults()
|
||||
lastChainId.current = chainId
|
||||
}, [chainId, setToDefaults])
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { NativeCurrency, Token } from '@uniswap/sdk-core'
|
||||
import { TokenInfo, TokenList } from '@uniswap/token-lists'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
|
||||
import resolveENSContentHash from 'lib/utils/resolveENSContentHash'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { createContext, PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
|
||||
|
||||
import fetchTokenList from './fetchTokenList'
|
||||
@ -14,19 +12,61 @@ import { validateTokens } from './validateTokenList'
|
||||
|
||||
export const DEFAULT_TOKEN_LIST = 'https://gateway.ipfs.io/ipns/tokens.uniswap.org'
|
||||
|
||||
const chainTokenMapAtom = atom<ChainTokenMap | null>(null)
|
||||
const MISSING_PROVIDER = Symbol()
|
||||
const ChainTokenMapContext = createContext<ChainTokenMap | undefined | typeof MISSING_PROVIDER>(MISSING_PROVIDER)
|
||||
|
||||
export function useIsTokenListLoaded() {
|
||||
return Boolean(useAtomValue(chainTokenMapAtom))
|
||||
function useChainTokenMapContext() {
|
||||
const chainTokenMap = useContext(ChainTokenMapContext)
|
||||
if (chainTokenMap === MISSING_PROVIDER) {
|
||||
throw new Error('TokenList hooks must be wrapped in a <TokenListProvider>')
|
||||
}
|
||||
return chainTokenMap
|
||||
}
|
||||
|
||||
export function useSyncTokenList(list: string | TokenInfo[] = DEFAULT_TOKEN_LIST): void {
|
||||
export function useIsTokenListLoaded() {
|
||||
return Boolean(useChainTokenMapContext())
|
||||
}
|
||||
|
||||
export default function useTokenList(): WrappedTokenInfo[] {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const chainTokenMap = useChainTokenMapContext()
|
||||
const tokenMap = chainId && chainTokenMap?.[chainId]
|
||||
return useMemo(() => {
|
||||
if (!tokenMap) return []
|
||||
return Object.values(tokenMap).map(({ token }) => token)
|
||||
}, [tokenMap])
|
||||
}
|
||||
|
||||
export type TokenMap = { [address: string]: Token }
|
||||
|
||||
export function useTokenMap(): TokenMap {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const chainTokenMap = useChainTokenMapContext()
|
||||
const tokenMap = chainId && chainTokenMap?.[chainId]
|
||||
return useMemo(() => {
|
||||
if (!tokenMap) return {}
|
||||
return Object.entries(tokenMap).reduce((map, [address, { token }]) => {
|
||||
map[address] = token
|
||||
return map
|
||||
}, {} as TokenMap)
|
||||
}, [tokenMap])
|
||||
}
|
||||
|
||||
export function useQueryCurrencies(query = ''): (WrappedTokenInfo | NativeCurrency)[] {
|
||||
return useQueryTokens(query, useTokenList())
|
||||
}
|
||||
|
||||
export function TokenListProvider({
|
||||
list = DEFAULT_TOKEN_LIST,
|
||||
children,
|
||||
}: PropsWithChildren<{ list?: string | TokenInfo[] }>) {
|
||||
// Error boundaries will not catch (non-rendering) async errors, but it should still be shown
|
||||
const [error, setError] = useState<Error>()
|
||||
if (error) throw error
|
||||
|
||||
const [chainTokenMap, setChainTokenMap] = useAtom(chainTokenMapAtom)
|
||||
useEffect(() => setChainTokenMap(null), [list, setChainTokenMap])
|
||||
const [chainTokenMap, setChainTokenMap] = useState<ChainTokenMap>()
|
||||
|
||||
useEffect(() => setChainTokenMap(undefined), [list])
|
||||
|
||||
const { chainId, library } = useActiveWeb3React()
|
||||
const resolver = useCallback(
|
||||
@ -70,34 +110,7 @@ export function useSyncTokenList(list: string | TokenInfo[] = DEFAULT_TOKEN_LIST
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [chainTokenMap, list, resolver, setChainTokenMap])
|
||||
}
|
||||
}, [chainTokenMap, list, resolver])
|
||||
|
||||
export default function useTokenList(): WrappedTokenInfo[] {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const chainTokenMap = useAtomValue(chainTokenMapAtom)
|
||||
const tokenMap = chainId && chainTokenMap?.[chainId]
|
||||
return useMemo(() => {
|
||||
if (!tokenMap) return []
|
||||
return Object.values(tokenMap).map(({ token }) => token)
|
||||
}, [tokenMap])
|
||||
}
|
||||
|
||||
export type TokenMap = { [address: string]: Token }
|
||||
|
||||
export function useTokenMap(): TokenMap {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const chainTokenMap = useAtomValue(chainTokenMapAtom)
|
||||
const tokenMap = chainId && chainTokenMap?.[chainId]
|
||||
return useMemo(() => {
|
||||
if (!tokenMap) return {}
|
||||
return Object.entries(tokenMap).reduce((map, [address, { token }]) => {
|
||||
map[address] = token
|
||||
return map
|
||||
}, {} as TokenMap)
|
||||
}, [tokenMap])
|
||||
}
|
||||
|
||||
export function useQueryCurrencies(query = ''): (WrappedTokenInfo | NativeCurrency)[] {
|
||||
return useQueryTokens(query, useTokenList())
|
||||
return <ChainTokenMapContext.Provider value={chainTokenMap}>{children}</ChainTokenMapContext.Provider>
|
||||
}
|
Loading…
Reference in New Issue
Block a user