diff --git a/.eslintrc.json b/.eslintrc.json index 5497c9c6d1..54875f3b34 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -18,7 +18,6 @@ "src/abis/types", "src/locales/**/*.js", "src/locales/**/en-US.po", - "src/state/data/generated.ts", "node_modules", "coverage", "build", diff --git a/.gitignore b/.gitignore index 5cfa216b2b..377587720d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,16 @@ # See https://help.github.com/ignore-files/ for more about ignoring files. + # generated contract types /src/types/v3 /src/abis/types /src/locales/**/*.js /src/locales/**/en-US.po /src/locales/**/pseudo.po -/src/state/data/generated.ts + +# generated graphql types +/src/graphql/schema/ +__generated__/ # dependencies /node_modules diff --git a/.prettierignore b/.prettierignore index bc2431c4df..40710857f5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1 @@ -/src/state/data/generated.ts \ No newline at end of file +/src/schema/schema.graphql \ No newline at end of file diff --git a/codegen.yml b/codegen.yml index 67fc86b9f8..0a2021031d 100644 --- a/codegen.yml +++ b/codegen.yml @@ -2,10 +2,6 @@ overrideExisting: true schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3' documents: 'src/**/!(*.d).{ts,tsx}' generates: - ./src/state/data/generated.ts: + ./src/graphql/schema/schema.graphql: plugins: - - typescript - - typescript-operations - - typescript-rtk-query: - importBaseApiFrom: './slice' - exportHooks: true + - schema-ast diff --git a/cypress/e2e/add-liquidity.test.ts b/cypress/e2e/add-liquidity.test.ts index ab2eb4b3ec..5f5403c457 100644 --- a/cypress/e2e/add-liquidity.test.ts +++ b/cypress/e2e/add-liquidity.test.ts @@ -37,8 +37,8 @@ describe('Add Liquidity', () => { it('loads fee tier distribution', () => { cy.fixture('feeTierDistribution.json').then((feeTierDistribution) => { cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3', (req: CyHttpMessages.IncomingHttpRequest) => { - if (hasQuery(req, 'feeTierDistribution')) { - req.alias = 'feeTierDistributionQuery' + if (hasQuery(req, 'FeeTierDistributionQuery')) { + req.alias = 'FeeTierDistributionQuery' req.reply({ body: { @@ -55,7 +55,7 @@ describe('Add Liquidity', () => { cy.visit('/add/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85/0xc778417E063141139Fce010982780140Aa0cD5Ab') - cy.wait('@feeTierDistributionQuery') + cy.wait('@FeeTierDistributionQuery') cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier') cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%') diff --git a/package.json b/package.json index ccb98b802c..351c7020a5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"", "contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*[!dbg].json\"", "contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3", - "graphql:generate": "graphql-codegen --config codegen.yml", + "relay": "relay-compiler", + "graphql:generate": "graphql-codegen --config codegen.yml && yarn relay", "prei18n:extract": "node prei18n-extract.js", "i18n:extract": "lingui extract --locale en-US", "i18n:compile": "yarn i18n:extract && lingui compile", @@ -22,6 +23,11 @@ "cypress:open": "cypress open --browser chrome --e2e", "cypress:run": "cypress run --browser chrome --e2e" }, + "relay": { + "src": "./src", + "language": "typescript", + "schema": "./src/graphql/schema/schema.graphql" + }, "jest": { "collectCoverageFrom": [ "src/components/**/*.ts*", @@ -58,8 +64,7 @@ "@craco/craco": "6.4.3", "@ethersproject/experimental": "^5.4.0", "@graphql-codegen/cli": "1.21.5", - "@graphql-codegen/typescript": "1.22.3", - "@graphql-codegen/typescript-operations": "^1.18.2", + "@graphql-codegen/schema-ast": "^2.5.1", "@graphql-codegen/typescript-rtk-query": "^1.1.1", "@lingui/cli": "^3.9.0", "@testing-library/jest-dom": "^5.16.4", @@ -90,6 +95,7 @@ "@types/wcag-contrast": "^3.0.0", "@typescript-eslint/eslint-plugin": "^4", "@typescript-eslint/parser": "^4", + "babel-plugin-relay": "^14.1.0", "@vanilla-extract/babel-plugin": "^1.1.7", "@vanilla-extract/webpack-plugin": "^2.1.11", "cypress": "^10.3.1", @@ -106,6 +112,7 @@ "ms.macro": "^2.0.0", "prettier": "^2.7.1", "react-scripts": "^4.0.3", + "relay-compiler": "^14.1.0", "serve": "^11.3.2", "typechain": "^5.0.0", "typescript": "^4.4.3" @@ -126,6 +133,7 @@ "@reach/portal": "^0.10.3", "@react-hook/window-scroll": "^1.3.0", "@reduxjs/toolkit": "^1.6.1", + "@types/react-relay": "^13.0.2", "@uniswap/governance": "^1.0.2", "@uniswap/liquidity-staker": "^1.0.2", "@uniswap/merkle-distributor": "1.0.1", @@ -174,7 +182,7 @@ "firebase": "^9.1.3", "focus-visible": "^5.2.0", "fortmatic": "^2.4.0", - "graphql": "^15.5.0", + "graphql": "^16.5.0", "graphql-request": "^3.4.0", "immer": "^9.0.6", "inter-ui": "^3.13.1", @@ -199,6 +207,7 @@ "react-popper": "^2.2.3", "react-query": "^3.39.1", "react-redux": "^8.0.2", + "react-relay": "^14.1.0", "react-router-dom": "^6.3.0", "react-spring": "^8.0.27", "react-table": "^7.8.0", @@ -208,6 +217,7 @@ "rebass": "^4.0.7", "redux": "^4.1.2", "redux-localstorage-simple": "^2.3.1", + "relay-hooks": "^7.1.0", "setimmediate": "^1.0.5", "styled-components": "^5.3.5", "tiny-invariant": "^1.2.0", diff --git a/src/components/LiquidityChartRangeInput/hooks.ts b/src/components/LiquidityChartRangeInput/hooks.ts index c8d6a204c2..04ea22fd7d 100644 --- a/src/components/LiquidityChartRangeInput/hooks.ts +++ b/src/components/LiquidityChartRangeInput/hooks.ts @@ -14,7 +14,7 @@ export function useDensityChartData({ currencyB: Currency | undefined feeAmount: FeeAmount | undefined }) { - const { isLoading, isUninitialized, isError, error, data } = usePoolActiveLiquidity(currencyA, currencyB, feeAmount) + const { isLoading, error, data } = usePoolActiveLiquidity(currencyA, currencyB, feeAmount) const formatData = useCallback(() => { if (!data?.length) { @@ -42,10 +42,8 @@ export function useDensityChartData({ return useMemo(() => { return { isLoading, - isUninitialized, - isError, error, - formattedData: !isLoading && !isUninitialized ? formatData() : undefined, + formattedData: !isLoading ? formatData() : undefined, } - }, [isLoading, isUninitialized, isError, error, formatData]) + }, [isLoading, error, formatData]) } diff --git a/src/components/LiquidityChartRangeInput/index.tsx b/src/components/LiquidityChartRangeInput/index.tsx index d54ff6d1e3..b99117c842 100644 --- a/src/components/LiquidityChartRangeInput/index.tsx +++ b/src/components/LiquidityChartRangeInput/index.tsx @@ -96,7 +96,7 @@ export default function LiquidityChartRangeInput({ const isSorted = currencyA && currencyB && currencyA?.wrapped.sortsBefore(currencyB?.wrapped) - const { isLoading, isUninitialized, isError, error, formattedData } = useDensityChartData({ + const { isLoading, error, formattedData } = useDensityChartData({ currencyA, currencyB, feeAmount, @@ -157,10 +157,12 @@ export default function LiquidityChartRangeInput({ [isSorted, price, ticksAtLimit] ) - if (isError) { + if (error) { sendEvent('exception', { description: error.toString(), fatal: false }) } + const isUninitialized = !currencyA || !currencyB || (formattedData === undefined && !isLoading) + return ( {isUninitialized ? ( @@ -170,7 +172,7 @@ export default function LiquidityChartRangeInput({ /> ) : isLoading ? ( } /> - ) : isError ? ( + ) : error ? ( Liquidity data not available.} icon={} diff --git a/src/constants/chains.ts b/src/constants/chains.ts index 8cd2f601ab..6150be3b09 100644 --- a/src/constants/chains.ts +++ b/src/constants/chains.ts @@ -44,7 +44,7 @@ export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = Object.values(Support (id) => typeof id === 'number' ) as SupportedChainId[] -export function isSupportedChain(chainId: number | undefined): chainId is SupportedChainId { +export function isSupportedChain(chainId: number | null | undefined): chainId is SupportedChainId { return !!chainId && !!SupportedChainId[chainId] } diff --git a/src/graphql/AllV3TicksQuery.ts b/src/graphql/AllV3TicksQuery.ts new file mode 100644 index 0000000000..0e256b8fb0 --- /dev/null +++ b/src/graphql/AllV3TicksQuery.ts @@ -0,0 +1,53 @@ +import graphql from 'babel-plugin-relay/macro' +import useInterval from 'lib/hooks/useInterval' +import { useCallback, useEffect, useState } from 'react' +import { fetchQuery, useRelayEnvironment } from 'relay-hooks' +import { useAppSelector } from 'state/hooks' + +import type { + AllV3TicksQuery as AllV3TicksQueryType, + AllV3TicksQuery$data, +} from './__generated__/AllV3TicksQuery.graphql' + +const query = graphql` + query AllV3TicksQuery($poolAddress: String!, $skip: Int!) { + ticks(first: 1000, skip: $skip, where: { poolAddress: $poolAddress }, orderBy: tickIdx) { + tick: tickIdx + liquidityNet + price0 + price1 + } + } +` + +export type Ticks = AllV3TicksQuery$data['ticks'] +export type TickData = Ticks[number] + +export default function useAllV3TicksQuery(poolAddress: string | undefined, skip: number, interval: number) { + const [data, setData] = useState(null) + const [error, setError] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const chainId = useAppSelector((state) => state.application.chainId) + const environment = useRelayEnvironment() + + const refreshData = useCallback(() => { + if (poolAddress && chainId) { + fetchQuery(environment, query, { + poolAddress: poolAddress.toLowerCase(), + skip, + }).subscribe({ + next: setData, + error: setError, + complete: () => setIsLoading(false), + }) + } else { + setIsLoading(false) + } + }, [poolAddress, skip, chainId, environment]) + + // Trigger fetch on first load + useEffect(refreshData, [refreshData, poolAddress, skip]) + + useInterval(refreshData, interval, true) + return { error, isLoading, data } +} diff --git a/src/graphql/FeeTierDistributionQuery.ts b/src/graphql/FeeTierDistributionQuery.ts new file mode 100644 index 0000000000..aefe7f97f0 --- /dev/null +++ b/src/graphql/FeeTierDistributionQuery.ts @@ -0,0 +1,69 @@ +import graphql from 'babel-plugin-relay/macro' +import useInterval from 'lib/hooks/useInterval' +import { useCallback, useEffect, useState } from 'react' +import { fetchQuery, useRelayEnvironment } from 'relay-hooks' +import { useAppSelector } from 'state/hooks' + +import type { + FeeTierDistributionQuery as FeeTierDistributionQueryType, + FeeTierDistributionQuery$data, +} from './__generated__/FeeTierDistributionQuery.graphql' + +const query = graphql` + query FeeTierDistributionQuery($token0: String!, $token1: String!) { + _meta { + block { + number + } + } + asToken0: pools( + orderBy: totalValueLockedToken0 + orderDirection: desc + where: { token0: $token0, token1: $token1 } + ) { + feeTier + totalValueLockedToken0 + totalValueLockedToken1 + } + asToken1: pools( + orderBy: totalValueLockedToken0 + orderDirection: desc + where: { token0: $token1, token1: $token0 } + ) { + feeTier + totalValueLockedToken0 + totalValueLockedToken1 + } + } +` + +export default function useFeeTierDistributionQuery( + token0: string | undefined, + token1: string | undefined, + interval: number +) { + const [data, setData] = useState(null) + const [error, setError] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const environment = useRelayEnvironment() + const chainId = useAppSelector((state) => state.application.chainId) + + const refreshData = useCallback(() => { + if (token0 && token1 && chainId) { + fetchQuery(environment, query, { + token0: token0.toLowerCase(), + token1: token1.toLowerCase(), + }).subscribe({ + next: setData, + error: setError, + complete: () => setIsLoading(false), + }) + } + }, [token0, token1, chainId, environment]) + + // Trigger fetch on first load + useEffect(refreshData, [refreshData, token0, token1]) + + useInterval(refreshData, interval, true) + return { error, isLoading, data } +} diff --git a/src/graphql/RelayEnvironment.ts b/src/graphql/RelayEnvironment.ts new file mode 100644 index 0000000000..29ce7ec28d --- /dev/null +++ b/src/graphql/RelayEnvironment.ts @@ -0,0 +1,9 @@ +import { Environment, Network, RecordSource, Store } from 'relay-runtime' + +import fetchGraphQL from './fetchGraphQL' + +// Export a singleton instance of Relay Environment configured with our network function: +export default new Environment({ + network: Network.create(fetchGraphQL), + store: new Store(new RecordSource()), +}) diff --git a/src/graphql/fetchGraphQL.ts b/src/graphql/fetchGraphQL.ts new file mode 100644 index 0000000000..5edda76bcb --- /dev/null +++ b/src/graphql/fetchGraphQL.ts @@ -0,0 +1,53 @@ +/** + * Helpful Resources + * https://github.com/sibelius/create-react-app-relay-modern/blob/master/src/relay/fetchQuery.js + * https://github.com/relay-tools/relay-compiler-language-typescript/blob/master/example/ts/app.tsx + */ + +import { SupportedChainId } from 'constants/chains' +import { Variables } from 'react-relay' +import { GraphQLResponse, ObservableFromValue, RequestParameters } from 'relay-runtime' + +import store, { AppState } from '../state/index' + +const CHAIN_SUBGRAPH_URL: Record = { + [SupportedChainId.MAINNET]: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3', + [SupportedChainId.RINKEBY]: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3', + + [SupportedChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-minimal', + + [SupportedChainId.OPTIMISM]: 'https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis', + + [SupportedChainId.POLYGON]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon', + + [SupportedChainId.CELO]: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo', +} + +const headers = { + Accept: 'application/json', + 'Content-type': 'application/json', +} + +// Define a function that fetches the results of a request (query/mutation/etc) +// and returns its results as a Promise: +const fetchQuery = (params: RequestParameters, variables: Variables): ObservableFromValue => { + const chainId = (store.getState() as AppState).application.chainId + + const subgraphUrl = + chainId && CHAIN_SUBGRAPH_URL[chainId] ? CHAIN_SUBGRAPH_URL[chainId] : CHAIN_SUBGRAPH_URL[SupportedChainId.MAINNET] + + const body = JSON.stringify({ + query: params.text, // GraphQL text from input + variables, + }) + + const response = fetch(subgraphUrl, { + method: 'POST', + headers, + body, + }).then((res) => res.json()) + + return response +} + +export default fetchQuery diff --git a/src/hooks/useFeeTierDistribution.ts b/src/hooks/useFeeTierDistribution.ts index f4c78b29e1..c829344904 100644 --- a/src/hooks/useFeeTierDistribution.ts +++ b/src/hooks/useFeeTierDistribution.ts @@ -1,13 +1,11 @@ -import { skipToken } from '@reduxjs/toolkit/query/react' import { Currency, Token } from '@uniswap/sdk-core' import { FeeAmount } from '@uniswap/v3-sdk' import { sendEvent } from 'components/analytics' import useBlockNumber from 'lib/hooks/useBlockNumber' import ms from 'ms.macro' import { useMemo } from 'react' -import { useFeeTierDistributionQuery } from 'state/data/enhanced' -import { FeeTierDistributionQuery } from 'state/data/generated' +import useFeeTierDistributionQuery from '../graphql/FeeTierDistributionQuery' import { PoolState, usePool } from './usePools' // maximum number of blocks past which we consider the data stale @@ -26,10 +24,7 @@ export function useFeeTierDistribution( currencyA: Currency | undefined, currencyB: Currency | undefined ): FeeTierDistribution { - const { isFetching, isLoading, isUninitialized, isError, distributions } = usePoolTVL( - currencyA?.wrapped, - currencyB?.wrapped - ) + const { isLoading, error, distributions } = usePoolTVL(currencyA?.wrapped, currencyB?.wrapped) // fetch all pool states to determine pool state const [poolStateVeryLow] = usePool(currencyA, currencyB, FeeAmount.LOWEST) @@ -38,10 +33,10 @@ export function useFeeTierDistribution( const [poolStateHigh] = usePool(currencyA, currencyB, FeeAmount.HIGH) return useMemo(() => { - if (isLoading || isFetching || isUninitialized || isError || !distributions) { + if (isLoading || error || !distributions) { return { - isLoading: isLoading || isFetching || !isUninitialized, - isError, + isLoading, + isError: !!error, distributions, } } @@ -53,7 +48,7 @@ export function useFeeTierDistribution( const percentages = !isLoading && - !isError && + !error && distributions && poolStateVeryLow !== PoolState.LOADING && poolStateLow !== PoolState.LOADING && @@ -72,42 +67,24 @@ export function useFeeTierDistribution( return { isLoading, - isError, + isError: !!error, distributions: percentages, largestUsageFeeTier: largestUsageFeeTier === -1 ? undefined : largestUsageFeeTier, } - }, [ - isLoading, - isFetching, - isUninitialized, - isError, - distributions, - poolStateVeryLow, - poolStateLow, - poolStateMedium, - poolStateHigh, - ]) + }, [isLoading, error, distributions, poolStateVeryLow, poolStateLow, poolStateMedium, poolStateHigh]) } function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { const latestBlock = useBlockNumber() + const { isLoading, error, data } = useFeeTierDistributionQuery(token0?.address, token1?.address, ms`30s`) - 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) ?? {} + const { asToken0, asToken1, _meta } = data ?? {} return useMemo(() => { if (!latestBlock || !_meta || !asToken0 || !asToken1) { return { isLoading, - isFetching, - isUninitialized, - isError, + error, } } @@ -116,9 +93,7 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { return { isLoading, - isFetching, - isUninitialized, - isError, + error, } } @@ -177,10 +152,8 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { return { isLoading, - isFetching, - isUninitialized, - isError, + error, distributions, } - }, [_meta, asToken0, asToken1, isLoading, isError, isFetching, isUninitialized, latestBlock]) + }, [_meta, asToken0, asToken1, isLoading, error, latestBlock]) } diff --git a/src/hooks/usePoolTickData.ts b/src/hooks/usePoolTickData.ts index 50bc6542d9..3c94090593 100644 --- a/src/hooks/usePoolTickData.ts +++ b/src/hooks/usePoolTickData.ts @@ -1,14 +1,13 @@ -import { skipToken } from '@reduxjs/toolkit/query/react' import { Currency } from '@uniswap/sdk-core' import { FeeAmount, nearestUsableTick, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk' import { useWeb3React } from '@web3-react/core' import { SupportedChainId } from 'constants/chains' import { ZERO_ADDRESS } from 'constants/misc' +import useAllV3TicksQuery, { TickData } from 'graphql/AllV3TicksQuery' import JSBI from 'jsbi' import { useSingleContractMultipleData } from 'lib/hooks/multicall' import ms from 'ms.macro' import { useEffect, useMemo, useState } from 'react' -import { useAllV3TicksQuery } from 'state/data/enhanced' import computeSurroundingTicks from 'utils/computeSurroundingTicks' import { V3_CORE_FACTORY_ADDRESSES } from '../constants/addresses' @@ -18,12 +17,6 @@ import { PoolState, usePool } from './usePools' const PRICE_FIXED_DIGITS = 8 const CHAIN_IDS_MISSING_SUBGRAPH_DATA = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.ARBITRUM_RINKEBY] -export interface TickData { - tick: number - liquidityNet: JSBI - liquidityGross: JSBI -} - // Tick with fields parsed to JSBIs, and active liquidity computed. export interface TickProcessed { tick: number @@ -118,7 +111,6 @@ function useTicksFromTickLens( return { tick: tickData.tick, liquidityNet: JSBI.BigInt(tickData.liquidityNet), - liquidityGross: JSBI.BigInt(tickData.liquidityGross), } }) ?? []), ], @@ -162,9 +154,7 @@ function useTicksFromSubgraph( ) : undefined - return useAllV3TicksQuery(poolAddress ? { poolAddress: poolAddress?.toLowerCase(), skip: 0 } : skipToken, { - pollingInterval: ms`30s`, - }) + return useAllV3TicksQuery(poolAddress, 0, ms`30s`) } // Fetches all ticks for a given pool @@ -174,10 +164,8 @@ function useAllV3Ticks( feeAmount: FeeAmount | undefined ): { isLoading: boolean - isUninitialized: boolean - isError: boolean error: unknown - ticks: TickData[] | undefined + ticks: readonly TickData[] | undefined } { const useSubgraph = currencyA ? !CHAIN_IDS_MISSING_SUBGRAPH_DATA.includes(currencyA.chainId) : true @@ -186,8 +174,6 @@ function useAllV3Ticks( return { isLoading: useSubgraph ? subgraphTickData.isLoading : tickLensTickData.isLoading, - isUninitialized: useSubgraph ? subgraphTickData.isUninitialized : false, - isError: useSubgraph ? subgraphTickData.isError : tickLensTickData.isError, error: useSubgraph ? subgraphTickData.error : tickLensTickData.isError, ticks: useSubgraph ? subgraphTickData.data?.ticks : tickLensTickData.tickData, } @@ -199,8 +185,6 @@ export function usePoolActiveLiquidity( feeAmount: FeeAmount | undefined ): { isLoading: boolean - isUninitialized: boolean - isError: boolean error: any activeTick: number | undefined data: TickProcessed[] | undefined @@ -210,7 +194,7 @@ export function usePoolActiveLiquidity( // 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) + const { isLoading, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount) return useMemo(() => { if ( @@ -220,13 +204,10 @@ export function usePoolActiveLiquidity( pool[0] !== PoolState.EXISTS || !ticks || ticks.length === 0 || - isLoading || - isUninitialized + isLoading ) { return { isLoading: isLoading || pool[0] === PoolState.LOADING, - isUninitialized, - isError, error, activeTick, data: undefined, @@ -246,8 +227,6 @@ export function usePoolActiveLiquidity( console.error('TickData pivot not found') return { isLoading, - isUninitialized, - isError, error, activeTick, data: undefined, @@ -269,11 +248,9 @@ export function usePoolActiveLiquidity( return { isLoading, - isUninitialized, - isError, error, activeTick, data: ticksProcessed, } - }, [currencyA, currencyB, activeTick, pool, ticks, isLoading, isUninitialized, isError, error]) + }, [currencyA, currencyB, activeTick, pool, ticks, isLoading, error]) } diff --git a/src/index.tsx b/src/index.tsx index ebb4990477..0532859c06 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,6 +4,7 @@ import 'polyfills' import 'components/analytics' import { FeatureFlagsProvider } from 'featureFlags' +import RelayEnvironment from 'graphql/RelayEnvironment' import { BlockNumberProvider } from 'lib/hooks/useBlockNumber' import { MulticallUpdater } from 'lib/state/multicall' import { StrictMode } from 'react' @@ -11,6 +12,7 @@ import { createRoot } from 'react-dom/client' import { QueryClient, QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' import { HashRouter } from 'react-router-dom' +import { RelayEnvironmentProvider } from 'relay-hooks' import Blocklist from './components/Blocklist' import Web3Provider from './components/Web3Provider' @@ -56,15 +58,17 @@ createRoot(container).render( - - - - - - - - - + + + + + + + + + + + diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 289ff96a2f..e3e445c43c 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -31,3 +31,7 @@ declare module 'multihashes' { declare module 'd3-curve-circlecorners' { declare function radius(r: number): d3.CurveFactory } + +declare module 'babel-plugin-relay/macro' { + export { graphql as default } from 'react-relay' +} diff --git a/src/state/application/updater.ts b/src/state/application/updater.ts index f961fc914d..7fc2ab7575 100644 --- a/src/state/application/updater.ts +++ b/src/state/application/updater.ts @@ -2,25 +2,11 @@ import { useWeb3React } from '@web3-react/core' import useDebounce from 'hooks/useDebounce' import useIsWindowVisible from 'hooks/useIsWindowVisible' import { useEffect, useState } from 'react' -import { api, CHAIN_TAG } from 'state/data/enhanced' -import { useAppDispatch, useAppSelector } from 'state/hooks' +import { useAppDispatch } from 'state/hooks' import { supportedChainId } from 'utils/supportedChainId' import { updateChainId } from './reducer' -function useQueryCacheInvalidator() { - const dispatch = useAppDispatch() - - // subscribe to `chainId` changes in the redux store rather than Web3 - // this will ensure that when `invalidateTags` is called, the latest - // `chainId` is available in redux to build the subgraph url - const chainId = useAppSelector((state) => state.application.chainId) - - useEffect(() => { - dispatch(api.util.invalidateTags([CHAIN_TAG])) - }, [chainId, dispatch]) -} - export default function Updater(): null { const { chainId, provider } = useWeb3React() const dispatch = useAppDispatch() @@ -28,8 +14,6 @@ export default function Updater(): null { const [activeChainId, setActiveChainId] = useState(chainId) - useQueryCacheInvalidator() - useEffect(() => { if (provider && chainId && windowVisible) { setActiveChainId(chainId) diff --git a/src/state/data/enhanced.ts b/src/state/data/enhanced.ts deleted file mode 100644 index 6d46256185..0000000000 --- a/src/state/data/enhanced.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { api as generatedApi } from './generated' - -// tag that should be applied to queries that need to be invalidated when the chain changes -export const CHAIN_TAG = 'Chain' - -// enhanced api to provide/invalidate tags -export const api = generatedApi.enhanceEndpoints({ - addTagTypes: [CHAIN_TAG], - endpoints: { - allV3Ticks: { - providesTags: [CHAIN_TAG], - }, - feeTierDistribution: { - providesTags: [CHAIN_TAG], - }, - }, -}) - -export const { useAllV3TicksQuery, useFeeTierDistributionQuery } = api diff --git a/src/state/data/slice.ts b/src/state/data/slice.ts deleted file mode 100644 index 03b78c0883..0000000000 --- a/src/state/data/slice.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { BaseQueryFn } from '@reduxjs/toolkit/query' -import { createApi } from '@reduxjs/toolkit/query/react' -import { SupportedChainId } from 'constants/chains' -import { DocumentNode } from 'graphql' -import { ClientError, gql, GraphQLClient } from 'graphql-request' -import { AppState } from 'state' - -// List of supported subgraphs. Note that the app currently only support one active subgraph at a time -const CHAIN_SUBGRAPH_URL: Record = { - [SupportedChainId.MAINNET]: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3', - [SupportedChainId.RINKEBY]: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3', - - [SupportedChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-minimal', - - [SupportedChainId.OPTIMISM]: 'https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis', - - [SupportedChainId.POLYGON]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon', - - [SupportedChainId.CELO]: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo', -} - -export const api = createApi({ - reducerPath: 'dataApi', - baseQuery: graphqlRequestBaseQuery(), - endpoints: (builder) => ({ - allV3Ticks: builder.query({ - query: ({ poolAddress, skip = 0 }) => ({ - document: gql` - query allV3Ticks($poolAddress: String!, $skip: Int!) { - ticks(first: 1000, skip: $skip, where: { poolAddress: $poolAddress }, orderBy: tickIdx) { - tick: tickIdx - liquidityNet - price0 - price1 - } - } - `, - variables: { - poolAddress, - skip, - }, - }), - }), - feeTierDistribution: builder.query({ - query: ({ token0, token1 }) => ({ - document: gql` - query feeTierDistribution($token0: String!, $token1: String!) { - _meta { - block { - number - } - } - asToken0: pools( - orderBy: totalValueLockedToken0 - orderDirection: desc - where: { token0: $token0, token1: $token1 } - ) { - feeTier - totalValueLockedToken0 - totalValueLockedToken1 - } - asToken1: pools( - orderBy: totalValueLockedToken0 - orderDirection: desc - where: { token0: $token1, token1: $token0 } - ) { - feeTier - totalValueLockedToken0 - totalValueLockedToken1 - } - } - `, - variables: { - token0, - token1, - }, - }), - }), - }), -}) - -// Graphql query client wrapper that builds a dynamic url based on chain id -function graphqlRequestBaseQuery(): BaseQueryFn< - { document: string | DocumentNode; variables?: any }, - unknown, - Pick, - Partial> -> { - return async ({ document, variables }, { getState }) => { - try { - const chainId = (getState() as AppState).application.chainId - - const subgraphUrl = chainId ? CHAIN_SUBGRAPH_URL[chainId] : undefined - - if (!subgraphUrl) { - return { - error: { - name: 'UnsupportedChainId', - message: `Subgraph queries against ChainId ${chainId} are not supported.`, - stack: '', - }, - } - } - - return { data: await new GraphQLClient(subgraphUrl).request(document, variables), meta: {} } - } catch (error) { - if (error instanceof ClientError) { - const { name, message, stack, request, response } = error - return { error: { name, message, stack }, meta: { request, response } } - } - throw error - } - } -} diff --git a/src/state/index.ts b/src/state/index.ts index 76c4b7fed4..48f595c5ca 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -8,7 +8,6 @@ import application from './application/reducer' import burn from './burn/reducer' import burnV3 from './burn/v3/reducer' import connection from './connection/reducer' -import { api as dataApi } from './data/slice' import { updateVersion } from './global/actions' import lists from './lists/reducer' import logs from './logs/slice' @@ -37,12 +36,10 @@ const store = configureStore({ multicall: multicall.reducer, lists, logs, - [dataApi.reducerPath]: dataApi.reducer, [routingApi.reducerPath]: routingApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: true }) - .concat(dataApi.middleware) .concat(routingApi.middleware) .concat(save({ states: PERSISTED_KEYS, debounce: 1000 })), preloadedState: load({ states: PERSISTED_KEYS, disableWarnings: isTestEnv() }), diff --git a/src/utils/computeSurroundingTicks.ts b/src/utils/computeSurroundingTicks.ts index 50c653c77c..e51e042b8d 100644 --- a/src/utils/computeSurroundingTicks.ts +++ b/src/utils/computeSurroundingTicks.ts @@ -1,8 +1,10 @@ import { Token } from '@uniswap/sdk-core' import { tickToPrice } from '@uniswap/v3-sdk' -import { TickData, TickProcessed } from 'hooks/usePoolTickData' +import { TickProcessed } from 'hooks/usePoolTickData' import JSBI from 'jsbi' +import { Ticks } from '../graphql/AllV3TicksQuery' + const PRICE_FIXED_DIGITS = 8 // Computes the numSurroundingTicks above or below the active tick. @@ -10,7 +12,7 @@ export default function computeSurroundingTicks( token0: Token, token1: Token, activeTickProcessed: TickProcessed, - sortedTickData: TickData[], + sortedTickData: Ticks, pivot: number, ascending: boolean ): TickProcessed[] { diff --git a/yarn.lock b/yarn.lock index 7ce40cbb27..da5672c198 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2195,16 +2195,26 @@ lodash "~4.17.0" tslib "~2.2.0" -"@graphql-codegen/typescript-operations@^1.18.2": - version "1.18.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-1.18.2.tgz#c1cba14eaf7584a875a63035f97b07fb232bcbae" - integrity sha512-AF9OCNBq0HuW3C5nsO11+53fgFGE40lNUtjSIJocvMcstEKvHx4GrzYO0XIpZsjRPrnyds00Y5xTSynLqB0XxA== +"@graphql-codegen/plugin-helpers@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.6.2.tgz#3c65d89fc9b61914235fc7cb14f1d48492d27944" + integrity sha512-bt5PNix0MwzWP53UdaYm6URrVMWU8RlQhrTSLFjxQ8ShS5zoTlQtpZJGZc5ONqFgKa83qbUmzXUtP8oRVVn8zw== dependencies: - "@graphql-codegen/plugin-helpers" "^1.18.7" - "@graphql-codegen/typescript" "^1.22.3" - "@graphql-codegen/visitor-plugin-common" "1.21.2" - auto-bind "~4.0.0" - tslib "~2.3.0" + "@graphql-tools/utils" "^8.8.0" + change-case-all "1.0.14" + common-tags "1.8.2" + import-from "4.0.0" + lodash "~4.17.0" + tslib "~2.4.0" + +"@graphql-codegen/schema-ast@^2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-2.5.1.tgz#ce030ae6de5dacd745848009ba0ca18c9c30910c" + integrity sha512-tewa5DEKbglWn7kYyVBkh3J8YQ5ALqAMVmZwiVFIGOao5u66nd+e4HuFqp0u+Jpz4SJGGi0ap/oFrEvlqLjd2A== + dependencies: + "@graphql-codegen/plugin-helpers" "^2.6.2" + "@graphql-tools/utils" "^8.8.0" + tslib "~2.4.0" "@graphql-codegen/typescript-rtk-query@^1.1.1": version "1.1.1" @@ -2217,16 +2227,6 @@ change-case-all "1.0.14" tslib "~2.2.0" -"@graphql-codegen/typescript@1.22.3", "@graphql-codegen/typescript@^1.22.3": - version "1.22.3" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-1.22.3.tgz#aaa85246974d74a9f544a950ae1611facabea7e6" - integrity sha512-qLSnVN2g/UxxzhRWHZcHw/Xkvx5wZh0RDzmg9MjAlPnDwAI89jg/ljKDwtTOfN+F6M8W4gQ9mjkWd6NxBQRgXw== - dependencies: - "@graphql-codegen/plugin-helpers" "^1.18.7" - "@graphql-codegen/visitor-plugin-common" "1.21.2" - auto-bind "~4.0.0" - tslib "~2.3.0" - "@graphql-codegen/visitor-plugin-common@1.21.2": version "1.21.2" resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-1.21.2.tgz#c72f1f47bee2ba03ceb48abf14e2cb82d9184b32" @@ -2449,6 +2449,13 @@ camel-case "4.1.2" tslib "~2.2.0" +"@graphql-tools/utils@^8.8.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.9.0.tgz#c6aa5f651c9c99e1aca55510af21b56ec296cdb7" + integrity sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg== + dependencies: + tslib "^2.4.0" + "@graphql-tools/wrap@^7.0.4": version "7.0.8" resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-7.0.8.tgz#ad41e487135ca3ea1ae0ea04bb3f596177fb4f50" @@ -3227,6 +3234,13 @@ redux-thunk "^2.4.1" reselect "^4.1.5" +"@restart/hooks@^0.3.1": + version "0.3.27" + resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.3.27.tgz#91f356d66d4699a8cd8b3d008402708b6a9dc505" + integrity sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw== + dependencies: + dequal "^2.0.2" + "@rollup/plugin-node-resolve@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca" @@ -4108,6 +4122,14 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" +"@types/react-relay@^13.0.2": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@types/react-relay/-/react-relay-13.0.2.tgz#85ac65b13b7a67f8c75fc32dd175160c28d3cc9b" + integrity sha512-QyPV/BVKyv5/3bZKILIJYa2dM1r2HOMYNe6vuFbs/4G1uWj9RCbJiTcWFK2OxH3y70p1k9/A5gPS3lFDm0CvHQ== + dependencies: + "@types/react" "*" + "@types/relay-runtime" "*" + "@types/react-router-dom@^5.3.3": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" @@ -4158,6 +4180,11 @@ "@types/styled-system" "*" "@types/styled-system__css" "*" +"@types/relay-runtime@*": + version "13.0.3" + resolved "https://registry.yarnpkg.com/@types/relay-runtime/-/relay-runtime-13.0.3.tgz#0139a02d24fd527c844af3063e943692fd181854" + integrity sha512-LZr9fiWspAtiFIMDcj/6LarYFqxd3jh3ASXULtWL5Tl5CHoDe48Il2nIAF66XKLLCG3QvDgHR8yLX6ZVWKjkkw== + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -6045,6 +6072,15 @@ babel-plugin-named-asset-import@^0.3.7: resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz#156cd55d3f1228a5765774340937afc8398067dd" integrity sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw== +babel-plugin-relay@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-relay/-/babel-plugin-relay-14.1.0.tgz#97128dd5f53f115c7d377d732c199a53eb48a1a7" + integrity sha512-1FTe0s07fGH/urhuVDWf9IPQd1UYcdvjCPPf5ixJJkK8+3cLAtseJ6dcyk1UnBSEDodRYwWLPhVOaGQIVvj3pw== + dependencies: + babel-plugin-macros "^2.0.0" + cosmiconfig "^5.0.5" + graphql "15.3.0" + "babel-plugin-styled-components@>= 1.12.0": version "1.13.1" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.1.tgz#5ecd28b207627c2a26ef8d5da401e9644065095a" @@ -7363,11 +7399,16 @@ commander@^6.1.0: resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -common-tags@1.8.0, common-tags@^1.8.0: +common-tags@1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz" integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== +common-tags@1.8.2, common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -7579,7 +7620,7 @@ cosmiconfig@7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cosmiconfig@^5.0.0: +cosmiconfig@^5.0.0, cosmiconfig@^5.0.5: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== @@ -7661,7 +7702,7 @@ cross-fetch@3.1.4: dependencies: node-fetch "2.6.1" -cross-fetch@^3.0.4, cross-fetch@^3.0.6, cross-fetch@^3.1.4, cross-fetch@^3.1.5: +cross-fetch@^3.0.6, cross-fetch@^3.1.4, cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -8583,6 +8624,11 @@ dependency-graph@^0.11.0: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== +dequal@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -9938,18 +9984,18 @@ fbjs-css-vars@^1.0.0: resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== -fbjs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" - integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== +fbjs@^3.0.0, fbjs@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" + integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== dependencies: - cross-fetch "^3.0.4" + cross-fetch "^3.1.5" fbjs-css-vars "^1.0.0" loose-envify "^1.0.0" object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" - ua-parser-js "^0.7.18" + ua-parser-js "^0.7.30" fd-slicer@~1.1.0: version "1.1.0" @@ -10630,11 +10676,21 @@ graphql-ws@^4.4.1: resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-4.9.0.tgz#5cfd8bb490b35e86583d8322f5d5d099c26e365c" integrity sha512-sHkK9+lUm20/BGawNEWNtVAeJzhZeBg21VmvmLoT5NdGVeZWv5PdIhkcayQIAgjSyyQ17WMKmbDijIPG2On+Ag== +graphql@15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" + integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w== + graphql@^15.5.0: version "15.5.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5" integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA== +graphql@^16.5.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.5.0.tgz#41b5c1182eaac7f3d47164fb247f61e4dfb69c85" + integrity sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -11106,6 +11162,11 @@ import-from@3.0.0: dependencies: resolve-from "^5.0.0" +import-from@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" + integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== + import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" @@ -15822,6 +15883,17 @@ react-refresh@^0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-relay@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/react-relay/-/react-relay-14.1.0.tgz#2a2349d33ca6558543340a12b363ee2de3db06a6" + integrity sha512-U4oHb5wn1LEi17x3AcZOy66MXs83tnYbsK7/YE1/3cQKCPrXhyVUQbEOC9L7jMX659jtS1NACae+7b03bryMCQ== + dependencies: + "@babel/runtime" "^7.0.0" + fbjs "^3.0.2" + invariant "^2.2.4" + nullthrows "^1.1.1" + relay-runtime "14.1.0" + react-remove-scroll-bar@^2.1.0: version "2.2.0" resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz" @@ -16261,6 +16333,19 @@ relay-compiler@10.1.0: signedsource "^1.0.0" yargs "^15.3.1" +relay-compiler@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/relay-compiler/-/relay-compiler-14.1.0.tgz#88e9c531eb14a6a31e6f14663982124d780bd1b6" + integrity sha512-P8+CXm+Hq96z5NNwYl7hyGo5GgvMZDs9mXBRv7txUbJO4Ql9mXio3+D9EX3VfevRWTuE4ahM37i3Ssx1H604vA== + +relay-hooks@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/relay-hooks/-/relay-hooks-7.1.0.tgz#884ae7d62d03236edc8199d7b63bd38ca12d8959" + integrity sha512-FhpjjjKK24gQ/FXEfpQkHzwmI55LhaDflGc7BbMaBcIJK75ZVKz/TWO1Jws3szQo3v5PMCIxQ43776qwqDk9/Q== + dependencies: + "@restart/hooks" "^0.3.1" + fbjs "^3.0.0" + relay-runtime@10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-10.1.0.tgz#4753bf36e95e8d862cef33608e3d98b4ed730d16" @@ -16269,6 +16354,15 @@ relay-runtime@10.1.0: "@babel/runtime" "^7.0.0" fbjs "^3.0.0" +relay-runtime@14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-14.1.0.tgz#44b317101f560a16caea2eef8a52e254b03908fa" + integrity sha512-t2DR2hZviHrdEQrOvFqwmvRWvZ0SjI/r4bS5f3qvMyXt4g1kw3RTb2RNVmbKGg6zEQhf7Na/brdqE4roApmclQ== + dependencies: + "@babel/runtime" "^7.0.0" + fbjs "^3.0.2" + invariant "^2.2.4" + remark-parse@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz" @@ -18105,10 +18199,10 @@ tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@~2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== tslib@~2.0.1: version "2.0.3" @@ -18125,6 +18219,11 @@ tslib@~2.2.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz" integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsutils@^3.17.1, tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -18254,10 +18353,10 @@ typical@^2.6.0, typical@^2.6.1: resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0= -ua-parser-js@^0.7.18, ua-parser-js@^0.7.28: - version "0.7.28" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" - integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== +ua-parser-js@^0.7.28, ua-parser-js@^0.7.30: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== uint8arrays@^2.1.3: version "2.1.5"