ci(release): publish latest release

parent 3582f6e3
IPFS hash of the deployment: IPFS hash of the deployment:
- CIDv0: `QmNryPgeKysHA94RrWHP8fND99CthjcCSUs93ejSbEMdC8` - CIDv0: `QmPSP5cRUzNoTLLmK32mHARzj3nuNRvytqWsdDetCNMgDM`
- CIDv1: `bafybeiahysggu6xwtpveh7ux7hvrc34exseqwgidnl7lob4eogww3m56au` - CIDv1: `bafybeiaqkn77amn3y4aj3h2sw2epgtsgothkkowwdpm6jxogowhmbxpv3a`
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org). The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
...@@ -10,15 +10,15 @@ You can also access the Uniswap Interface from an IPFS gateway. ...@@ -10,15 +10,15 @@ You can also access the Uniswap Interface from an IPFS gateway.
Your Uniswap settings are never remembered across different URLs. Your Uniswap settings are never remembered across different URLs.
IPFS gateways: IPFS gateways:
- https://bafybeiahysggu6xwtpveh7ux7hvrc34exseqwgidnl7lob4eogww3m56au.ipfs.dweb.link/ - https://bafybeiaqkn77amn3y4aj3h2sw2epgtsgothkkowwdpm6jxogowhmbxpv3a.ipfs.dweb.link/
- https://bafybeiahysggu6xwtpveh7ux7hvrc34exseqwgidnl7lob4eogww3m56au.ipfs.cf-ipfs.com/ - https://bafybeiaqkn77amn3y4aj3h2sw2epgtsgothkkowwdpm6jxogowhmbxpv3a.ipfs.cf-ipfs.com/
- [ipfs://QmNryPgeKysHA94RrWHP8fND99CthjcCSUs93ejSbEMdC8/](ipfs://QmNryPgeKysHA94RrWHP8fND99CthjcCSUs93ejSbEMdC8/) - [ipfs://QmPSP5cRUzNoTLLmK32mHARzj3nuNRvytqWsdDetCNMgDM/](ipfs://QmPSP5cRUzNoTLLmK32mHARzj3nuNRvytqWsdDetCNMgDM/)
### 5.31.1 (2024-06-06) ## 5.32.0 (2024-06-10)
### Bug Fixes ### Features
* **web:** patch wagmi to fix MM bug - prod (#8842) 34c7bc6 * **web:** Remove last of thegraph usage -prod (#8870) 910cb06
web/5.31.1 web/5.32.0
\ No newline at end of file \ No newline at end of file
...@@ -17,7 +17,6 @@ ignores: [ ...@@ -17,7 +17,6 @@ ignores: [
"esbuild-register", "esbuild-register",
## GraphQL ## GraphQL
"@graphql-codegen/*", "@graphql-codegen/*",
"get-graphql-schema",
## React Scripts and subpackages used from within it ## React Scripts and subpackages used from within it
"case-sensitive-paths-webpack-plugin", "case-sensitive-paths-webpack-plugin",
"react-dev-utils", "react-dev-utils",
......
...@@ -15,5 +15,4 @@ REACT_APP_SENTRY_TRACES_SAMPLE_RATE=0.003 ...@@ -15,5 +15,4 @@ REACT_APP_SENTRY_TRACES_SAMPLE_RATE=0.003
REACT_APP_STATSIG_PROXY_URL="https://interface.gateway.uniswap.org/v1/statsig-proxy" REACT_APP_STATSIG_PROXY_URL="https://interface.gateway.uniswap.org/v1/statsig-proxy"
REACT_APP_QUICKNODE_MAINNET_RPC_URL="https://ultra-blue-flower.quiknode.pro/770b22d5f362c537bc8fe19b034c45b22958f880" REACT_APP_QUICKNODE_MAINNET_RPC_URL="https://ultra-blue-flower.quiknode.pro/770b22d5f362c537bc8fe19b034c45b22958f880"
REACT_APP_QUICKNODE_ARBITRUM_RPC_URL="https://tiniest-stylish-arrow.arbitrum-mainnet.quiknode.pro/d06833352b8de605914d9e24a390d8b4d3aff7ba" REACT_APP_QUICKNODE_ARBITRUM_RPC_URL="https://tiniest-stylish-arrow.arbitrum-mainnet.quiknode.pro/d06833352b8de605914d9e24a390d8b4d3aff7ba"
THE_GRAPH_SCHEMA_ENDPOINT="https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap"
REACT_APP_IS_UNISWAP_INTERFACE=true REACT_APP_IS_UNISWAP_INTERFACE=true
overrideExisting: true
schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap'
generates:
./src/graphql/thegraph/schema/schema.graphql:
plugins:
- schema-ast
import { CyHttpMessages } from 'cypress/types/net-stubbing'
import { getTestSelector, resetHardhatChain } from '../utils' import { getTestSelector, resetHardhatChain } from '../utils'
import { aliasQuery, hasQuery } from '../utils/graphql-test-utils'
describe('Add Liquidity', () => { describe('Add Liquidity', () => {
beforeEach(() => {
cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3?source=uniswap', (req) => {
aliasQuery(req, 'feeTierDistribution')
})
})
it('loads the token pair', () => { it('loads the token pair', () => {
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH/500') cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH/500')
cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI') cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI')
...@@ -44,33 +35,11 @@ describe('Add Liquidity', () => { ...@@ -44,33 +35,11 @@ describe('Add Liquidity', () => {
}) })
it('loads fee tier distribution', () => { it('loads fee tier distribution', () => {
cy.fixture('feeTierDistribution.json').then((feeTierDistribution) => { cy.interceptGraphqlOperation('FeeTierDistribution', 'feeTierDistribution.json')
cy.intercept(
'POST',
'/subgraphs/name/uniswap/uniswap-v3?source=uniswap',
(req: CyHttpMessages.IncomingHttpRequest) => {
if (hasQuery(req, 'FeeTierDistribution')) {
req.alias = 'FeeTierDistribution'
req.reply({
body: {
data: {
...feeTierDistribution,
},
},
headers: {
'access-control-allow-origin': '*',
},
})
}
}
)
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH') cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH')
cy.wait('@FeeTierDistribution') cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.30% fee tier')
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.30% fee tier') cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '77% select')
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40% select')
})
}) })
it('disables increment and decrement until initial prices are inputted', () => { it('disables increment and decrement until initial prices are inputted', () => {
......
{ {
"_meta": { "data": {
"block": { "v3PoolsForTokenPair": [
"number": 99999999 {
} "feeTier": 3000.0,
}, "token0Supply": 3084.78636993,
"asToken0": [ "token1Supply": 76658.86823272712,
{ "__typename": "V3Pool"
"feeTier": "100", },
"totalValueLockedToken0": "0", {
"totalValueLockedToken1": "3" "feeTier": 500.0,
}, "token0Supply": 917.54087138,
{ "token1Supply": 22788.333363067817,
"feeTier": "500", "__typename": "V3Pool"
"totalValueLockedToken0": "0", },
"totalValueLockedToken1": "1" {
}, "feeTier": 10000.0,
{ "token0Supply": 14.67505995,
"feeTier": "3000", "token1Supply": 276.9691974507059,
"totalValueLockedToken0": "0", "__typename": "V3Pool"
"totalValueLockedToken1": "4" },
}, {
{ "feeTier": 100.0,
"feeTier": "10000", "token0Supply": 0.04782301,
"totalValueLockedToken0": "0", "token1Supply": 1.677630863841559,
"totalValueLockedToken1": "2" "__typename": "V3Pool"
} }
], ]
"asToken1": [] }
} }
// Utility to match GraphQL mutation based on the query name
export const hasQuery = (req: any, queryName: string) => {
const { body } = req
return Object.prototype.hasOwnProperty.call(body, 'query') && body.query.includes(queryName)
}
// Alias query if queryName matches
export const aliasQuery = (req: any, queryName: string) => {
if (hasQuery(req, queryName)) {
req.alias = `${queryName}Query`
}
}
/* eslint-env node */
import type { CodegenConfig } from '@graphql-codegen/cli'
// Generates TS objects from the schemas returned by graphql queries
// To learn more: https://www.apollographql.com/docs/react/development-testing/static-typing/#setting-up-your-project
const config: CodegenConfig = {
overwrite: true,
schema: './src/graphql/thegraph/schema.graphql',
documents: ['./src/graphql/thegraph/**', '!./src/graphql/thegraph/__generated__/**'],
generates: {
'src/graphql/thegraph/__generated__/types-and-hooks.ts': {
plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
config: {
withHooks: true,
// This avoid all generated schemas being wrapped in Maybe https://the-guild.dev/graphql/codegen/plugins/typescript/typescript#maybevalue-string-default-value-t--null
maybeValue: 'T',
},
},
},
}
// This is used in package.json when generating apollo schemas however the linter stills flags this as unused
// eslint-disable-next-line import/no-unused-modules
export default config
/* eslint-env node */
module.exports = {
src: './src',
language: 'typescript',
schema: './src/graphql/thegraph/schema.graphql',
exclude: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**', '**/data/**'],
}
...@@ -7,10 +7,6 @@ ...@@ -7,10 +7,6 @@
"ajv": "node scripts/compile-ajv-validators.js", "ajv": "node scripts/compile-ajv-validators.js",
"check:deps:usage": "depcheck", "check:deps:usage": "depcheck",
"check:circular": "concurrently \"../../scripts/check-circular-imports.sh ./src/pages/App.tsx 6\" \"../../scripts/check-circular-imports.sh ./src/setupTests.ts 0\"", "check:circular": "concurrently \"../../scripts/check-circular-imports.sh ./src/pages/App.tsx 6\" \"../../scripts/check-circular-imports.sh ./src/setupTests.ts 0\"",
"graphql:schema": "node scripts/fetch-schema.js",
"graphql:generate:thegraph": "graphql-codegen --config graphql.thegraph.codegen.config.ts",
"graphql:generate": "yarn graphql:generate:thegraph",
"graphql": "yarn graphql:schema && yarn graphql:generate",
"sitemap:generate": "node scripts/generate-sitemap.js", "sitemap:generate": "node scripts/generate-sitemap.js",
"i18n:upload": "./scripts/crowdin.sh upload", "i18n:upload": "./scripts/crowdin.sh upload",
"i18n:download": "./scripts/crowdin.sh download", "i18n:download": "./scripts/crowdin.sh download",
...@@ -230,7 +226,6 @@ ...@@ -230,7 +226,6 @@
"fancy-canvas": "2.1.0", "fancy-canvas": "2.1.0",
"focus-visible": "5.2.0", "focus-visible": "5.2.0",
"framer-motion": "10.17.6", "framer-motion": "10.17.6",
"get-graphql-schema": "^2.1.2",
"graphql": "16.6.0", "graphql": "16.6.0",
"i18next": "23.10.0", "i18next": "23.10.0",
"i18next-resources-to-backend": "^1.2.0", "i18next-resources-to-backend": "^1.2.0",
......
...@@ -50,8 +50,6 @@ ...@@ -50,8 +50,6 @@
"https://api.avax.network/ext/bc/C/rpc", "https://api.avax.network/ext/bc/C/rpc",
"https://api.moonpay.com/", "https://api.moonpay.com/",
"https://api.opensea.io", "https://api.opensea.io",
"https://api.studio.thegraph.com/",
"https://api.thegraph.com/",
"https://bsc-dataseed1.binance.org/", "https://bsc-dataseed1.binance.org/",
"https://bsc-dataseed1.bnbchain.org", "https://bsc-dataseed1.bnbchain.org",
"https://buy.moonpay.com/", "https://buy.moonpay.com/",
......
/* eslint-env node */
require('dotenv').config({ path: '.env.production' })
const child_process = require('child_process')
const fs = require('fs/promises')
const { promisify } = require('util')
const thegraphConfig = require('../graphql.thegraph.config')
const exec = promisify(child_process.exec)
function fetchSchema(url, outputFile) {
exec(`npx --silent get-graphql-schema -h Origin=https://app.uniswap.org ${url}`)
.then(({ stderr, stdout }) => {
if (stderr) {
throw new Error(stderr)
} else {
fs.writeFile(outputFile, stdout)
}
})
.catch((err) => {
console.error(err)
console.error(`Failed to fetch schema from ${url}`)
})
}
fetchSchema(process.env.THE_GRAPH_SCHEMA_ENDPOINT, thegraphConfig.schema)
...@@ -22,7 +22,7 @@ export const useMenuContent = (): MenuSection[] => { ...@@ -22,7 +22,7 @@ export const useMenuContent = (): MenuSection[] => {
items: [ items: [
{ label: t('Pool'), href: '/pool', internal: true, overflow: true }, { label: t('Pool'), href: '/pool', internal: true, overflow: true },
{ label: t('Vote'), href: 'https://vote.uniswapfoundation.org/' }, { label: t('Vote'), href: 'https://vote.uniswapfoundation.org/' },
{ label: t('Analytics'), href: 'https://info.uniswap.org/' }, { label: t('Analytics'), href: '/explore', internal: true },
], ],
}, },
{ {
......
...@@ -11,8 +11,7 @@ import { ...@@ -11,8 +11,7 @@ import {
PoolTableTransactionType, PoolTableTransactionType,
usePoolTransactions, usePoolTransactions,
} from 'graphql/data/pools/usePoolTransactions' } from 'graphql/data/pools/usePoolTransactions'
import { getSupportedGraphQlChain, supportedChainIdFromGQLChain } from 'graphql/data/util' import { OrderDirection, getSupportedGraphQlChain, supportedChainIdFromGQLChain } from 'graphql/data/util'
import { OrderDirection, Transaction_OrderBy } from 'graphql/thegraph/__generated__/types-and-hooks'
import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency' import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
import { Trans } from 'i18n' import { Trans } from 'i18n'
import { useMemo, useReducer, useState } from 'react' import { useMemo, useReducer, useState } from 'react'
...@@ -32,11 +31,6 @@ const TableWrapper = styled.div` ...@@ -32,11 +31,6 @@ const TableWrapper = styled.div`
min-height: 256px; min-height: 256px;
` `
type PoolTxTableSortState = {
sortBy: Transaction_OrderBy
sortDirection: OrderDirection
}
enum PoolTransactionColumn { enum PoolTransactionColumn {
Timestamp, Timestamp,
Type, Type,
...@@ -85,10 +79,6 @@ export function PoolDetailsTransactionsTable({ ...@@ -85,10 +79,6 @@ export function PoolDetailsTransactionsTable({
PoolTableTransactionType.MINT, PoolTableTransactionType.MINT,
]) ])
const [sortState] = useState<PoolTxTableSortState>({
sortBy: Transaction_OrderBy.Timestamp,
sortDirection: OrderDirection.Desc,
})
const { transactions, loading, loadMore, error } = usePoolTransactions( const { transactions, loading, loadMore, error } = usePoolTransactions(
poolAddress, poolAddress,
chain.id, chain.id,
...@@ -106,8 +96,8 @@ export function PoolDetailsTransactionsTable({ ...@@ -106,8 +96,8 @@ export function PoolDetailsTransactionsTable({
header: () => ( header: () => (
<Cell minWidth={PoolTransactionColumnWidth[PoolTransactionColumn.Timestamp]} justifyContent="flex-start"> <Cell minWidth={PoolTransactionColumnWidth[PoolTransactionColumn.Timestamp]} justifyContent="flex-start">
<Row gap="4px"> <Row gap="4px">
{sortState.sortBy === Transaction_OrderBy.Timestamp && <HeaderArrow direction={OrderDirection.Desc} />} <HeaderArrow direction={OrderDirection.Desc} />
<HeaderSortText $active={sortState.sortBy === Transaction_OrderBy.Timestamp}> <HeaderSortText $active>
<Trans i18nKey="common.time" /> <Trans i18nKey="common.time" />
</HeaderSortText> </HeaderSortText>
</Row> </Row>
...@@ -288,7 +278,6 @@ export function PoolDetailsTransactionsTable({ ...@@ -288,7 +278,6 @@ export function PoolDetailsTransactionsTable({
formatFiatPrice, formatFiatPrice,
formatNumber, formatNumber,
showLoadingSkeleton, showLoadingSkeleton,
sortState.sortBy,
token0, token0,
token1?.symbol, token1?.symbol,
]) ])
......
...@@ -71,10 +71,6 @@ const EXTERNAL_APIS = [ ...@@ -71,10 +71,6 @@ const EXTERNAL_APIS = [
name: 'Google Analytics & Amplitude', name: 'Google Analytics & Amplitude',
description: <Trans i18nKey="privacy.anonymizedLogs" />, description: <Trans i18nKey="privacy.anonymizedLogs" />,
}, },
{
name: 'The Graph',
description: <Trans i18nKey="privacy.theGraph" />,
},
] ]
export function PrivacyPolicyModal() { export function PrivacyPolicyModal() {
......
...@@ -8,7 +8,6 @@ import { useAbbreviatedTimeString } from 'components/Table/utils' ...@@ -8,7 +8,6 @@ import { useAbbreviatedTimeString } from 'components/Table/utils'
import { MouseoverTooltip, TooltipSize } from 'components/Tooltip' import { MouseoverTooltip, TooltipSize } from 'components/Tooltip'
import { NATIVE_CHAIN_ID } from 'constants/tokens' import { NATIVE_CHAIN_ID } from 'constants/tokens'
import { OrderDirection, getTokenDetailsURL, supportedChainIdFromGQLChain, unwrapToken } from 'graphql/data/util' import { OrderDirection, getTokenDetailsURL, supportedChainIdFromGQLChain, unwrapToken } from 'graphql/data/util'
import { OrderDirection as TheGraphOrderDirection } from 'graphql/thegraph/__generated__/types-and-hooks'
import { useCurrency } from 'hooks/Tokens' import { useCurrency } from 'hooks/Tokens'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
import { Trans } from 'i18n' import { Trans } from 'i18n'
...@@ -164,7 +163,7 @@ export const ClickableHeaderRow = styled(Row)<{ $justify?: string }>` ...@@ -164,7 +163,7 @@ export const ClickableHeaderRow = styled(Row)<{ $justify?: string }>`
gap: 4px; gap: 4px;
${ClickableStyle} ${ClickableStyle}
` `
export const HeaderArrow = styled(ArrowDown)<{ direction: OrderDirection | TheGraphOrderDirection }>` export const HeaderArrow = styled(ArrowDown)<{ direction: OrderDirection }>`
height: 16px; height: 16px;
width: 16px; width: 16px;
color: ${({ theme }) => theme.neutral1}; color: ${({ theme }) => theme.neutral1};
......
...@@ -6,7 +6,7 @@ import { TokenDetailsPoolsTable } from 'components/Tokens/TokenDetails/tables/To ...@@ -6,7 +6,7 @@ import { TokenDetailsPoolsTable } from 'components/Tokens/TokenDetails/tables/To
import { usePoolsFromTokenAddress } from 'graphql/data/pools/usePoolsFromTokenAddress' import { usePoolsFromTokenAddress } from 'graphql/data/pools/usePoolsFromTokenAddress'
import Router from 'react-router-dom' import Router from 'react-router-dom'
import { mocked } from 'test-utils/mocked' import { mocked } from 'test-utils/mocked'
import { validBEPoolToken0, validBEPoolToken1, validParams, validPoolToken0 } from 'test-utils/pools/fixtures' import { validBEPoolToken0, validBEPoolToken1, validParams } from 'test-utils/pools/fixtures'
import { render, screen } from 'test-utils/render' import { render, screen } from 'test-utils/render'
import { ProtocolVersion } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { ProtocolVersion } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
...@@ -16,7 +16,7 @@ jest.mock('react-router-dom', () => ({ ...@@ -16,7 +16,7 @@ jest.mock('react-router-dom', () => ({
useParams: jest.fn(), useParams: jest.fn(),
})) }))
const mockToken = new Token(ChainId.MAINNET, validPoolToken0.id, 18) const mockToken = new Token(ChainId.MAINNET, validBEPoolToken0.id, 18)
describe('TDPPoolTable', () => { describe('TDPPoolTable', () => {
beforeEach(() => { beforeEach(() => {
...@@ -75,7 +75,7 @@ describe('TDPPoolTable', () => { ...@@ -75,7 +75,7 @@ describe('TDPPoolTable', () => {
}) })
const { asFragment } = render(<TokenDetailsPoolsTable chainId={ChainId.MAINNET} referenceToken={mockToken} />) const { asFragment } = render(<TokenDetailsPoolsTable chainId={ChainId.MAINNET} referenceToken={mockToken} />)
expect(screen.getByTestId(`tdp-pools-table-${validPoolToken0.id}`)).not.toBeNull() expect(screen.getByTestId(`tdp-pools-table-${validBEPoolToken0.id}`)).not.toBeNull()
expect(asFragment()).toMatchSnapshot() expect(asFragment()).toMatchSnapshot()
}) })
}) })
...@@ -16,8 +16,7 @@ import { ...@@ -16,8 +16,7 @@ import {
import { SupportedInterfaceChainId } from 'constants/chains' import { SupportedInterfaceChainId } from 'constants/chains'
import { useUpdateManualOutage } from 'featureFlags/flags/outageBanner' import { useUpdateManualOutage } from 'featureFlags/flags/outageBanner'
import { TokenTransactionType, useTokenTransactions } from 'graphql/data/useTokenTransactions' import { TokenTransactionType, useTokenTransactions } from 'graphql/data/useTokenTransactions'
import { unwrapToken } from 'graphql/data/util' import { OrderDirection, unwrapToken } from 'graphql/data/util'
import { OrderDirection, Swap_OrderBy } from 'graphql/thegraph/__generated__/types-and-hooks'
import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency' import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
import { Trans } from 'i18n' import { Trans } from 'i18n'
import { useMemo, useReducer, useState } from 'react' import { useMemo, useReducer, useState } from 'react'
...@@ -53,11 +52,6 @@ interface SwapLeg { ...@@ -53,11 +52,6 @@ interface SwapLeg {
token: GQLToken token: GQLToken
} }
type TokenTxTableSortState = {
sortBy: Swap_OrderBy
sortDirection: OrderDirection
}
export function TransactionsTable({ export function TransactionsTable({
chainId, chainId,
referenceToken, referenceToken,
...@@ -69,10 +63,6 @@ export function TransactionsTable({ ...@@ -69,10 +63,6 @@ export function TransactionsTable({
const { formatNumber, formatFiatPrice } = useFormatter() const { formatNumber, formatFiatPrice } = useFormatter()
const [filterModalIsOpen, toggleFilterModal] = useReducer((s) => !s, false) const [filterModalIsOpen, toggleFilterModal] = useReducer((s) => !s, false)
const [filter, setFilters] = useState<TokenTransactionType[]>([TokenTransactionType.BUY, TokenTransactionType.SELL]) const [filter, setFilters] = useState<TokenTransactionType[]>([TokenTransactionType.BUY, TokenTransactionType.SELL])
const [sortState] = useState<TokenTxTableSortState>({
sortBy: Swap_OrderBy.Timestamp,
sortDirection: OrderDirection.Desc,
})
const { transactions, loading, loadMore, errorV2, errorV3 } = useTokenTransactions( const { transactions, loading, loadMore, errorV2, errorV3 } = useTokenTransactions(
referenceToken.address, referenceToken.address,
chainId, chainId,
...@@ -126,8 +116,8 @@ export function TransactionsTable({ ...@@ -126,8 +116,8 @@ export function TransactionsTable({
header: () => ( header: () => (
<Cell minWidth={120} justifyContent="flex-start" grow> <Cell minWidth={120} justifyContent="flex-start" grow>
<Row gap="xs"> <Row gap="xs">
{sortState.sortBy === Swap_OrderBy.Timestamp && <HeaderArrow direction={sortState.sortDirection} />} <HeaderArrow direction={OrderDirection.Desc} />
<HeaderSortText $active={sortState.sortBy === Swap_OrderBy.Timestamp}> <HeaderSortText $active>
<Trans i18nKey="common.time" /> <Trans i18nKey="common.time" />
</HeaderSortText> </HeaderSortText>
</Row> </Row>
...@@ -230,10 +220,7 @@ export function TransactionsTable({ ...@@ -230,10 +220,7 @@ export function TransactionsTable({
header: () => ( header: () => (
<Cell minWidth={125} justifyContent="flex-end"> <Cell minWidth={125} justifyContent="flex-end">
<Row gap="xs" justify="flex-end"> <Row gap="xs" justify="flex-end">
{sortState.sortBy === Swap_OrderBy.AmountUsd && <HeaderArrow direction={sortState.sortDirection} />} <HeaderSortText>{activeLocalCurrency}</HeaderSortText>
<HeaderSortText $active={sortState.sortBy === Swap_OrderBy.AmountUsd}>
{activeLocalCurrency}
</HeaderSortText>
</Row> </Row>
</Cell> </Cell>
), ),
...@@ -262,8 +249,6 @@ export function TransactionsTable({ ...@@ -262,8 +249,6 @@ export function TransactionsTable({
}), }),
] ]
}, [ }, [
sortState.sortBy,
sortState.sortDirection,
showLoadingSkeleton, showLoadingSkeleton,
chainId, chainId,
filterModalIsOpen, filterModalIsOpen,
......
...@@ -972,12 +972,6 @@ export const INFURA_PREFIX_TO_CHAIN_ID: { [prefix: string]: SupportedInterfaceCh ...@@ -972,12 +972,6 @@ export const INFURA_PREFIX_TO_CHAIN_ID: { [prefix: string]: SupportedInterfaceCh
.map(([key, value]) => [value.infuraPrefix, parseInt(key) as SupportedInterfaceChainId]) .map(([key, value]) => [value.infuraPrefix, parseInt(key) as SupportedInterfaceChainId])
) )
export const CHAIN_SUBGRAPH_URL = Object.fromEntries(
Object.entries(CHAIN_INFO)
.filter(([, value]) => !!value.subgraphUrl)
.map(([key, value]) => [parseInt(key) as SupportedInterfaceChainId, value.subgraphUrl])
) as Record<SupportedInterfaceChainId, string>
/** /**
* Get the priority of a chainId based on its relevance to the user. * Get the priority of a chainId based on its relevance to the user.
* @param {ChainId} chainId - The chainId to determine the priority for. * @param {ChainId} chainId - The chainId to determine the priority for.
......
import { AllV3TicksQuery } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
export type Ticks = NonNullable<NonNullable<AllV3TicksQuery['v3Pool']>['ticks']>
export type TickData = Ticks[number]
import { AllV3TicksQuery } from './__generated__/types-and-hooks'
export type Ticks = AllV3TicksQuery['ticks']
export type TickData = Ticks[number]
import { ApolloError, useQuery } from '@apollo/client'
import { useMemo } from 'react'
import { FeeTierDistributionDocument, FeeTierDistributionQuery } from './__generated__/types-and-hooks'
import { apolloClient } from './apollo'
export default function useFeeTierDistributionQuery(
token0: string | undefined,
token1: string | undefined,
interval: number
): { error?: ApolloError; isLoading: boolean; data: FeeTierDistributionQuery } {
const {
data,
loading: isLoading,
error,
} = useQuery(FeeTierDistributionDocument, {
variables: {
token0: token0?.toLowerCase(),
token1: token1?.toLowerCase(),
},
pollInterval: interval,
client: apolloClient,
})
return useMemo(
() => ({
error,
isLoading,
data,
}),
[data, error, isLoading]
)
}
import { ApolloClient, ApolloLink, concat, HttpLink, InMemoryCache, NormalizedCacheObject } from '@apollo/client'
import { ChainId } from '@uniswap/sdk-core'
import { CHAIN_SUBGRAPH_URL, isSupportedChainId } from 'constants/chains'
import store from '../../state/index'
const httpLink = new HttpLink({ uri: CHAIN_SUBGRAPH_URL[ChainId.MAINNET] })
// This middleware will allow us to dynamically update the uri for the requests based off chainId
// For more information: https://www.apollographql.com/docs/react/networking/advanced-http-networking/
const authMiddleware = new ApolloLink((operation, forward) => {
// add the authorization to the headers
const chainId = store.getState().application.chainId
operation.setContext(() => ({
uri:
isSupportedChainId(chainId) && CHAIN_SUBGRAPH_URL[chainId]
? CHAIN_SUBGRAPH_URL[chainId]
: CHAIN_SUBGRAPH_URL[ChainId.MAINNET],
}))
return forward(operation)
})
export const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: concat(authMiddleware, httpLink),
})
export const chainToApolloClient: Record<number, ApolloClient<NormalizedCacheObject>> = Object.fromEntries(
Object.entries(CHAIN_SUBGRAPH_URL).map(([chainId, url]) => [
chainId,
new ApolloClient({
cache: new InMemoryCache(),
uri: url,
}),
])
)
query AllV3Ticks($poolAddress: String, $skip: Int!) {
ticks(
first: 1000
skip: $skip
where: { poolAddress: $poolAddress }
orderBy: tickIdx
) {
tick: tickIdx
liquidityNet
price0
price1
}
}
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
}
}
This diff is collapsed.
import { Currency, Token } from '@uniswap/sdk-core' import { Currency, Token } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk' import { FeeAmount } from '@uniswap/v3-sdk'
import useBlockNumber from 'lib/hooks/useBlockNumber' import { chainIdToBackendChain } from 'constants/chains'
import ms from 'ms' import ms from 'ms'
import { useMemo } from 'react' import { useMemo } from 'react'
import {
import useFeeTierDistributionQuery from '../graphql/thegraph/FeeTierDistributionQuery' useFeeTierDistributionQuery,
useIsV3SubgraphStaleQuery,
} from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import { logger } from 'utilities/src/logger/logger'
import { PoolState, usePool } from './usePools' import { PoolState, usePool } from './usePools'
// maximum number of blocks past which we consider the data stale
const MAX_DATA_BLOCK_AGE = 20
interface FeeTierDistribution { interface FeeTierDistribution {
isLoading: boolean isLoading: boolean
isError: boolean isError: boolean
...@@ -74,34 +74,47 @@ export function useFeeTierDistribution( ...@@ -74,34 +74,47 @@ export function useFeeTierDistribution(
} }
function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { function usePoolTVL(token0: Token | undefined, token1: Token | undefined) {
const latestBlock = useBlockNumber() const chain = chainIdToBackendChain({ chainId: token0?.chainId, withFallback: true })
const { isLoading, error, data } = useFeeTierDistributionQuery(token0?.address, token1?.address, ms(`30s`)) const { loading, error, data } = useFeeTierDistributionQuery({
variables: {
const { asToken0, asToken1, _meta } = data ?? {} chain,
token0: token0?.address ?? '',
token1: token1?.address ?? '',
},
pollInterval: ms(`30s`),
})
const { data: isSubgraphStaleData, error: isSubgraphStaleError } = useIsV3SubgraphStaleQuery({
variables: { chain },
pollInterval: ms(`30s`),
})
const { v3PoolsForTokenPair } = data ?? {}
return useMemo(() => { return useMemo(() => {
if (!latestBlock || !_meta || !asToken0 || !asToken1) { if (isSubgraphStaleError || !v3PoolsForTokenPair) {
return { return {
isLoading, isLoading: loading,
error, error: error ?? isSubgraphStaleError,
} }
} }
if (latestBlock - (_meta?.block?.number ?? 0) > MAX_DATA_BLOCK_AGE) { if (isSubgraphStaleData?.isV3SubgraphStale) {
console.log(`Graph stale (latest block: ${latestBlock})`) logger.info('useFeeTierDistribution', 'usePoolTVL', `Subgraph stale`)
return { return {
isLoading, isLoading: loading,
error, error,
} }
} }
const all = asToken0.concat(asToken1)
// sum tvl for token0 and token1 by fee tier // sum tvl for token0 and token1 by fee tier
const tvlByFeeTier = all.reduce<{ [feeAmount: number]: [number | undefined, number | undefined] }>( const tvlByFeeTier = v3PoolsForTokenPair.reduce<{ [feeAmount: number]: [number | undefined, number | undefined] }>(
(acc, value) => { (acc, value) => {
acc[value.feeTier][0] = (acc[value.feeTier][0] ?? 0) + Number(value.totalValueLockedToken0) if (!value.feeTier) {
acc[value.feeTier][1] = (acc[value.feeTier][1] ?? 0) + Number(value.totalValueLockedToken1) return acc
}
acc[value.feeTier][0] = (acc[value.feeTier][0] ?? 0) + Number(value.token0Supply)
acc[value.feeTier][1] = (acc[value.feeTier][1] ?? 0) + Number(value.token1Supply)
return acc return acc
}, },
{ {
...@@ -149,9 +162,9 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) { ...@@ -149,9 +162,9 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) {
} }
return { return {
isLoading, isLoading: loading,
error, error,
distributions, distributions,
} }
}, [_meta, asToken0, asToken1, isLoading, error, latestBlock]) }, [isSubgraphStaleError, v3PoolsForTokenPair, isSubgraphStaleData?.isV3SubgraphStale, loading, error])
} }
import { ChainId, Currency, Price, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core' import { ChainId, Currency, Price, Token, V3_CORE_FACTORY_ADDRESSES } from '@uniswap/sdk-core'
import { FeeAmount, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk' import { FeeAmount, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { chainIdToBackendChain, useSupportedChainId } from 'constants/chains'
import { TickData, Ticks } from 'graphql/thegraph/AllV3TicksQuery' import { TickData, Ticks } from 'graphql/data/AllV3TicksQuery'
import { useAllV3TicksQuery } from 'graphql/thegraph/__generated__/types-and-hooks' import { useAccount } from 'hooks/useAccount'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import ms from 'ms' import ms from 'ms'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { useAllV3TicksQuery } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import computeSurroundingTicks from 'utils/computeSurroundingTicks' import computeSurroundingTicks from 'utils/computeSurroundingTicks'
import { chainToApolloClient } from 'graphql/thegraph/apollo'
import { PoolState, usePoolMultichain } from './usePools' import { PoolState, usePoolMultichain } from './usePools'
const PRICE_FIXED_DIGITS = 8 const PRICE_FIXED_DIGITS = 8
...@@ -25,6 +25,7 @@ export interface TickProcessed { ...@@ -25,6 +25,7 @@ export interface TickProcessed {
const getActiveTick = (tickCurrent: number | undefined, feeAmount: FeeAmount | undefined) => const getActiveTick = (tickCurrent: number | undefined, feeAmount: FeeAmount | undefined) =>
tickCurrent && feeAmount ? Math.floor(tickCurrent / TICK_SPACINGS[feeAmount]) * TICK_SPACINGS[feeAmount] : undefined tickCurrent && feeAmount ? Math.floor(tickCurrent / TICK_SPACINGS[feeAmount]) * TICK_SPACINGS[feeAmount] : undefined
const MAX_TICK_FETCH_VALUE = 1000
function useTicksFromSubgraph( function useTicksFromSubgraph(
currencyA: Currency | undefined, currencyA: Currency | undefined,
currencyB: Currency | undefined, currencyB: Currency | undefined,
...@@ -32,7 +33,6 @@ function useTicksFromSubgraph( ...@@ -32,7 +33,6 @@ function useTicksFromSubgraph(
skip = 0, skip = 0,
chainId: ChainId chainId: ChainId
) { ) {
const apolloClient = chainToApolloClient[chainId]
const poolAddress = const poolAddress =
currencyA && currencyB && feeAmount currencyA && currencyB && feeAmount
? Pool.getAddress( ? Pool.getAddress(
...@@ -43,16 +43,20 @@ function useTicksFromSubgraph( ...@@ -43,16 +43,20 @@ function useTicksFromSubgraph(
chainId ? V3_CORE_FACTORY_ADDRESSES[chainId] : undefined chainId ? V3_CORE_FACTORY_ADDRESSES[chainId] : undefined
) )
: undefined : undefined
const supportedChainId = useSupportedChainId(chainId)
return useAllV3TicksQuery({ return useAllV3TicksQuery({
variables: { poolAddress: poolAddress?.toLowerCase(), skip }, variables: {
address: poolAddress?.toLowerCase() ?? '',
chain: chainIdToBackendChain({ chainId: supportedChainId, withFallback: true }),
skip,
first: MAX_TICK_FETCH_VALUE,
},
skip: !poolAddress, skip: !poolAddress,
pollInterval: ms(`30s`), pollInterval: ms(`30s`),
client: apolloClient,
}) })
} }
const MAX_THE_GRAPH_TICK_FETCH_VALUE = 1000
// Fetches all ticks for a given pool // Fetches all ticks for a given pool
function useAllV3Ticks( function useAllV3Ticks(
currencyA: Currency | undefined, currencyA: Currency | undefined,
...@@ -67,18 +71,19 @@ function useAllV3Ticks( ...@@ -67,18 +71,19 @@ function useAllV3Ticks(
const [skipNumber, setSkipNumber] = useState(0) const [skipNumber, setSkipNumber] = useState(0)
const [subgraphTickData, setSubgraphTickData] = useState<Ticks>([]) const [subgraphTickData, setSubgraphTickData] = useState<Ticks>([])
const { data, error, loading: isLoading } = useTicksFromSubgraph(currencyA, currencyB, feeAmount, skipNumber, chainId) const { data, error, loading: isLoading } = useTicksFromSubgraph(currencyA, currencyB, feeAmount, skipNumber, chainId)
const ticks: Ticks = data?.v3Pool?.ticks as Ticks
useEffect(() => { useEffect(() => {
if (data?.ticks.length) { if (ticks?.length) {
setSubgraphTickData((tickData) => [...tickData, ...data.ticks]) setSubgraphTickData((tickData) => [...tickData, ...ticks])
if (data.ticks.length === MAX_THE_GRAPH_TICK_FETCH_VALUE) { if (ticks?.length === MAX_TICK_FETCH_VALUE) {
setSkipNumber((skipNumber) => skipNumber + MAX_THE_GRAPH_TICK_FETCH_VALUE) setSkipNumber((skipNumber) => skipNumber + MAX_TICK_FETCH_VALUE)
} }
} }
}, [data?.ticks]) }, [ticks])
return { return {
isLoading: isLoading || data?.ticks.length === MAX_THE_GRAPH_TICK_FETCH_VALUE, isLoading: isLoading || ticks?.length === MAX_TICK_FETCH_VALUE,
error, error,
ticks: subgraphTickData, ticks: subgraphTickData,
} }
...@@ -98,7 +103,7 @@ export function usePoolActiveLiquidity( ...@@ -98,7 +103,7 @@ export function usePoolActiveLiquidity(
sqrtPriceX96?: JSBI sqrtPriceX96?: JSBI
data?: TickProcessed[] data?: TickProcessed[]
} { } {
const defaultChainId = useWeb3React().chainId ?? ChainId.MAINNET const defaultChainId = useAccount().chainId ?? ChainId.MAINNET
const pool = usePoolMultichain(currencyA?.wrapped, currencyB?.wrapped, feeAmount, chainId ?? defaultChainId) const pool = usePoolMultichain(currencyA?.wrapped, currencyB?.wrapped, feeAmount, chainId ?? defaultChainId)
const liquidity = pool[1]?.liquidity const liquidity = pool[1]?.liquidity
const sqrtPriceX96 = pool[1]?.sqrtRatioX96 const sqrtPriceX96 = pool[1]?.sqrtRatioX96
...@@ -133,7 +138,7 @@ export function usePoolActiveLiquidity( ...@@ -133,7 +138,7 @@ export function usePoolActiveLiquidity(
// find where the active tick would be to partition the array // find where the active tick would be to partition the array
// if the active tick is initialized, the pivot will be an element // if the active tick is initialized, the pivot will be an element
// if not, take the previous tick as pivot // if not, take the previous tick as pivot
const pivot = ticks.findIndex(({ tick }) => tick > activeTick) - 1 const pivot = ticks.findIndex((tickData) => tickData?.tick && tickData.tick > activeTick) - 1
if (pivot < 0) { if (pivot < 0) {
// consider setting a local error // consider setting a local error
...@@ -150,7 +155,8 @@ export function usePoolActiveLiquidity( ...@@ -150,7 +155,8 @@ export function usePoolActiveLiquidity(
const activeTickProcessed: TickProcessed = { const activeTickProcessed: TickProcessed = {
liquidityActive: JSBI.BigInt(pool[1]?.liquidity ?? 0), liquidityActive: JSBI.BigInt(pool[1]?.liquidity ?? 0),
tick: activeTick, tick: activeTick,
liquidityNet: Number(ticks[pivot].tick) === activeTick ? JSBI.BigInt(ticks[pivot].liquidityNet) : JSBI.BigInt(0), liquidityNet:
Number(ticks[pivot]?.tick) === activeTick ? JSBI.BigInt(ticks[pivot]?.liquidityNet ?? 0) : JSBI.BigInt(0),
price0: sdkPrice.toFixed(PRICE_FIXED_DIGITS), price0: sdkPrice.toFixed(PRICE_FIXED_DIGITS),
sdkPrice, sdkPrice,
} }
......
...@@ -798,7 +798,6 @@ ...@@ -798,7 +798,6 @@
"privacy.anonymizedLogs": "The app logs anonymized usage statistics in order to improve over time.", "privacy.anonymizedLogs": "The app logs anonymized usage statistics in order to improve over time.",
"privacy.autoRouter": "The app fetches the optimal trade route from a Uniswap Labs server.", "privacy.autoRouter": "The app fetches the optimal trade route from a Uniswap Labs server.",
"privacy.infura": "The app fetches on-chain data and constructs contract calls with an Infura API.", "privacy.infura": "The app fetches on-chain data and constructs contract calls with an Infura API.",
"privacy.theGraph": "The app fetches blockchain data from The Graph’s hosted service.",
"privacy.thirdPartyApis": "This app uses the following third-party APIs:", "privacy.thirdPartyApis": "This app uses the following third-party APIs:",
"privacy.trm": "The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.", "privacy.trm": "The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.",
"privacy.uniswaptos": "Uniswap Labs’ Terms of Service", "privacy.uniswaptos": "Uniswap Labs’ Terms of Service",
......
...@@ -15,8 +15,7 @@ import { ...@@ -15,8 +15,7 @@ import {
import { useChainFromUrlParam } from 'constants/chains' import { useChainFromUrlParam } from 'constants/chains'
import { useUpdateManualOutage } from 'featureFlags/flags/outageBanner' import { useUpdateManualOutage } from 'featureFlags/flags/outageBanner'
import { BETypeToTransactionType, TransactionType, useAllTransactions } from 'graphql/data/useAllTransactions' import { BETypeToTransactionType, TransactionType, useAllTransactions } from 'graphql/data/useAllTransactions'
import { getSupportedGraphQlChain } from 'graphql/data/util' import { OrderDirection, getSupportedGraphQlChain } from 'graphql/data/util'
import { OrderDirection, Transaction_OrderBy } from 'graphql/thegraph/__generated__/types-and-hooks'
import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency' import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
import { Trans } from 'i18n' import { Trans } from 'i18n'
import { useMemo, useReducer, useState } from 'react' import { useMemo, useReducer, useState } from 'react'
...@@ -29,11 +28,6 @@ import { shortenAddress } from 'utilities/src/addresses' ...@@ -29,11 +28,6 @@ import { shortenAddress } from 'utilities/src/addresses'
import { useFormatter } from 'utils/formatNumbers' import { useFormatter } from 'utils/formatNumbers'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
type ExploreTxTableSortState = {
sortBy: Transaction_OrderBy
sortDirection: OrderDirection
}
export default function RecentTransactions() { export default function RecentTransactions() {
const activeLocalCurrency = useActiveLocalCurrency() const activeLocalCurrency = useActiveLocalCurrency()
const { formatNumber, formatFiatPrice } = useFormatter() const { formatNumber, formatFiatPrice } = useFormatter()
...@@ -45,10 +39,6 @@ export default function RecentTransactions() { ...@@ -45,10 +39,6 @@ export default function RecentTransactions() {
]) ])
const chain = getSupportedGraphQlChain(useChainFromUrlParam(), { fallbackToEthereum: true }) const chain = getSupportedGraphQlChain(useChainFromUrlParam(), { fallbackToEthereum: true })
const [sortState] = useState<ExploreTxTableSortState>({
sortBy: Transaction_OrderBy.Timestamp,
sortDirection: OrderDirection.Desc,
})
const { transactions, loading, loadMore, errorV2, errorV3 } = useAllTransactions(chain.backendChain.chain, filter) const { transactions, loading, loadMore, errorV2, errorV3 } = useAllTransactions(chain.backendChain.chain, filter)
const combinedError = const combinedError =
errorV2 && errorV3 errorV2 && errorV3
...@@ -66,10 +56,8 @@ export default function RecentTransactions() { ...@@ -66,10 +56,8 @@ export default function RecentTransactions() {
header: () => ( header: () => (
<Cell minWidth={120} justifyContent="flex-start" grow> <Cell minWidth={120} justifyContent="flex-start" grow>
<Row gap="4px"> <Row gap="4px">
{sortState.sortBy === Transaction_OrderBy.Timestamp && ( <HeaderArrow direction={OrderDirection.Desc} />
<HeaderArrow direction={sortState.sortDirection} /> <HeaderSortText $active>
)}
<HeaderSortText $active={sortState.sortBy === Transaction_OrderBy.Timestamp}>
<Trans i18nKey="common.time" /> <Trans i18nKey="common.time" />
</HeaderSortText> </HeaderSortText>
</Row> </Row>
...@@ -197,17 +185,7 @@ export default function RecentTransactions() { ...@@ -197,17 +185,7 @@ export default function RecentTransactions() {
), ),
}), }),
] ]
}, [ }, [activeLocalCurrency, chain.id, filter, filterModalIsOpen, formatFiatPrice, formatNumber, showLoadingSkeleton])
activeLocalCurrency,
chain.id,
filter,
filterModalIsOpen,
formatFiatPrice,
formatNumber,
showLoadingSkeleton,
sortState.sortBy,
sortState.sortDirection,
])
return ( return (
<Table <Table
......
...@@ -144,7 +144,7 @@ const LearnMoreArrow = styled(ArrowRightCircle)` ...@@ -144,7 +144,7 @@ const LearnMoreArrow = styled(ArrowRightCircle)`
const ProtocolDescription = () => <Trans i18nKey="landing.protocolDescription" /> const ProtocolDescription = () => <Trans i18nKey="landing.protocolDescription" />
function LearnMore() { function LearnMore() {
return ( return (
<LearnMoreButton href="https://info.uniswap.org"> <LearnMoreButton href="/explore">
<Row gap="sm" align="center"> <Row gap="sm" align="center">
<Trans i18nKey="common.learnMore.link" /> <Trans i18nKey="common.learnMore.link" />
<LearnMoreArrow /> <LearnMoreArrow />
......
...@@ -95,7 +95,7 @@ describe('PoolDetailsPage', () => { ...@@ -95,7 +95,7 @@ describe('PoolDetailsPage', () => {
}) })
}) })
it('not found page displayed when no data is received from thegraph', () => { it('not found page displayed when no data is received from backend', () => {
mocked(usePoolData).mockReturnValue({ mocked(usePoolData).mockReturnValue({
data: undefined, data: undefined,
loading: false, loading: false,
......
...@@ -3,22 +3,17 @@ import { ChainId, Currency, WETH9 } from '@uniswap/sdk-core' ...@@ -3,22 +3,17 @@ import { ChainId, Currency, WETH9 } from '@uniswap/sdk-core'
import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk' import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk'
import { USDC_MAINNET } from 'constants/tokens' import { USDC_MAINNET } from 'constants/tokens'
import { PoolData } from 'graphql/data/pools/usePoolData' import { PoolData } from 'graphql/data/pools/usePoolData'
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks' import { Token } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import { Token as BEToken } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' } export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
export const validPoolToken0 = { export const validBEPoolToken0 = {
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
symbol: 'USDC', symbol: 'USDC',
name: 'USD Coin', name: 'USD Coin',
decimals: '6',
derivedETH: '0.0006240873011635544626425964678706127', derivedETH: '0.0006240873011635544626425964678706127',
__typename: 'Token', __typename: 'Token',
} as Token
export const validBEPoolToken0 = {
...validPoolToken0,
address: validPoolToken0.id,
chain: 'ETHEREUM', chain: 'ETHEREUM',
decimals: 6, decimals: 6,
project: { project: {
...@@ -29,7 +24,7 @@ export const validBEPoolToken0 = { ...@@ -29,7 +24,7 @@ export const validBEPoolToken0 = {
url: 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png', url: 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
}, },
}, },
} as BEToken } as Token
export const validUSDCCurrency = { export const validUSDCCurrency = {
isNative: false, isNative: false,
...@@ -43,20 +38,16 @@ export const validUSDCCurrency = { ...@@ -43,20 +38,16 @@ export const validUSDCCurrency = {
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png', 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
_checksummedAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', _checksummedAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
_tags: null, _tags: null,
wrapped: validPoolToken0, wrapped: validBEPoolToken0,
} as unknown as Currency } as unknown as Currency
const validPoolToken1 = { export const validBEPoolToken1 = {
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
symbol: 'WETH', symbol: 'WETH',
name: 'Wrapped Ether', name: 'Wrapped Ether',
decimals: '18',
derivedETH: '1', derivedETH: '1',
__typename: 'Token', __typename: 'Token',
} as Token address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
export const validBEPoolToken1 = { id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
...validPoolToken1,
address: validPoolToken1.id,
chain: 'ETHEREUM', chain: 'ETHEREUM',
decimals: 18, decimals: 18,
project: { project: {
...@@ -67,7 +58,7 @@ export const validBEPoolToken1 = { ...@@ -67,7 +58,7 @@ export const validBEPoolToken1 = {
url: 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png', url: 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png',
}, },
}, },
} as BEToken } as Token
export const owner = '0xf5b6bb25f5beaea03dd014c6ef9fa9f3926bf36c' export const owner = '0xf5b6bb25f5beaea03dd014c6ef9fa9f3926bf36c'
......
import { Price, Token } from '@uniswap/sdk-core' import { Price, Token } from '@uniswap/sdk-core'
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk' import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { TickData } from 'graphql/thegraph/AllV3TicksQuery' import { TickData } from 'graphql/data/AllV3TicksQuery'
import { TickProcessed } from 'hooks/usePoolTickData' import { TickProcessed } from 'hooks/usePoolTickData'
import JSBI from 'jsbi' import JSBI from 'jsbi'
...@@ -8,7 +8,7 @@ import computeSurroundingTicks from './computeSurroundingTicks' ...@@ -8,7 +8,7 @@ import computeSurroundingTicks from './computeSurroundingTicks'
const getV3Tick = (tick: number, liquidityNet: number): TickData => ({ const getV3Tick = (tick: number, liquidityNet: number): TickData => ({
tick, tick,
liquidityNet: JSBI.BigInt(liquidityNet), liquidityNet: JSBI.BigInt(liquidityNet).toString(),
price0: undefined, price0: undefined,
price1: undefined, price1: undefined,
}) })
......
...@@ -3,7 +3,7 @@ import { tickToPrice } from '@uniswap/v3-sdk' ...@@ -3,7 +3,7 @@ import { tickToPrice } from '@uniswap/v3-sdk'
import { TickProcessed } from 'hooks/usePoolTickData' import { TickProcessed } from 'hooks/usePoolTickData'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { Ticks } from '../graphql/thegraph/AllV3TicksQuery' import { Ticks } from '../graphql/data/AllV3TicksQuery'
const PRICE_FIXED_DIGITS = 8 const PRICE_FIXED_DIGITS = 8
...@@ -23,12 +23,12 @@ export default function computeSurroundingTicks( ...@@ -23,12 +23,12 @@ export default function computeSurroundingTicks(
// building active liquidity for every tick. // building active liquidity for every tick.
let processedTicks: TickProcessed[] = [] let processedTicks: TickProcessed[] = []
for (let i = pivot + (ascending ? 1 : -1); ascending ? i < sortedTickData.length : i >= 0; ascending ? i++ : i--) { for (let i = pivot + (ascending ? 1 : -1); ascending ? i < sortedTickData.length : i >= 0; ascending ? i++ : i--) {
const tick = Number(sortedTickData[i].tick) const tick = Number(sortedTickData[i]?.tick)
const sdkPrice = tickToPrice(token0, token1, tick) const sdkPrice = tickToPrice(token0, token1, tick)
const currentTickProcessed: TickProcessed = { const currentTickProcessed: TickProcessed = {
liquidityActive: previousTickProcessed.liquidityActive, liquidityActive: previousTickProcessed.liquidityActive,
tick, tick,
liquidityNet: JSBI.BigInt(sortedTickData[i].liquidityNet), liquidityNet: JSBI.BigInt(sortedTickData[i]?.liquidityNet ?? ''),
price0: sdkPrice.toFixed(PRICE_FIXED_DIGITS), price0: sdkPrice.toFixed(PRICE_FIXED_DIGITS),
sdkPrice, sdkPrice,
} }
...@@ -40,7 +40,7 @@ export default function computeSurroundingTicks( ...@@ -40,7 +40,7 @@ export default function computeSurroundingTicks(
if (ascending) { if (ascending) {
currentTickProcessed.liquidityActive = JSBI.add( currentTickProcessed.liquidityActive = JSBI.add(
previousTickProcessed.liquidityActive, previousTickProcessed.liquidityActive,
JSBI.BigInt(sortedTickData[i].liquidityNet) JSBI.BigInt(sortedTickData[i]?.liquidityNet ?? 0)
) )
} else if (!ascending && JSBI.notEqual(previousTickProcessed.liquidityNet, JSBI.BigInt(0))) { } else if (!ascending && JSBI.notEqual(previousTickProcessed.liquidityNet, JSBI.BigInt(0))) {
// We are iterating descending, so look at the previous tick and apply any net liquidity. // We are iterating descending, so look at the previous tick and apply any net liquidity.
......
...@@ -11,7 +11,6 @@ ignores: [ ...@@ -11,7 +11,6 @@ ignores: [
"tsconfig", "tsconfig",
## GraphQL ## GraphQL
"@graphql-codegen/*", "@graphql-codegen/*",
"get-graphql-schema",
# i18n # i18n
"i18next-resources-for-ts", "i18next-resources-for-ts",
] ]
...@@ -880,12 +880,14 @@ type PushNotification { ...@@ -880,12 +880,14 @@ type PushNotification {
} }
type Query { type Query {
isV3SubgraphStale(chain: Chain!): Boolean
historicalProtocolVolume(chain: Chain!, version: ProtocolVersion!, duration: HistoryDuration!): [TimestampedAmount!] historicalProtocolVolume(chain: Chain!, version: ProtocolVersion!, duration: HistoryDuration!): [TimestampedAmount!]
dailyProtocolTvl(chain: Chain!, version: ProtocolVersion!): [TimestampedAmount!] dailyProtocolTvl(chain: Chain!, version: ProtocolVersion!): [TimestampedAmount!]
""" returns top v3 pools sorted by total value locked in desc order""" """ returns top v3 pools sorted by total value locked in desc order"""
topV3Pools(chain: Chain!, first: Int!, tvlCursor: Float, tokenFilter: String): [V3Pool!] topV3Pools(chain: Chain!, first: Int!, tvlCursor: Float, tokenFilter: String): [V3Pool!]
v3Pool(chain: Chain!, address: String!): V3Pool v3Pool(chain: Chain!, address: String!): V3Pool
v3PoolsForTokenPair(chain: Chain!, token0: String!, token1: String!): [V3Pool!]
v3Transactions(chain: Chain!, first: Int!, timestampCursor: Int): [PoolTransaction!] v3Transactions(chain: Chain!, first: Int!, timestampCursor: Int): [PoolTransaction!]
""" returns top v2 pairs sorted by total value locked in desc order""" """ returns top v2 pairs sorted by total value locked in desc order"""
...@@ -1296,7 +1298,7 @@ type V3Pool implements IPool { ...@@ -1296,7 +1298,7 @@ type V3Pool implements IPool {
historicalVolume(duration: HistoryDuration!): [TimestampedAmount] historicalVolume(duration: HistoryDuration!): [TimestampedAmount]
priceHistory(duration: HistoryDuration!): [TimestampedPoolPrice] priceHistory(duration: HistoryDuration!): [TimestampedPoolPrice]
transactions(first: Int!, timestampCursor: Int): [PoolTransaction] transactions(first: Int!, timestampCursor: Int): [PoolTransaction]
ticks(first: Int!, tickIdxCursor: Int): [V3PoolTick] ticks(skip: Int, first: Int): [V3PoolTick]
} }
type V3PoolTick { type V3PoolTick {
...@@ -1304,5 +1306,7 @@ type V3PoolTick { ...@@ -1304,5 +1306,7 @@ type V3PoolTick {
tickIdx: Int tickIdx: Int
liquidityGross: String liquidityGross: String
liquidityNet: String liquidityNet: String
price0: String
price1: String
} }
query AllV3Ticks ($chain: Chain!, $address: String!, $skip: Int, $first: Int){
v3Pool(chain: $chain, address: $address) {
ticks(skip: $skip, first: $first) {
tick: tickIdx
liquidityNet
price0
price1
}
}
}
query FeeTierDistribution($chain: Chain!, $token0: String!, $token1: String!) {
v3PoolsForTokenPair(chain: $chain, token0: $token0, token1: $token1) {
feeTier
token0Supply
token1Supply
}
}
query isV3SubgraphStale($chain: Chain!) {
isV3SubgraphStale(chain: $chain)
}
...@@ -72,18 +72,18 @@ export function queryResolvers<T extends QueryResolvers>( ...@@ -72,18 +72,18 @@ export function queryResolvers<T extends QueryResolvers>(
): Promise<ResolverReturnType<R>> => { ): Promise<ResolverReturnType<R>> => {
const [parent, args, context, info] = params const [parent, args, context, info] = params
const resolvedObj = isResolverWithResolve(resolver) const resolvedValue = isResolverWithResolve(resolver)
? resolver.resolve(parent, args, context, info) ? resolver.resolve(parent, args, context, info)
: isResolverFunction(resolver) : isResolverFunction(resolver)
? resolver(parent, args, context, info) ? resolver(parent, args, context, info)
: null : null
const filteredObj = await filterObjectFields( const updatedValue = await filterObjectFields(
info.fieldNodes[0]?.selectionSet, info.fieldNodes[0]?.selectionSet,
resolvedObj ?? null resolvedValue
) )
// cloneDeepWith returns any type so we need to cast it manually // cloneDeepWith returns any type so we need to cast it manually
const resultObj = cloneDeepWith(filteredObj, undefinedToNull) as ResolverReturnType<R> const resultObj = cloneDeepWith(updatedValue, undefinedToNull) as ResolverReturnType<R>
// Resolve the corresponding promise // Resolve the corresponding promise
if (promiseResolvers[key]) { if (promiseResolvers[key]) {
...@@ -100,12 +100,18 @@ export function queryResolvers<T extends QueryResolvers>( ...@@ -100,12 +100,18 @@ export function queryResolvers<T extends QueryResolvers>(
} }
} }
async function filterObjectFields<T extends object>( type Scalar = number | string | boolean | bigint | symbol | undefined
function isObject<T extends object | Scalar>(value: T): value is Exclude<T, Scalar> {
return typeof value === 'object'
}
async function filterObjectFields<T extends object | Scalar>(
selectionSet: SelectionSetNode | undefined, selectionSet: SelectionSetNode | undefined,
sourceObject: T | Promise<Maybe<ResolverTypeWrapper<T>>> | null sourceValue: T | Promise<Maybe<ResolverTypeWrapper<T>>> | null
): Promise<T | null> { ): Promise<T | null> {
// resolved source object can be a Promise or a regular object // resolved source value can be a Promise or a plain value
const source = await sourceObject const source = await sourceValue
if (!source || !selectionSet) { if (!source || !selectionSet) {
return source ?? null return source ?? null
...@@ -115,12 +121,17 @@ async function filterObjectFields<T extends object>( ...@@ -115,12 +121,17 @@ async function filterObjectFields<T extends object>(
return Promise.all(source.map((obj) => filterObjectFields(selectionSet, obj))) as T return Promise.all(source.map((obj) => filterObjectFields(selectionSet, obj))) as T
} }
if (!isObject(source)) {
return source
}
const result: Record<string, any> = {} const result: Record<string, any> = {}
for (const selection of selectionSet.selections) { for (const selection of selectionSet.selections) {
if (selection.kind !== 'Field') { if (selection.kind !== 'Field') {
continue continue
} }
const key = selection.name.value const key = selection.name.value
const value = source[key as keyof typeof source] const value = source[key as keyof typeof source]
......
...@@ -72,12 +72,10 @@ ...@@ -72,12 +72,10 @@
}, },
"graphql:schema": { "graphql:schema": {
"env": [ "env": [
"THE_GRAPH_SCHEMA_ENDPOINT",
"REACT_APP_AWS_API_ENDPOINT", "REACT_APP_AWS_API_ENDPOINT",
"scripts/**" "scripts/**"
], ],
"inputs": [ "inputs": [
"scripts/fetch-schema.js",
".env.production", ".env.production",
"graphql.*.ts" "graphql.*.ts"
], ],
...@@ -90,7 +88,6 @@ ...@@ -90,7 +88,6 @@
"inputs": [ "inputs": [
"codegen.ts", "codegen.ts",
"src/**/schema.graphql", "src/**/schema.graphql",
"scripts/fetch-schema.js",
"src/graphql/**", "src/graphql/**",
"src/data/**/*.graphql" "src/data/**/*.graphql"
], ],
......
...@@ -13635,7 +13635,6 @@ __metadata: ...@@ -13635,7 +13635,6 @@ __metadata:
fancy-canvas: 2.1.0 fancy-canvas: 2.1.0
focus-visible: 5.2.0 focus-visible: 5.2.0
framer-motion: 10.17.6 framer-motion: 10.17.6
get-graphql-schema: ^2.1.2
graphql: 16.6.0 graphql: 16.6.0
hardhat: 2.14.0 hardhat: 2.14.0
husky: ^8.0.3 husky: ^8.0.3
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment