Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
361e0ca8d7 | ||
|
|
cc0a757ddd | ||
|
|
31632d3c5b | ||
|
|
9cfbec4b8b | ||
|
|
b5ac5d882f | ||
|
|
130606cab4 | ||
|
|
fa56919a06 | ||
|
|
633f65676e | ||
|
|
9bccb7ae3a | ||
|
|
8a2e4123c6 | ||
|
|
e93ddbedfa | ||
|
|
1667b56a04 | ||
|
|
6e995d6c09 | ||
|
|
f096112716 | ||
|
|
50c7d36164 | ||
|
|
8a7f1d51ce |
1
.github/workflows/integration-tests.yaml
vendored
1
.github/workflows/integration-tests.yaml
vendored
@@ -46,5 +46,6 @@ jobs:
|
||||
- run: yarn integration-test
|
||||
env:
|
||||
CYPRESS_INTEGRATION_TEST_PRIVATE_KEY: ${{ secrets.CYPRESS_INTEGRATION_TEST_PRIVATE_KEY }}
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
|
||||
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,6 +7,7 @@
|
||||
/src/locales/**/*.ts
|
||||
/src/locales/**/*.json
|
||||
/src/locales/**/en-US.po
|
||||
/src/state/data/generated.ts
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
@@ -39,4 +40,4 @@ package-lock.json
|
||||
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
cypress/fixtures/example.json
|
||||
cypress/fixtures/example.json
|
||||
|
||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
||||
/src/state/data/generated.ts
|
||||
10
codegen.yml
Normal file
10
codegen.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3'
|
||||
documents: 'src/**/!(*.d).{ts,tsx}'
|
||||
generates:
|
||||
./src/state/data/generated.ts:
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- typescript-rtk-query:
|
||||
importBaseApiFrom: './slice'
|
||||
exportHooks: true
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"projectId": "yp82ef",
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"pluginsFile": false,
|
||||
"fixturesFolder": false,
|
||||
|
||||
@@ -4,6 +4,7 @@ describe('Landing Page', () => {
|
||||
beforeEach(() => cy.visit('/'))
|
||||
it('loads swap page', () => {
|
||||
cy.get('#swap-page')
|
||||
cy.screenshot()
|
||||
})
|
||||
|
||||
it('redirects to url /swap', () => {
|
||||
|
||||
18
package.json
18
package.json
@@ -5,6 +5,10 @@
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@ethersproject/experimental": "^5.2.0",
|
||||
"@graphql-codegen/cli": "1.21.5",
|
||||
"@graphql-codegen/typescript": "1.22.3",
|
||||
"@graphql-codegen/typescript-operations": "^1.18.2",
|
||||
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
|
||||
"@lingui/cli": "^3.9.0",
|
||||
"@lingui/loader": "^3.9.0",
|
||||
"@lingui/macro": "^3.9.0",
|
||||
@@ -14,7 +18,8 @@
|
||||
"@reach/dialog": "^0.10.3",
|
||||
"@reach/portal": "^0.10.3",
|
||||
"@react-hook/window-scroll": "^1.3.0",
|
||||
"@reduxjs/toolkit": "^1.3.5",
|
||||
"@reduxjs/toolkit": "^1.6.0",
|
||||
"@rtk-query/graphql-request-base-query": "^1.0.3",
|
||||
"@typechain/ethers-v5": "^7.0.0",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/lingui__core": "^2.7.1",
|
||||
@@ -66,6 +71,8 @@
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-plugin-react-hooks": "^4.0.0",
|
||||
"ethers": "^5.2.0",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
"inter-ui": "^3.13.1",
|
||||
"lightweight-charts": "^3.3.0",
|
||||
"lodash.flatmap": "^4.5.0",
|
||||
@@ -92,6 +99,7 @@
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
"rebass": "^4.0.7",
|
||||
"redux-devtools-extension": "^2.13.9",
|
||||
"redux-localstorage-simple": "^2.3.1",
|
||||
"serve": "^11.3.2",
|
||||
"start-server-and-test": "^1.11.0",
|
||||
@@ -115,13 +123,15 @@
|
||||
"compile-contract-types": "yarn compile-external-abi-types && yarn compile-v3-contract-types",
|
||||
"compile-external-abi-types": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
|
||||
"compile-v3-contract-types": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
|
||||
"build": "yarn compile-contract-types && yarn i18n:extract && yarn i18n:compile && react-scripts build",
|
||||
"build": "yarn compile-contract-types && yarn graphql:generate && yarn i18n:extract && yarn i18n:compile && react-scripts build",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "lingui compile",
|
||||
"integration-test": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run'",
|
||||
"integration-test": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
|
||||
"graphql:generate": "graphql-codegen --config codegen.yml",
|
||||
"postinstall": "yarn compile-contract-types",
|
||||
"start": "yarn compile-contract-types && react-scripts start",
|
||||
"test": "react-scripts test --env=jsdom"
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"prestart": "yarn graphql:generate && touch src/locales/en-US.po"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app",
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
pointer-events: none;
|
||||
width: 200vw;
|
||||
height: 200vh;
|
||||
mix-blend-mode: color;
|
||||
background: radial-gradient(50% 50% at 50% 50%, #fc077d10 0%, rgba(255, 255, 255, 0) 100%);
|
||||
transform: translate(-50vw, -100vh);
|
||||
z-index: -1;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
import Logo from '../Logo'
|
||||
|
||||
export const getTokenLogoURL = (address: string) =>
|
||||
`https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${address}/logo.png`
|
||||
`https://raw.githubusercontent.com/uniswap/assets/master/blockchains/ethereum/assets/${address}/logo.png`
|
||||
|
||||
const StyledEthereumLogo = styled.img<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
|
||||
@@ -10,7 +10,7 @@ async function getColorFromToken(token: Token): Promise<string | null> {
|
||||
return Promise.resolve('#FAAB14')
|
||||
}
|
||||
|
||||
const path = `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${token.address}/logo.png`
|
||||
const path = `https://raw.githubusercontent.com/uniswap/assets/master/blockchains/ethereum/assets/${token.address}/logo.png`
|
||||
|
||||
return Vibrant.from(path)
|
||||
.getPalette()
|
||||
|
||||
@@ -19,6 +19,7 @@ import MulticallUpdater from './state/multicall/updater'
|
||||
import TransactionUpdater from './state/transactions/updater'
|
||||
import UserUpdater from './state/user/updater'
|
||||
import ThemeProvider, { ThemedGlobalStyle } from './theme'
|
||||
import RadialGradientByChainUpdater from './theme/RadialGradientByChainUpdater'
|
||||
import getLibrary from './utils/getLibrary'
|
||||
|
||||
const Web3ProviderNetwork = createWeb3ReactRoot(NetworkContextName)
|
||||
@@ -50,6 +51,7 @@ if (typeof GOOGLE_ANALYTICS_ID === 'string') {
|
||||
function Updaters() {
|
||||
return (
|
||||
<>
|
||||
<RadialGradientByChainUpdater />
|
||||
<ListsUpdater />
|
||||
<UserUpdater />
|
||||
<ApplicationUpdater />
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"X-Crowdin-File-ID: 4\n"
|
||||
"Project-Id-Version: uniswap-interface\n"
|
||||
"Language-Team: German\n"
|
||||
"PO-Revision-Date: 2021-06-27 05:04\n"
|
||||
"PO-Revision-Date: 2021-06-29 09:04\n"
|
||||
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"X-Crowdin-File-ID: 4\n"
|
||||
"Project-Id-Version: uniswap-interface\n"
|
||||
"Language-Team: Japanese\n"
|
||||
"PO-Revision-Date: 2021-06-27 05:04\n"
|
||||
"PO-Revision-Date: 2021-07-01 10:04\n"
|
||||
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
@@ -272,11 +272,11 @@ msgstr "{0} を承認中"
|
||||
|
||||
#: src/components/Header/NetworkCard.tsx
|
||||
msgid "Arbitrum Explorer"
|
||||
msgstr "アービトラムエクスプローラー"
|
||||
msgstr "Arbitrumエクスプローラー"
|
||||
|
||||
#: src/components/Header/NetworkCard.tsx
|
||||
msgid "Arbitrum Token Bridge"
|
||||
msgstr "アービトラムトークンブリッジ"
|
||||
msgstr "Arbitrumトークンブリッジ"
|
||||
|
||||
#: src/components/Settings/index.tsx
|
||||
msgid "Are you sure?"
|
||||
@@ -1615,7 +1615,7 @@ msgstr "Uniswap移行コントラクト↗"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "Uniswap on <0>Arbitrum</0>"
|
||||
msgstr "<0>アービトラムでのユニスワップ</0>"
|
||||
msgstr "<0>アービトラム</0>でのユニスワップ"
|
||||
|
||||
#: src/components/SearchModal/ImportToken.tsx
|
||||
msgid "Unknown Source"
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"X-Crowdin-File-ID: 4\n"
|
||||
"Project-Id-Version: uniswap-interface\n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"PO-Revision-Date: 2021-06-28 16:04\n"
|
||||
"PO-Revision-Date: 2021-07-01 10:04\n"
|
||||
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
@@ -37,7 +37,7 @@ msgstr "(最大值)"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "(View on Explorer)"
|
||||
msgstr "(在浏览器查看)"
|
||||
msgstr "(在以太坊资源浏览器上查看)"
|
||||
|
||||
#: src/components/Header/UniBalanceContent.tsx
|
||||
msgid "(claim)"
|
||||
@@ -328,7 +328,7 @@ msgstr "已屏蔽地址"
|
||||
|
||||
#: src/components/PositionCard/index.tsx
|
||||
msgid "By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity."
|
||||
msgstr "通过注入流动资金,您将按您在流动池中所占份额赚取对应交易量的0.3%手续费。手续费将实时累计,添加到流动池中,您可以通过赎回您的流动资金将手续费也赎回。"
|
||||
msgstr "通过添加流动性,您将按您在流动池中所占比例赚取对应交易量的0.3%手续费。手续费将实时累加到流动池中,在您取回流动性时也将同时取回您赚取的手续费。"
|
||||
|
||||
#: src/components/SearchModal/ImportList.tsx
|
||||
msgid "By adding this list you are implicitly trusting that the data is correct. Anyone can create a list, including creating fake versions of existing lists and lists that claim to represent projects that do not have one."
|
||||
@@ -463,7 +463,7 @@ msgstr "收取手续费的操作将为您提取您当前已累积的手续费。
|
||||
|
||||
#: src/components/SearchModal/CommonBases.tsx
|
||||
msgid "Common bases"
|
||||
msgstr "共同基础"
|
||||
msgstr "常用代币"
|
||||
|
||||
#: src/pages/RemoveLiquidity/index.tsx
|
||||
msgid "Confirm"
|
||||
@@ -615,7 +615,7 @@ msgstr "充入流动资金"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "Deposit to Arbitrum"
|
||||
msgstr "存款到 Arbitrum"
|
||||
msgstr "充值到 Arbitrum"
|
||||
|
||||
#: src/pages/Earn/index.tsx
|
||||
msgid "Deposit your Liquidity Provider tokens to receive UNI, the Uniswap protocol governance token."
|
||||
@@ -1231,7 +1231,7 @@ msgstr "最近的交易"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "Recipient"
|
||||
msgstr "接受者"
|
||||
msgstr "接收方"
|
||||
|
||||
#: src/components/PositionCard/V2.tsx
|
||||
#: src/components/PositionCard/index.tsx
|
||||
@@ -1462,7 +1462,7 @@ msgstr "这些代币通常与其他代币配对。"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "This is an alpha release of Uniswap on the Arbitrum network. You must bridge L1 assets to the network to swap them."
|
||||
msgstr "这是 Arbitrum 网络上 Uniswap 的 alpha 版本。您需要先将 L1 资产桥接到 Arbitrum 网络才能使用。"
|
||||
msgstr "这是 Arbitrum 网络上 Uniswap 的 alpha 版本。您必须桥接 L1 资产才能进行兑换。"
|
||||
|
||||
#: src/components/SearchModal/ImportToken.tsx
|
||||
msgid "This token doesn't appear on the active token list(s). Make sure this is the token that you want to trade."
|
||||
@@ -1574,7 +1574,7 @@ msgstr "UNI {0}/{1} 被摧毁"
|
||||
|
||||
#: src/pages/Earn/Manage.tsx
|
||||
msgid "UNI-V2 LP tokens are required. Once you've added liquidity to the {0}-{1} pool you can stake your liquidity tokens on this page."
|
||||
msgstr "需要 UNI-V2 流动池代币。一旦您已注入流动资金到 {0}-{1} 池,您就可以在此页面上抵押您的流动池代币。"
|
||||
msgstr "需要 UNI-V2 LP 代币。在您注入流动性到 {0}-{1} 池后,您就可以在此页面上抵押您的流动性代币。"
|
||||
|
||||
#: src/pages/Earn/Manage.tsx
|
||||
msgid "UNI-V2 {0}-{1}"
|
||||
@@ -1615,7 +1615,7 @@ msgstr "Uniswap 迁移合约↗"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "Uniswap on <0>Arbitrum</0>"
|
||||
msgstr "Uniswap on <0> Arbitrum</0>"
|
||||
msgstr "<0> Arbitrum</0> 网络上的 Uniswap"
|
||||
|
||||
#: src/components/SearchModal/ImportToken.tsx
|
||||
msgid "Unknown Source"
|
||||
@@ -1746,7 +1746,7 @@ msgstr "等待确认"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "Wallet Address or ENS name"
|
||||
msgstr "钱包地址或 ENS 名称"
|
||||
msgstr "钱包地址或 ENS 名"
|
||||
|
||||
#: src/components/earn/StakingModal.tsx
|
||||
msgid "Weekly Rewards"
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"X-Crowdin-File-ID: 4\n"
|
||||
"Project-Id-Version: uniswap-interface\n"
|
||||
"Language-Team: Chinese Traditional\n"
|
||||
"PO-Revision-Date: 2021-06-27 05:04\n"
|
||||
"PO-Revision-Date: 2021-07-01 10:04\n"
|
||||
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
@@ -37,7 +37,7 @@ msgstr "(最大值)"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "(View on Explorer)"
|
||||
msgstr "(在資源管理器上查看)"
|
||||
msgstr "(在以太坊資源瀏覽器上查看)"
|
||||
|
||||
#: src/components/Header/UniBalanceContent.tsx
|
||||
msgid "(claim)"
|
||||
@@ -272,11 +272,11 @@ msgstr "批準 {0}"
|
||||
|
||||
#: src/components/Header/NetworkCard.tsx
|
||||
msgid "Arbitrum Explorer"
|
||||
msgstr "套利瀏覽器"
|
||||
msgstr "Arbitrum 瀏覽器"
|
||||
|
||||
#: src/components/Header/NetworkCard.tsx
|
||||
msgid "Arbitrum Token Bridge"
|
||||
msgstr "套利代幣橋"
|
||||
msgstr "Arbitrum 代幣橋"
|
||||
|
||||
#: src/components/Settings/index.tsx
|
||||
msgid "Are you sure?"
|
||||
@@ -328,7 +328,7 @@ msgstr "已屏蔽地址"
|
||||
|
||||
#: src/components/PositionCard/index.tsx
|
||||
msgid "By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity."
|
||||
msgstr "通過註入流動資金,您將按您在流動池中所占份額賺取對應交易量的0.3%手續費。手續費將實時累計,添加到流動池中,您可以通過贖回您的流動資金將手續費也贖回。"
|
||||
msgstr "通過添加流動性,您將按您在流動池中所佔比例賺取對應交易量的0.3%手續費。手續費將實時累加到流動池中,在您取回流動性時也將同時取回您賺取的手續費。"
|
||||
|
||||
#: src/components/SearchModal/ImportList.tsx
|
||||
msgid "By adding this list you are implicitly trusting that the data is correct. Anyone can create a list, including creating fake versions of existing lists and lists that claim to represent projects that do not have one."
|
||||
@@ -463,7 +463,7 @@ msgstr "收取手續費的操作將為您提取您當前已累積的手續費。
|
||||
|
||||
#: src/components/SearchModal/CommonBases.tsx
|
||||
msgid "Common bases"
|
||||
msgstr "共同基礎"
|
||||
msgstr "常用代幣"
|
||||
|
||||
#: src/pages/RemoveLiquidity/index.tsx
|
||||
msgid "Confirm"
|
||||
@@ -615,7 +615,7 @@ msgstr "存入流動資金"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "Deposit to Arbitrum"
|
||||
msgstr "存款到 Arbitrum"
|
||||
msgstr "充值到 Arbitrum"
|
||||
|
||||
#: src/pages/Earn/index.tsx
|
||||
msgid "Deposit your Liquidity Provider tokens to receive UNI, the Uniswap protocol governance token."
|
||||
@@ -874,7 +874,7 @@ msgstr "瞭解"
|
||||
|
||||
#: src/components/Header/NetworkCard.tsx
|
||||
msgid "Learn more"
|
||||
msgstr "學到更多"
|
||||
msgstr "瞭解更多"
|
||||
|
||||
#: src/components/claim/ClaimModal.tsx
|
||||
#: src/pages/Pool/PositionPage.tsx
|
||||
@@ -1231,7 +1231,7 @@ msgstr "最近交易"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "Recipient"
|
||||
msgstr "接受者"
|
||||
msgstr "接收方"
|
||||
|
||||
#: src/components/PositionCard/V2.tsx
|
||||
#: src/components/PositionCard/index.tsx
|
||||
@@ -1462,7 +1462,7 @@ msgstr "這些代幣通常與其他代幣配對。"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "This is an alpha release of Uniswap on the Arbitrum network. You must bridge L1 assets to the network to swap them."
|
||||
msgstr "這是 Arbitrum 網絡上 Uniswap 的 alpha 版本。您必須將 L1 資產橋接到網絡才能交換它們。"
|
||||
msgstr "這是 Arbitrum 網絡上 Uniswap 的 alpha 版本。您必須橋接 L1 資產才能進行兌換。"
|
||||
|
||||
#: src/components/SearchModal/ImportToken.tsx
|
||||
msgid "This token doesn't appear on the active token list(s). Make sure this is the token that you want to trade."
|
||||
@@ -1574,7 +1574,7 @@ msgstr "UNI {0}/{1} 已銷毀"
|
||||
|
||||
#: src/pages/Earn/Manage.tsx
|
||||
msgid "UNI-V2 LP tokens are required. Once you've added liquidity to the {0}-{1} pool you can stake your liquidity tokens on this page."
|
||||
msgstr "需要 UNI-V2 流動池代幣。一旦您已註入流動資金到 {0}-{1} 池,您就可以在此頁面上抵押您的流動池代幣。"
|
||||
msgstr "需要 UNI-V2 LP 代幣。在您注入流動性到 {0}-{1} 池後,您就可以在此頁面上抵押您的流動性代幣。"
|
||||
|
||||
#: src/pages/Earn/Manage.tsx
|
||||
msgid "UNI-V2 {0}-{1}"
|
||||
@@ -1615,7 +1615,7 @@ msgstr "Uniswap 遷移合約↗"
|
||||
|
||||
#: src/components/swap/SwapNetworkAlert.tsx
|
||||
msgid "Uniswap on <0>Arbitrum</0>"
|
||||
msgstr "Uniswap on <0> Arbitrum</0>"
|
||||
msgstr "<0> Arbitrum</0> 網絡上的 Uniswap"
|
||||
|
||||
#: src/components/SearchModal/ImportToken.tsx
|
||||
msgid "Unknown Source"
|
||||
@@ -1746,7 +1746,7 @@ msgstr "等待確認中"
|
||||
|
||||
#: src/components/AddressInputPanel/index.tsx
|
||||
msgid "Wallet Address or ENS name"
|
||||
msgstr "錢包地址或 ENS 名稱"
|
||||
msgstr "錢包地址或 ENS 名"
|
||||
|
||||
#: src/components/earn/StakingModal.tsx
|
||||
msgid "Weekly Rewards"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import useDebounce from '../../hooks/useDebounce'
|
||||
import useIsWindowVisible from '../../hooks/useIsWindowVisible'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { updateBlockNumber } from './actions'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
|
||||
export default function Updater(): null {
|
||||
const { library, chainId } = useActiveWeb3React()
|
||||
@@ -54,25 +53,5 @@ export default function Updater(): null {
|
||||
dispatch(updateBlockNumber({ chainId: debouncedState.chainId, blockNumber: debouncedState.blockNumber }))
|
||||
}, [windowVisible, dispatch, debouncedState.blockNumber, debouncedState.chainId])
|
||||
|
||||
// manage background color
|
||||
const background = document.getElementById('background-radial-gradient')
|
||||
useEffect(() => {
|
||||
if (!background) {
|
||||
return
|
||||
}
|
||||
|
||||
let gradient
|
||||
switch (chainId) {
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
gradient =
|
||||
'radial-gradient(96.19% 96.19% at 50% -5.43%, hsla(204, 87%, 55%, 0.2) 0%, hsla(227, 0%, 0%, 0) 100%)'
|
||||
break
|
||||
default:
|
||||
gradient = 'radial-gradient(50% 50% at 50% 50%, #fc077d10 0%, rgba(255, 255, 255, 0) 100%)'
|
||||
}
|
||||
|
||||
background.style.background = gradient
|
||||
}, [background, chainId])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
110
src/state/data/slice.ts
Normal file
110
src/state/data/slice.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { createApi } from '@reduxjs/toolkit/query/react'
|
||||
import { gql, GraphQLClient } from 'graphql-request'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { reduce } from 'lodash'
|
||||
import { graphqlRequestBaseQuery } from '@rtk-query/graphql-request-base-query'
|
||||
|
||||
import { FeeTierDistribution, PoolTVL } from './types'
|
||||
|
||||
export const UNISWAP_V3_GRAPH_URL = 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3'
|
||||
|
||||
export const client = new GraphQLClient(UNISWAP_V3_GRAPH_URL)
|
||||
export const api = createApi({
|
||||
reducerPath: 'dataApi',
|
||||
baseQuery: graphqlRequestBaseQuery({ client }),
|
||||
endpoints: (builder) => ({
|
||||
getFeeTierDistribution: builder.query<FeeTierDistribution, { token0: string; token1: string }>({
|
||||
query: ({ token0, token1 }) => ({
|
||||
document: gql`
|
||||
query pools($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,
|
||||
},
|
||||
}),
|
||||
transformResponse: (poolTvl: PoolTVL) => {
|
||||
const all = poolTvl.asToken0.concat(poolTvl.asToken1)
|
||||
|
||||
// sum tvl for token0 and token1 by fee tier
|
||||
const tvlByFeeTer = all.reduce<{ [feeAmount: number]: [number | undefined, number | undefined] }>(
|
||||
(acc, value) => {
|
||||
acc[value.feeTier][0] = (acc[value.feeTier][0] ?? 0) + Number(value.totalValueLockedToken0)
|
||||
acc[value.feeTier][1] = (acc[value.feeTier][1] ?? 0) + Number(value.totalValueLockedToken1)
|
||||
return acc
|
||||
},
|
||||
{
|
||||
[FeeAmount.LOW]: [undefined, undefined],
|
||||
[FeeAmount.MEDIUM]: [undefined, undefined],
|
||||
[FeeAmount.HIGH]: [undefined, undefined],
|
||||
}
|
||||
)
|
||||
|
||||
// sum total tvl for token0 and token1
|
||||
const [sumToken0Tvl, sumToken1Tvl] = reduce(
|
||||
tvlByFeeTer,
|
||||
(acc: [number, number], value) => {
|
||||
acc[0] += value[0] ?? 0
|
||||
acc[1] += value[1] ?? 0
|
||||
return acc
|
||||
},
|
||||
[0, 0]
|
||||
)
|
||||
|
||||
// returns undefined if both tvl0 and tvl1 are undefined (pool not created)
|
||||
const mean = (tvl0: number | undefined, sumTvl0: number, tvl1: number | undefined, sumTvl1: number) =>
|
||||
tvl0 === undefined && tvl1 === undefined ? undefined : ((tvl0 ?? 0) + (tvl1 ?? 0)) / (sumTvl0 + sumTvl1) || 0
|
||||
|
||||
return {
|
||||
block: poolTvl._meta.block.number,
|
||||
distributions: {
|
||||
[FeeAmount.LOW]: mean(
|
||||
tvlByFeeTer[FeeAmount.LOW][0],
|
||||
sumToken0Tvl,
|
||||
tvlByFeeTer[FeeAmount.LOW][1],
|
||||
sumToken1Tvl
|
||||
),
|
||||
[FeeAmount.MEDIUM]: mean(
|
||||
tvlByFeeTer[FeeAmount.MEDIUM][0],
|
||||
sumToken0Tvl,
|
||||
tvlByFeeTer[FeeAmount.MEDIUM][1],
|
||||
sumToken1Tvl
|
||||
),
|
||||
[FeeAmount.HIGH]: mean(
|
||||
tvlByFeeTer[FeeAmount.HIGH][0],
|
||||
sumToken0Tvl,
|
||||
tvlByFeeTer[FeeAmount.HIGH][1],
|
||||
sumToken1Tvl
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetFeeTierDistributionQuery } = api
|
||||
28
src/state/data/types.ts
Normal file
28
src/state/data/types.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
|
||||
export interface PoolTVL {
|
||||
_meta: {
|
||||
block: {
|
||||
number: number
|
||||
}
|
||||
}
|
||||
asToken0: {
|
||||
feeTier: FeeAmount
|
||||
totalValueLockedToken0: number
|
||||
totalValueLockedToken1: number
|
||||
}[]
|
||||
asToken1: {
|
||||
feeTier: FeeAmount
|
||||
totalValueLockedToken0: number
|
||||
totalValueLockedToken1: number
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface FeeTierDistribution {
|
||||
block: number
|
||||
distributions: {
|
||||
[FeeAmount.LOW]: number | undefined
|
||||
[FeeAmount.MEDIUM]: number | undefined
|
||||
[FeeAmount.HIGH]: number | undefined
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import { save, load } from 'redux-localstorage-simple'
|
||||
|
||||
import application from './application/reducer'
|
||||
@@ -12,6 +12,7 @@ import lists from './lists/reducer'
|
||||
import burn from './burn/reducer'
|
||||
import burnV3 from './burn/v3/reducer'
|
||||
import multicall from './multicall/reducer'
|
||||
import { api } from './data/slice'
|
||||
|
||||
const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists']
|
||||
|
||||
@@ -27,8 +28,12 @@ const store = configureStore({
|
||||
burnV3,
|
||||
multicall,
|
||||
lists,
|
||||
[api.reducerPath]: api.reducer,
|
||||
},
|
||||
middleware: [...getDefaultMiddleware({ thunk: false }), save({ states: PERSISTED_KEYS, debounce: 1000 })],
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({ thunk: true })
|
||||
.concat(api.middleware)
|
||||
.concat(save({ states: PERSISTED_KEYS, debounce: 1000 })),
|
||||
preloadedState: load({ states: PERSISTED_KEYS }),
|
||||
})
|
||||
|
||||
|
||||
@@ -39,13 +39,13 @@ export function parseCallKey(callKey: string): Call {
|
||||
|
||||
export interface ListenerOptions {
|
||||
// how often this data should be fetched, by default 1
|
||||
readonly blocksPerFetch?: number
|
||||
readonly blocksPerFetch: number
|
||||
}
|
||||
|
||||
export const addMulticallListeners = createAction<{ chainId: number; calls: Call[]; options?: ListenerOptions }>(
|
||||
export const addMulticallListeners = createAction<{ chainId: number; calls: Call[]; options: ListenerOptions }>(
|
||||
'multicall/addMulticallListeners'
|
||||
)
|
||||
export const removeMulticallListeners = createAction<{ chainId: number; calls: Call[]; options?: ListenerOptions }>(
|
||||
export const removeMulticallListeners = createAction<{ chainId: number; calls: Call[]; options: ListenerOptions }>(
|
||||
'multicall/removeMulticallListeners'
|
||||
)
|
||||
export const fetchingMulticallResults = createAction<{ chainId: number; calls: Call[]; fetchingBlockNumber: number }>(
|
||||
|
||||
@@ -48,7 +48,10 @@ export const NEVER_RELOAD: ListenerOptions = {
|
||||
}
|
||||
|
||||
// the lowest level call for subscribing to contract data
|
||||
function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): CallResult[] {
|
||||
function useCallsData(
|
||||
calls: (Call | undefined)[],
|
||||
{ blocksPerFetch }: ListenerOptions = { blocksPerFetch: 1 }
|
||||
): CallResult[] {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const callResults = useAppSelector((state) => state.multicall.callResults)
|
||||
const dispatch = useAppDispatch()
|
||||
@@ -73,7 +76,7 @@ function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): C
|
||||
addMulticallListeners({
|
||||
chainId,
|
||||
calls,
|
||||
options,
|
||||
options: { blocksPerFetch },
|
||||
})
|
||||
)
|
||||
|
||||
@@ -82,11 +85,11 @@ function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): C
|
||||
removeMulticallListeners({
|
||||
chainId,
|
||||
calls,
|
||||
options,
|
||||
options: { blocksPerFetch },
|
||||
})
|
||||
)
|
||||
}
|
||||
}, [chainId, dispatch, options, serializedCallKeys])
|
||||
}, [chainId, dispatch, blocksPerFetch, serializedCallKeys])
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
|
||||
@@ -32,6 +32,7 @@ describe('multicall reducer', () => {
|
||||
callData: '0x',
|
||||
},
|
||||
],
|
||||
options: { blocksPerFetch: 1 },
|
||||
})
|
||||
)
|
||||
expect(store.getState()).toEqual({
|
||||
@@ -58,6 +59,7 @@ describe('multicall reducer', () => {
|
||||
},
|
||||
],
|
||||
chainId: 1,
|
||||
options: { blocksPerFetch: 1 },
|
||||
})
|
||||
)
|
||||
expect(store.getState()).toEqual({ callResults: {}, callListeners: {} })
|
||||
@@ -72,6 +74,7 @@ describe('multicall reducer', () => {
|
||||
callData: '0x',
|
||||
},
|
||||
],
|
||||
options: { blocksPerFetch: 1 },
|
||||
})
|
||||
)
|
||||
store.dispatch(
|
||||
@@ -83,6 +86,7 @@ describe('multicall reducer', () => {
|
||||
},
|
||||
],
|
||||
chainId: 1,
|
||||
options: { blocksPerFetch: 1 },
|
||||
})
|
||||
)
|
||||
expect(store.getState()).toEqual({
|
||||
|
||||
@@ -37,20 +37,41 @@ const initialState: MulticallState = {
|
||||
|
||||
export default createReducer(initialState, (builder) =>
|
||||
builder
|
||||
.addCase(addMulticallListeners, (state, { payload: { calls, chainId, options: { blocksPerFetch = 1 } = {} } }) => {
|
||||
const listeners: MulticallState['callListeners'] = state.callListeners
|
||||
? state.callListeners
|
||||
: (state.callListeners = {})
|
||||
listeners[chainId] = listeners[chainId] ?? {}
|
||||
calls.forEach((call) => {
|
||||
const callKey = toCallKey(call)
|
||||
listeners[chainId][callKey] = listeners[chainId][callKey] ?? {}
|
||||
listeners[chainId][callKey][blocksPerFetch] = (listeners[chainId][callKey][blocksPerFetch] ?? 0) + 1
|
||||
})
|
||||
})
|
||||
.addCase(
|
||||
addMulticallListeners,
|
||||
(
|
||||
state,
|
||||
{
|
||||
payload: {
|
||||
calls,
|
||||
chainId,
|
||||
options: { blocksPerFetch },
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const listeners: MulticallState['callListeners'] = state.callListeners
|
||||
? state.callListeners
|
||||
: (state.callListeners = {})
|
||||
listeners[chainId] = listeners[chainId] ?? {}
|
||||
calls.forEach((call) => {
|
||||
const callKey = toCallKey(call)
|
||||
listeners[chainId][callKey] = listeners[chainId][callKey] ?? {}
|
||||
listeners[chainId][callKey][blocksPerFetch] = (listeners[chainId][callKey][blocksPerFetch] ?? 0) + 1
|
||||
})
|
||||
}
|
||||
)
|
||||
.addCase(
|
||||
removeMulticallListeners,
|
||||
(state, { payload: { chainId, calls, options: { blocksPerFetch = 1 } = {} } }) => {
|
||||
(
|
||||
state,
|
||||
{
|
||||
payload: {
|
||||
chainId,
|
||||
calls,
|
||||
options: { blocksPerFetch },
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const listeners: MulticallState['callListeners'] = state.callListeners
|
||||
? state.callListeners
|
||||
: (state.callListeners = {})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useMulticall2Contract } from '../../hooks/useContract'
|
||||
import useDebounce from '../../hooks/useDebounce'
|
||||
import chunkArray from '../../utils/chunkArray'
|
||||
import { retry, RetryableError } from '../../utils/retry'
|
||||
import { updateBlockNumber } from '../application/actions'
|
||||
import { useBlockNumber } from '../application/hooks'
|
||||
import { AppState } from '../index'
|
||||
import {
|
||||
@@ -149,8 +150,8 @@ export default function Updater(): null {
|
||||
|
||||
const chunkedCalls = chunkArray(calls)
|
||||
|
||||
if (cancellations.current?.blockNumber !== latestBlockNumber) {
|
||||
cancellations.current?.cancellations?.forEach((c) => c())
|
||||
if (cancellations.current && cancellations.current.blockNumber !== latestBlockNumber) {
|
||||
cancellations.current.cancellations.forEach((c) => c())
|
||||
}
|
||||
|
||||
dispatch(
|
||||
@@ -171,8 +172,6 @@ export default function Updater(): null {
|
||||
})
|
||||
promise
|
||||
.then(({ results: returnData, blockNumber: fetchBlockNumber }) => {
|
||||
cancellations.current = { cancellations: [], blockNumber: latestBlockNumber }
|
||||
|
||||
// accumulates the length of all previous indices
|
||||
const firstCallKeyIndex = chunkedCalls.slice(0, index).reduce<number>((memo, curr) => memo + curr.length, 0)
|
||||
const lastCallKeyIndex = firstCallKeyIndex + returnData.length
|
||||
@@ -216,10 +215,14 @@ export default function Updater(): null {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (fetchBlockNumber > latestBlockNumber) {
|
||||
dispatch(updateBlockNumber({ chainId, blockNumber: fetchBlockNumber }))
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
if (error.isCancelledError) {
|
||||
console.debug('Cancelled fetch for blockNumber', latestBlockNumber)
|
||||
console.debug('Cancelled fetch for blockNumber', latestBlockNumber, chunk, chainId)
|
||||
return
|
||||
}
|
||||
console.error('Failed to fetch multicall chunk', chunk, chainId, error)
|
||||
|
||||
22
src/theme/RadialGradientByChainUpdater.ts
Normal file
22
src/theme/RadialGradientByChainUpdater.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useEffect } from 'react'
|
||||
import { SupportedChainId } from '../constants/chains'
|
||||
import { useActiveWeb3React } from '../hooks/web3'
|
||||
|
||||
const backgroundRadialGradientElement = document.getElementById('background-radial-gradient')
|
||||
export default function RadialGradientByChainUpdater(): null {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
// manage background color
|
||||
useEffect(() => {
|
||||
if (!backgroundRadialGradientElement) {
|
||||
return
|
||||
}
|
||||
|
||||
if (chainId === SupportedChainId.ARBITRUM_ONE) {
|
||||
backgroundRadialGradientElement.style.background =
|
||||
'radial-gradient(96.19% 96.19% at 50% -5.43%, hsla(204, 87%, 55%, 0.2) 0%, hsla(227, 0%, 0%, 0) 100%)'
|
||||
} else {
|
||||
backgroundRadialGradientElement.style.background = ''
|
||||
}
|
||||
}, [chainId])
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user