diff --git a/src/hooks/Tokens.ts b/src/hooks/Tokens.ts deleted file mode 100644 index dff601aca39..00000000000 --- a/src/hooks/Tokens.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { arrayify } from '@ethersproject/bytes' -import { parseBytes32String } from '@ethersproject/strings' -import { Currency, Token } from '@uniswap/sdk-core' -import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains' -import { useMemo } from 'react' - -import { createTokenFilterFunction } from '../components/SearchModal/filtering' -import { ExtendedEther, WETH9_EXTENDED } from '../constants/tokens' -import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks' -import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo' -import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks' -import { useUserAddedTokens } from '../state/user/hooks' -import { isAddress } from '../utils' -import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks' -import { useBytes32TokenContract, useTokenContract } from './useContract' -import { useActiveWeb3React } from './web3' - -// reduce token map into standard address <-> Token mapping, optionally include user added tokens -function useTokensFromMap(tokenMap: TokenAddressMap, includeUserAdded: boolean): { [address: string]: Token } { - const { chainId } = useActiveWeb3React() - const userAddedTokens = useUserAddedTokens() - - return useMemo(() => { - if (!chainId) return {} - - // reduce to just tokens - const mapWithoutUrls = Object.keys(tokenMap[chainId] ?? {}).reduce<{ [address: string]: Token }>( - (newMap, address) => { - newMap[address] = tokenMap[chainId][address].token - return newMap - }, - {} - ) - - if (includeUserAdded) { - return ( - userAddedTokens - // reduce into all ALL_TOKENS filtered by the current chain - .reduce<{ [address: string]: Token }>( - (tokenMap, token) => { - tokenMap[token.address] = token - return tokenMap - }, - // must make a copy because reduce modifies the map, and we do not - // want to make a copy in every iteration - { ...mapWithoutUrls } - ) - ) - } - - return mapWithoutUrls - }, [chainId, userAddedTokens, tokenMap, includeUserAdded]) -} - -export function useAllTokens(): { [address: string]: Token } { - const allTokens = useCombinedActiveList() - return useTokensFromMap(allTokens, true) -} - -type BridgeInfo = Record< - SupportedChainId, - { - tokenAddress: string - originBridgeAddress: string - destBridgeAddress: string - } -> - -export function useUnsupportedTokens(): { [address: string]: Token } { - const { chainId } = useActiveWeb3React() - const listsByUrl = useAllLists() - const unsupportedTokensMap = useUnsupportedTokenList() - const unsupportedTokens = useTokensFromMap(unsupportedTokensMap, false) - - // 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)) { - return {} - } - - if (!listsByUrl) { - return {} - } - - const listUrl = CHAIN_INFO[chainId as SupportedL2ChainId].defaultListUrl - const { current: list } = listsByUrl[listUrl] - if (!list) { - return {} - } - - const unsupportedSet = new Set(Object.keys(unsupportedTokens)) - - return list.tokens.reduce((acc, tokenInfo) => { - const bridgeInfo = tokenInfo.extensions?.bridgeInfo as unknown as BridgeInfo - if ( - bridgeInfo && - bridgeInfo[SupportedChainId.MAINNET] && - bridgeInfo[SupportedChainId.MAINNET].tokenAddress && - unsupportedSet.has(bridgeInfo[SupportedChainId.MAINNET].tokenAddress) - ) { - const address = bridgeInfo[SupportedChainId.MAINNET].tokenAddress - // don't rely on decimals--it's possible that a token could be bridged w/ different decimals on the L2 - return { ...acc, [address]: new Token(SupportedChainId.MAINNET, address, tokenInfo.decimals) } - } - return acc - }, {}) - }, [chainId, listsByUrl, unsupportedTokens]) - - return { ...unsupportedTokens, ...l2InferredBlockedTokens } -} - -export function useSearchInactiveTokenLists(search: string | undefined, minResults = 10): WrappedTokenInfo[] { - const lists = useAllLists() - const inactiveUrls = useInactiveListUrls() - const { chainId } = useActiveWeb3React() - const activeTokens = useAllTokens() - return useMemo(() => { - if (!search || search.trim().length === 0) return [] - const tokenFilter = createTokenFilterFunction(search) - const result: WrappedTokenInfo[] = [] - const addressSet: { [address: string]: true } = {} - for (const url of inactiveUrls) { - const list = lists[url].current - if (!list) continue - for (const tokenInfo of list.tokens) { - if (tokenInfo.chainId === chainId && tokenFilter(tokenInfo)) { - const wrapped: WrappedTokenInfo = new WrappedTokenInfo(tokenInfo, list) - if (!(wrapped.address in activeTokens) && !addressSet[wrapped.address]) { - addressSet[wrapped.address] = true - result.push(wrapped) - if (result.length >= minResults) return result - } - } - } - } - return result - }, [activeTokens, chainId, inactiveUrls, lists, minResults, search]) -} - -export function useIsTokenActive(token: Token | undefined | null): boolean { - const activeTokens = useAllTokens() - - if (!activeTokens || !token) { - return false - } - - return !!activeTokens[token.address] -} - -// Check if currency is included in custom list from user storage -export function useIsUserAddedToken(currency: Currency | undefined | null): boolean { - const userAddedTokens = useUserAddedTokens() - - if (!currency) { - return false - } - - return !!userAddedTokens.find((token) => currency.equals(token)) -} - -// parse a name or symbol from a token response -const BYTES32_REGEX = /^0x[a-fA-F0-9]{64}$/ - -function parseStringOrBytes32(str: string | undefined, bytes32: string | undefined, defaultValue: string): string { - return str && str.length > 0 - ? str - : // need to check for proper bytes string and valid terminator - bytes32 && BYTES32_REGEX.test(bytes32) && arrayify(bytes32)[31] === 0 - ? parseBytes32String(bytes32) - : defaultValue -} - -// undefined if invalid or does not exist -// null if loading or null was passed -// otherwise returns the token -export function useToken(tokenAddress?: string | null): Token | undefined | null { - const { chainId } = useActiveWeb3React() - const tokens = useAllTokens() - - const address = isAddress(tokenAddress) - - const tokenContract = useTokenContract(address ? address : undefined, false) - const tokenContractBytes32 = useBytes32TokenContract(address ? address : undefined, false) - const token: Token | undefined = address ? tokens[address] : undefined - - const tokenName = useSingleCallResult(token ? undefined : tokenContract, 'name', undefined, NEVER_RELOAD) - const tokenNameBytes32 = useSingleCallResult( - token ? undefined : tokenContractBytes32, - 'name', - undefined, - NEVER_RELOAD - ) - const symbol = useSingleCallResult(token ? undefined : tokenContract, 'symbol', undefined, NEVER_RELOAD) - const symbolBytes32 = useSingleCallResult(token ? undefined : tokenContractBytes32, 'symbol', undefined, NEVER_RELOAD) - const decimals = useSingleCallResult(token ? undefined : tokenContract, 'decimals', undefined, NEVER_RELOAD) - - return useMemo(() => { - if (token) return token - if (tokenAddress === null) return null - if (!chainId || !address) return undefined - if (decimals.loading || symbol.loading || tokenName.loading) return null - if (decimals.result) { - return new Token( - chainId, - address, - decimals.result[0], - parseStringOrBytes32(symbol.result?.[0], symbolBytes32.result?.[0], 'UNKNOWN'), - parseStringOrBytes32(tokenName.result?.[0], tokenNameBytes32.result?.[0], 'Unknown Token') - ) - } - return undefined - }, [ - address, - chainId, - decimals.loading, - decimals.result, - symbol.loading, - symbol.result, - symbolBytes32.result, - token, - tokenAddress, - tokenName.loading, - tokenName.result, - tokenNameBytes32.result, - ]) -} - -export function useCurrency(currencyId: string | null | undefined): Currency | null | undefined { - const { chainId } = useActiveWeb3React() - const isETH = currencyId?.toUpperCase() === 'ETH' - const token = useToken(isETH ? undefined : currencyId) - const extendedEther = useMemo( - () => - chainId - ? ExtendedEther.onChain(chainId) - : // display mainnet when not connected - ExtendedEther.onChain(SupportedChainId.MAINNET), - [chainId] - ) - const weth = chainId ? WETH9_EXTENDED[chainId] : undefined - if (currencyId === null || currencyId === undefined) return currencyId - if (weth?.address?.toUpperCase() === currencyId?.toUpperCase()) return weth - return isETH ? extendedEther : token -} diff --git a/src/hooks/useActiveLocale.ts b/src/hooks/useActiveLocale.ts deleted file mode 100644 index d14b34863eb..00000000000 --- a/src/hooks/useActiveLocale.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { DEFAULT_LOCALE, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales' -import { useMemo } from 'react' -import store from 'state' -import { useUserLocale } from 'state/user/hooks' - -import useParsedQueryString from './useParsedQueryString' -import { parsedQueryString } from './useParsedQueryString' - -/** - * Given a locale string (e.g. from user agent), return the best match for corresponding SupportedLocale - * @param maybeSupportedLocale the fuzzy locale identifier - */ -function parseLocale(maybeSupportedLocale: unknown): SupportedLocale | undefined { - if (typeof maybeSupportedLocale !== 'string') return undefined - const lowerMaybeSupportedLocale = maybeSupportedLocale.toLowerCase() - return SUPPORTED_LOCALES.find( - (locale) => locale.toLowerCase() === lowerMaybeSupportedLocale || locale.split('-')[0] === lowerMaybeSupportedLocale - ) -} - -/** - * Returns the supported locale read from the user agent (navigator) - */ -export function navigatorLocale(): SupportedLocale | undefined { - if (!navigator.language) return undefined - - const [language, region] = navigator.language.split('-') - - if (region) { - return parseLocale(`${language}-${region.toUpperCase()}`) ?? parseLocale(language) - } - - return parseLocale(language) -} - -function storeLocale(): SupportedLocale | undefined { - return store.getState().user.userLocale ?? undefined -} - -export const initialLocale = - parseLocale(parsedQueryString().lng) ?? storeLocale() ?? navigatorLocale() ?? DEFAULT_LOCALE - -function useUrlLocale() { - const parsed = useParsedQueryString() - return parseLocale(parsed.lng) -} - -/** - * Returns the currently active locale, from a combination of user agent, query string, and user settings stored in redux - * Stores the query string locale in redux (if set) to persist across sessions - */ -export function useActiveLocale(): SupportedLocale { - const urlLocale = useUrlLocale() - const userLocale = useUserLocale() - return useMemo(() => urlLocale ?? userLocale ?? navigatorLocale() ?? DEFAULT_LOCALE, [urlLocale, userLocale]) -} diff --git a/src/hooks/useAddTokenToMetamask.ts b/src/hooks/useAddTokenToMetamask.ts deleted file mode 100644 index a8a582ed5e8..00000000000 --- a/src/hooks/useAddTokenToMetamask.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Currency, Token } from '@uniswap/sdk-core' -import { useActiveWeb3React } from 'hooks/web3' -import { useCallback, useState } from 'react' - -import { getTokenLogoURL } from './../components/CurrencyLogo/index' - -export default function useAddTokenToMetamask(currencyToAdd: Currency | undefined): { - addToken: () => void - success: boolean | undefined -} { - const { library } = useActiveWeb3React() - - const token: Token | undefined = currencyToAdd?.wrapped - - const [success, setSuccess] = useState() - - const addToken = useCallback(() => { - if (library && library.provider.isMetaMask && library.provider.request && token) { - library.provider - .request({ - method: 'wallet_watchAsset', - params: { - //@ts-ignore // need this for incorrect ethers provider type - type: 'ERC20', - options: { - address: token.address, - symbol: token.symbol, - decimals: token.decimals, - image: getTokenLogoURL(token.address), - }, - }, - }) - .then((success) => { - setSuccess(success) - }) - .catch(() => setSuccess(false)) - } else { - setSuccess(false) - } - }, [library, token]) - - return { addToken, success } -} diff --git a/src/hooks/useAllCurrencyCombinations.ts b/src/hooks/useAllCurrencyCombinations.ts deleted file mode 100644 index 4edcf37acdf..00000000000 --- a/src/hooks/useAllCurrencyCombinations.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Currency, Token } from '@uniswap/sdk-core' -import { useMemo } from 'react' - -import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../constants/routing' - -export function useAllCurrencyCombinations(currencyA?: Currency, currencyB?: Currency): [Token, Token][] { - const chainId = currencyA?.chainId - - const [tokenA, tokenB] = chainId ? [currencyA?.wrapped, currencyB?.wrapped] : [undefined, undefined] - - const bases: Token[] = useMemo(() => { - if (!chainId || chainId !== tokenB?.chainId) return [] - - const common = BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? [] - const additionalA = tokenA ? ADDITIONAL_BASES[chainId]?.[tokenA.address] ?? [] : [] - const additionalB = tokenB ? ADDITIONAL_BASES[chainId]?.[tokenB.address] ?? [] : [] - - return [...common, ...additionalA, ...additionalB] - }, [chainId, tokenA, tokenB]) - - const basePairs: [Token, Token][] = useMemo( - () => - bases - .flatMap((base): [Token, Token][] => bases.map((otherBase) => [base, otherBase])) - // though redundant with the first filter below, that expression runs more often, so this is probably worthwhile - .filter(([t0, t1]) => !t0.equals(t1)), - [bases] - ) - - return useMemo( - () => - tokenA && tokenB - ? [ - // the direct pair - [tokenA, tokenB] as [Token, Token], - // token A against all bases - ...bases.map((base): [Token, Token] => [tokenA, base]), - // token B against all bases - ...bases.map((base): [Token, Token] => [tokenB, base]), - // each base against all bases - ...basePairs, - ] - // filter out invalid pairs comprised of the same asset (e.g. WETH<>WETH) - .filter(([t0, t1]) => !t0.equals(t1)) - // filter out duplicate pairs - .filter(([t0, t1], i, otherPairs) => { - // find the first index in the array at which there are the same 2 tokens as the current - const firstIndexInOtherPairs = otherPairs.findIndex(([t0Other, t1Other]) => { - return (t0.equals(t0Other) && t1.equals(t1Other)) || (t0.equals(t1Other) && t1.equals(t0Other)) - }) - // only accept the first occurrence of the same 2 tokens - return firstIndexInOtherPairs === i - }) - // optionally filter out some pairs for tokens with custom bases defined - .filter(([tokenA, tokenB]) => { - if (!chainId) return true - const customBases = CUSTOM_BASES[chainId] - - const customBasesA: Token[] | undefined = customBases?.[tokenA.address] - const customBasesB: Token[] | undefined = customBases?.[tokenB.address] - - if (!customBasesA && !customBasesB) return true - - if (customBasesA && !customBasesA.find((base) => tokenB.equals(base))) return false - if (customBasesB && !customBasesB.find((base) => tokenA.equals(base))) return false - - return true - }) - : [], - [tokenA, tokenB, bases, basePairs, chainId] - ) -} diff --git a/src/hooks/useAllV3Routes.ts b/src/hooks/useAllV3Routes.ts deleted file mode 100644 index 22ca97821cd..00000000000 --- a/src/hooks/useAllV3Routes.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Currency } from '@uniswap/sdk-core' -import { Pool, Route } from '@uniswap/v3-sdk' -import { useMemo } from 'react' - -import { useV3SwapPools } from './useV3SwapPools' -import { useActiveWeb3React } from './web3' - -/** - * Returns true if poolA is equivalent to poolB - * @param poolA one of the two pools - * @param poolB the other pool - */ -function poolEquals(poolA: Pool, poolB: Pool): boolean { - return ( - poolA === poolB || - (poolA.token0.equals(poolB.token0) && poolA.token1.equals(poolB.token1) && poolA.fee === poolB.fee) - ) -} - -function computeAllRoutes( - currencyIn: Currency, - currencyOut: Currency, - pools: Pool[], - chainId: number, - currentPath: Pool[] = [], - allPaths: Route[] = [], - startCurrencyIn: Currency = currencyIn, - maxHops = 2 -): Route[] { - const tokenIn = currencyIn?.wrapped - const tokenOut = currencyOut?.wrapped - if (!tokenIn || !tokenOut) throw new Error('Missing tokenIn/tokenOut') - - for (const pool of pools) { - if (!pool.involvesToken(tokenIn) || currentPath.find((pathPool) => poolEquals(pool, pathPool))) continue - - const outputToken = pool.token0.equals(tokenIn) ? pool.token1 : pool.token0 - if (outputToken.equals(tokenOut)) { - allPaths.push(new Route([...currentPath, pool], startCurrencyIn, currencyOut)) - } else if (maxHops > 1) { - computeAllRoutes( - outputToken, - currencyOut, - pools, - chainId, - [...currentPath, pool], - allPaths, - startCurrencyIn, - maxHops - 1 - ) - } - } - - return allPaths -} - -/** - * Returns all the routes from an input currency to an output currency - * @param currencyIn the input currency - * @param currencyOut the output currency - */ -export function useAllV3Routes( - currencyIn?: Currency, - currencyOut?: Currency -): { loading: boolean; routes: Route[] } { - const { chainId } = useActiveWeb3React() - const { pools, loading: poolsLoading } = useV3SwapPools(currencyIn, currencyOut) - - return useMemo(() => { - if (poolsLoading || !chainId || !pools || !currencyIn || !currencyOut) return { loading: true, routes: [] } - - const routes = computeAllRoutes(currencyIn, currencyOut, pools, chainId, [], [], currencyIn, 2) - return { loading: false, routes } - }, [chainId, currencyIn, currencyOut, pools, poolsLoading]) -} diff --git a/src/hooks/useApeModeQueryParamReader.ts b/src/hooks/useApeModeQueryParamReader.ts deleted file mode 100644 index 87fb8941804..00000000000 --- a/src/hooks/useApeModeQueryParamReader.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect } from 'react' -import { useAppDispatch } from 'state/hooks' - -import { updateUserExpertMode } from '../state/user/actions' -import useParsedQueryString from './useParsedQueryString' - -export default function ApeModeQueryParamReader(): null { - useApeModeQueryParamReader() - return null -} - -function useApeModeQueryParamReader() { - const dispatch = useAppDispatch() - const { ape } = useParsedQueryString() - - useEffect(() => { - if (typeof ape !== 'string') return - if (ape === '' || ape.toLowerCase() === 'true') { - dispatch(updateUserExpertMode({ userExpertMode: true })) - } - }) -} diff --git a/src/hooks/useArgentWalletContract.ts b/src/hooks/useArgentWalletContract.ts deleted file mode 100644 index fa814feee4f..00000000000 --- a/src/hooks/useArgentWalletContract.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ArgentWalletContractABI from '../abis/argent-wallet-contract.json' -import { ArgentWalletContract } from '../abis/types' -import { useContract } from './useContract' -import useIsArgentWallet from './useIsArgentWallet' -import { useActiveWeb3React } from './web3' - -export function useArgentWalletContract(): ArgentWalletContract | null { - const { account } = useActiveWeb3React() - const isArgentWallet = useIsArgentWallet() - return useContract( - isArgentWallet ? account ?? undefined : undefined, - ArgentWalletContractABI, - true - ) as ArgentWalletContract -} diff --git a/src/hooks/useBestV2Trade.ts b/src/hooks/useBestV2Trade.ts deleted file mode 100644 index 094d2276acf..00000000000 --- a/src/hooks/useBestV2Trade.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' -import { Pair, Trade } from '@uniswap/v2-sdk' -import { useMemo } from 'react' -import { isTradeBetter } from 'utils/isTradeBetter' - -import { BETTER_TRADE_LESS_HOPS_THRESHOLD } from '../constants/misc' -import { useAllCurrencyCombinations } from './useAllCurrencyCombinations' -import { PairState, useV2Pairs } from './useV2Pairs' - -function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] { - const allCurrencyCombinations = useAllCurrencyCombinations(currencyA, currencyB) - - const allPairs = useV2Pairs(allCurrencyCombinations) - - return useMemo( - () => - Object.values( - allPairs - // filter out invalid pairs - .filter((result): result is [PairState.EXISTS, Pair] => Boolean(result[0] === PairState.EXISTS && result[1])) - .map(([, pair]) => pair) - ), - [allPairs] - ) -} - -const MAX_HOPS = 3 - -/** - * Returns the best v2 trade for a desired swap - * @param tradeType whether the swap is an exact in/out - * @param amountSpecified the exact amount to swap in/out - * @param otherCurrency the desired output/payment currency - */ -export function useBestV2Trade( - tradeType: TradeType.EXACT_INPUT | TradeType.EXACT_OUTPUT, - amountSpecified?: CurrencyAmount, - otherCurrency?: Currency, - { maxHops = MAX_HOPS } = {} -): Trade | null { - const [currencyIn, currencyOut] = useMemo( - () => - tradeType === TradeType.EXACT_INPUT - ? [amountSpecified?.currency, otherCurrency] - : [otherCurrency, amountSpecified?.currency], - [tradeType, amountSpecified, otherCurrency] - ) - const allowedPairs = useAllCommonPairs(currencyIn, currencyOut) - - return useMemo(() => { - if (amountSpecified && currencyIn && currencyOut && allowedPairs.length > 0) { - if (maxHops === 1) { - const options = { maxHops: 1, maxNumResults: 1 } - if (tradeType === TradeType.EXACT_INPUT) { - const amountIn = amountSpecified - return Trade.bestTradeExactIn(allowedPairs, amountIn, currencyOut, options)[0] ?? null - } else { - const amountOut = amountSpecified - return Trade.bestTradeExactOut(allowedPairs, currencyIn, amountOut, options)[0] ?? null - } - } - - // search through trades with varying hops, find best trade out of them - let bestTradeSoFar: Trade | null = null - for (let i = 1; i <= maxHops; i++) { - const options = { maxHops: i, maxNumResults: 1 } - let currentTrade: Trade | null - - if (tradeType === TradeType.EXACT_INPUT) { - const amountIn = amountSpecified - currentTrade = Trade.bestTradeExactIn(allowedPairs, amountIn, currencyOut, options)[0] ?? null - } else { - const amountOut = amountSpecified - currentTrade = Trade.bestTradeExactOut(allowedPairs, currencyIn, amountOut, options)[0] ?? null - } - - // if current trade is best yet, save it - if (isTradeBetter(bestTradeSoFar, currentTrade, BETTER_TRADE_LESS_HOPS_THRESHOLD)) { - bestTradeSoFar = currentTrade - } - } - return bestTradeSoFar - } - - return null - }, [tradeType, amountSpecified, currencyIn, currencyOut, allowedPairs, maxHops]) -} diff --git a/src/hooks/useColor.ts b/src/hooks/useColor.ts deleted file mode 100644 index bb60c8ff69d..00000000000 --- a/src/hooks/useColor.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Token } from '@uniswap/sdk-core' -import { SupportedChainId } from 'constants/chains' -import Vibrant from 'node-vibrant/lib/bundle' -import { shade } from 'polished' -import { useLayoutEffect, useState } from 'react' -import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' -import uriToHttp from 'utils/uriToHttp' -import { hex } from 'wcag-contrast' - -function URIForEthToken(address: string) { - return `https://raw.githubusercontent.com/uniswap/assets/master/blockchains/ethereum/assets/${address}/logo.png` -} - -async function getColorFromToken(token: Token): Promise { - if (!(token instanceof WrappedTokenInfo)) { - return null - } - - const wrappedToken = token as WrappedTokenInfo - const { address } = wrappedToken - let { logoURI } = wrappedToken - if (!logoURI) { - if (token.chainId !== SupportedChainId.MAINNET) { - return null - } else { - logoURI = URIForEthToken(address) - } - } - - try { - return await getColorFromUriPath(logoURI) - } catch (e) { - if (logoURI === URIForEthToken(address)) { - return null - } - - try { - logoURI = URIForEthToken(address) - return await getColorFromUriPath(logoURI) - } catch (e) {} - } - - return null -} - -async function getColorFromUriPath(uri: string): Promise { - const formattedPath = uriToHttp(uri)[0] - - const palette = await Vibrant.from(formattedPath).getPalette() - if (!palette?.Vibrant) { - return null - } - - let detectedHex = palette.Vibrant.hex - let AAscore = hex(detectedHex, '#FFF') - while (AAscore < 3) { - detectedHex = shade(0.005, detectedHex) - AAscore = hex(detectedHex, '#FFF') - } - - return detectedHex -} - -export function useColor(token?: Token) { - const [color, setColor] = useState('#2172E5') - - useLayoutEffect(() => { - let stale = false - - if (token) { - getColorFromToken(token).then((tokenColor) => { - if (!stale && tokenColor !== null) { - setColor(tokenColor) - } - }) - } - - return () => { - stale = true - setColor('#2172E5') - } - }, [token]) - - return color -} - -export function useListColor(listImageUri?: string) { - const [color, setColor] = useState('#2172E5') - - useLayoutEffect(() => { - let stale = false - - if (listImageUri) { - getColorFromUriPath(listImageUri).then((color) => { - if (!stale && color !== null) { - setColor(color) - } - }) - } - - return () => { - stale = true - setColor('#2172E5') - } - }, [listImageUri]) - - return color -} diff --git a/src/hooks/useContract.ts b/src/hooks/useContract.ts deleted file mode 100644 index 0350251325e..00000000000 --- a/src/hooks/useContract.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { Contract } from '@ethersproject/contracts' -import { abi as GOVERNANCE_ABI } from '@uniswap/governance/build/GovernorAlpha.json' -import { abi as UNI_ABI } from '@uniswap/governance/build/Uni.json' -import { abi as STAKING_REWARDS_ABI } from '@uniswap/liquidity-staker/build/StakingRewards.json' -import { abi as MERKLE_DISTRIBUTOR_ABI } from '@uniswap/merkle-distributor/build/MerkleDistributor.json' -import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json' -import { abi as IUniswapV2Router02ABI } from '@uniswap/v2-periphery/build/IUniswapV2Router02.json' -import { abi as QuoterABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json' -import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json' -import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json' -import { abi as V2MigratorABI } from '@uniswap/v3-periphery/artifacts/contracts/V3Migrator.sol/V3Migrator.json' -import ARGENT_WALLET_DETECTOR_ABI from 'abis/argent-wallet-detector.json' -import EIP_2612 from 'abis/eip_2612.json' -import ENS_PUBLIC_RESOLVER_ABI from 'abis/ens-public-resolver.json' -import ENS_ABI from 'abis/ens-registrar.json' -import ERC20_ABI from 'abis/erc20.json' -import ERC20_BYTES32_ABI from 'abis/erc20_bytes32.json' -import ERC721_ABI from 'abis/erc721.json' -import ERC1155_ABI from 'abis/erc1155.json' -import GOVERNOR_BRAVO_ABI from 'abis/governor-bravo.json' -import WETH_ABI from 'abis/weth.json' -import { - ARGENT_WALLET_DETECTOR_ADDRESS, - ENS_REGISTRAR_ADDRESSES, - GOVERNANCE_ALPHA_V0_ADDRESSES, - GOVERNANCE_ALPHA_V1_ADDRESSES, - GOVERNANCE_BRAVO_ADDRESSES, - MERKLE_DISTRIBUTOR_ADDRESS, - MULTICALL_ADDRESS, - NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, - QUOTER_ADDRESSES, - V2_ROUTER_ADDRESS, - V3_MIGRATOR_ADDRESSES, -} from 'constants/addresses' -import { useMemo } from 'react' -import { NonfungiblePositionManager, Quoter, UniswapInterfaceMulticall } from 'types/v3' -import { V3Migrator } from 'types/v3/V3Migrator' -import { getContract } from 'utils' - -import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Erc721, Erc1155, Weth } from '../abis/types' -import { UNI, WETH9_EXTENDED } from '../constants/tokens' -import { useActiveWeb3React } from './web3' - -// returns null on errors -export function useContract( - addressOrAddressMap: string | { [chainId: number]: string } | undefined, - ABI: any, - withSignerIfPossible = true -): T | null { - const { library, account, chainId } = useActiveWeb3React() - - return useMemo(() => { - if (!addressOrAddressMap || !ABI || !library || !chainId) return null - let address: string | undefined - if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap - else address = addressOrAddressMap[chainId] - if (!address) return null - try { - return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined) - } catch (error) { - console.error('Failed to get contract', error) - return null - } - }, [addressOrAddressMap, ABI, library, chainId, withSignerIfPossible, account]) as T -} - -export function useV2MigratorContract() { - return useContract(V3_MIGRATOR_ADDRESSES, V2MigratorABI, true) -} - -export function useTokenContract(tokenAddress?: string, withSignerIfPossible?: boolean) { - return useContract(tokenAddress, ERC20_ABI, withSignerIfPossible) -} - -export function useWETHContract(withSignerIfPossible?: boolean) { - const { chainId } = useActiveWeb3React() - return useContract(chainId ? WETH9_EXTENDED[chainId]?.address : undefined, WETH_ABI, withSignerIfPossible) -} - -export function useERC721Contract(nftAddress?: string) { - return useContract(nftAddress, ERC721_ABI, false) -} - -export function useERC1155Contract(nftAddress?: string) { - return useContract(nftAddress, ERC1155_ABI, false) -} - -export function useArgentWalletDetectorContract() { - return useContract(ARGENT_WALLET_DETECTOR_ADDRESS, ARGENT_WALLET_DETECTOR_ABI, false) -} - -export function useENSRegistrarContract(withSignerIfPossible?: boolean) { - return useContract(ENS_REGISTRAR_ADDRESSES, ENS_ABI, withSignerIfPossible) -} - -export function useENSResolverContract(address: string | undefined, withSignerIfPossible?: boolean) { - return useContract(address, ENS_PUBLIC_RESOLVER_ABI, withSignerIfPossible) -} - -export function useBytes32TokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(tokenAddress, ERC20_BYTES32_ABI, withSignerIfPossible) -} - -export function useEIP2612Contract(tokenAddress?: string): Contract | null { - return useContract(tokenAddress, EIP_2612, false) -} - -export function usePairContract(pairAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(pairAddress, IUniswapV2PairABI, withSignerIfPossible) -} - -export function useV2RouterContract(): Contract | null { - return useContract(V2_ROUTER_ADDRESS, IUniswapV2Router02ABI, true) -} - -export function useMulticall2Contract() { - return useContract(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall -} - -export function useMerkleDistributorContract() { - return useContract(MERKLE_DISTRIBUTOR_ADDRESS, MERKLE_DISTRIBUTOR_ABI, true) -} - -export function useGovernanceV0Contract(): Contract | null { - return useContract(GOVERNANCE_ALPHA_V0_ADDRESSES, GOVERNANCE_ABI, false) -} - -export function useGovernanceV1Contract(): Contract | null { - return useContract(GOVERNANCE_ALPHA_V1_ADDRESSES, GOVERNANCE_ABI, false) -} - -export function useGovernanceBravoContract(): Contract | null { - return useContract(GOVERNANCE_BRAVO_ADDRESSES, GOVERNOR_BRAVO_ABI, true) -} - -export const useLatestGovernanceContract = useGovernanceBravoContract - -export function useUniContract() { - const { chainId } = useActiveWeb3React() - return useContract(chainId ? UNI[chainId]?.address : undefined, UNI_ABI, true) -} - -export function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean) { - return useContract(stakingAddress, STAKING_REWARDS_ABI, withSignerIfPossible) -} - -export function useV3NFTPositionManagerContract(withSignerIfPossible?: boolean): NonfungiblePositionManager | null { - return useContract( - NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, - NFTPositionManagerABI, - withSignerIfPossible - ) -} - -export function useV3Quoter() { - return useContract(QUOTER_ADDRESSES, QuoterABI) -} diff --git a/src/hooks/useCopyClipboard.ts b/src/hooks/useCopyClipboard.ts deleted file mode 100644 index 2317753f7e8..00000000000 --- a/src/hooks/useCopyClipboard.ts +++ /dev/null @@ -1,26 +0,0 @@ -import copy from 'copy-to-clipboard' -import { useCallback, useEffect, useState } from 'react' - -export default function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => void] { - const [isCopied, setIsCopied] = useState(false) - - const staticCopy = useCallback((text) => { - const didCopy = copy(text) - setIsCopied(didCopy) - }, []) - - useEffect(() => { - if (isCopied) { - const hide = setTimeout(() => { - setIsCopied(false) - }, timeout) - - return () => { - clearTimeout(hide) - } - } - return undefined - }, [isCopied, setIsCopied, timeout]) - - return [isCopied, staticCopy] -} diff --git a/src/hooks/useCurrentBlockTimestamp.ts b/src/hooks/useCurrentBlockTimestamp.ts deleted file mode 100644 index 9124062bad9..00000000000 --- a/src/hooks/useCurrentBlockTimestamp.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { useMulticall2Contract } from './useContract' - -// gets the current timestamp from the blockchain -export default function useCurrentBlockTimestamp(): BigNumber | undefined { - const multicall = useMulticall2Contract() - return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0] -} diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts deleted file mode 100644 index f753299da49..00000000000 --- a/src/hooks/useDebounce.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect, useState } from 'react' - -// modified from https://usehooks.com/useDebounce/ -export default function useDebounce(value: T, delay: number): T { - const [debouncedValue, setDebouncedValue] = useState(value) - - useEffect(() => { - // Update debounced value after delay - const handler = setTimeout(() => { - setDebouncedValue(value) - }, delay) - - // Cancel the timeout if value changes (also on delay change or unmount) - // This is how we prevent debounced value from updating if value is changed ... - // .. within the delay period. Timeout gets cleared and restarted. - return () => { - clearTimeout(handler) - } - }, [value, delay]) - - return debouncedValue -} diff --git a/src/hooks/useDebouncedChangeHandler.tsx b/src/hooks/useDebouncedChangeHandler.tsx deleted file mode 100644 index 21a71f9b903..00000000000 --- a/src/hooks/useDebouncedChangeHandler.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react' - -/** - * Easy way to debounce the handling of a rapidly changing value, e.g. a changing slider input - * @param value value that is rapidly changing - * @param onChange change handler that should receive the debounced updates to the value - * @param debouncedMs how long we should wait for changes to be applied - */ -export default function useDebouncedChangeHandler( - value: T, - onChange: (newValue: T) => void, - debouncedMs = 100 -): [T, (value: T) => void] { - const [inner, setInner] = useState(() => value) - const timer = useRef>() - - const onChangeInner = useCallback( - (newValue: T) => { - setInner(newValue) - if (timer.current) { - clearTimeout(timer.current) - } - timer.current = setTimeout(() => { - onChange(newValue) - timer.current = undefined - }, debouncedMs) - }, - [debouncedMs, onChange] - ) - - useEffect(() => { - if (timer.current) { - clearTimeout(timer.current) - timer.current = undefined - } - setInner(value) - }, [value]) - - return [inner, onChangeInner] -} diff --git a/src/hooks/useDerivedPositionInfo.ts b/src/hooks/useDerivedPositionInfo.ts deleted file mode 100644 index 99c1cb1fd2c..00000000000 --- a/src/hooks/useDerivedPositionInfo.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Pool, Position } from '@uniswap/v3-sdk' -import { usePool } from 'hooks/usePools' -import { PositionDetails } from 'types/position' - -import { useCurrency } from './Tokens' - -export function useDerivedPositionInfo(positionDetails: PositionDetails | undefined): { - position: Position | undefined - pool: Pool | undefined -} { - const currency0 = useCurrency(positionDetails?.token0) - const currency1 = useCurrency(positionDetails?.token1) - - // construct pool data - const [, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, positionDetails?.fee) - - let position = undefined - if (pool && positionDetails) { - position = new Position({ - pool, - liquidity: positionDetails.liquidity.toString(), - tickLower: positionDetails.tickLower, - tickUpper: positionDetails.tickUpper, - }) - } - - return { - position, - pool: pool ?? undefined, - } -} diff --git a/src/hooks/useENS.ts b/src/hooks/useENS.ts deleted file mode 100644 index c36bd5bd287..00000000000 --- a/src/hooks/useENS.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { isAddress } from '../utils' -import useENSAddress from './useENSAddress' -import useENSName from './useENSName' - -/** - * Given a name or address, does a lookup to resolve to an address and name - * @param nameOrAddress ENS name or address - */ -export default function useENS(nameOrAddress?: string | null): { - loading: boolean - address: string | null - name: string | null -} { - const validated = isAddress(nameOrAddress) - const reverseLookup = useENSName(validated ? validated : undefined) - const lookup = useENSAddress(nameOrAddress) - - return { - loading: reverseLookup.loading || lookup.loading, - address: validated ? validated : lookup.address, - name: reverseLookup.ENSName ? reverseLookup.ENSName : !validated && lookup.address ? nameOrAddress || null : null, - } -} diff --git a/src/hooks/useENSAddress.ts b/src/hooks/useENSAddress.ts deleted file mode 100644 index a4565d9e95a..00000000000 --- a/src/hooks/useENSAddress.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { namehash } from '@ethersproject/hash' -import { useMemo } from 'react' - -import { useSingleCallResult } from '../state/multicall/hooks' -import isZero from '../utils/isZero' -import { useENSRegistrarContract, useENSResolverContract } from './useContract' -import useDebounce from './useDebounce' - -/** - * Does a lookup for an ENS name to find its address. - */ -export default function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } { - const debouncedName = useDebounce(ensName, 200) - const ensNodeArgument = useMemo(() => { - if (!debouncedName) return [undefined] - try { - return debouncedName ? [namehash(debouncedName)] : [undefined] - } catch (error) { - return [undefined] - } - }, [debouncedName]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const addr = useSingleCallResult(resolverContract, 'addr', ensNodeArgument) - - const changed = debouncedName !== ensName - return { - address: changed ? null : addr.result?.[0] ?? null, - loading: changed || resolverAddress.loading || addr.loading, - } -} diff --git a/src/hooks/useENSAvatar.ts b/src/hooks/useENSAvatar.ts deleted file mode 100644 index 8e6d07d16bc..00000000000 --- a/src/hooks/useENSAvatar.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { namehash } from '@ethersproject/hash' -import { useEffect, useMemo, useState } from 'react' -import uriToHttp from 'utils/uriToHttp' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { isAddress } from '../utils' -import isZero from '../utils/isZero' -import { useENSRegistrarContract, useENSResolverContract, useERC721Contract, useERC1155Contract } from './useContract' -import useDebounce from './useDebounce' -import useENSName from './useENSName' -import { useActiveWeb3React } from './web3' - -/** - * Returns the ENS avatar URI, if available. - * Spec: https://gist.github.com/Arachnid/9db60bd75277969ee1689c8742b75182. - */ -export default function useENSAvatar( - address?: string, - enforceOwnership = true -): { avatar: string | null; loading: boolean } { - const debouncedAddress = useDebounce(address, 200) - const node = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return undefined - try { - return debouncedAddress ? namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`) : undefined - } catch (error) { - return undefined - } - }, [debouncedAddress]) - - const addressAvatar = useAvatarFromNode(node) - const nameAvatar = useAvatarFromNode(namehash(useENSName(address).ENSName ?? '')) - let avatar = addressAvatar.avatar || nameAvatar.avatar - - const nftAvatar = useAvatarFromNFT(avatar, enforceOwnership) - avatar = nftAvatar.avatar || avatar - - const http = avatar && uriToHttp(avatar)[0] - - const changed = debouncedAddress !== address - return { - avatar: changed ? null : http ?? null, - loading: changed || addressAvatar.loading || nameAvatar.loading || nftAvatar.loading, - } -} - -function useAvatarFromNode(node?: string): { avatar?: string; loading: boolean } { - const nodeArgument = useMemo(() => [node], [node]) - const textArgument = useMemo(() => [node, 'avatar'], [node]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', nodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const avatar = useSingleCallResult(resolverContract, 'text', textArgument) - - return { - avatar: avatar.result?.[0], - loading: resolverAddress.loading || avatar.loading, - } -} - -function useAvatarFromNFT(nftUri = '', enforceOwnership: boolean): { avatar?: string; loading: boolean } { - const parts = nftUri.toLowerCase().split(':') - const protocol = parts[0] - // ignore the chain from eip155 - // TODO: when we are able, pull only from the specified chain - const [, erc] = parts[1]?.split('/') ?? [] - const [contractAddress, id] = parts[2]?.split('/') ?? [] - const isERC721 = protocol === 'eip155' && erc === 'erc721' - const isERC1155 = protocol === 'eip155' && erc === 'erc1155' - const erc721 = useERC721Uri(isERC721 ? contractAddress : undefined, id, enforceOwnership) - const erc1155 = useERC1155Uri(isERC1155 ? contractAddress : undefined, id, enforceOwnership) - const uri = erc721.uri || erc1155.uri - const http = uri && uriToHttp(uri)[0] - - const [loading, setLoading] = useState(false) - const [avatar, setAvatar] = useState(undefined) - useEffect(() => { - setAvatar(undefined) - if (http) { - setLoading(true) - fetch(http) - .then((res) => res.json()) - .then(({ image }) => { - setAvatar(image) - }) - .catch((e) => console.warn(e)) - .finally(() => { - setLoading(false) - }) - } - }, [http]) - - return { avatar, loading: erc721.loading || erc1155.loading || loading } -} - -function useERC721Uri( - contractAddress: string | undefined, - id: string | undefined, - enforceOwnership: boolean -): { uri?: string; loading: boolean } { - const idArgument = useMemo(() => [id], [id]) - const { account } = useActiveWeb3React() - const contract = useERC721Contract(contractAddress) - const owner = useSingleCallResult(contract, 'ownerOf', idArgument) - const uri = useSingleCallResult(contract, 'tokenURI', idArgument) - return { - uri: !enforceOwnership || account === owner.result?.[0] ? uri.result?.[0] : undefined, - loading: owner.loading || uri.loading, - } -} - -function useERC1155Uri( - contractAddress: string | undefined, - id: string | undefined, - enforceOwnership: boolean -): { uri?: string; loading: boolean } { - const { account } = useActiveWeb3React() - const idArgument = useMemo(() => [id], [id]) - const accountArgument = useMemo(() => [account || '', id], [account, id]) - const contract = useERC1155Contract(contractAddress) - const balance = useSingleCallResult(contract, 'balanceOf', accountArgument) - const uri = useSingleCallResult(contract, 'uri', idArgument) - return { - uri: !enforceOwnership || balance.result?.[0] > 0 ? uri.result?.[0] : undefined, - loading: balance.loading || uri.loading, - } -} diff --git a/src/hooks/useENSContentHash.ts b/src/hooks/useENSContentHash.ts deleted file mode 100644 index 9f002d092a5..00000000000 --- a/src/hooks/useENSContentHash.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { namehash } from '@ethersproject/hash' -import { useMemo } from 'react' - -import { useSingleCallResult } from '../state/multicall/hooks' -import isZero from '../utils/isZero' -import { useENSRegistrarContract, useENSResolverContract } from './useContract' - -/** - * Does a lookup for an ENS name to find its contenthash. - */ -export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } { - const ensNodeArgument = useMemo(() => { - if (!ensName) return [undefined] - try { - return ensName ? [namehash(ensName)] : [undefined] - } catch (error) { - return [undefined] - } - }, [ensName]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddress = resolverAddressResult.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddress && isZero(resolverAddress) ? undefined : resolverAddress, - false - ) - const contenthash = useSingleCallResult(resolverContract, 'contenthash', ensNodeArgument) - - return { - contenthash: contenthash.result?.[0] ?? null, - loading: resolverAddressResult.loading || contenthash.loading, - } -} diff --git a/src/hooks/useENSName.ts b/src/hooks/useENSName.ts deleted file mode 100644 index f0b7d1d8bf0..00000000000 --- a/src/hooks/useENSName.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { namehash } from '@ethersproject/hash' -import { useMemo } from 'react' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { isAddress } from '../utils' -import isZero from '../utils/isZero' -import { useENSRegistrarContract, useENSResolverContract } from './useContract' -import useDebounce from './useDebounce' - -/** - * Does a reverse lookup for an address to find its ENS name. - * Note this is not the same as looking up an ENS name to find an address. - */ -export default function useENSName(address?: string): { ENSName: string | null; loading: boolean } { - const debouncedAddress = useDebounce(address, 200) - const ensNodeArgument = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined] - try { - return debouncedAddress ? [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] : [undefined] - } catch (error) { - return [undefined] - } - }, [debouncedAddress]) - const registrarContract = useENSRegistrarContract(false) - const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddressResult = resolverAddress.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false - ) - const name = useSingleCallResult(resolverContract, 'name', ensNodeArgument) - - const changed = debouncedAddress !== address - return { - ENSName: changed ? null : name.result?.[0] ?? null, - loading: changed || resolverAddress.loading || name.loading, - } -} diff --git a/src/hooks/useFeeTierDistribution.ts b/src/hooks/useFeeTierDistribution.ts deleted file mode 100644 index be7f4677cf6..00000000000 --- a/src/hooks/useFeeTierDistribution.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { skipToken } from '@reduxjs/toolkit/query/react' -import { Currency, Token } from '@uniswap/sdk-core' -import { FeeAmount } from '@uniswap/v3-sdk' -import ms from 'ms.macro' -import { useMemo } from 'react' -import ReactGA from 'react-ga' -import { useBlockNumber } from 'state/application/hooks' -import { useFeeTierDistributionQuery } from 'state/data/enhanced' -import { FeeTierDistributionQuery } from 'state/data/generated' - -import { PoolState, usePool } from './usePools' - -// maximum number of blocks past which we consider the data stale -const MAX_DATA_BLOCK_AGE = 20 - -interface FeeTierDistribution { - isLoading: boolean - isError: boolean - largestUsageFeeTier?: FeeAmount | undefined - - // distributions as percentages of overall liquidity - distributions?: Record -} - -export function useFeeTierDistribution( - currencyA: Currency | undefined, - currencyB: Currency | undefined -): FeeTierDistribution { - const { isFetching, isLoading, isUninitialized, isError, distributions } = usePoolTVL( - currencyA?.wrapped, - currencyB?.wrapped - ) - - // fetch all pool states to determine pool state - const [poolStateVeryLow] = usePool(currencyA, currencyB, FeeAmount.LOWEST) - const [poolStateLow] = usePool(currencyA, currencyB, FeeAmount.LOW) - const [poolStateMedium] = usePool(currencyA, currencyB, FeeAmount.MEDIUM) - const [poolStateHigh] = usePool(currencyA, currencyB, FeeAmount.HIGH) - - return useMemo(() => { - if (isLoading || isFetching || isUninitialized || isError || !distributions) { - return { - isLoading: isLoading || isFetching || !isUninitialized, - isError, - distributions, - } - } - - const largestUsageFeeTier = Object.keys(distributions) - .map((d) => Number(d)) - .filter((d: FeeAmount) => distributions[d] !== 0 && distributions[d] !== undefined) - .reduce((a: FeeAmount, b: FeeAmount) => ((distributions[a] ?? 0) > (distributions[b] ?? 0) ? a : b), -1) - - const percentages = - !isLoading && - !isError && - distributions && - poolStateVeryLow !== PoolState.LOADING && - poolStateLow !== PoolState.LOADING && - poolStateMedium !== PoolState.LOADING && - poolStateHigh !== PoolState.LOADING - ? { - [FeeAmount.LOWEST]: - poolStateVeryLow === PoolState.EXISTS ? (distributions[FeeAmount.LOWEST] ?? 0) * 100 : undefined, - [FeeAmount.LOW]: poolStateLow === PoolState.EXISTS ? (distributions[FeeAmount.LOW] ?? 0) * 100 : undefined, - [FeeAmount.MEDIUM]: - poolStateMedium === PoolState.EXISTS ? (distributions[FeeAmount.MEDIUM] ?? 0) * 100 : undefined, - [FeeAmount.HIGH]: - poolStateHigh === PoolState.EXISTS ? (distributions[FeeAmount.HIGH] ?? 0) * 100 : undefined, - } - : undefined - - return { - isLoading, - isError, - distributions: percentages, - largestUsageFeeTier: largestUsageFeeTier === -1 ? undefined : largestUsageFeeTier, - } - }, [ - isLoading, - isFetching, - isUninitialized, - isError, - distributions, - poolStateVeryLow, - poolStateLow, - poolStateMedium, - poolStateHigh, - ]) -} - -function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { - const latestBlock = useBlockNumber() - - const { isLoading, isFetching, isUninitialized, isError, data } = useFeeTierDistributionQuery( - token0 && token1 ? { token0: token0.address.toLowerCase(), token1: token1.address.toLowerCase() } : skipToken, - { - pollingInterval: ms`30s`, - } - ) - - const { asToken0, asToken1, _meta } = (data as FeeTierDistributionQuery) ?? {} - - return useMemo(() => { - if (!latestBlock || !_meta || !asToken0 || !asToken1) { - return { - isLoading, - isFetching, - isUninitialized, - isError, - } - } - - if (latestBlock - (_meta?.block?.number ?? 0) > MAX_DATA_BLOCK_AGE) { - ReactGA.exception({ - description: `Graph stale (latest block: ${latestBlock})`, - }) - - return { - isLoading, - isFetching, - isUninitialized, - isError, - } - } - - const all = asToken0.concat(asToken1) - - // sum tvl for token0 and token1 by fee tier - const tvlByFeeTier = all.reduce<{ [feeAmount: number]: [number | undefined, number | undefined] }>( - (acc, value) => { - acc[value.feeTier][0] = (acc[value.feeTier][0] ?? 0) + Number(value.totalValueLockedToken0) - acc[value.feeTier][1] = (acc[value.feeTier][1] ?? 0) + Number(value.totalValueLockedToken1) - return acc - }, - { - [FeeAmount.LOWEST]: [undefined, undefined], - [FeeAmount.LOW]: [undefined, undefined], - [FeeAmount.MEDIUM]: [undefined, undefined], - [FeeAmount.HIGH]: [undefined, undefined], - } as Record - ) - - // sum total tvl for token0 and token1 - const [sumToken0Tvl, sumToken1Tvl] = Object.values(tvlByFeeTier).reduce( - (acc: [number, number], value) => { - acc[0] += value[0] ?? 0 - acc[1] += value[1] ?? 0 - return acc - }, - [0, 0] - ) - - // returns undefined if both tvl0 and tvl1 are undefined (pool not created) - const mean = (tvl0: number | undefined, sumTvl0: number, tvl1: number | undefined, sumTvl1: number) => - tvl0 === undefined && tvl1 === undefined ? undefined : ((tvl0 ?? 0) + (tvl1 ?? 0)) / (sumTvl0 + sumTvl1) || 0 - - const distributions: Record = { - [FeeAmount.LOWEST]: mean( - tvlByFeeTier[FeeAmount.LOWEST][0], - sumToken0Tvl, - tvlByFeeTier[FeeAmount.LOWEST][1], - sumToken1Tvl - ), - [FeeAmount.LOW]: mean(tvlByFeeTier[FeeAmount.LOW][0], sumToken0Tvl, tvlByFeeTier[FeeAmount.LOW][1], sumToken1Tvl), - [FeeAmount.MEDIUM]: mean( - tvlByFeeTier[FeeAmount.MEDIUM][0], - sumToken0Tvl, - tvlByFeeTier[FeeAmount.MEDIUM][1], - sumToken1Tvl - ), - [FeeAmount.HIGH]: mean( - tvlByFeeTier[FeeAmount.HIGH][0], - sumToken0Tvl, - tvlByFeeTier[FeeAmount.HIGH][1], - sumToken1Tvl - ), - } - - return { - isLoading, - isFetching, - isUninitialized, - isError, - distributions, - } - }, [_meta, asToken0, asToken1, isLoading, isError, isFetching, isUninitialized, latestBlock]) -} diff --git a/src/hooks/useFetchListCallback.ts b/src/hooks/useFetchListCallback.ts deleted file mode 100644 index 12cb4df60c2..00000000000 --- a/src/hooks/useFetchListCallback.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { nanoid } from '@reduxjs/toolkit' -import { TokenList } from '@uniswap/token-lists' -import { useCallback } from 'react' -import { useAppDispatch } from 'state/hooks' - -import { getNetworkLibrary } from '../connectors' -import { fetchTokenList } from '../state/lists/actions' -import getTokenList from '../utils/getTokenList' -import resolveENSContentHash from '../utils/resolveENSContentHash' -import { useActiveWeb3React } from './web3' - -export function useFetchListCallback(): (listUrl: string, sendDispatch?: boolean) => Promise { - const { chainId, library } = useActiveWeb3React() - const dispatch = useAppDispatch() - - const ensResolver = useCallback( - async (ensName: string) => { - if (!library || chainId !== 1) { - const networkLibrary = getNetworkLibrary() - const network = await networkLibrary.getNetwork() - if (networkLibrary && network.chainId === 1) { - return resolveENSContentHash(ensName, networkLibrary) - } - throw new Error('Could not construct mainnet ENS resolver') - } - return resolveENSContentHash(ensName, library) - }, - [chainId, library] - ) - - // note: prevent dispatch if using for list search or unsupported list - return useCallback( - async (listUrl: string, sendDispatch = true) => { - const requestId = nanoid() - sendDispatch && dispatch(fetchTokenList.pending({ requestId, url: listUrl })) - return getTokenList(listUrl, ensResolver) - .then((tokenList) => { - sendDispatch && dispatch(fetchTokenList.fulfilled({ url: listUrl, tokenList, requestId })) - return tokenList - }) - .catch((error) => { - console.debug(`Failed to get list at url ${listUrl}`, error) - sendDispatch && dispatch(fetchTokenList.rejected({ url: listUrl, requestId, errorMessage: error.message })) - throw error - }) - }, - [dispatch, ensResolver] - ) -} diff --git a/src/hooks/useGasPrice.ts b/src/hooks/useGasPrice.ts deleted file mode 100644 index 87a132cbd46..00000000000 --- a/src/hooks/useGasPrice.ts +++ /dev/null @@ -1,26 +0,0 @@ -import JSBI from 'jsbi' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { useContract } from './useContract' -import useENSAddress from './useENSAddress' - -const CHAIN_DATA_ABI = [ - { - inputs: [], - name: 'latestAnswer', - outputs: [{ internalType: 'int256', name: '', type: 'int256' }], - stateMutability: 'view', - type: 'function', - }, -] - -/** - * Returns the price of 1 gas in WEI for the currently selected network using the chainlink fast gas price oracle - */ -export default function useGasPrice(): JSBI | undefined { - const { address } = useENSAddress('fast-gas-gwei.data.eth') - const contract = useContract(address ?? undefined, CHAIN_DATA_ABI, false) - - const resultStr = useSingleCallResult(contract, 'latestAnswer').result?.[0]?.toString() - return typeof resultStr === 'string' ? JSBI.BigInt(resultStr) : undefined -} diff --git a/src/hooks/useHttpLocations.ts b/src/hooks/useHttpLocations.ts deleted file mode 100644 index 37c49b7b827..00000000000 --- a/src/hooks/useHttpLocations.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useMemo } from 'react' - -import contenthashToUri from '../utils/contenthashToUri' -import { parseENSAddress } from '../utils/parseENSAddress' -import uriToHttp from '../utils/uriToHttp' -import useENSContentHash from './useENSContentHash' - -export default function useHttpLocations(uri: string | undefined): string[] { - const ens = useMemo(() => (uri ? parseENSAddress(uri) : undefined), [uri]) - const resolvedContentHash = useENSContentHash(ens?.ensName) - return useMemo(() => { - if (ens) { - return resolvedContentHash.contenthash ? uriToHttp(contenthashToUri(resolvedContentHash.contenthash)) : [] - } else { - return uri ? uriToHttp(uri) : [] - } - }, [ens, resolvedContentHash.contenthash, uri]) -} diff --git a/src/hooks/useInterval.ts b/src/hooks/useInterval.ts deleted file mode 100644 index bc12bbced17..00000000000 --- a/src/hooks/useInterval.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { useEffect, useRef } from 'react' - -export default function useInterval(callback: () => void, delay: null | number, leading = true) { - const savedCallback = useRef<() => void>() - - // Remember the latest callback. - useEffect(() => { - savedCallback.current = callback - }, [callback]) - - // Set up the interval. - useEffect(() => { - function tick() { - const current = savedCallback.current - current && current() - } - - if (delay !== null) { - if (leading) tick() - const id = setInterval(tick, delay) - return () => clearInterval(id) - } - return undefined - }, [delay, leading]) -} diff --git a/src/hooks/useIsArgentWallet.ts b/src/hooks/useIsArgentWallet.ts deleted file mode 100644 index 8e34375a7d2..00000000000 --- a/src/hooks/useIsArgentWallet.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMemo } from 'react' - -import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks' -import { useArgentWalletDetectorContract } from './useContract' -import { useActiveWeb3React } from './web3' - -export default function useIsArgentWallet(): boolean { - const { account } = useActiveWeb3React() - const argentWalletDetector = useArgentWalletDetectorContract() - const inputs = useMemo(() => [account ?? undefined], [account]) - const call = useSingleCallResult(argentWalletDetector, 'isArgentWallet', inputs, NEVER_RELOAD) - return call?.result?.[0] ?? false -} diff --git a/src/hooks/useIsSwapUnsupported.ts b/src/hooks/useIsSwapUnsupported.ts deleted file mode 100644 index f9a87b7dc84..00000000000 --- a/src/hooks/useIsSwapUnsupported.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Currency } from '@uniswap/sdk-core' -import { useMemo } from 'react' - -import { useUnsupportedTokens } from './Tokens' - -/** - * Returns true if the input currency or output currency cannot be traded in the interface - * @param currencyIn the input currency to check - * @param currencyOut the output currency to check - */ -export function useIsSwapUnsupported(currencyIn?: Currency | null, currencyOut?: Currency | null): boolean { - const unsupportedTokens = useUnsupportedTokens() - return useMemo(() => { - if (!unsupportedTokens) { - return false - } - const currencyInUnsupported = Boolean(currencyIn?.isToken && unsupportedTokens[currencyIn.address]) - const currencyOutUnsupported = Boolean(currencyOut?.isToken && unsupportedTokens[currencyOut.address]) - return currencyInUnsupported || currencyOutUnsupported - }, [currencyIn, currencyOut, unsupportedTokens]) -} diff --git a/src/hooks/useIsTickAtLimit.ts b/src/hooks/useIsTickAtLimit.ts deleted file mode 100644 index 8763d239cc8..00000000000 --- a/src/hooks/useIsTickAtLimit.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { FeeAmount, nearestUsableTick, TICK_SPACINGS, TickMath } from '@uniswap/v3-sdk' -import { useMemo } from 'react' -import { Bound } from 'state/mint/v3/actions' - -export default function useIsTickAtLimit( - feeAmount: FeeAmount | undefined, - tickLower: number | undefined, - tickUpper: number | undefined -) { - return useMemo( - () => ({ - [Bound.LOWER]: - feeAmount && tickLower - ? tickLower === nearestUsableTick(TickMath.MIN_TICK, TICK_SPACINGS[feeAmount as FeeAmount]) - : undefined, - [Bound.UPPER]: - feeAmount && tickUpper - ? tickUpper === nearestUsableTick(TickMath.MAX_TICK, TICK_SPACINGS[feeAmount as FeeAmount]) - : undefined, - }), - [feeAmount, tickLower, tickUpper] - ) -} diff --git a/src/hooks/useIsWindowVisible.ts b/src/hooks/useIsWindowVisible.ts deleted file mode 100644 index efefad54528..00000000000 --- a/src/hooks/useIsWindowVisible.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' - -const VISIBILITY_STATE_SUPPORTED = 'visibilityState' in document - -function isWindowVisible() { - return !VISIBILITY_STATE_SUPPORTED || document.visibilityState !== 'hidden' -} - -/** - * Returns whether the window is currently visible to the user. - */ -export default function useIsWindowVisible(): boolean { - const [focused, setFocused] = useState(isWindowVisible()) - const listener = useCallback(() => { - setFocused(isWindowVisible()) - }, [setFocused]) - - useEffect(() => { - if (!VISIBILITY_STATE_SUPPORTED) return undefined - - document.addEventListener('visibilitychange', listener) - return () => { - document.removeEventListener('visibilitychange', listener) - } - }, [listener]) - - return focused -} diff --git a/src/hooks/useLast.ts b/src/hooks/useLast.ts deleted file mode 100644 index 33f169bd229..00000000000 --- a/src/hooks/useLast.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useState } from 'react' - -/** - * Returns the last value of type T that passes a filter function - * @param value changing value - * @param filterFn function that determines whether a given value should be considered for the last value - */ -export default function useLast( - value: T | undefined | null, - filterFn?: (value: T | null | undefined) => boolean -): T | null | undefined { - const [last, setLast] = useState(filterFn && filterFn(value) ? value : undefined) - useEffect(() => { - setLast((last) => { - const shouldUse: boolean = filterFn ? filterFn(value) : true - if (shouldUse) return value - return last - }) - }, [filterFn, value]) - return last -} diff --git a/src/hooks/useLocationLinkProps.ts b/src/hooks/useLocationLinkProps.ts deleted file mode 100644 index ec8d8444417..00000000000 --- a/src/hooks/useLocationLinkProps.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { SupportedLocale } from 'constants/locales' -import { LocationDescriptor } from 'history' -import useParsedQueryString from 'hooks/useParsedQueryString' -import { stringify } from 'qs' -import { useMemo } from 'react' -import ReactGA from 'react-ga' -import { useLocation } from 'react-router-dom' - -import { useActiveLocale } from './useActiveLocale' - -export function useLocationLinkProps(locale: SupportedLocale | null): { - to?: LocationDescriptor - onClick?: () => void -} { - const location = useLocation() - const qs = useParsedQueryString() - const activeLocale = useActiveLocale() - - return useMemo( - () => - !locale - ? {} - : { - to: { - ...location, - search: stringify({ ...qs, lng: locale }), - }, - onClick: () => { - ReactGA.event({ - category: 'Localization', - action: 'Switch Locale', - label: `${activeLocale} -> ${locale}`, - }) - }, - }, - [location, qs, activeLocale, locale] - ) -} diff --git a/src/hooks/useMachineTime.ts b/src/hooks/useMachineTime.ts deleted file mode 100644 index f35dabc79f2..00000000000 --- a/src/hooks/useMachineTime.ts +++ /dev/null @@ -1,14 +0,0 @@ -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 diff --git a/src/hooks/useMonitoringEventCallback.ts b/src/hooks/useMonitoringEventCallback.ts deleted file mode 100644 index 87296f6fcf0..00000000000 --- a/src/hooks/useMonitoringEventCallback.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { TransactionResponse } from '@ethersproject/providers' -import { initializeApp } from 'firebase/app' -import { getDatabase, push, ref } from 'firebase/database' -import { useCallback } from 'react' -import { TransactionInfo, TransactionType } from 'state/transactions/actions' - -import { useActiveWeb3React } from './web3' - -type PartialTransactionResponse = Pick - -const SUPPORTED_TRANSACTION_TYPES = [ - TransactionType.ADD_LIQUIDITY_V2_POOL, - TransactionType.ADD_LIQUIDITY_V3_POOL, - TransactionType.CREATE_V3_POOL, - TransactionType.REMOVE_LIQUIDITY_V3, - TransactionType.SWAP, -] - -const FIREBASE_API_KEY = process.env.REACT_APP_FIREBASE_KEY -const firebaseEnabled = typeof FIREBASE_API_KEY !== 'undefined' -if (firebaseEnabled) initializeFirebase() - -function useMonitoringEventCallback() { - const { chainId } = useActiveWeb3React() - - return useCallback( - async function log( - type: string, - { - transactionResponse, - walletAddress, - }: { transactionResponse: PartialTransactionResponse; walletAddress: string | undefined } - ) { - if (!firebaseEnabled) return - - const db = getDatabase() - - if (!walletAddress) { - console.debug('Wallet address required to log monitoring events.') - return - } - try { - push(ref(db, 'trm'), { - chainId, - origin: location.origin, - timestamp: Date.now(), - tx: transactionResponse, - type, - walletAddress, - }) - } catch (e) { - console.debug('Error adding document: ', e) - } - }, - [chainId] - ) -} - -export function useTransactionMonitoringEventCallback() { - const { account } = useActiveWeb3React() - const log = useMonitoringEventCallback() - - return useCallback( - (info: TransactionInfo, transactionResponse: TransactionResponse) => { - if (SUPPORTED_TRANSACTION_TYPES.includes(info.type)) { - log(TransactionType[info.type], { - transactionResponse: (({ hash, v, r, s }: PartialTransactionResponse) => ({ hash, v, r, s }))( - transactionResponse - ), - walletAddress: account ?? undefined, - }) - } - }, - [account, log] - ) -} - -export function useWalletConnectMonitoringEventCallback() { - const log = useMonitoringEventCallback() - - return useCallback( - (walletAddress) => { - log('WALLET_CONNECTED', { transactionResponse: { hash: '', r: '', s: '', v: -1 }, walletAddress }) - }, - [log] - ) -} - -function initializeFirebase() { - initializeApp({ - apiKey: process.env.REACT_APP_FIREBASE_KEY, - authDomain: 'interface-monitoring.firebaseapp.com', - databaseURL: 'https://interface-monitoring-default-rtdb.firebaseio.com', - projectId: 'interface-monitoring', - storageBucket: 'interface-monitoring.appspot.com', - messagingSenderId: '968187720053', - appId: '1:968187720053:web:acedf72dce629d470be33c', - }) -} diff --git a/src/hooks/useOnClickOutside.tsx b/src/hooks/useOnClickOutside.tsx deleted file mode 100644 index 0307fe9d025..00000000000 --- a/src/hooks/useOnClickOutside.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { RefObject, useEffect, useRef } from 'react' - -export function useOnClickOutside( - node: RefObject, - handler: undefined | (() => void) -) { - const handlerRef = useRef void)>(handler) - useEffect(() => { - handlerRef.current = handler - }, [handler]) - - useEffect(() => { - const handleClickOutside = (e: MouseEvent) => { - if (node.current?.contains(e.target as Node) ?? false) { - return - } - if (handlerRef.current) handlerRef.current() - } - - document.addEventListener('mousedown', handleClickOutside) - - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, [node]) -} diff --git a/src/hooks/useParsedQueryString.ts b/src/hooks/useParsedQueryString.ts deleted file mode 100644 index 0d9bfd0123b..00000000000 --- a/src/hooks/useParsedQueryString.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { parse, ParsedQs } from 'qs' -import { useMemo } from 'react' -import { useLocation } from 'react-router-dom' - -export function parsedQueryString(search?: string): ParsedQs { - if (!search) { - // react-router-dom places search string in the hash - const hash = window.location.hash - search = hash.substr(hash.indexOf('?')) - } - return search && search.length > 1 ? parse(search, { parseArrays: false, ignoreQueryPrefix: true }) : {} -} - -export default function useParsedQueryString(): ParsedQs { - const { search } = useLocation() - return useMemo(() => parsedQueryString(search), [search]) -} diff --git a/src/hooks/usePoolTickData.ts b/src/hooks/usePoolTickData.ts deleted file mode 100644 index 334c95f00dd..00000000000 --- a/src/hooks/usePoolTickData.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { skipToken } from '@reduxjs/toolkit/query/react' -import { Currency } from '@uniswap/sdk-core' -import { FeeAmount, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk' -import JSBI from 'jsbi' -import ms from 'ms.macro' -import { useMemo } from 'react' -import { useAllV3TicksQuery } from 'state/data/enhanced' -import { AllV3TicksQuery } from 'state/data/generated' -import computeSurroundingTicks from 'utils/computeSurroundingTicks' - -import { PoolState, usePool } from './usePools' - -const PRICE_FIXED_DIGITS = 8 - -// Tick with fields parsed to JSBIs, and active liquidity computed. -export interface TickProcessed { - tickIdx: number - liquidityActive: JSBI - liquidityNet: JSBI - price0: string -} - -const getActiveTick = (tickCurrent: number | undefined, feeAmount: FeeAmount | undefined) => - tickCurrent && feeAmount ? Math.floor(tickCurrent / TICK_SPACINGS[feeAmount]) * TICK_SPACINGS[feeAmount] : undefined - -// Fetches all ticks for a given pool -export function useAllV3Ticks( - currencyA: Currency | undefined, - currencyB: Currency | undefined, - feeAmount: FeeAmount | undefined -) { - const poolAddress = - currencyA && currencyB && feeAmount ? Pool.getAddress(currencyA?.wrapped, currencyB?.wrapped, feeAmount) : undefined - - const { isLoading, isError, error, isUninitialized, data } = useAllV3TicksQuery( - poolAddress ? { poolAddress: poolAddress?.toLowerCase(), skip: 0 } : skipToken, - { - pollingInterval: ms`30s`, - } - ) - - return { - isLoading, - isUninitialized, - isError, - error, - ticks: data?.ticks as AllV3TicksQuery['ticks'], - } -} - -export function usePoolActiveLiquidity( - currencyA: Currency | undefined, - currencyB: Currency | undefined, - feeAmount: FeeAmount | undefined -): { - isLoading: boolean - isUninitialized: boolean - isError: boolean - error: any - activeTick: number | undefined - data: TickProcessed[] | undefined -} { - const pool = usePool(currencyA, currencyB, feeAmount) - - // Find nearest valid tick for pool in case tick is not initialized. - const activeTick = useMemo(() => getActiveTick(pool[1]?.tickCurrent, feeAmount), [pool, feeAmount]) - - const { isLoading, isUninitialized, isError, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount) - - return useMemo(() => { - if ( - !currencyA || - !currencyB || - activeTick === undefined || - pool[0] !== PoolState.EXISTS || - !ticks || - ticks.length === 0 || - isLoading || - isUninitialized - ) { - return { - isLoading: isLoading || pool[0] === PoolState.LOADING, - isUninitialized, - isError, - error, - activeTick, - data: undefined, - } - } - - const token0 = currencyA?.wrapped - const token1 = currencyB?.wrapped - - // find where the active tick would be to partition the array - // if the active tick is initialized, the pivot will be an element - // if not, take the previous tick as pivot - const pivot = ticks.findIndex(({ tickIdx }) => tickIdx > activeTick) - 1 - - if (pivot < 0) { - // consider setting a local error - console.error('TickData pivot not found') - return { - isLoading, - isUninitialized, - isError, - error, - activeTick, - data: undefined, - } - } - - const activeTickProcessed: TickProcessed = { - liquidityActive: JSBI.BigInt(pool[1]?.liquidity ?? 0), - tickIdx: activeTick, - liquidityNet: - Number(ticks[pivot].tickIdx) === activeTick ? JSBI.BigInt(ticks[pivot].liquidityNet) : JSBI.BigInt(0), - price0: tickToPrice(token0, token1, activeTick).toFixed(PRICE_FIXED_DIGITS), - } - - const subsequentTicks = computeSurroundingTicks(token0, token1, activeTickProcessed, ticks, pivot, true) - - const previousTicks = computeSurroundingTicks(token0, token1, activeTickProcessed, ticks, pivot, false) - - const ticksProcessed = previousTicks.concat(activeTickProcessed).concat(subsequentTicks) - - return { - isLoading, - isUninitialized, - isError, - error, - activeTick, - data: ticksProcessed, - } - }, [currencyA, currencyB, activeTick, pool, ticks, isLoading, isUninitialized, isError, error]) -} diff --git a/src/hooks/usePools.ts b/src/hooks/usePools.ts deleted file mode 100644 index d179b1ac54e..00000000000 --- a/src/hooks/usePools.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Interface } from '@ethersproject/abi' -import { Currency, Token } from '@uniswap/sdk-core' -import { abi as IUniswapV3PoolStateABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json' -import { computePoolAddress } from '@uniswap/v3-sdk' -import { FeeAmount, Pool } from '@uniswap/v3-sdk' -import { useMemo } from 'react' - -import { V3_CORE_FACTORY_ADDRESSES } from '../constants/addresses' -import { useMultipleContractSingleData } from '../state/multicall/hooks' -import { IUniswapV3PoolStateInterface } from '../types/v3/IUniswapV3PoolState' -import { useActiveWeb3React } from './web3' - -const POOL_STATE_INTERFACE = new Interface(IUniswapV3PoolStateABI) as IUniswapV3PoolStateInterface - -export enum PoolState { - LOADING, - NOT_EXISTS, - EXISTS, - INVALID, -} - -export function usePools( - poolKeys: [Currency | undefined, Currency | undefined, FeeAmount | undefined][] -): [PoolState, Pool | null][] { - const { chainId } = useActiveWeb3React() - - const transformed: ([Token, Token, FeeAmount] | null)[] = useMemo(() => { - return poolKeys.map(([currencyA, currencyB, feeAmount]) => { - if (!chainId || !currencyA || !currencyB || !feeAmount) return null - - const tokenA = currencyA?.wrapped - const tokenB = currencyB?.wrapped - if (!tokenA || !tokenB || tokenA.equals(tokenB)) return null - const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] - return [token0, token1, feeAmount] - }) - }, [chainId, poolKeys]) - - const poolAddresses: (string | undefined)[] = useMemo(() => { - const v3CoreFactoryAddress = chainId && V3_CORE_FACTORY_ADDRESSES[chainId] - - return transformed.map((value) => { - if (!v3CoreFactoryAddress || !value) return undefined - return computePoolAddress({ - factoryAddress: v3CoreFactoryAddress, - tokenA: value[0], - tokenB: value[1], - fee: value[2], - }) - }) - }, [chainId, transformed]) - - const slot0s = useMultipleContractSingleData(poolAddresses, POOL_STATE_INTERFACE, 'slot0') - const liquidities = useMultipleContractSingleData(poolAddresses, POOL_STATE_INTERFACE, 'liquidity') - - return useMemo(() => { - return poolKeys.map((_key, index) => { - const [token0, token1, fee] = transformed[index] ?? [] - if (!token0 || !token1 || !fee) return [PoolState.INVALID, null] - - const { result: slot0, loading: slot0Loading, valid: slot0Valid } = slot0s[index] - const { result: liquidity, loading: liquidityLoading, valid: liquidityValid } = liquidities[index] - - if (!slot0Valid || !liquidityValid) return [PoolState.INVALID, null] - if (slot0Loading || liquidityLoading) return [PoolState.LOADING, null] - - if (!slot0 || !liquidity) return [PoolState.NOT_EXISTS, null] - - if (!slot0.sqrtPriceX96 || slot0.sqrtPriceX96.eq(0)) return [PoolState.NOT_EXISTS, null] - - try { - return [PoolState.EXISTS, new Pool(token0, token1, fee, slot0.sqrtPriceX96, liquidity[0], slot0.tick)] - } catch (error) { - console.error('Error when constructing the pool', error) - return [PoolState.NOT_EXISTS, null] - } - }) - }, [liquidities, poolKeys, slot0s, transformed]) -} - -export function usePool( - currencyA: Currency | undefined, - currencyB: Currency | undefined, - feeAmount: FeeAmount | undefined -): [PoolState, Pool | null] { - const poolKeys: [Currency | undefined, Currency | undefined, FeeAmount | undefined][] = useMemo( - () => [[currencyA, currencyB, feeAmount]], - [currencyA, currencyB, feeAmount] - ) - - return usePools(poolKeys)[0] -} diff --git a/src/hooks/usePositionTokenURI.ts b/src/hooks/usePositionTokenURI.ts deleted file mode 100644 index 2f42eedf8af..00000000000 --- a/src/hooks/usePositionTokenURI.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' -import JSBI from 'jsbi' -import { useMemo } from 'react' - -import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks' -import { useV3NFTPositionManagerContract } from './useContract' - -type TokenId = number | JSBI | BigNumber - -const STARTS_WITH = 'data:application/json;base64,' - -type UsePositionTokenURIResult = - | { - valid: true - loading: false - result: { - name: string - description: string - image: string - } - } - | { - valid: false - loading: false - } - | { - valid: true - loading: true - } - -export function usePositionTokenURI(tokenId: TokenId | undefined): UsePositionTokenURIResult { - const contract = useV3NFTPositionManagerContract() - const inputs = useMemo( - () => [tokenId instanceof BigNumber ? tokenId.toHexString() : tokenId?.toString(16)], - [tokenId] - ) - const { result, error, loading, valid } = useSingleCallResult(contract, 'tokenURI', inputs, { - ...NEVER_RELOAD, - gasRequired: 3_000_000, - }) - - return useMemo(() => { - if (error || !valid || !tokenId) { - return { - valid: false, - loading: false, - } - } - if (loading) { - return { - valid: true, - loading: true, - } - } - if (!result) { - return { - valid: false, - loading: false, - } - } - const [tokenURI] = result as [string] - if (!tokenURI || !tokenURI.startsWith(STARTS_WITH)) - return { - valid: false, - loading: false, - } - - try { - const json = JSON.parse(atob(tokenURI.slice(STARTS_WITH.length))) - - return { - valid: true, - loading: false, - result: json, - } - } catch (error) { - return { valid: false, loading: false } - } - }, [error, loading, result, tokenId, valid]) -} diff --git a/src/hooks/usePrevious.ts b/src/hooks/usePrevious.ts deleted file mode 100644 index 18d5ba3dba5..00000000000 --- a/src/hooks/usePrevious.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useEffect, useRef } from 'react' - -// modified from https://usehooks.com/usePrevious/ -export default function usePrevious(value: T) { - // The ref object is a generic container whose current property is mutable ... - // ... and can hold any value, similar to an instance property on a class - const ref = useRef() - - // Store current value in ref - useEffect(() => { - ref.current = value - }, [value]) // Only re-run if value changes - - // Return previous value (happens before update in useEffect above) - return ref.current -} diff --git a/src/hooks/useSocksBalance.ts b/src/hooks/useSocksBalance.ts deleted file mode 100644 index 87f87c1dc3b..00000000000 --- a/src/hooks/useSocksBalance.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Token } from '@uniswap/sdk-core' -import { SOCKS_CONTROLLER_ADDRESSES } from 'constants/addresses' -import { SupportedChainId } from 'constants/chains' -import { useMemo } from 'react' -import { useTokenBalance } from 'state/wallet/hooks' - -import { useActiveWeb3React } from './web3' - -// technically a 721, not an ERC20, but suffices for our purposes -const SOCKS = new Token(SupportedChainId.MAINNET, SOCKS_CONTROLLER_ADDRESSES[SupportedChainId.MAINNET], 0) - -export function useHasSocks(): boolean | undefined { - const { account, chainId } = useActiveWeb3React() - - const balance = useTokenBalance(account ?? undefined, chainId === SupportedChainId.MAINNET ? SOCKS : undefined) - - return useMemo(() => Boolean(balance?.greaterThan(0)), [balance]) -} diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts deleted file mode 100644 index e17893e1543..00000000000 --- a/src/hooks/useTheme.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useContext } from 'react' -import { ThemeContext } from 'styled-components/macro' - -export default function useTheme() { - return useContext(ThemeContext) -} diff --git a/src/hooks/useToggle.ts b/src/hooks/useToggle.ts deleted file mode 100644 index 2da340a46b7..00000000000 --- a/src/hooks/useToggle.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useCallback, useState } from 'react' - -export default function useToggle(initialState = false): [boolean, () => void] { - const [state, setState] = useState(initialState) - const toggle = useCallback(() => setState((state) => !state), []) - return [state, toggle] -} diff --git a/src/hooks/useToggledVersion.ts b/src/hooks/useToggledVersion.ts deleted file mode 100644 index 71f3d5359e7..00000000000 --- a/src/hooks/useToggledVersion.ts +++ /dev/null @@ -1,21 +0,0 @@ -import useParsedQueryString from './useParsedQueryString' - -export enum Version { - v2 = 'V2', - v3 = 'V3', -} - -export default function useToggledVersion(): Version | undefined { - const { use } = useParsedQueryString() - if (typeof use !== 'string') { - return undefined - } - switch (use.toLowerCase()) { - case 'v2': - return Version.v2 - case 'v3': - return Version.v3 - default: - return undefined - } -} diff --git a/src/hooks/useTokenAllowance.ts b/src/hooks/useTokenAllowance.ts deleted file mode 100644 index f1edb8dc286..00000000000 --- a/src/hooks/useTokenAllowance.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CurrencyAmount, Token } from '@uniswap/sdk-core' -import { useMemo } from 'react' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { useTokenContract } from './useContract' - -export function useTokenAllowance(token?: Token, owner?: string, spender?: string): CurrencyAmount | undefined { - const contract = useTokenContract(token?.address, false) - - const inputs = useMemo(() => [owner, spender], [owner, spender]) - const allowance = useSingleCallResult(contract, 'allowance', inputs).result - - return useMemo( - () => (token && allowance ? CurrencyAmount.fromRawAmount(token, allowance.toString()) : undefined), - [token, allowance] - ) -} diff --git a/src/hooks/useTokenInfoFromActiveList.ts b/src/hooks/useTokenInfoFromActiveList.ts deleted file mode 100644 index dbd50d66ed0..00000000000 --- a/src/hooks/useTokenInfoFromActiveList.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Currency } from '@uniswap/sdk-core' -import { useActiveWeb3React } from 'hooks/web3' -import { useMemo } from 'react' -import { useCombinedActiveList } from 'state/lists/hooks' - -/** - * Returns a WrappedTokenInfo from the active token lists when possible, - * or the passed token otherwise. */ -export function useTokenInfoFromActiveList(currency: Currency) { - const { chainId } = useActiveWeb3React() - const activeList = useCombinedActiveList() - - return useMemo(() => { - if (!chainId) return - if (currency.isNative) return currency - - try { - return activeList[chainId][currency.wrapped.address].token - } catch (e) { - return currency - } - }, [activeList, chainId, currency]) -} diff --git a/src/hooks/useTotalSupply.ts b/src/hooks/useTotalSupply.ts deleted file mode 100644 index 8d424d6d409..00000000000 --- a/src/hooks/useTotalSupply.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' -import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' - -import { useSingleCallResult } from '../state/multicall/hooks' -import { useTokenContract } from './useContract' - -// returns undefined if input token is undefined, or fails to get token contract, -// or contract total supply cannot be fetched -export function useTotalSupply(token?: Currency): CurrencyAmount | undefined { - const contract = useTokenContract(token?.isToken ? token.address : undefined, false) - - const totalSupply: BigNumber = useSingleCallResult(contract, 'totalSupply')?.result?.[0] - - return token?.isToken && totalSupply ? CurrencyAmount.fromRawAmount(token, totalSupply.toString()) : undefined -} diff --git a/src/hooks/useTransactionDeadline.ts b/src/hooks/useTransactionDeadline.ts deleted file mode 100644 index 4ae41cb7f90..00000000000 --- a/src/hooks/useTransactionDeadline.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' -import { L2_CHAIN_IDS } from 'constants/chains' -import { L2_DEADLINE_FROM_NOW } from 'constants/misc' -import { useMemo } from 'react' -import { useAppSelector } from 'state/hooks' - -import useCurrentBlockTimestamp from './useCurrentBlockTimestamp' -import { useActiveWeb3React } from './web3' - -// combines the block timestamp with the user setting to give the deadline that should be used for any submitted transaction -export default function useTransactionDeadline(): BigNumber | undefined { - const { chainId } = useActiveWeb3React() - const ttl = useAppSelector((state) => state.user.userDeadline) - const blockTimestamp = useCurrentBlockTimestamp() - return useMemo(() => { - if (blockTimestamp && chainId && L2_CHAIN_IDS.includes(chainId)) return blockTimestamp.add(L2_DEADLINE_FROM_NOW) - if (blockTimestamp && ttl) return blockTimestamp.add(ttl) - return undefined - }, [blockTimestamp, chainId, ttl]) -} diff --git a/src/hooks/useV2Pairs.ts b/src/hooks/useV2Pairs.ts deleted file mode 100644 index 946e134e2f6..00000000000 --- a/src/hooks/useV2Pairs.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Interface } from '@ethersproject/abi' -import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json' -import { computePairAddress, Pair } from '@uniswap/v2-sdk' -import { useMemo } from 'react' - -import { V2_FACTORY_ADDRESSES } from '../constants/addresses' -import { useMultipleContractSingleData } from '../state/multicall/hooks' - -const PAIR_INTERFACE = new Interface(IUniswapV2PairABI) - -export enum PairState { - LOADING, - NOT_EXISTS, - EXISTS, - INVALID, -} - -export function useV2Pairs(currencies: [Currency | undefined, Currency | undefined][]): [PairState, Pair | null][] { - const tokens = useMemo( - () => currencies.map(([currencyA, currencyB]) => [currencyA?.wrapped, currencyB?.wrapped]), - [currencies] - ) - - const pairAddresses = useMemo( - () => - tokens.map(([tokenA, tokenB]) => { - return tokenA && - tokenB && - tokenA.chainId === tokenB.chainId && - !tokenA.equals(tokenB) && - V2_FACTORY_ADDRESSES[tokenA.chainId] - ? computePairAddress({ factoryAddress: V2_FACTORY_ADDRESSES[tokenA.chainId], tokenA, tokenB }) - : undefined - }), - [tokens] - ) - - const results = useMultipleContractSingleData(pairAddresses, PAIR_INTERFACE, 'getReserves') - - return useMemo(() => { - return results.map((result, i) => { - const { result: reserves, loading } = result - const tokenA = tokens[i][0] - const tokenB = tokens[i][1] - - if (loading) return [PairState.LOADING, null] - if (!tokenA || !tokenB || tokenA.equals(tokenB)) return [PairState.INVALID, null] - if (!reserves) return [PairState.NOT_EXISTS, null] - const { reserve0, reserve1 } = reserves - const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] - return [ - PairState.EXISTS, - new Pair( - CurrencyAmount.fromRawAmount(token0, reserve0.toString()), - CurrencyAmount.fromRawAmount(token1, reserve1.toString()) - ), - ] - }) - }, [results, tokens]) -} - -export function useV2Pair(tokenA?: Currency, tokenB?: Currency): [PairState, Pair | null] { - const inputs: [[Currency | undefined, Currency | undefined]] = useMemo(() => [[tokenA, tokenB]], [tokenA, tokenB]) - return useV2Pairs(inputs)[0] -} diff --git a/src/hooks/useV3PositionFees.ts b/src/hooks/useV3PositionFees.ts deleted file mode 100644 index 15f98965ea4..00000000000 --- a/src/hooks/useV3PositionFees.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' -import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Pool } from '@uniswap/v3-sdk' -import { useEffect, useState } from 'react' -import { useBlockNumber } from 'state/application/hooks' -import { useSingleCallResult } from 'state/multicall/hooks' -import { unwrappedToken } from 'utils/unwrappedToken' - -import { useV3NFTPositionManagerContract } from './useContract' - -const MAX_UINT128 = BigNumber.from(2).pow(128).sub(1) - -// compute current + counterfactual fees for a v3 position -export function useV3PositionFees( - pool?: Pool, - tokenId?: BigNumber, - asWETH = false -): [CurrencyAmount, CurrencyAmount] | [undefined, undefined] { - const positionManager = useV3NFTPositionManagerContract(false) - const owner: string | undefined = useSingleCallResult(tokenId ? positionManager : null, 'ownerOf', [tokenId]) - .result?.[0] - - const tokenIdHexString = tokenId?.toHexString() - const latestBlockNumber = useBlockNumber() - - // TODO find a way to get this into multicall - // latestBlockNumber is included to ensure data stays up-to-date every block - const [amounts, setAmounts] = useState<[BigNumber, BigNumber]>() - useEffect(() => { - let stale = false - - if (positionManager && tokenIdHexString && owner && typeof latestBlockNumber === 'number') { - positionManager.callStatic - .collect( - { - tokenId: tokenIdHexString, - recipient: owner, // some tokens might fail if transferred to address(0) - amount0Max: MAX_UINT128, - amount1Max: MAX_UINT128, - }, - { from: owner } // need to simulate the call as the owner - ) - .then((results) => { - if (!stale) setAmounts([results.amount0, results.amount1]) - }) - } - - return () => { - stale = true - } - }, [positionManager, tokenIdHexString, owner, latestBlockNumber]) - - if (pool && amounts) { - return [ - CurrencyAmount.fromRawAmount(!asWETH ? unwrappedToken(pool.token0) : pool.token0, amounts[0].toString()), - CurrencyAmount.fromRawAmount(!asWETH ? unwrappedToken(pool.token1) : pool.token1, amounts[1].toString()), - ] - } else { - return [undefined, undefined] - } -} diff --git a/src/hooks/useV3Positions.ts b/src/hooks/useV3Positions.ts deleted file mode 100644 index 4f545104aaf..00000000000 --- a/src/hooks/useV3Positions.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber' -import { useMemo } from 'react' -import { Result, useSingleCallResult, useSingleContractMultipleData } from 'state/multicall/hooks' -import { PositionDetails } from 'types/position' - -import { useV3NFTPositionManagerContract } from './useContract' - -interface UseV3PositionsResults { - loading: boolean - positions: PositionDetails[] | undefined -} - -function useV3PositionsFromTokenIds(tokenIds: BigNumber[] | undefined): UseV3PositionsResults { - const positionManager = useV3NFTPositionManagerContract() - const inputs = useMemo(() => (tokenIds ? tokenIds.map((tokenId) => [BigNumber.from(tokenId)]) : []), [tokenIds]) - const results = useSingleContractMultipleData(positionManager, 'positions', inputs) - - const loading = useMemo(() => results.some(({ loading }) => loading), [results]) - const error = useMemo(() => results.some(({ error }) => error), [results]) - - const positions = useMemo(() => { - if (!loading && !error && tokenIds) { - return results.map((call, i) => { - const tokenId = tokenIds[i] - const result = call.result as Result - return { - tokenId, - fee: result.fee, - feeGrowthInside0LastX128: result.feeGrowthInside0LastX128, - feeGrowthInside1LastX128: result.feeGrowthInside1LastX128, - liquidity: result.liquidity, - nonce: result.nonce, - operator: result.operator, - tickLower: result.tickLower, - tickUpper: result.tickUpper, - token0: result.token0, - token1: result.token1, - tokensOwed0: result.tokensOwed0, - tokensOwed1: result.tokensOwed1, - } - }) - } - return undefined - }, [loading, error, results, tokenIds]) - - return { - loading, - positions: positions?.map((position, i) => ({ ...position, tokenId: inputs[i][0] })), - } -} - -interface UseV3PositionResults { - loading: boolean - position: PositionDetails | undefined -} - -export function useV3PositionFromTokenId(tokenId: BigNumber | undefined): UseV3PositionResults { - const position = useV3PositionsFromTokenIds(tokenId ? [tokenId] : undefined) - return { - loading: position.loading, - position: position.positions?.[0], - } -} - -export function useV3Positions(account: string | null | undefined): UseV3PositionsResults { - const positionManager = useV3NFTPositionManagerContract() - - const { loading: balanceLoading, result: balanceResult } = useSingleCallResult(positionManager, 'balanceOf', [ - account ?? undefined, - ]) - - // we don't expect any account balance to ever exceed the bounds of max safe int - const accountBalance: number | undefined = balanceResult?.[0]?.toNumber() - - const tokenIdsArgs = useMemo(() => { - if (accountBalance && account) { - const tokenRequests = [] - for (let i = 0; i < accountBalance; i++) { - tokenRequests.push([account, i]) - } - return tokenRequests - } - return [] - }, [account, accountBalance]) - - const tokenIdResults = useSingleContractMultipleData(positionManager, 'tokenOfOwnerByIndex', tokenIdsArgs) - const someTokenIdsLoading = useMemo(() => tokenIdResults.some(({ loading }) => loading), [tokenIdResults]) - - const tokenIds = useMemo(() => { - if (account) { - return tokenIdResults - .map(({ result }) => result) - .filter((result): result is Result => !!result) - .map((result) => BigNumber.from(result[0])) - } - return [] - }, [account, tokenIdResults]) - - const { positions, loading: positionsLoading } = useV3PositionsFromTokenIds(tokenIds) - - return { - loading: someTokenIdsLoading || balanceLoading || positionsLoading, - positions, - } -} diff --git a/src/hooks/useV3SwapPools.ts b/src/hooks/useV3SwapPools.ts deleted file mode 100644 index 05ebea4f43e..00000000000 --- a/src/hooks/useV3SwapPools.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Currency, Token } from '@uniswap/sdk-core' -import { FeeAmount, Pool } from '@uniswap/v3-sdk' -import { SupportedChainId } from 'constants/chains' -import { useMemo } from 'react' - -import { useAllCurrencyCombinations } from './useAllCurrencyCombinations' -import { PoolState, usePools } from './usePools' -import { useActiveWeb3React } from './web3' - -/** - * Returns all the existing pools that should be considered for swapping between an input currency and an output currency - * @param currencyIn the input currency - * @param currencyOut the output currency - */ -export function useV3SwapPools( - currencyIn?: Currency, - currencyOut?: Currency -): { - pools: Pool[] - loading: boolean -} { - const { chainId } = useActiveWeb3React() - - const allCurrencyCombinations = useAllCurrencyCombinations(currencyIn, currencyOut) - - const allCurrencyCombinationsWithAllFees: [Token, Token, FeeAmount][] = useMemo( - () => - allCurrencyCombinations.reduce<[Token, Token, FeeAmount][]>((list, [tokenA, tokenB]) => { - return chainId === SupportedChainId.MAINNET - ? list.concat([ - [tokenA, tokenB, FeeAmount.LOW], - [tokenA, tokenB, FeeAmount.MEDIUM], - [tokenA, tokenB, FeeAmount.HIGH], - ]) - : list.concat([ - [tokenA, tokenB, FeeAmount.LOWEST], - [tokenA, tokenB, FeeAmount.LOW], - [tokenA, tokenB, FeeAmount.MEDIUM], - [tokenA, tokenB, FeeAmount.HIGH], - ]) - }, []), - [allCurrencyCombinations, chainId] - ) - - const pools = usePools(allCurrencyCombinationsWithAllFees) - - return useMemo(() => { - return { - pools: pools - .filter((tuple): tuple is [PoolState.EXISTS, Pool] => { - return tuple[0] === PoolState.EXISTS && tuple[1] !== null - }) - .map(([, pool]) => pool), - loading: pools.some(([state]) => state === PoolState.LOADING), - } - }, [pools]) -} diff --git a/src/hooks/useWindowSize.ts b/src/hooks/useWindowSize.ts deleted file mode 100644 index e497064a07b..00000000000 --- a/src/hooks/useWindowSize.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useEffect, useState } from 'react' - -const isClient = typeof window === 'object' - -function getSize() { - return { - width: isClient ? window.innerWidth : undefined, - height: isClient ? window.innerHeight : undefined, - } -} - -// https://usehooks.com/useWindowSize/ -export function useWindowSize() { - const [windowSize, setWindowSize] = useState(getSize) - - useEffect(() => { - function handleResize() { - setWindowSize(getSize()) - } - - if (isClient) { - window.addEventListener('resize', handleResize) - return () => { - window.removeEventListener('resize', handleResize) - } - } - return undefined - }, []) - - return windowSize -} diff --git a/src/hooks/useWrapCallback.ts b/src/hooks/useWrapCallback.ts deleted file mode 100644 index 5cbabf70233..00000000000 --- a/src/hooks/useWrapCallback.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Currency } from '@uniswap/sdk-core' -import { useMemo } from 'react' - -import { WETH9_EXTENDED } from '../constants/tokens' -import { tryParseAmount } from '../state/swap/hooks' -import { TransactionType } from '../state/transactions/actions' -import { useTransactionAdder } from '../state/transactions/hooks' -import { useCurrencyBalance } from '../state/wallet/hooks' -import { useWETHContract } from './useContract' -import { useActiveWeb3React } from './web3' - -export enum WrapType { - NOT_APPLICABLE, - WRAP, - UNWRAP, -} - -const NOT_APPLICABLE = { wrapType: WrapType.NOT_APPLICABLE } -/** - * Given the selected input and output currency, return a wrap callback - * @param inputCurrency the selected input currency - * @param outputCurrency the selected output currency - * @param typedValue the user input value - */ -export default function useWrapCallback( - inputCurrency: Currency | undefined | null, - outputCurrency: Currency | undefined | null, - typedValue: string | undefined -): { wrapType: WrapType; execute?: undefined | (() => Promise); inputError?: string } { - const { chainId, account } = useActiveWeb3React() - const wethContract = useWETHContract() - const balance = useCurrencyBalance(account ?? undefined, inputCurrency ?? undefined) - // we can always parse the amount typed as the input currency, since wrapping is 1:1 - const inputAmount = useMemo(() => tryParseAmount(typedValue, inputCurrency ?? undefined), [inputCurrency, typedValue]) - const addTransaction = useTransactionAdder() - - return useMemo(() => { - if (!wethContract || !chainId || !inputCurrency || !outputCurrency) return NOT_APPLICABLE - const weth = WETH9_EXTENDED[chainId] - if (!weth) return NOT_APPLICABLE - - const hasInputAmount = Boolean(inputAmount?.greaterThan('0')) - const sufficientBalance = inputAmount && balance && !balance.lessThan(inputAmount) - - if (inputCurrency.isNative && weth.equals(outputCurrency)) { - return { - wrapType: WrapType.WRAP, - execute: - sufficientBalance && inputAmount - ? async () => { - try { - const txReceipt = await wethContract.deposit({ value: `0x${inputAmount.quotient.toString(16)}` }) - addTransaction(txReceipt, { - type: TransactionType.WRAP, - unwrapped: false, - currencyAmountRaw: inputAmount?.quotient.toString(), - }) - } catch (error) { - console.error('Could not deposit', error) - } - } - : undefined, - inputError: sufficientBalance ? undefined : hasInputAmount ? 'Insufficient ETH balance' : 'Enter ETH amount', - } - } else if (weth.equals(inputCurrency) && outputCurrency.isNative) { - return { - wrapType: WrapType.UNWRAP, - execute: - sufficientBalance && inputAmount - ? async () => { - try { - const txReceipt = await wethContract.withdraw(`0x${inputAmount.quotient.toString(16)}`) - addTransaction(txReceipt, { - type: TransactionType.WRAP, - unwrapped: true, - currencyAmountRaw: inputAmount?.quotient.toString(), - }) - } catch (error) { - console.error('Could not withdraw', error) - } - } - : undefined, - inputError: sufficientBalance ? undefined : hasInputAmount ? 'Insufficient WETH balance' : 'Enter WETH amount', - } - } else { - return NOT_APPLICABLE - } - }, [wethContract, chainId, inputCurrency, outputCurrency, inputAmount, balance, addTransaction]) -} diff --git a/src/hooks/web3.ts b/src/hooks/web3.ts deleted file mode 100644 index 7bf54020a9f..00000000000 --- a/src/hooks/web3.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Web3Provider } from '@ethersproject/providers' -import { useWeb3React } from '@web3-react/core' -import { useEffect, useState } from 'react' - -import { gnosisSafe, injected } from '../connectors' -import { IS_IN_IFRAME, NetworkContextName } from '../constants/misc' -import { isMobile } from '../utils/userAgent' - -export function useActiveWeb3React() { - const context = useWeb3React() - const contextNetwork = useWeb3React(NetworkContextName) - return context.active ? context : contextNetwork -} - -export function useEagerConnect() { - const { activate, active } = useWeb3React() - const [tried, setTried] = useState(false) - - // gnosisSafe.isSafeApp() races a timeout against postMessage, so it delays pageload if we are not in a safe app; - // if we are not embedded in an iframe, it is not worth checking - const [triedSafe, setTriedSafe] = useState(!IS_IN_IFRAME) - - // first, try connecting to a gnosis safe - useEffect(() => { - if (!triedSafe) { - gnosisSafe.isSafeApp().then((loadedInSafe) => { - if (loadedInSafe) { - activate(gnosisSafe, undefined, true).catch(() => { - setTriedSafe(true) - }) - } else { - setTriedSafe(true) - } - }) - } - }, [activate, setTriedSafe, triedSafe]) - - // then, if that fails, try connecting to an injected connector - useEffect(() => { - if (!active && triedSafe) { - injected.isAuthorized().then((isAuthorized) => { - if (isAuthorized) { - activate(injected, undefined, true).catch(() => { - setTried(true) - }) - } else { - if (isMobile && window.ethereum) { - activate(injected, undefined, true).catch(() => { - setTried(true) - }) - } else { - setTried(true) - } - } - }) - } - }, [activate, active, triedSafe]) - - // wait until we get confirmation of a connection to flip the flag - useEffect(() => { - if (active) { - setTried(true) - } - }, [active]) - - return tried -} - -/** - * Use for network and injected - logs user in - * and out after checking what network theyre on - */ -export function useInactiveListener(suppress = false) { - const { active, error, activate } = useWeb3React() - - useEffect(() => { - const { ethereum } = window - - if (ethereum && ethereum.on && !active && !error && !suppress) { - const handleChainChanged = () => { - // eat errors - activate(injected, undefined, true).catch((error) => { - console.error('Failed to activate after chain changed', error) - }) - } - - const handleAccountsChanged = (accounts: string[]) => { - if (accounts.length > 0) { - // eat errors - activate(injected, undefined, true).catch((error) => { - console.error('Failed to activate after accounts changed', error) - }) - } - } - - ethereum.on('chainChanged', handleChainChanged) - ethereum.on('accountsChanged', handleAccountsChanged) - - return () => { - if (ethereum.removeListener) { - ethereum.removeListener('chainChanged', handleChainChanged) - ethereum.removeListener('accountsChanged', handleAccountsChanged) - } - } - } - return undefined - }, [active, error, suppress, activate]) -}