Compare commits
266 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d989c61de5 | ||
|
|
5dd8059734 | ||
|
|
b50e5511ea | ||
|
|
1efe5e9cd5 | ||
|
|
2944dc4d0b | ||
|
|
29ae755f2a | ||
|
|
27b831b301 | ||
|
|
6d9d38819e | ||
|
|
2de29129ed | ||
|
|
52af0e506b | ||
|
|
4d69c946bf | ||
|
|
542bf0bf66 | ||
|
|
a4fbfae4ba | ||
|
|
b2288258f2 | ||
|
|
8703013b2d | ||
|
|
4f6173675d | ||
|
|
2469eb58b9 | ||
|
|
e0a8ac2408 | ||
|
|
0a736b5e62 | ||
|
|
b44eb8877c | ||
|
|
92e61fa34b | ||
|
|
ef62fd33b2 | ||
|
|
96a42f66d4 | ||
|
|
c446f20d2f | ||
|
|
5a1ef8fb7d | ||
|
|
2863971640 | ||
|
|
dcaf10ec29 | ||
|
|
bca5113569 | ||
|
|
6779c1a024 | ||
|
|
f79ef12494 | ||
|
|
7bcda46934 | ||
|
|
f4ba24cfd5 | ||
|
|
59c6ab16dd | ||
|
|
db17dcbf2c | ||
|
|
1835de7f5f | ||
|
|
00f158209c | ||
|
|
2108ceedd5 | ||
|
|
ad080470da | ||
|
|
fc34912b53 | ||
|
|
c25d2b894c | ||
|
|
83c99b8c04 | ||
|
|
ccdf1e7575 | ||
|
|
c9faafee5e | ||
|
|
26a44fb51b | ||
|
|
1e16ac8449 | ||
|
|
5b5e76573d | ||
|
|
27cdbd0d5f | ||
|
|
b2a30b9bf1 | ||
|
|
dfad7b89ab | ||
|
|
4fe35ea42e | ||
|
|
0d852b6165 | ||
|
|
8ac3b836bd | ||
|
|
12bc5957b4 | ||
|
|
a33187c33b | ||
|
|
248bc07cf1 | ||
|
|
369f8c94e3 | ||
|
|
de5f0541ee | ||
|
|
48b3efc612 | ||
|
|
90c59f31f3 | ||
|
|
0e709c257b | ||
|
|
7a3bb8de1d | ||
|
|
8018d1b9dc | ||
|
|
1297aa57d3 | ||
|
|
30e30189e1 | ||
|
|
6a602cf6d7 | ||
|
|
4c966caa2a | ||
|
|
a60ea703b0 | ||
|
|
ae664dc264 | ||
|
|
b152b11515 | ||
|
|
0f51991109 | ||
|
|
da8884d87d | ||
|
|
79bdc0c5ee | ||
|
|
82c30681ea | ||
|
|
41ef961679 | ||
|
|
7de63ab462 | ||
|
|
59c5989721 | ||
|
|
b042d2b3b4 | ||
|
|
897e7f4581 | ||
|
|
a7fb7dc906 | ||
|
|
5fe89b9d6c | ||
|
|
acbcd3763c | ||
|
|
01c467b48c | ||
|
|
636abe3b7b | ||
|
|
8404c6076c | ||
|
|
b4aac94c2c | ||
|
|
f47fcc9c17 | ||
|
|
b5d27e2063 | ||
|
|
26275ca580 | ||
|
|
92b7ca8f55 | ||
|
|
c5ea01ce19 | ||
|
|
88712b5065 | ||
|
|
1af34ae016 | ||
|
|
9cb19dd0ea | ||
|
|
02a77254c7 | ||
|
|
69ed7015ab | ||
|
|
ff16d3f18f | ||
|
|
5175cb6d1f | ||
|
|
b33686855d | ||
|
|
75ecc5810e | ||
|
|
c30eb89725 | ||
|
|
108feace02 | ||
|
|
e2c013a4d8 | ||
|
|
66308257d6 | ||
|
|
fd160531cc | ||
|
|
da36e638c2 | ||
|
|
fad55b8dbc | ||
|
|
c9c59698de | ||
|
|
828967031f | ||
|
|
440ac0cba0 | ||
|
|
b5a72cd63b | ||
|
|
37f273aab4 | ||
|
|
3acd993ec0 | ||
|
|
58778b5775 | ||
|
|
5bc21bebc3 | ||
|
|
c3d6727438 | ||
|
|
290f4bc1cb | ||
|
|
f95275d5ac | ||
|
|
0ec2dd4173 | ||
|
|
3b3db6f6d0 | ||
|
|
707abd0071 | ||
|
|
2efc1fb372 | ||
|
|
55b37825f3 | ||
|
|
bb27b7a2ef | ||
|
|
c595ba951b | ||
|
|
96a122d7b8 | ||
|
|
610f7d3581 | ||
|
|
781e774ce7 | ||
|
|
2aa1e40481 | ||
|
|
1c278d5012 | ||
|
|
a323a5c48b | ||
|
|
43931dd689 | ||
|
|
efa3d5529c | ||
|
|
5c0246cfc6 | ||
|
|
ee32418ff8 | ||
|
|
6e22389791 | ||
|
|
8064dd8ede | ||
|
|
921310ef52 | ||
|
|
7b90fe137e | ||
|
|
05b2711a8a | ||
|
|
d060782242 | ||
|
|
e19e8492c9 | ||
|
|
800b5e0bda | ||
|
|
fc637071f9 | ||
|
|
1b78ceec10 | ||
|
|
e5be3ebf8f | ||
|
|
1c73719766 | ||
|
|
14c91f9bba | ||
|
|
4b762ef5c9 | ||
|
|
c82b4fae64 | ||
|
|
ab8c1e3e90 | ||
|
|
7055d60406 | ||
|
|
c641cec651 | ||
|
|
b6a47c734f | ||
|
|
7aecf5d398 | ||
|
|
5bf2b81743 | ||
|
|
ed247065a7 | ||
|
|
0d0ad633fb | ||
|
|
4a8f1d9b96 | ||
|
|
043fb95d22 | ||
|
|
06536bc925 | ||
|
|
a598a15799 | ||
|
|
b0265c081e | ||
|
|
47aff6ff74 | ||
|
|
56717005e6 | ||
|
|
b50d10cbb2 | ||
|
|
ce96873a72 | ||
|
|
779625a04e | ||
|
|
d1e0812684 | ||
|
|
98e62b4f93 | ||
|
|
9fb0d424c2 | ||
|
|
8d145b908e | ||
|
|
c7633d910b | ||
|
|
1f89a46a3f | ||
|
|
8d54b01878 | ||
|
|
ffe334ccbf | ||
|
|
ffe2bd315e | ||
|
|
cee4b8c77a | ||
|
|
3153db9f73 | ||
|
|
bbdb5f3f56 | ||
|
|
7f9c56b68c | ||
|
|
2b69974fdc | ||
|
|
5236065769 | ||
|
|
52128a2dcd | ||
|
|
c9642c6cd0 | ||
|
|
b878d764e5 | ||
|
|
6a4f067ac0 | ||
|
|
e9407bb6bd | ||
|
|
8d822fd0e0 | ||
|
|
6404ee6e0b | ||
|
|
8ac3ed1128 | ||
|
|
b501974a76 | ||
|
|
567fb0181c | ||
|
|
8a37c427e6 | ||
|
|
034b3e3e58 | ||
|
|
053000e5fc | ||
|
|
b77e7deb49 | ||
|
|
c3321ae793 | ||
|
|
5dec0cf72b | ||
|
|
1efda07e7a | ||
|
|
fd819260f9 | ||
|
|
8e3b2cb4b8 | ||
|
|
d54783a324 | ||
|
|
850a20f6ad | ||
|
|
99f681818f | ||
|
|
1127e74357 | ||
|
|
27843f6189 | ||
|
|
1b10c88c51 | ||
|
|
5d97cbf6ad | ||
|
|
064a73ca1b | ||
|
|
e5a1cb4276 | ||
|
|
e68e1afd9d | ||
|
|
8784a761d6 | ||
|
|
7aa0f500d6 | ||
|
|
06a8151ede | ||
|
|
ac2642fedc | ||
|
|
ac962fb00d | ||
|
|
f3bcf64144 | ||
|
|
711b2ca85c | ||
|
|
aa97ec01d3 | ||
|
|
83b70f3aa6 | ||
|
|
e37dd77680 | ||
|
|
aa37b23126 | ||
|
|
5a90f13a03 | ||
|
|
8c213f9001 | ||
|
|
5722902f96 | ||
|
|
27412e49d5 | ||
|
|
90dfdc6bef | ||
|
|
4f896361be | ||
|
|
c9bc166c1a | ||
|
|
cecbf770c6 | ||
|
|
a7041ea700 | ||
|
|
5413303d24 | ||
|
|
103e18496f | ||
|
|
0e678465cb | ||
|
|
6b68baaa4d | ||
|
|
3c5e3744f1 | ||
|
|
d93b6f795e | ||
|
|
f145a56f4a | ||
|
|
7622290557 | ||
|
|
226544402a | ||
|
|
49fee909bc | ||
|
|
f458ec8e12 | ||
|
|
f9fc506db4 | ||
|
|
5b7a80d10d | ||
|
|
db8dab4559 | ||
|
|
7cc1b899ea | ||
|
|
339a35cb1b | ||
|
|
e2bd8020f3 | ||
|
|
571a932d6e | ||
|
|
3923438011 | ||
|
|
4ed9c7ba94 | ||
|
|
1ead35e782 | ||
|
|
0af516b884 | ||
|
|
13c42a384b | ||
|
|
458e04f94c | ||
|
|
587edf46ea | ||
|
|
768f7659d2 | ||
|
|
96db27722b | ||
|
|
f047f0d196 | ||
|
|
7ac1ed3f52 | ||
|
|
205412fe1e | ||
|
|
43e1fe9764 | ||
|
|
e9a9dd9779 | ||
|
|
fa3325b7e4 | ||
|
|
19aa7173ab | ||
|
|
a3238c701a |
1
.env
@@ -1 +1,2 @@
|
||||
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_LOCALES="locales"
|
||||
@@ -58,10 +58,6 @@
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"name": "lodash",
|
||||
"message": "Please import from 'lodash/module' directly to support tree-shaking."
|
||||
},
|
||||
{
|
||||
"name": "ethers",
|
||||
"message": "Please import from '@ethersproject/module' directly to support tree-shaking."
|
||||
|
||||
40
.github/workflows/bundle.yaml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Widgets
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn widgets:build
|
||||
2
.github/workflows/integration-tests.yaml
vendored
@@ -38,10 +38,10 @@ jobs:
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- run: yarn cypress install
|
||||
|
||||
- run: yarn build
|
||||
env:
|
||||
CI: false
|
||||
REACT_APP_NETWORK_URL: 'https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847'
|
||||
REACT_APP_SERVICE_WORKER: false
|
||||
|
||||
- run: yarn test:e2e
|
||||
|
||||
10
.gitignore
vendored
@@ -3,8 +3,12 @@
|
||||
# generated contract types
|
||||
/src/types/v3
|
||||
/src/abis/types
|
||||
/src/lib/locales/**/*.js
|
||||
/src/lib/locales/**/en-US.po
|
||||
/src/lib/locales/**/pseudo.po
|
||||
/src/locales/**/*.js
|
||||
/src/locales/**/en-US.po
|
||||
/src/locales/**/pseudo.po
|
||||
/src/state/data/generated.ts
|
||||
|
||||
# dependencies
|
||||
@@ -13,11 +17,11 @@
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
# builds
|
||||
/build
|
||||
|
||||
# bundle
|
||||
/cosmos-export
|
||||
/dist
|
||||
/dts
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@@ -73,4 +73,4 @@ We sync to the repository on a schedule, rather than download translations at bu
|
||||
|
||||
You can contribute by joining Crowdin to proofread existing translations [here](https://crowdin.com/project/uniswap-interface/invite?d=93i5n413q403t4g473p443o4c3t2g3s21343u2c3n403l4b3v2735353i4g4k4l4g453j4g4o4j4e4k4b323l4a3h463s4g453q443m4e3t2b303s2a35353l403o443v293e303k4g4n4r4g483i4g4r4j4e4o473i5n4a3t463t4o4)
|
||||
|
||||
Or, ask to join us as a translator in the Discord!
|
||||
Or, ask to join us as a translator in the Discord!!
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"staticPath": "public",
|
||||
"watchDirs": ["src"],
|
||||
"watchDirs": [
|
||||
"src"
|
||||
],
|
||||
"webpack": {
|
||||
"configPath": "react-scripts/config/webpack.config"
|
||||
}
|
||||
"configPath": "react-scripts/config/webpack.config",
|
||||
"overridePath": "cosmos.override.cjs"
|
||||
},
|
||||
"port": 5001
|
||||
}
|
||||
|
||||
26
cosmos.override.cjs
Normal file
@@ -0,0 +1,26 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { DefinePlugin } = require('webpack')
|
||||
|
||||
// Renders the cosmos fixtures in isolation, instead of using public/index.html.
|
||||
module.exports = (webpackConfig) => ({
|
||||
...webpackConfig,
|
||||
plugins: webpackConfig.plugins.map((plugin) => {
|
||||
if (plugin instanceof HtmlWebpackPlugin) {
|
||||
return new HtmlWebpackPlugin({
|
||||
templateContent: '<body></body>',
|
||||
})
|
||||
}
|
||||
if (plugin instanceof DefinePlugin) {
|
||||
return new DefinePlugin({
|
||||
...plugin.definitions,
|
||||
'process.env': {
|
||||
...plugin.definitions['process.env'],
|
||||
REACT_APP_IS_WIDGET: true,
|
||||
REACT_APP_LOCALES: '"../locales"',
|
||||
},
|
||||
})
|
||||
}
|
||||
return plugin
|
||||
}),
|
||||
})
|
||||
@@ -2,16 +2,27 @@ describe('Swap', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/swap')
|
||||
})
|
||||
|
||||
it('starts with an ETH/USDC swap and quotes it', () => {
|
||||
cy.get('#swap-currency-input .token-amount-input').should('have.value', '1')
|
||||
cy.get('#swap-currency-input .token-symbol-container').should('contain.text', 'ETH')
|
||||
cy.get('#swap-currency-output .token-amount-input').should('not.have.value', '')
|
||||
cy.get('#swap-currency-output .token-symbol-container').should('contain.text', 'USDC')
|
||||
})
|
||||
|
||||
it('can enter an amount into input', () => {
|
||||
cy.get('#swap-currency-input .token-amount-input').type('0.001', { delay: 200 }).should('have.value', '0.001')
|
||||
cy.get('#swap-currency-input .token-amount-input')
|
||||
.clear()
|
||||
.type('0.001', { delay: 200 })
|
||||
.should('have.value', '0.001')
|
||||
})
|
||||
|
||||
it('zero swap amount', () => {
|
||||
cy.get('#swap-currency-input .token-amount-input').type('0.0', { delay: 200 }).should('have.value', '0.0')
|
||||
cy.get('#swap-currency-input .token-amount-input').clear().type('0.0', { delay: 200 }).should('have.value', '0.0')
|
||||
})
|
||||
|
||||
it('invalid swap amount', () => {
|
||||
cy.get('#swap-currency-input .token-amount-input').type('\\', { delay: 200 }).should('have.value', '')
|
||||
cy.get('#swap-currency-input .token-amount-input').clear().type('\\', { delay: 200 }).should('have.value', '')
|
||||
})
|
||||
|
||||
it('can enter an amount into output', () => {
|
||||
|
||||
@@ -46,11 +46,13 @@ const linguiConfig = {
|
||||
'vi-VN',
|
||||
'zh-CN',
|
||||
'zh-TW',
|
||||
'pseudo',
|
||||
],
|
||||
orderBy: 'messageId',
|
||||
rootDir: '.',
|
||||
runtimeConfigModule: ['@lingui/core', 'i18n'],
|
||||
sourceLocale: 'en-US',
|
||||
pseudoLocale: 'pseudo',
|
||||
}
|
||||
|
||||
export default linguiConfig
|
||||
|
||||
180
package.json
@@ -1,31 +1,57 @@
|
||||
{
|
||||
"name": "@uniswap/interface",
|
||||
"name": "@uniswap/widgets",
|
||||
"version": "0.0.21-beta",
|
||||
"description": "Uniswap Interface",
|
||||
"homepage": ".",
|
||||
"main": "dist/interface.js",
|
||||
"module": "dist/interface.esm.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"lib",
|
||||
"dist"
|
||||
],
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"types": "dist/index.d.ts",
|
||||
"main": "dist/cjs/index.cjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/cjs/index.cjs"
|
||||
},
|
||||
"./locales/*": {
|
||||
"import": "./dist/locales/*.js",
|
||||
"require": "./dist/cjs/locales/*.cjs"
|
||||
},
|
||||
"./fonts.css": {
|
||||
"import": "./dist/fonts.css",
|
||||
"require": "./dist/fonts.css"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@gnosis.pm/safe-apps-web3-react": "^0.6.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/core": "^3.9.0",
|
||||
"@lingui/macro": "^3.9.0",
|
||||
"@lingui/react": "^3.9.0",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@reach/dialog": "^0.10.3",
|
||||
"@reach/portal": "^0.10.3",
|
||||
"@react-hook/window-scroll": "^1.3.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@rollup/plugin-alias": "^3.1.9",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^21.0.1",
|
||||
"@rollup/plugin-eslint": "^8.0.1",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@rollup/plugin-replace": "^3.0.1",
|
||||
"@rollup/plugin-typescript": "^8.3.0",
|
||||
"@rollup/plugin-url": "^6.1.0",
|
||||
"@svgr/rollup": "^6.2.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@testing-library/react-hooks": "^7.0.2",
|
||||
@@ -54,90 +80,84 @@
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^4.1.0",
|
||||
"@uniswap/default-token-list": "^3.0.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "1.0.1",
|
||||
"@uniswap/redux-multicall": "^1.0.0",
|
||||
"@uniswap/router-sdk": "^1.0.1",
|
||||
"@uniswap/sdk-core": "^3.0.1",
|
||||
"@uniswap/smart-order-router": "^2.5.4",
|
||||
"@uniswap/token-lists": "^1.0.0-beta.27",
|
||||
"@uniswap/v2-core": "1.0.0",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^3.0.1",
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.7.1",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
"@web3-react/portis-connector": "^6.0.9",
|
||||
"@web3-react/walletconnect-connector": "^7.0.2-alpha.0",
|
||||
"@web3-react/walletlink-connector": "^6.2.8",
|
||||
"ajv": "^6.12.3",
|
||||
"@web3-react/metamask": "8.0.13-beta.0",
|
||||
"@web3-react/walletconnect": "8.0.18-beta.0",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"cids": "^1.0.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^7.7.0",
|
||||
"d3": "^7.0.0",
|
||||
"eslint": "^7.11.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-better-styled-components": "^1.1.2",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-plugin-react-hooks": "^4.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"ethers": "^5.4.6",
|
||||
"firebase": "^9.1.3",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
"inter-ui": "^3.13.1",
|
||||
"jest-styled-components": "^7.0.5",
|
||||
"microbundle": "^0.13.3",
|
||||
"ms.macro": "^2.0.0",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashes": "^4.0.2",
|
||||
"node-vibrant": "^3.2.1-alpha.1",
|
||||
"polished": "^3.3.2",
|
||||
"polyfill-object.fromentries": "^1.0.1",
|
||||
"prettier": "^2.2.1",
|
||||
"qs": "^6.9.4",
|
||||
"react": "^17.0.1",
|
||||
"react-confetti": "^6.0.0",
|
||||
"react-cosmos": "^5.6.3",
|
||||
"react-cosmos": "^5.6.6",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-ga": "^2.5.7",
|
||||
"react-is": "^17.0.2",
|
||||
"react-markdown": "^4.3.1",
|
||||
"react-popper": "^2.2.3",
|
||||
"react-redux": "^7.2.2",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-use-gesture": "^6.0.14",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
"rebass": "^4.0.7",
|
||||
"redux": "^4.1.2",
|
||||
"redux-localstorage-simple": "^2.3.1",
|
||||
"rollup": "^2.63.0",
|
||||
"rollup-plugin-copy": "^3.4.0",
|
||||
"rollup-plugin-delete": "^2.0.0",
|
||||
"rollup-plugin-dts": "^4.1.0",
|
||||
"rollup-plugin-multi-input": "^1.3.1",
|
||||
"rollup-plugin-node-externals": "^3.1.2",
|
||||
"rollup-plugin-scss": "^3.0.0",
|
||||
"rollup-plugin-typescript2": "^0.31.1",
|
||||
"sass": "^1.45.1",
|
||||
"serve": "^11.3.2",
|
||||
"start-server-and-test": "^1.11.0",
|
||||
"styled-components": "^5.3.0",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.2.3",
|
||||
"typescript": "^4.4.3",
|
||||
"ua-parser-js": "^0.7.28",
|
||||
"use-count-up": "^2.2.5",
|
||||
"use-resize-observer": "^8.0.0",
|
||||
"wcag-contrast": "^3.0.0",
|
||||
"web-vitals": "^2.1.0",
|
||||
"web3-react-abstract-connector": "npm:@web3-react/abstract-connector@^6.0.7",
|
||||
"web3-react-fortmatic-connector": "npm:@web3-react/fortmatic-connector@^6.0.9",
|
||||
"web3-react-injected-connector": "npm:@web3-react/injected-connector@^6.0.7",
|
||||
"web3-react-portis-connector": "npm:@web3-react/portis-connector@^6.0.9",
|
||||
"web3-react-types": "npm:@web3-react/types@^6.0.7",
|
||||
"web3-react-walletconnect-connector": "npm:@web3-react/walletconnect-connector@^7.0.2-alpha.0",
|
||||
"web3-react-walletlink-connector": "npm:@web3-react/walletlink-connector@^6.2.13",
|
||||
"workbox-core": "^6.1.0",
|
||||
"workbox-precaching": "^6.1.0",
|
||||
"workbox-routing": "^6.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@walletconnect/ethereum-provider": "1.6.5"
|
||||
"@walletconnect/ethereum-provider": "1.7.1"
|
||||
},
|
||||
"scripts": {
|
||||
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"",
|
||||
@@ -147,13 +167,15 @@
|
||||
"prei18n:extract": "touch src/locales/en-US.po",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "yarn i18n:extract && lingui compile",
|
||||
"postinstall": "yarn contracts:compile && yarn graphql:generate && yarn i18n:compile",
|
||||
"i18n:pseudo": "lingui extract --locale pseudo && lingui compile",
|
||||
"prepare": "yarn contracts:compile && yarn graphql:generate && yarn i18n:compile",
|
||||
"prepublishOnly": "yarn widgets:build",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=./custom-test-env.js",
|
||||
"test": "react-scripts test --env=./custom-test-env.cjs",
|
||||
"test:e2e": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
|
||||
"bundle": "microbundle --tsconfig tsconfig.lib.json src/lib/index.tsx --format esm,cjs",
|
||||
"cosmos": "open http://localhost:5000 && cross-env FAST_REFRESH=false cosmos"
|
||||
"widgets:start": "cosmos",
|
||||
"widgets:build": "rollup --config --failAfterWarnings --configPlugin typescript2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -168,5 +190,73 @@
|
||||
]
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {}
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.17.0",
|
||||
"@ethersproject/abi": "^5.4.1",
|
||||
"@ethersproject/abstract-provider": "^5.4.1",
|
||||
"@ethersproject/abstract-signer": "^5.4.1",
|
||||
"@ethersproject/address": "^5.4.0",
|
||||
"@ethersproject/bignumber": "^5.4.2",
|
||||
"@ethersproject/bytes": "^5.4.0",
|
||||
"@ethersproject/constants": "^5.4.0",
|
||||
"@ethersproject/contracts": "^5.4.1",
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@ethersproject/hash": "^5.4.0",
|
||||
"@ethersproject/providers": "^5.4.0",
|
||||
"@ethersproject/solidity": "^5.4.0",
|
||||
"@ethersproject/strings": "^5.4.0",
|
||||
"@ethersproject/units": "^5.4.0",
|
||||
"@ethersproject/wallet": "^5.4.0",
|
||||
"@fontsource/ibm-plex-mono": "^4.5.1",
|
||||
"@fontsource/inter": "^4.5.1",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@uniswap/redux-multicall": "^1.0.0",
|
||||
"@uniswap/router-sdk": "^1.0.3",
|
||||
"@uniswap/sdk-core": "^3.0.1",
|
||||
"@uniswap/smart-order-router": "^2.5.10",
|
||||
"@uniswap/token-lists": "^1.0.0-beta.27",
|
||||
"@uniswap/v2-sdk": "^3.0.1",
|
||||
"@uniswap/v3-sdk": "^3.8.2",
|
||||
"@web3-react/core": "8.0.17-beta.0",
|
||||
"@web3-react/eip1193": "8.0.12-beta.0",
|
||||
"@web3-react/empty": "8.0.10-beta.0",
|
||||
"@web3-react/types": "8.0.10-beta.0",
|
||||
"@web3-react/url": "8.0.12-beta.0",
|
||||
"ajv": "^6.12.3",
|
||||
"cids": "^1.0.0",
|
||||
"immer": "^9.0.6",
|
||||
"jotai": "^1.3.7",
|
||||
"jsbi": "^3.1.4",
|
||||
"make-plural": "^7.0.0",
|
||||
"ms.macro": "^2.0.0",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashes": "^4.0.2",
|
||||
"node-vibrant": "^3.2.1-alpha.1",
|
||||
"polished": "^3.3.2",
|
||||
"popper-max-size-modifier": "^0.2.0",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-popper": "^2.2.3",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
"rebass": "^4.0.7",
|
||||
"setimmediate": "^1.0.5",
|
||||
"styled-components": "^5.3.0",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
"wcag-contrast": "^3.0.0",
|
||||
"web3-react-core": "npm:@web3-react/core@^6.0.9",
|
||||
"wicg-inert": "^3.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/runtime": "^7.17.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-redux": "^7.2.2",
|
||||
"redux": "^4.1.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.6",
|
||||
"encoding": "^0.1.13",
|
||||
"utf-8-validate": "^5.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
176
rollup.config.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Bundles the widgets library, which is released independently of the interface application.
|
||||
* This library lives in src/lib, but shares code with the interface application.
|
||||
*/
|
||||
|
||||
import alias from '@rollup/plugin-alias'
|
||||
import babel from '@rollup/plugin-babel'
|
||||
import commonjs from '@rollup/plugin-commonjs'
|
||||
import json from '@rollup/plugin-json'
|
||||
import resolve from '@rollup/plugin-node-resolve'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import typescript from '@rollup/plugin-typescript'
|
||||
import url from '@rollup/plugin-url'
|
||||
import svgr from '@svgr/rollup'
|
||||
import path from 'path'
|
||||
import { RollupWarning } from 'rollup'
|
||||
import copy from 'rollup-plugin-copy'
|
||||
import del from 'rollup-plugin-delete'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
// @ts-ignore // missing types
|
||||
import multi from 'rollup-plugin-multi-input'
|
||||
import externals from 'rollup-plugin-node-externals'
|
||||
import sass from 'rollup-plugin-scss'
|
||||
import { CompilerOptions } from 'typescript'
|
||||
|
||||
const REPLACEMENTS = {
|
||||
'process.env.REACT_APP_IS_WIDGET': true,
|
||||
'process.env.REACT_APP_LOCALES': '"./locales"',
|
||||
// esm requires fully-specified paths:
|
||||
'react/jsx-runtime': 'react/jsx-runtime.js',
|
||||
}
|
||||
|
||||
const EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx']
|
||||
const ASSET_EXTENSIONS = ['.png', '.svg']
|
||||
function isAsset(source: string) {
|
||||
const extname = path.extname(source)
|
||||
return extname && [...ASSET_EXTENSIONS, '.css', '.scss'].includes(extname)
|
||||
}
|
||||
|
||||
const TS_CONFIG = './tsconfig.lib.json'
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { baseUrl, paths }: CompilerOptions = require(TS_CONFIG).compilerOptions
|
||||
const aliases = Object.entries({ ...paths }).flatMap(([find, replacements]) => {
|
||||
return replacements.map((replacement) => ({
|
||||
find: path.dirname(find),
|
||||
replacement: path.join(__dirname, baseUrl || '.', path.dirname(replacement)),
|
||||
}))
|
||||
})
|
||||
|
||||
const plugins = [
|
||||
// Dependency resolution
|
||||
resolve({ extensions: EXTENSIONS }), // resolves third-party modules within node_modules/
|
||||
alias({ entries: aliases }), // resolves paths aliased through the tsconfig (babel does not use tsconfig path resolution)
|
||||
|
||||
// Source code transformation
|
||||
replace({ ...REPLACEMENTS, preventAssignment: true }),
|
||||
json(), // imports json as ES6; doing so enables type-checking and module resolution
|
||||
]
|
||||
|
||||
const check = {
|
||||
input: 'src/lib/index.tsx',
|
||||
output: { file: 'dist/widgets.tsc', inlineDynamicImports: true },
|
||||
external: isAsset,
|
||||
plugins: [
|
||||
externals({ exclude: ['constants'], deps: true, peerDeps: true }), // marks builtins, dependencies, and peerDependencies external
|
||||
...plugins,
|
||||
typescript({ tsconfig: TS_CONFIG }),
|
||||
],
|
||||
onwarn: squelchTranspilationWarnings, // this pipeline is only for typechecking and generating definitions
|
||||
}
|
||||
|
||||
const type = {
|
||||
input: 'dist/dts/lib/index.d.ts',
|
||||
output: { file: 'dist/index.d.ts' },
|
||||
external: isAsset,
|
||||
plugins: [
|
||||
externals({ exclude: ['constants'], deps: true, peerDeps: true }),
|
||||
dts({ compilerOptions: { baseUrl: 'dist/dts' } }),
|
||||
process.env.ROLLUP_WATCH ? undefined : del({ hook: 'buildEnd', targets: ['dist/widgets.tsc', 'dist/dts'] }),
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* This exports scheme works for nextjs and for CRA5.
|
||||
*
|
||||
* It will also work for CRA4 if you use direct imports:
|
||||
* instead of `import { SwapWidget } from '@uniswap/widgets'`,
|
||||
* `import { SwapWidget } from '@uniswap/widgets/dist/index.js'`.
|
||||
* I do not know why CRA4 does not seem to use exports for resolution.
|
||||
*
|
||||
* Note that chunks are enabled. This is so the tokenlist spec can be loaded async,
|
||||
* to improve first load time (due to ajv). Locales are also in separate chunks.
|
||||
*
|
||||
* Lastly, note that JSON and lingui are bundled into the library, as neither are fully
|
||||
* supported/compatible with ES Modules. Both _could_ be bundled only with esm, but this
|
||||
* yields a less complex pipeline.
|
||||
*/
|
||||
|
||||
const transpile = {
|
||||
input: 'src/lib/index.tsx',
|
||||
output: [
|
||||
{
|
||||
dir: 'dist',
|
||||
format: 'esm',
|
||||
sourcemap: false,
|
||||
},
|
||||
{
|
||||
dir: 'dist/cjs',
|
||||
entryFileNames: '[name].cjs',
|
||||
chunkFileNames: '[name]-[hash].cjs',
|
||||
format: 'cjs',
|
||||
sourcemap: false,
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
externals({
|
||||
exclude: [
|
||||
'constants',
|
||||
/@lingui\/(core|react)/, // @lingui incorrectly exports esm, so it must be bundled in
|
||||
/\.json$/, // esm does not support JSON loading, so it must be bundled in
|
||||
],
|
||||
deps: true,
|
||||
peerDeps: true,
|
||||
}),
|
||||
...plugins,
|
||||
|
||||
// Source code transformation
|
||||
url({ include: ASSET_EXTENSIONS.map((extname) => '**/*' + extname), limit: Infinity }), // imports assets as data URIs
|
||||
svgr({ exportType: 'named', svgo: false }), // imports svgs as React components
|
||||
sass({ output: 'dist/fonts.css' }), // generates fonts.css
|
||||
commonjs(), // transforms cjs dependencies into tree-shakeable ES modules
|
||||
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
presets: ['@babel/preset-env', ['@babel/preset-react', { runtime: 'automatic' }], '@babel/preset-typescript'],
|
||||
extensions: EXTENSIONS,
|
||||
plugins: [
|
||||
'macros', // enables @lingui and styled-components macros
|
||||
'@babel/plugin-transform-runtime', // embeds the babel runtime for library distribution
|
||||
],
|
||||
}),
|
||||
],
|
||||
onwarn: squelchTypeWarnings, // this pipeline is only for transpilation
|
||||
}
|
||||
|
||||
const locales = {
|
||||
input: 'src/locales/*.js',
|
||||
output: [
|
||||
{
|
||||
dir: 'dist',
|
||||
format: 'esm',
|
||||
sourcemap: false,
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
copy({
|
||||
copyOnce: true,
|
||||
targets: [{ src: 'src/locales/*.js', dest: 'dist/cjs/locales', rename: (name) => `${name}.cjs` }],
|
||||
}),
|
||||
commonjs(),
|
||||
multi(),
|
||||
],
|
||||
}
|
||||
|
||||
const config = [check, type, transpile, locales]
|
||||
export default config
|
||||
|
||||
function squelchTranspilationWarnings(warning: RollupWarning, warn: (warning: RollupWarning) => void) {
|
||||
if (warning.pluginCode === 'TS5055') return
|
||||
warn(warning)
|
||||
}
|
||||
|
||||
function squelchTypeWarnings(warning: RollupWarning, warn: (warning: RollupWarning) => void) {
|
||||
if (warning.code === 'UNUSED_EXTERNAL_IMPORT') return
|
||||
warn(warning)
|
||||
}
|
||||
BIN
src/assets/images/santa-hat.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
9
src/assets/images/survey-orb.svg
Normal file
|
After Width: | Height: | Size: 572 KiB |
BIN
src/assets/images/ukraine.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg width="100%" height="35" viewBox="800 0 300 200" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="0" x2="2000" y1="100" y2="100" stroke="currentColor" stroke-width="20" stroke-linecap="round" stroke-dasharray="1, 45"/>
|
||||
<svg width="100%" height="35" viewBox="850 0 300 200" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="0" x2="3000" y1="100" y2="100" stroke="currentColor" stroke-width="20" stroke-linecap="round" stroke-dasharray="1, 45"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 233 B After Width: | Height: | Size: 233 B |
4
src/assets/svg/matic-token-icon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="512" cy="512" r="512" fill="#8247E5"/>
|
||||
<path d="M681.469 402.456C669.189 395.312 653.224 395.312 639.716 402.456L543.928 457.228L478.842 492.949L383.055 547.721C370.774 554.865 354.81 554.865 341.301 547.721L265.162 504.856C252.882 497.712 244.286 484.614 244.286 470.325V385.786C244.286 371.498 251.654 358.4 265.162 351.256L340.073 309.581C352.353 302.437 368.318 302.437 381.827 309.581L456.737 351.256C469.018 358.4 477.614 371.498 477.614 385.786V440.558L542.7 403.646V348.874C542.7 334.586 535.332 321.488 521.824 314.344L383.055 235.758C370.774 228.614 354.81 228.614 341.301 235.758L200.076 314.344C186.567 321.488 179.199 334.586 179.199 348.874V507.237C179.199 521.525 186.567 534.623 200.076 541.767L341.301 620.353C353.582 627.498 369.546 627.498 383.055 620.353L478.842 566.772L543.928 529.86L639.716 476.279C651.996 469.135 667.961 469.135 681.469 476.279L756.38 517.953C768.66 525.098 777.257 538.195 777.257 552.484V637.023C777.257 651.312 769.888 664.409 756.38 671.553L681.469 714.419C669.189 721.563 653.224 721.563 639.716 714.419L564.805 672.744C552.525 665.6 543.928 652.502 543.928 638.214V583.442L478.842 620.353V675.125C478.842 689.414 486.21 702.512 499.719 709.656L640.944 788.242C653.224 795.386 669.189 795.386 682.697 788.242L823.922 709.656C836.203 702.512 844.799 689.414 844.799 675.125V516.763C844.799 502.474 837.431 489.377 823.922 482.232L681.469 402.456Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,16 +1,5 @@
|
||||
<svg width="170" height="168" viewBox="0 0 170 168" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path opacity="0.6" d="M85.05 168C132.022 168 170.1 130.105 170.1 83.3593C170.1 36.6135 0 36.6135 0 83.3593C0 130.105 38.0782 168 85.05 168Z" fill="#FF505F"/>
|
||||
<path opacity="0.6" d="M85.05 168C132.022 168 170.1 130.105 170.1 83.3593C170.1 36.6135 0 36.6135 0 83.3593C0 130.105 38.0782 168 85.05 168Z" fill="#FF0320"/>
|
||||
<path d="M85.05 0C132.022 0 170.1 37.8949 170.1 84.6407C170.1 131.386 0 131.386 0 84.6407C0 37.8949 38.0782 0 85.05 0Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.665 64.0394L112.444 12.3742L89.0263 78.9477L144.665 64.0394Z" fill="#FF4E65"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M143.777 64.215L112.444 12.3742L165.349 58.4347L143.777 64.215Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.551 63.613L142.479 124.467L88.912 78.5213L144.551 63.613Z" fill="#D0001A"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M143.663 63.7886L142.479 124.467L165.235 58.0083L143.663 63.7886Z" fill="#FF697B"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="170" height="168" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="250" cy="250" r="250" fill="#FF0420"/>
|
||||
<path d="M177.133 316.446C162.247 316.446 150.051 312.943 140.544 305.938C131.162 298.808 126.471 288.676 126.471 275.541C126.471 272.789 126.784 269.411 127.409 265.408C129.036 256.402 131.35 245.581 134.352 232.947C142.858 198.547 164.812 181.347 200.213 181.347C209.845 181.347 218.476 182.973 226.107 186.225C233.738 189.352 239.742 194.106 244.12 200.486C248.498 206.74 250.688 214.246 250.688 223.002C250.688 225.629 250.375 228.944 249.749 232.947C247.873 244.08 245.621 254.901 242.994 265.408C238.616 282.546 231.048 295.368 220.29 303.874C209.532 312.255 195.147 316.446 177.133 316.446ZM179.76 289.426C186.766 289.426 192.707 287.362 197.586 283.234C202.59 279.106 206.155 272.789 208.281 264.283C211.158 252.524 213.348 242.266 214.849 233.51C215.349 230.883 215.599 228.194 215.599 225.441C215.599 214.058 209.657 208.366 197.774 208.366C190.768 208.366 184.764 210.43 179.76 214.558C174.882 218.687 171.379 225.004 169.253 233.51C167.001 241.891 164.749 252.149 162.498 264.283C161.997 266.784 161.747 269.411 161.747 272.163C161.747 283.672 167.752 289.426 179.76 289.426Z" fill="white"/>
|
||||
<path d="M259.303 314.57C257.927 314.57 256.863 314.132 256.113 313.256C255.487 312.255 255.3 311.13 255.55 309.879L281.444 187.914C281.694 186.538 282.382 185.412 283.508 184.536C284.634 183.661 285.822 183.223 287.073 183.223H336.985C350.87 183.223 362.003 186.1 370.384 191.854C378.891 197.609 383.144 205.927 383.144 216.81C383.144 219.937 382.769 223.19 382.018 226.567C378.891 240.953 372.574 251.586 363.067 258.466C353.685 265.346 340.8 268.786 324.413 268.786H299.082L290.451 309.879C290.2 311.255 289.512 312.38 288.387 313.256C287.261 314.132 286.072 314.57 284.822 314.57H259.303ZM325.727 242.892C330.98 242.892 335.546 241.453 339.424 238.576C343.427 235.699 346.054 231.571 347.305 226.192C347.68 224.065 347.868 222.189 347.868 220.563C347.868 216.935 346.805 214.183 344.678 212.307C342.551 210.305 338.924 209.305 333.795 209.305H311.278L304.148 242.892H325.727Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.1 KiB |
16
src/assets/svg/polygon-matic-logo.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 38.4 33.5" style="enable-background:new 0 0 38.4 33.5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#8247E5;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M29,10.2c-0.7-0.4-1.6-0.4-2.4,0L21,13.5l-3.8,2.1l-5.5,3.3c-0.7,0.4-1.6,0.4-2.4,0L5,16.3
|
||||
c-0.7-0.4-1.2-1.2-1.2-2.1v-5c0-0.8,0.4-1.6,1.2-2.1l4.3-2.5c0.7-0.4,1.6-0.4,2.4,0L16,7.2c0.7,0.4,1.2,1.2,1.2,2.1v3.3l3.8-2.2V7
|
||||
c0-0.8-0.4-1.6-1.2-2.1l-8-4.7c-0.7-0.4-1.6-0.4-2.4,0L1.2,5C0.4,5.4,0,6.2,0,7v9.4c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
|
||||
c0.7,0.4,1.6,0.4,2.4,0l5.5-3.2l3.8-2.2l5.5-3.2c0.7-0.4,1.6-0.4,2.4,0l4.3,2.5c0.7,0.4,1.2,1.2,1.2,2.1v5c0,0.8-0.4,1.6-1.2,2.1
|
||||
L29,28.8c-0.7,0.4-1.6,0.4-2.4,0l-4.3-2.5c-0.7-0.4-1.2-1.2-1.2-2.1V21l-3.8,2.2v3.3c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
|
||||
c0.7,0.4,1.6,0.4,2.4,0l8.1-4.7c0.7-0.4,1.2-1.2,1.2-2.1V17c0-0.8-0.4-1.6-1.2-2.1L29,10.2z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,7 +1,7 @@
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { CheckCircle, Triangle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useAllTransactions } from '../../state/transactions/hooks'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { Fraction, TradeType } from '@uniswap/sdk-core'
|
||||
import JSBI from 'jsbi'
|
||||
|
||||
import { nativeOnChain } from '../../constants/tokens'
|
||||
import { useCurrency, useToken } from '../../hooks/Tokens'
|
||||
import useENSName from '../../hooks/useENSName'
|
||||
import { VoteOption } from '../../state/governance/types'
|
||||
@@ -130,18 +131,33 @@ function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInf
|
||||
return <Trans>Delegate voting power to {ENSName ?? delegatee}</Trans>
|
||||
}
|
||||
|
||||
function WrapSummary({ info: { currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
|
||||
function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
|
||||
const native = chainId ? nativeOnChain(chainId) : undefined
|
||||
|
||||
if (unwrapped) {
|
||||
return (
|
||||
<Trans>
|
||||
Unwrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'WETH'} decimals={18} sigFigs={6} /> to
|
||||
ETH
|
||||
Unwrap{' '}
|
||||
<FormattedCurrencyAmount
|
||||
rawAmount={currencyAmountRaw}
|
||||
symbol={native?.wrapped?.symbol ?? 'WETH'}
|
||||
decimals={18}
|
||||
sigFigs={6}
|
||||
/>{' '}
|
||||
to {native?.symbol ?? 'ETH'}
|
||||
</Trans>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Trans>
|
||||
Wrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'ETH'} decimals={18} sigFigs={6} /> to WETH
|
||||
Wrap{' '}
|
||||
<FormattedCurrencyAmount
|
||||
rawAmount={currencyAmountRaw}
|
||||
symbol={native?.symbol ?? 'ETH'}
|
||||
decimals={18}
|
||||
sigFigs={6}
|
||||
/>{' '}
|
||||
to {native?.wrapped?.symbol ?? 'WETH'}
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { Connector } from '@web3-react/types'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useCallback, useContext } from 'react'
|
||||
import { ExternalLink as LinkIcon } from 'react-feather'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
|
||||
import { ReactComponent as Close } from '../../assets/images/x.svg'
|
||||
import { injected, portis, walletlink } from '../../connectors'
|
||||
import { SUPPORTED_WALLETS } from '../../constants/wallet'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { clearAllTransactions } from '../../state/transactions/actions'
|
||||
import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import { shortenAddress } from '../../utils'
|
||||
@@ -176,7 +177,7 @@ const IconWrapper = styled.div<{ size?: number }>`
|
||||
`};
|
||||
`
|
||||
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<StatusIcon connector={connector} />
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useCallback, useContext } from 'react'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { AutoColumn } from '../Column'
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useMemo } from 'react'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
|
||||
// SDN OFAC addresses
|
||||
const BLOCKED_ADDRESSES: string[] = [
|
||||
'0x7Db418b5D567A4e0E8c59Ad71BE1FcE48f3E6107',
|
||||
@@ -20,6 +19,20 @@ const BLOCKED_ADDRESSES: string[] = [
|
||||
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
|
||||
'0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963',
|
||||
'0x308eD4B7b49797e1A98D3818bFF6fe5385410370',
|
||||
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B',
|
||||
'0x6f1ca141a28907f78ebaa64fb83a9088b02a83',
|
||||
'0x6acdfba02d390b97ac2b2d42a63e85293bcc1',
|
||||
'0x48549a34ae37b12f6a30566245176994e17c6',
|
||||
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121',
|
||||
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e',
|
||||
'0x3cbded43efdaf0fc77b9c55f6fc9988fcc9b757d',
|
||||
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B6b45',
|
||||
'0x6f1ca141a28907f78ebaa64fb83a9088b02a8352',
|
||||
'0x6acdfba02d390b97ac2b2d42a63e85293bcc160e',
|
||||
'0x48549a34ae37b12f6a30566245176994e17c6b4a',
|
||||
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121b0',
|
||||
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e4a',
|
||||
'0x629e7Da20197a5429d30da36E77d06CdF796b71A',
|
||||
]
|
||||
|
||||
export default function Blocklist({ children }: { children: ReactNode }) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export const BaseButton = styled(RebassButton)<
|
||||
border-radius: ${({ $borderRadius }) => $borderRadius ?? '20px'};
|
||||
outline: none;
|
||||
border: 1px solid transparent;
|
||||
color: white;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer, loadingOpacityMixin } from 'components/Loader/styled'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { darken } from 'polished'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { Lock } from 'react-feather'
|
||||
@@ -11,7 +12,6 @@ import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useCurrencyBalance } from '../../state/wallet/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonGray } from '../Button'
|
||||
|
||||
@@ -1,59 +1,18 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import React, { useMemo } from 'react'
|
||||
import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import EthereumLogo from '../../assets/images/ethereum-logo.png'
|
||||
import useHttpLocations from '../../hooks/useHttpLocations'
|
||||
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
import Logo from '../Logo'
|
||||
|
||||
type Network = 'ethereum' | 'arbitrum' | 'optimism'
|
||||
|
||||
function chainIdToNetworkName(networkId: SupportedChainId): Network {
|
||||
switch (networkId) {
|
||||
case SupportedChainId.MAINNET:
|
||||
return 'ethereum'
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
return 'arbitrum'
|
||||
case SupportedChainId.OPTIMISM:
|
||||
return 'optimism'
|
||||
default:
|
||||
return 'ethereum'
|
||||
}
|
||||
}
|
||||
|
||||
export const getTokenLogoURL = (
|
||||
address: string,
|
||||
chainId: SupportedChainId = SupportedChainId.MAINNET
|
||||
): string | void => {
|
||||
const networkName = chainIdToNetworkName(chainId)
|
||||
const networksWithUrls = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.MAINNET, SupportedChainId.OPTIMISM]
|
||||
if (networksWithUrls.includes(chainId)) {
|
||||
return `https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/${networkName}/assets/${address}/logo.png`
|
||||
}
|
||||
}
|
||||
|
||||
const StyledEthereumLogo = styled.img<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||
|
||||
border-radius: 50%;
|
||||
-mox-box-shadow: 0 0 1px white;
|
||||
-webkit-box-shadow: 0 0 1px white;
|
||||
box-shadow: 0 0 1px white;
|
||||
border: 0px solid rgba(255, 255, 255, 0);
|
||||
`
|
||||
|
||||
const StyledLogo = styled(Logo)<{ size: string }>`
|
||||
const StyledLogo = styled(Logo)<{ size: string; native: boolean }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||
border-radius: 50%;
|
||||
-mox-box-shadow: 0 0 1px black;
|
||||
-webkit-box-shadow: 0 0 1px black;
|
||||
box-shadow: 0 0 1px black;
|
||||
-mox-box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
|
||||
-webkit-box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
|
||||
box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
|
||||
border: 0px solid rgba(255, 255, 255, 0);
|
||||
`
|
||||
|
||||
@@ -67,28 +26,16 @@ export default function CurrencyLogo({
|
||||
size?: string
|
||||
style?: React.CSSProperties
|
||||
}) {
|
||||
const uriLocations = useHttpLocations(currency instanceof WrappedTokenInfo ? currency.logoURI : undefined)
|
||||
const logoURIs = useCurrencyLogoURIs(currency)
|
||||
|
||||
const srcs: string[] = useMemo(() => {
|
||||
if (!currency || currency.isNative) return []
|
||||
|
||||
if (currency.isToken) {
|
||||
const defaultUrls = []
|
||||
const url = getTokenLogoURL(currency.address, currency.chainId)
|
||||
if (url) {
|
||||
defaultUrls.push(url)
|
||||
}
|
||||
if (currency instanceof WrappedTokenInfo) {
|
||||
return [...uriLocations, ...defaultUrls]
|
||||
}
|
||||
return defaultUrls
|
||||
}
|
||||
return []
|
||||
}, [currency, uriLocations])
|
||||
|
||||
if (currency?.isNative) {
|
||||
return <StyledEthereumLogo src={EthereumLogo} alt="ethereum logo" size={size} style={style} {...rest} />
|
||||
}
|
||||
|
||||
return <StyledLogo size={size} srcs={srcs} alt={`${currency?.symbol ?? 'token'} logo`} style={style} {...rest} />
|
||||
return (
|
||||
<StyledLogo
|
||||
size={size}
|
||||
native={currency?.isNative ?? false}
|
||||
srcs={logoURIs}
|
||||
alt={`${currency?.symbol ?? 'token'} logo`}
|
||||
style={style}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { AlertOctagon } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink } from 'theme'
|
||||
|
||||
import { isL2ChainId } from '../../utils/chains'
|
||||
|
||||
const Root = styled.div`
|
||||
background-color: ${({ theme }) => (theme.darkMode ? '#888D9B' : '#CED0D9')};
|
||||
border-radius: 18px;
|
||||
@@ -18,7 +20,6 @@ const Root = styled.div`
|
||||
max-width: 880px;
|
||||
`
|
||||
const WarningIcon = styled(AlertOctagon)`
|
||||
display: block;
|
||||
margin: auto 16px auto 0;
|
||||
min-height: 22px;
|
||||
min-width: 22px;
|
||||
@@ -28,50 +29,54 @@ const ReadMoreLink = styled(ExternalLink)`
|
||||
text-decoration: underline;
|
||||
`
|
||||
|
||||
export default function DowntimeWarning() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
if (!chainId || !L2_CHAIN_IDS.includes(chainId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const Content = () => {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.OPTIMISM:
|
||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||
return (
|
||||
<div>
|
||||
<Trans>
|
||||
Optimistic Ethereum is in Beta and may experience downtime. Optimism expects planned downtime to upgrade
|
||||
the network in the near future. During downtime, your position will not earn fees and you will be unable
|
||||
to remove liquidity.{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5406082-what-happens-if-the-optimistic-ethereum-network-experiences-downtime">
|
||||
Read more.
|
||||
</ReadMoreLink>
|
||||
</Trans>
|
||||
</div>
|
||||
)
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
return (
|
||||
<div>
|
||||
<Trans>
|
||||
Arbitrum is in Beta and may experience downtime. During downtime, your position will not earn fees and you
|
||||
will be unable to remove liquidity.{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5576122-arbitrum-network-downtime">
|
||||
Read more.
|
||||
</ReadMoreLink>
|
||||
</Trans>
|
||||
</div>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function Wrapper({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<Root>
|
||||
<WarningIcon />
|
||||
<Content />
|
||||
<div>{children}</div>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a downtime warning for the network if it's relevant
|
||||
*/
|
||||
export default function DowntimeWarning() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
if (!isL2ChainId(chainId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
switch (chainId) {
|
||||
case SupportedChainId.OPTIMISM:
|
||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||
return (
|
||||
<Wrapper>
|
||||
<Trans>
|
||||
Optimism is in Beta and may experience downtime. Optimism expects planned downtime to upgrade the network in
|
||||
the near future. During downtime, your position will not earn fees and you will be unable to remove
|
||||
liquidity.{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5406082-what-happens-if-the-optimistic-ethereum-network-experiences-downtime">
|
||||
Read more.
|
||||
</ReadMoreLink>
|
||||
</Trans>
|
||||
</Wrapper>
|
||||
)
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
return (
|
||||
<Wrapper>
|
||||
<Trans>
|
||||
Arbitrum is in Beta and may experience downtime. During downtime, your position will not earn fees and you
|
||||
will be unable to remove liquidity.{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5576122-arbitrum-network-downtime">
|
||||
Read more.
|
||||
</ReadMoreLink>
|
||||
</Trans>
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { ButtonGray } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState, usePools } from 'hooks/usePools'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { DynamicSection } from 'pages/AddLiquidity/styled'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CHAIN_INFO, L2ChainInfo, SupportedChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { CHAIN_INFO, L2ChainInfo } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { AlertOctagon } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
|
||||
26
src/components/Header/HolidayOrnament.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { ReactElement } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import SantaHat from '../../assets/images/santa-hat.png'
|
||||
|
||||
const SantaHatImage = styled.img`
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
height: 18px;
|
||||
`
|
||||
|
||||
const Christmas = <SantaHatImage src={SantaHat} alt="Santa hat" />
|
||||
|
||||
const DATE_TO_ORNAMENT: { [date: string]: ReactElement } = {
|
||||
'12-24': Christmas,
|
||||
'12-25': Christmas,
|
||||
}
|
||||
|
||||
const HolidayOrnament = () => {
|
||||
// months in javascript are 0 indexed...
|
||||
const today = `${new Date().getMonth() + 1}-${new Date().getDate()}`
|
||||
return DATE_TO_ORNAMENT[today] || null
|
||||
}
|
||||
|
||||
export default HolidayOrnament
|
||||
@@ -1,22 +1,22 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import {
|
||||
ARBITRUM_HELP_CENTER_LINK,
|
||||
CHAIN_INFO,
|
||||
L2_CHAIN_IDS,
|
||||
OPTIMISM_HELP_CENTER_LINK,
|
||||
SupportedChainId,
|
||||
SupportedL2ChainId,
|
||||
} from 'constants/chains'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import { CHAIN_IDS_TO_NAMES, SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useCallback, useRef } from 'react'
|
||||
import useParsedQueryString from 'hooks/useParsedQueryString'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { ParsedQs } from 'qs'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { ArrowDownCircle, ChevronDown } from 'react-feather'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useModalOpen, useToggleModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import { useAppSelector } from 'state/hooks'
|
||||
import { addPopup, ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { switchToNetwork } from 'utils/switchToNetwork'
|
||||
import { replaceURLParam } from 'utils/routes'
|
||||
|
||||
import { useAppDispatch } from '../../state/hooks'
|
||||
import { switchToNetwork } from '../../utils/switchToNetwork'
|
||||
|
||||
const ActiveRowLinkList = styled.div`
|
||||
display: flex;
|
||||
@@ -51,6 +51,16 @@ const FlyoutHeader = styled.div`
|
||||
font-weight: 400;
|
||||
`
|
||||
const FlyoutMenu = styled.div`
|
||||
position: absolute;
|
||||
top: 54px;
|
||||
width: 272px;
|
||||
z-index: 99;
|
||||
padding-top: 10px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
top: 40px;
|
||||
}
|
||||
`
|
||||
const FlyoutMenuContents = styled.div`
|
||||
align-items: flex-start;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
|
||||
@@ -61,16 +71,9 @@ const FlyoutMenu = styled.div`
|
||||
font-size: 16px;
|
||||
overflow: auto;
|
||||
padding: 16px;
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
width: 272px;
|
||||
z-index: 99;
|
||||
& > *:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
top: 50px;
|
||||
}
|
||||
`
|
||||
const FlyoutRow = styled.div<{ active: boolean }>`
|
||||
align-items: center;
|
||||
@@ -114,7 +117,7 @@ const SelectorControls = styled.div<{ interactive: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
border: 2px solid ${({ theme }) => theme.bg0};
|
||||
border-radius: 12px;
|
||||
border-radius: 16px;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
|
||||
display: flex;
|
||||
@@ -134,9 +137,9 @@ const SelectorWrapper = styled.div`
|
||||
}
|
||||
`
|
||||
const StyledChevronDown = styled(ChevronDown)`
|
||||
width: 12px;
|
||||
width: 16px;
|
||||
`
|
||||
const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
||||
const BridgeLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
@@ -144,11 +147,14 @@ const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
||||
case SupportedChainId.OPTIMISM:
|
||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||
return <Trans>Optimism Gateway</Trans>
|
||||
case SupportedChainId.POLYGON:
|
||||
case SupportedChainId.POLYGON_MUMBAI:
|
||||
return <Trans>Polygon Bridge</Trans>
|
||||
default:
|
||||
return <Trans>Bridge</Trans>
|
||||
}
|
||||
}
|
||||
const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
||||
const ExplorerLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
@@ -156,91 +162,169 @@ const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
||||
case SupportedChainId.OPTIMISM:
|
||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||
return <Trans>Optimistic Etherscan</Trans>
|
||||
case SupportedChainId.POLYGON:
|
||||
case SupportedChainId.POLYGON_MUMBAI:
|
||||
return <Trans>Polygonscan</Trans>
|
||||
default:
|
||||
return <Trans>Explorer</Trans>
|
||||
return <Trans>Etherscan</Trans>
|
||||
}
|
||||
}
|
||||
|
||||
function Row({
|
||||
targetChain,
|
||||
onSelectChain,
|
||||
}: {
|
||||
targetChain: SupportedChainId
|
||||
onSelectChain: (targetChain: number) => void
|
||||
}) {
|
||||
const { library, chainId } = useActiveWeb3React()
|
||||
if (!library || !chainId) {
|
||||
return null
|
||||
}
|
||||
const active = chainId === targetChain
|
||||
const { helpCenterUrl, explorer, bridge, label, logoUrl } = CHAIN_INFO[targetChain]
|
||||
|
||||
const rowContent = (
|
||||
<FlyoutRow onClick={() => onSelectChain(targetChain)} active={active}>
|
||||
<Logo src={logoUrl} />
|
||||
<NetworkLabel>{label}</NetworkLabel>
|
||||
{chainId === targetChain && <FlyoutRowActiveIndicator />}
|
||||
</FlyoutRow>
|
||||
)
|
||||
|
||||
if (active) {
|
||||
return (
|
||||
<ActiveRowWrapper>
|
||||
{rowContent}
|
||||
<ActiveRowLinkList>
|
||||
{bridge ? (
|
||||
<ExternalLink href={bridge}>
|
||||
<BridgeLabel chainId={chainId} /> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
) : null}
|
||||
{explorer ? (
|
||||
<ExternalLink href={explorer}>
|
||||
<ExplorerLabel chainId={chainId} /> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
) : null}
|
||||
{helpCenterUrl ? (
|
||||
<ExternalLink href={helpCenterUrl}>
|
||||
<Trans>Help Center</Trans> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
) : null}
|
||||
</ActiveRowLinkList>
|
||||
</ActiveRowWrapper>
|
||||
)
|
||||
}
|
||||
return rowContent
|
||||
}
|
||||
|
||||
const getParsedChainId = (parsedQs?: ParsedQs) => {
|
||||
const chain = parsedQs?.chain
|
||||
if (!chain || typeof chain !== 'string') return { urlChain: undefined, urlChainId: undefined }
|
||||
|
||||
return { urlChain: chain.toLowerCase(), urlChainId: getChainIdFromName(chain) }
|
||||
}
|
||||
|
||||
const getChainIdFromName = (name: string) => {
|
||||
const entry = Object.entries(CHAIN_IDS_TO_NAMES).find(([_, n]) => n === name)
|
||||
const chainId = entry?.[0]
|
||||
return chainId ? parseInt(chainId) : undefined
|
||||
}
|
||||
|
||||
const getChainNameFromId = (id: string | number) => {
|
||||
// casting here may not be right but fine to return undefined if it's not a supported chain ID
|
||||
return CHAIN_IDS_TO_NAMES[id as SupportedChainId] || ''
|
||||
}
|
||||
|
||||
export default function NetworkSelector() {
|
||||
const { chainId, library } = useActiveWeb3React()
|
||||
const parsedQs = useParsedQueryString()
|
||||
const { urlChain, urlChainId } = getParsedChainId(parsedQs)
|
||||
const prevChainId = usePrevious(chainId)
|
||||
const node = useRef<HTMLDivElement>()
|
||||
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
|
||||
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
|
||||
useOnClickOutside(node, open ? toggle : undefined)
|
||||
const implements3085 = useAppSelector((state) => state.application.implements3085)
|
||||
|
||||
const history = useHistory()
|
||||
|
||||
const info = chainId ? CHAIN_INFO[chainId] : undefined
|
||||
|
||||
const isOnL2 = chainId ? L2_CHAIN_IDS.includes(chainId) : false
|
||||
const showSelector = Boolean(implements3085 || isOnL2)
|
||||
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const conditionalToggle = useCallback(() => {
|
||||
if (showSelector) {
|
||||
toggle()
|
||||
const handleChainSwitch = useCallback(
|
||||
(targetChain: number, skipToggle?: boolean) => {
|
||||
if (!library) return
|
||||
switchToNetwork({ library, chainId: targetChain })
|
||||
.then(() => {
|
||||
if (!skipToggle) {
|
||||
toggle()
|
||||
}
|
||||
history.replace({
|
||||
search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(targetChain)),
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to switch networks', error)
|
||||
|
||||
// we want app network <-> chainId param to be in sync, so if user changes the network by changing the URL
|
||||
// but the request fails, revert the URL back to current chainId
|
||||
if (chainId) {
|
||||
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
|
||||
}
|
||||
|
||||
if (!skipToggle) {
|
||||
toggle()
|
||||
}
|
||||
|
||||
dispatch(addPopup({ content: { failedSwitchNetwork: targetChain }, key: `failed-network-switch` }))
|
||||
})
|
||||
},
|
||||
[dispatch, library, toggle, history, chainId]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!chainId || !prevChainId) return
|
||||
|
||||
// when network change originates from wallet or dropdown selector, just update URL
|
||||
if (chainId !== prevChainId) {
|
||||
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
|
||||
// otherwise assume network change originates from URL
|
||||
} else if (urlChainId && urlChainId !== chainId) {
|
||||
handleChainSwitch(urlChainId, true)
|
||||
}
|
||||
}, [showSelector, toggle])
|
||||
}, [chainId, urlChainId, prevChainId, handleChainSwitch, history])
|
||||
|
||||
// set chain parameter on initial load if not there
|
||||
useEffect(() => {
|
||||
if (chainId && !urlChainId) {
|
||||
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
|
||||
}
|
||||
}, [chainId, history, urlChainId, urlChain])
|
||||
|
||||
if (!chainId || !info || !library) {
|
||||
return null
|
||||
}
|
||||
|
||||
function Row({ targetChain }: { targetChain: number }) {
|
||||
if (!library || !chainId || (!implements3085 && targetChain !== chainId)) {
|
||||
return null
|
||||
}
|
||||
const handleRowClick = () => {
|
||||
switchToNetwork({ library, chainId: targetChain })
|
||||
toggle()
|
||||
}
|
||||
const active = chainId === targetChain
|
||||
const hasExtendedInfo = L2_CHAIN_IDS.includes(targetChain)
|
||||
const isOptimism = targetChain === SupportedChainId.OPTIMISM
|
||||
const rowText = `${CHAIN_INFO[targetChain].label}${isOptimism ? ' (Optimism)' : ''}`
|
||||
const RowContent = () => (
|
||||
<FlyoutRow onClick={handleRowClick} active={active}>
|
||||
<Logo src={CHAIN_INFO[targetChain].logoUrl} />
|
||||
<NetworkLabel>{rowText}</NetworkLabel>
|
||||
{chainId === targetChain && <FlyoutRowActiveIndicator />}
|
||||
</FlyoutRow>
|
||||
)
|
||||
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
|
||||
if (active && hasExtendedInfo) {
|
||||
return (
|
||||
<ActiveRowWrapper>
|
||||
<RowContent />
|
||||
<ActiveRowLinkList>
|
||||
<ExternalLink href={CHAIN_INFO[targetChain as SupportedL2ChainId].bridge}>
|
||||
<BridgeText chainId={chainId} /> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
<ExternalLink href={CHAIN_INFO[targetChain].explorer}>
|
||||
<ExplorerText chainId={chainId} /> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
<ExternalLink href={helpCenterLink}>
|
||||
<Trans>Help Center</Trans> <LinkOutCircle />
|
||||
</ExternalLink>
|
||||
</ActiveRowLinkList>
|
||||
</ActiveRowWrapper>
|
||||
)
|
||||
}
|
||||
return <RowContent />
|
||||
}
|
||||
|
||||
return (
|
||||
<SelectorWrapper ref={node as any}>
|
||||
<SelectorControls onClick={conditionalToggle} interactive={showSelector}>
|
||||
<SelectorLogo interactive={showSelector} src={info.logoUrl || mainnetInfo.logoUrl} />
|
||||
<SelectorWrapper ref={node as any} onMouseEnter={toggle} onMouseLeave={toggle}>
|
||||
<SelectorControls interactive>
|
||||
<SelectorLogo interactive src={info.logoUrl} />
|
||||
<SelectorLabel>{info.label}</SelectorLabel>
|
||||
{showSelector && <StyledChevronDown />}
|
||||
<StyledChevronDown />
|
||||
</SelectorControls>
|
||||
{open && (
|
||||
<FlyoutMenu>
|
||||
<FlyoutHeader>
|
||||
<Trans>Select a network</Trans>
|
||||
</FlyoutHeader>
|
||||
<Row targetChain={SupportedChainId.MAINNET} />
|
||||
<Row targetChain={SupportedChainId.OPTIMISM} />
|
||||
<Row targetChain={SupportedChainId.ARBITRUM_ONE} />
|
||||
<FlyoutMenuContents>
|
||||
<FlyoutHeader>
|
||||
<Trans>Select a network</Trans>
|
||||
</FlyoutHeader>
|
||||
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.MAINNET} />
|
||||
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.POLYGON} />
|
||||
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.OPTIMISM} />
|
||||
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.ARBITRUM_ONE} />
|
||||
</FlyoutMenuContents>
|
||||
</FlyoutMenu>
|
||||
)}
|
||||
</SelectorWrapper>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { RowFixed } from 'components/Row'
|
||||
import { CHAIN_INFO } from 'constants/chains'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||
import useGasPrice from 'hooks/useGasPrice'
|
||||
import useMachineTimeMs from 'hooks/useMachineTime'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import JSBI from 'jsbi'
|
||||
import useBlockNumber from 'lib/hooks/useBlockNumber'
|
||||
import ms from 'ms.macro'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useBlockNumber } from 'state/application/hooks'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||
@@ -147,8 +147,8 @@ export default function Polling() {
|
||||
<MouseoverTooltip
|
||||
text={
|
||||
<Trans>
|
||||
{`The current fast gas amount for sending a transaction on L1.
|
||||
Gas fees are paid in Ethereum's native currency Ether (ETH) and denominated in gwei. `}
|
||||
The current fast gas amount for sending a transaction on L1. Gas fees are paid in
|
||||
Ethereum's native currency Ether (ETH) and denominated in GWEI.
|
||||
</Trans>
|
||||
}
|
||||
>
|
||||
@@ -166,7 +166,7 @@ export default function Polling() {
|
||||
}
|
||||
>
|
||||
<MouseoverTooltip
|
||||
text={<Trans>{`The most recent block number on this network. Prices update on every block.`}</Trans>}
|
||||
text={<Trans>The most recent block number on this network. Prices update on every block.</Trans>}
|
||||
>
|
||||
{blockNumber} 
|
||||
</MouseoverTooltip>
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||
import { useMemo } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import tokenLogo from '../../assets/images/token-logo.png'
|
||||
import { UNI } from '../../constants/tokens'
|
||||
import { useMerkleDistributorContract } from '../../hooks/useContract'
|
||||
import useCurrentBlockTimestamp from '../../hooks/useCurrentBlockTimestamp'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import useUSDCPrice from '../../hooks/useUSDCPrice'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTotalUniEarned } from '../../state/stake/hooks'
|
||||
import { useAggregateUniBalance, useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { ExternalLink, StyledInternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||
import { computeUniCirculation } from '../../utils/computeUniCirculation'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { Break, CardBGImage, CardNoise, CardSection, DataCard } from '../earn/styled'
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
const ContentWrapper = styled(AutoColumn)`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const ModalUpper = styled(DataCard)`
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
|
||||
background: radial-gradient(76.02% 75.41% at 1.84% 0%, #ff007a 0%, #021d43 100%);
|
||||
padding: 0.5rem;
|
||||
`
|
||||
|
||||
const StyledClose = styled(X)`
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
`
|
||||
|
||||
/**
|
||||
* Content for balance stats modal
|
||||
*/
|
||||
export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowUniBalanceModal: any }) {
|
||||
const { account, chainId } = useActiveWeb3React()
|
||||
const uni = chainId ? UNI[chainId] : undefined
|
||||
|
||||
const total = useAggregateUniBalance()
|
||||
const uniBalance: CurrencyAmount<Token> | undefined = useTokenBalance(account ?? undefined, uni)
|
||||
const uniToClaim: CurrencyAmount<Token> | undefined = useTotalUniEarned()
|
||||
|
||||
const totalSupply: CurrencyAmount<Token> | undefined = useTotalSupply(uni)
|
||||
const uniPrice = useUSDCPrice(uni)
|
||||
const blockTimestamp = useCurrentBlockTimestamp()
|
||||
const unclaimedUni = useTokenBalance(useMerkleDistributorContract()?.address, uni)
|
||||
const circulation: CurrencyAmount<Token> | undefined = useMemo(
|
||||
() =>
|
||||
blockTimestamp && uni && chainId === 1 ? computeUniCirculation(uni, blockTimestamp, unclaimedUni) : totalSupply,
|
||||
[blockTimestamp, chainId, totalSupply, unclaimedUni, uni]
|
||||
)
|
||||
|
||||
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||
|
||||
return (
|
||||
<ContentWrapper gap="lg">
|
||||
<ModalUpper>
|
||||
<CardBGImage />
|
||||
<CardNoise />
|
||||
<CardSection gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Your UNI Breakdown</Trans>
|
||||
</ThemedText.White>
|
||||
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
|
||||
</RowBetween>
|
||||
</CardSection>
|
||||
<Break />
|
||||
{account && (
|
||||
<>
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md" justify="center">
|
||||
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
|
||||
<ThemedText.White fontSize={48} fontWeight={600} color="white">
|
||||
{total?.toFixed(2, { groupSeparator: ',' })}
|
||||
</ThemedText.White>
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Balance:</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Unclaimed:</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">
|
||||
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
|
||||
{uniToClaim && uniToClaim.greaterThan('0') && (
|
||||
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
|
||||
<Trans>(claim)</Trans>
|
||||
</StyledInternalLink>
|
||||
)}
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<Break />
|
||||
</>
|
||||
)}
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>UNI price:</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">${uniPrice?.toFixed(2) ?? '-'}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>UNI in circulation:</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Total Supply</Trans>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
{uni && uni.chainId === 1 ? (
|
||||
<ExternalLink href={`${infoLink}/token/${uni.address}`}>
|
||||
<Trans>View UNI Analytics</Trans>
|
||||
</ExternalLink>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
</ModalUpper>
|
||||
</ContentWrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,30 +1,29 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useScrollPosition from '@react-hook/window-scroll'
|
||||
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { darken } from 'polished'
|
||||
import { useState } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { Text } from 'rebass'
|
||||
import { useShowClaimPopup, useToggleSelfClaimModal } from 'state/application/hooks'
|
||||
import { useUserHasAvailableClaim } from 'state/claim/hooks'
|
||||
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
import { useETHBalances } from 'state/wallet/hooks'
|
||||
import { useNativeCurrencyBalances } from 'state/wallet/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import ClaimModal from '../claim/ClaimModal'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
import Menu from '../Menu'
|
||||
import Modal from '../Modal'
|
||||
import Row from '../Row'
|
||||
import { Dots } from '../swap/styleds'
|
||||
import Web3Status from '../Web3Status'
|
||||
import HolidayOrnament from './HolidayOrnament'
|
||||
import NetworkSelector from './NetworkSelector'
|
||||
import UniBalanceContent from './UniBalanceContent'
|
||||
|
||||
const HeaderFrame = styled.div<{ showBackground: boolean }>`
|
||||
display: grid;
|
||||
@@ -91,7 +90,7 @@ const HeaderLinks = styled(Row)`
|
||||
justify-self: center;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
width: fit-content;
|
||||
padding: 4px;
|
||||
padding: 2px;
|
||||
border-radius: 16px;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
@@ -123,10 +122,11 @@ const AccountElement = styled.div<{ active: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: ${({ theme, active }) => (!active ? theme.bg1 : theme.bg1)};
|
||||
border-radius: 12px;
|
||||
background-color: ${({ theme, active }) => (!active ? theme.bg0 : theme.bg0)};
|
||||
border-radius: 16px;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
|
||||
:focus {
|
||||
border: 1px solid blue;
|
||||
@@ -181,6 +181,8 @@ const UniIcon = styled.div`
|
||||
:hover {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const activeClassName = 'ACTIVE'
|
||||
@@ -202,11 +204,11 @@ const StyledNavLink = styled(NavLink).attrs({
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
&.${activeClassName} {
|
||||
border-radius: 12px;
|
||||
border-radius: 14px;
|
||||
font-weight: 600;
|
||||
justify-content: center;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
}
|
||||
|
||||
:hover,
|
||||
@@ -231,7 +233,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
|
||||
font-weight: 500;
|
||||
|
||||
&.${activeClassName} {
|
||||
border-radius: 12px;
|
||||
border-radius: 14px;
|
||||
font-weight: 600;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
}
|
||||
@@ -246,7 +248,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
|
||||
export default function Header() {
|
||||
const { account, chainId } = useActiveWeb3React()
|
||||
|
||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
||||
const userEthBalance = useNativeCurrencyBalances(account ? [account] : [])?.[account ?? '']
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const { white, black } = useTheme()
|
||||
|
||||
@@ -256,21 +258,22 @@ export default function Header() {
|
||||
|
||||
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
|
||||
|
||||
const [showUniBalanceModal, setShowUniBalanceModal] = useState(false)
|
||||
const showClaimPopup = useShowClaimPopup()
|
||||
|
||||
const scrollY = useScrollPosition()
|
||||
|
||||
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||
const {
|
||||
infoLink,
|
||||
nativeCurrency: { symbol: nativeCurrencySymbol },
|
||||
} = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||
|
||||
return (
|
||||
<HeaderFrame showBackground={scrollY > 45}>
|
||||
<ClaimModal />
|
||||
<Modal isOpen={showUniBalanceModal} onDismiss={() => setShowUniBalanceModal(false)}>
|
||||
<UniBalanceContent setShowUniBalanceModal={setShowUniBalanceModal} />
|
||||
</Modal>
|
||||
<Title href=".">
|
||||
<UniIcon>
|
||||
<Logo fill={darkMode ? white : black} width="24px" height="100%" title="logo" />
|
||||
<HolidayOrnament />
|
||||
</UniIcon>
|
||||
</Title>
|
||||
<HeaderLinks>
|
||||
@@ -325,7 +328,9 @@ export default function Header() {
|
||||
<AccountElement active={!!account}>
|
||||
{account && userEthBalance ? (
|
||||
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||
<Trans>{userEthBalance?.toSignificant(3)} ETH</Trans>
|
||||
<Trans>
|
||||
{userEthBalance?.toSignificant(3)} {nativeCurrencySymbol}
|
||||
</Trans>
|
||||
</BalanceText>
|
||||
) : null}
|
||||
<Web3Status />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { Connector } from '@web3-react/types'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
@@ -7,7 +8,7 @@ import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
|
||||
import Identicon from '../Identicon'
|
||||
|
||||
export default function StatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
export default function StatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
|
||||
switch (connector) {
|
||||
case injected:
|
||||
return <Identicon />
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import jazzicon from '@metamask/jazzicon'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useENSAvatar from 'hooks/useENSAvatar'
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
|
||||
const StyledIdenticon = styled.div`
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
||||
import JSBI from 'jsbi'
|
||||
import { TickProcessed, usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import { ChartEntry } from './types'
|
||||
|
||||
export interface TickProcessed {
|
||||
liquidityActive: JSBI
|
||||
price0: string
|
||||
}
|
||||
|
||||
export function useDensityChartData({
|
||||
currencyA,
|
||||
currencyB,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
@@ -25,7 +26,6 @@ import styled, { css } from 'styled-components/macro'
|
||||
|
||||
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useModalOpen, useToggleModal } from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { ExternalLink } from '../../theme'
|
||||
@@ -49,12 +49,11 @@ const StyledMenuButton = styled.button`
|
||||
background-color: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 38px;
|
||||
height: 40px;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
border: 1px solid ${({ theme }) => theme.bg0};
|
||||
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 12px;
|
||||
border-radius: 16px;
|
||||
|
||||
:hover,
|
||||
:focus {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useContext } from 'react'
|
||||
import { ArrowUpCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
|
||||
@@ -1,157 +1,93 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import {
|
||||
ARBITRUM_HELP_CENTER_LINK,
|
||||
L2_CHAIN_IDS,
|
||||
OPTIMISM_HELP_CENTER_LINK,
|
||||
SupportedChainId,
|
||||
SupportedL2ChainId,
|
||||
} from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { ArrowDownCircle, X } from 'react-feather'
|
||||
import { useArbitrumAlphaAlert, useDarkModeManager, useOptimismAlphaAlert } from 'state/user/hooks'
|
||||
import { useETHBalances } from 'state/wallet/hooks'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ArrowUpRight } from 'react-feather'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, HideSmall } from 'theme'
|
||||
|
||||
import { CHAIN_INFO } from '../../constants/chains'
|
||||
|
||||
export const DesktopTextBreak = styled.div`
|
||||
display: none;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
import { AutoRow } from '../Row'
|
||||
|
||||
const L2Icon = styled.img`
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
justify-self: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 16px;
|
||||
`
|
||||
const BetaTag = styled.span<{ color: string }>`
|
||||
align-items: center;
|
||||
background-color: ${({ color }) => color};
|
||||
border-radius: 6px;
|
||||
color: ${({ theme }) => theme.white};
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
height: 28px;
|
||||
justify-content: center;
|
||||
left: -16px;
|
||||
position: absolute;
|
||||
transform: rotate(-15deg);
|
||||
top: -16px;
|
||||
width: 60px;
|
||||
z-index: 1;
|
||||
`
|
||||
const Body = styled.p`
|
||||
font-size: 12px;
|
||||
grid-column: 1 / 3;
|
||||
line-height: 143%;
|
||||
margin: 0;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
`
|
||||
export const Controls = styled.div<{ thin?: boolean }>`
|
||||
|
||||
export const Controls = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
${({ thin }) =>
|
||||
thin &&
|
||||
css`
|
||||
margin: auto 32px auto 0;
|
||||
`}
|
||||
`
|
||||
const CloseIcon = styled(X)`
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
padding: 0 20px 20px 20px;
|
||||
`
|
||||
|
||||
const BodyText = styled.div`
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-gap: 4px;
|
||||
grid-template-columns: 40px 4fr;
|
||||
grid-template-rows: auto auto;
|
||||
margin: 20px 16px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
grid-template-columns: 42px 4fr;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
`
|
||||
const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
border-radius: 8px;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
color: ${({ color }) => color};
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 44px;
|
||||
justify-content: space-between;
|
||||
margin: 0 0 20px 0;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
:hover,
|
||||
:focus,
|
||||
:active {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
transition: background-color 150ms ease-in-out;
|
||||
${({ thin }) =>
|
||||
thin &&
|
||||
css`
|
||||
font-size: 14px;
|
||||
margin: auto;
|
||||
width: 112px;
|
||||
`}
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 8px;
|
||||
font-size: 14px;
|
||||
`
|
||||
const RootWrapper = styled.div`
|
||||
position: relative;
|
||||
margin-top: 16px;
|
||||
`
|
||||
export const ArbitrumWrapperBackgroundDarkMode = css`
|
||||
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
|
||||
radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.3) 0%, rgba(33, 114, 229, 0.3) 100%), hsla(0, 0%, 100%, 0.1);
|
||||
`
|
||||
export const ArbitrumWrapperBackgroundLightMode = css`
|
||||
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
|
||||
radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1);
|
||||
`
|
||||
export const OptimismWrapperBackgroundDarkMode = css`
|
||||
background: radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%),
|
||||
radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.5) 0%, rgba(235, 0, 255, 0.345) 96%);
|
||||
`
|
||||
export const OptimismWrapperBackgroundLightMode = css`
|
||||
background: radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),
|
||||
radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.5);
|
||||
`
|
||||
const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string; thin?: boolean }>`
|
||||
${({ chainId, darkMode }) =>
|
||||
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? darkMode
|
||||
? OptimismWrapperBackgroundDarkMode
|
||||
: OptimismWrapperBackgroundLightMode
|
||||
: darkMode
|
||||
? ArbitrumWrapperBackgroundDarkMode
|
||||
: ArbitrumWrapperBackgroundLightMode};
|
||||
|
||||
const SHOULD_SHOW_ALERT = {
|
||||
[SupportedChainId.OPTIMISM]: true,
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: true,
|
||||
[SupportedChainId.ARBITRUM_ONE]: true,
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: true,
|
||||
[SupportedChainId.POLYGON]: true,
|
||||
[SupportedChainId.POLYGON_MUMBAI]: true,
|
||||
}
|
||||
|
||||
type NetworkAlertChains = keyof typeof SHOULD_SHOW_ALERT
|
||||
|
||||
const BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID: {
|
||||
[darkMode in 'dark' | 'light']: { [chainId in NetworkAlertChains]: string }
|
||||
} = {
|
||||
dark: {
|
||||
[SupportedChainId.POLYGON]:
|
||||
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
|
||||
[SupportedChainId.POLYGON_MUMBAI]:
|
||||
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
|
||||
[SupportedChainId.OPTIMISM]:
|
||||
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.01) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.01) 0%, rgba(235, 0, 255, 0.01) 96%)',
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]:
|
||||
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.04) 0%, rgba(235, 0, 255, 0.01 96%)',
|
||||
[SupportedChainId.ARBITRUM_ONE]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.01) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.05) 100%), hsla(0, 0%, 100%, 0.05)',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.05) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.1) 100%), hsla(0, 0%, 100%, 0.05)',
|
||||
},
|
||||
light: {
|
||||
[SupportedChainId.POLYGON]:
|
||||
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
|
||||
[SupportedChainId.POLYGON_MUMBAI]:
|
||||
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
|
||||
[SupportedChainId.OPTIMISM]:
|
||||
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]:
|
||||
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
|
||||
[SupportedChainId.ARBITRUM_ONE]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
|
||||
},
|
||||
}
|
||||
|
||||
const ContentWrapper = styled.div<{ chainId: NetworkAlertChains; darkMode: boolean; logoUrl: string }>`
|
||||
background: ${({ chainId, darkMode }) => BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID[darkMode ? 'dark' : 'light'][chainId]};
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 480px;
|
||||
min-height: 174px;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
${({ thin }) =>
|
||||
thin &&
|
||||
css`
|
||||
flex-direction: row;
|
||||
max-width: max-content;
|
||||
min-height: min-content;
|
||||
`}
|
||||
|
||||
:before {
|
||||
background-image: url(${({ logoUrl }) => logoUrl});
|
||||
background-repeat: no-repeat;
|
||||
@@ -165,116 +101,73 @@ const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean
|
||||
z-index: -1;
|
||||
}
|
||||
`
|
||||
const Header = styled.h2<{ thin?: boolean }>`
|
||||
const Header = styled.h2`
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding-right: 30px;
|
||||
display: ${({ thin }) => (thin ? 'none' : 'block')};
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
margin-left: 12px;
|
||||
transform: rotate(230deg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
`
|
||||
const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
|
||||
|
||||
const LinkOutToBridge = styled(ExternalLink)`
|
||||
align-items: center;
|
||||
background-color: black;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 44px;
|
||||
justify-content: space-between;
|
||||
margin: 0 12px 20px 18px;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
:hover,
|
||||
:focus,
|
||||
:active {
|
||||
background-color: black;
|
||||
}
|
||||
${({ thin }) =>
|
||||
thin &&
|
||||
css`
|
||||
font-size: 14px;
|
||||
margin: auto 10px;
|
||||
width: 168px;
|
||||
`}
|
||||
padding: 6px 8px;
|
||||
margin-right: 12px;
|
||||
text-decoration: none !important;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
interface NetworkAlertProps {
|
||||
thin?: boolean
|
||||
const StyledArrowUpRight = styled(ArrowUpRight)`
|
||||
margin-left: 12px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
`
|
||||
|
||||
const TEXT_COLORS: { [chainId in NetworkAlertChains]: string } = {
|
||||
[SupportedChainId.POLYGON]: 'rgba(130, 71, 229)',
|
||||
[SupportedChainId.POLYGON_MUMBAI]: 'rgba(130, 71, 229)',
|
||||
[SupportedChainId.OPTIMISM]: '#ff3856',
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: '#ff3856',
|
||||
[SupportedChainId.ARBITRUM_ONE]: '#0490ed',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: '#0490ed',
|
||||
}
|
||||
|
||||
export function NetworkAlert(props: NetworkAlertProps) {
|
||||
const { account, chainId } = useActiveWeb3React()
|
||||
function shouldShowAlert(chainId: number | undefined): chainId is NetworkAlertChains {
|
||||
return Boolean(chainId && SHOULD_SHOW_ALERT[chainId as unknown as NetworkAlertChains])
|
||||
}
|
||||
|
||||
export function NetworkAlert() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
|
||||
const [optimismAlphaAcknowledged, setOptimismAlphaAcknowledged] = useOptimismAlphaAlert()
|
||||
const [locallyDismissed, setLocallyDimissed] = useState(false)
|
||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
||||
|
||||
const dismiss = useCallback(() => {
|
||||
if (userEthBalance?.greaterThan(0)) {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.OPTIMISM:
|
||||
setOptimismAlphaAcknowledged(true)
|
||||
break
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
setArbitrumAlphaAcknowledged(true)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
setLocallyDimissed(true)
|
||||
}
|
||||
}, [chainId, setArbitrumAlphaAcknowledged, setOptimismAlphaAcknowledged, userEthBalance])
|
||||
|
||||
const onOptimismAndOptimismAcknowledged = SupportedChainId.OPTIMISM === chainId && optimismAlphaAcknowledged
|
||||
const onArbitrumAndArbitrumAcknowledged = SupportedChainId.ARBITRUM_ONE === chainId && arbitrumAlphaAcknowledged
|
||||
if (
|
||||
!chainId ||
|
||||
!L2_CHAIN_IDS.includes(chainId) ||
|
||||
onArbitrumAndArbitrumAcknowledged ||
|
||||
onOptimismAndOptimismAcknowledged ||
|
||||
locallyDismissed
|
||||
) {
|
||||
if (!shouldShowAlert(chainId)) {
|
||||
return null
|
||||
}
|
||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
||||
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
|
||||
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
|
||||
const showCloseIcon = Boolean(userEthBalance?.greaterThan(0) && !props.thin)
|
||||
return (
|
||||
|
||||
const { label, logoUrl, bridge } = CHAIN_INFO[chainId]
|
||||
const textColor = TEXT_COLORS[chainId]
|
||||
|
||||
return bridge ? (
|
||||
<RootWrapper>
|
||||
<BetaTag color={isOptimism ? '#ff0420' : '#0490ed'}>Beta</BetaTag>
|
||||
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl} thin={props.thin}>
|
||||
{showCloseIcon && <CloseIcon onClick={dismiss} />}
|
||||
<BodyText>
|
||||
<L2Icon src={info.logoUrl} />
|
||||
<Header thin={props.thin}>
|
||||
<Trans>Uniswap on {info.label}</Trans>
|
||||
</Header>
|
||||
<Body>
|
||||
<Trans>
|
||||
To start trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
|
||||
release and learn about the risks before using {info.label}.
|
||||
</Trans>
|
||||
</Body>
|
||||
</BodyText>
|
||||
<Controls thin={props.thin}>
|
||||
<LinkOutToBridge href={depositUrl} thin={props.thin}>
|
||||
<Trans>Deposit Assets</Trans>
|
||||
<LinkOutCircle />
|
||||
</LinkOutToBridge>
|
||||
<LearnMoreLink href={helpCenterLink} thin={props.thin}>
|
||||
<Trans>Learn More</Trans>
|
||||
</LearnMoreLink>
|
||||
</Controls>
|
||||
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={logoUrl}>
|
||||
<LinkOutToBridge href={bridge}>
|
||||
<BodyText color={textColor}>
|
||||
<L2Icon src={logoUrl} />
|
||||
<AutoRow>
|
||||
<Header>
|
||||
<Trans>{label} token bridge</Trans>
|
||||
</Header>
|
||||
<HideSmall>
|
||||
<Trans>Deposit tokens to the {label} network.</Trans>
|
||||
</HideSmall>
|
||||
</AutoRow>
|
||||
</BodyText>
|
||||
<StyledArrowUpRight color={textColor} />
|
||||
</LinkOutToBridge>
|
||||
</ContentWrapper>
|
||||
</RootWrapper>
|
||||
)
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Options, Placement } from '@popperjs/core'
|
||||
import Portal from '@reach/portal'
|
||||
import useInterval from 'lib/hooks/useInterval'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { usePopper } from 'react-popper'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import useInterval from '../../hooks/useInterval'
|
||||
|
||||
const PopoverContainer = styled.div<{ show: boolean }>`
|
||||
z-index: 9999;
|
||||
visibility: ${(props) => (props.show ? 'visible' : 'hidden')};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { Heart, X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
|
||||
import tokenLogo from '../../assets/images/token-logo.png'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import {
|
||||
useModalOpen,
|
||||
useShowClaimPopup,
|
||||
|
||||
139
src/components/Popups/DonationLink.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import FlagImage from 'assets/images/ukraine.png'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import { X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { useDarkModeManager, useShowDonationLink } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
const darkGradient = `radial-gradient(87.53% 3032.45% at 5.16% 10.13%, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%),
|
||||
linear-gradient(0deg, rgba(0, 91, 187, 0.35), rgba(0, 91, 187, 0.35)), #000000;`
|
||||
const lightGradient = `radial-gradient(87.53% 3032.45% at 5.16% 10.13%, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%), linear-gradient(0deg, #CBE4FF, #CBE4FF), linear-gradient(0deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.09)), radial-gradient(100% 93.36% at 0% 6.64%, #8BC4FF 0%, #FFF5BF 100%);`
|
||||
|
||||
const Wrapper = styled(AutoColumn)<{ darkMode: boolean }>`
|
||||
background: #edeef2;
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
max-width: 360px;
|
||||
background: ${({ darkMode }) => (darkMode ? darkGradient : lightGradient)};
|
||||
color: ${({ theme }) => theme.text1};
|
||||
z-index: ${Z_INDEX.deprecated_content};
|
||||
|
||||
:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
& > * {
|
||||
z-index: ${Z_INDEX.fixed};
|
||||
}
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
:before {
|
||||
background-image: url(${FlagImage});
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
background-size: 300px;
|
||||
content: '';
|
||||
height: 1200px;
|
||||
width: 400px;
|
||||
opacity: 0.1;
|
||||
position: absolute;
|
||||
transform: rotate(25deg) translate(-140px, -60px);
|
||||
width: 300px;
|
||||
z-index: ${Z_INDEX.deprecated_zero};
|
||||
}
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
max-width: 100%;
|
||||
`}
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
position: relative;
|
||||
bottom: unset;
|
||||
`}
|
||||
`
|
||||
|
||||
const WrappedCloseIcon = styled(X)`
|
||||
stroke: ${({ theme }) => theme.text2};
|
||||
z-index: ${Z_INDEX.tooltip};
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
|
||||
export const StyledFlagImage = styled.div`
|
||||
margin-right: 12px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 100%;
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
width: 9px;
|
||||
height: 18px;
|
||||
}
|
||||
&:before {
|
||||
float: left;
|
||||
border-top-left-radius: 9px;
|
||||
border-bottom-left-radius: 9px;
|
||||
background: #005bbb;
|
||||
}
|
||||
&:after {
|
||||
float: right;
|
||||
border-top-right-radius: 9px;
|
||||
border-bottom-right-radius: 9px;
|
||||
background: #ffd500;
|
||||
}
|
||||
transform: rotate(90deg);
|
||||
`
|
||||
|
||||
const StyledLink = styled(ExternalLink)`
|
||||
text-decoration: none !important;
|
||||
`
|
||||
|
||||
export default function DonationLink() {
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [, setVisible] = useShowDonationLink()
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
gap="10px"
|
||||
darkMode={darkMode}
|
||||
as={StyledLink}
|
||||
target="https://donate.uniswap.org/#/swap"
|
||||
href="https://donate.uniswap.org/#/swap"
|
||||
onClickCapture={() => {
|
||||
ReactGA.event({
|
||||
category: 'Donate',
|
||||
action: 'Link to Ukraine site.',
|
||||
})
|
||||
}}
|
||||
>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<StyledFlagImage />
|
||||
<ThemedText.Body fontWeight={600} fontSize={'18px'}>
|
||||
<Trans>Donate to Ukraine</Trans>
|
||||
</ThemedText.Body>
|
||||
</RowFixed>
|
||||
<WrappedCloseIcon
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setVisible(false)
|
||||
return false
|
||||
}}
|
||||
/>
|
||||
</RowBetween>
|
||||
<ThemedText.Body fontWeight={400} fontSize="12px" color="text2">
|
||||
<Trans>Directly support the Ukrainian government by donating tokens.</Trans>
|
||||
</ThemedText.Body>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
35
src/components/Popups/FailedNetworkSwitchPopup.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useContext } from 'react'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { AutoRow } from '../Row'
|
||||
|
||||
const RowNoFlex = styled(AutoRow)`
|
||||
flex-wrap: nowrap;
|
||||
`
|
||||
|
||||
export default function FailedNetworkSwitchPopup({ chainId }: { chainId: SupportedChainId }) {
|
||||
const chainInfo = CHAIN_INFO[chainId]
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
return (
|
||||
<RowNoFlex>
|
||||
<div style={{ paddingRight: 16 }}>
|
||||
<AlertCircle color={theme.red1} size={24} />
|
||||
</div>
|
||||
<AutoColumn gap="8px">
|
||||
<ThemedText.Body fontWeight={500}>
|
||||
<Trans>
|
||||
Failed to switch networks from the Uniswap Interface. In order to use Uniswap on {chainInfo.label}, you must
|
||||
change the network in your wallet.
|
||||
</Trans>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</RowNoFlex>
|
||||
)
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useRemovePopup } from '../../state/application/hooks'
|
||||
import { PopupContent } from '../../state/application/reducer'
|
||||
import FailedNetworkSwitchPopup from './FailedNetworkSwitchPopup'
|
||||
import TransactionPopup from './TransactionPopup'
|
||||
|
||||
const StyledClose = styled(X)`
|
||||
@@ -77,6 +78,8 @@ export default function PopupItem({
|
||||
txn: { hash },
|
||||
} = content
|
||||
popupContent = <TransactionPopup hash={hash} />
|
||||
} else if ('failedSwitchNetwork' in content) {
|
||||
popupContent = <FailedNetworkSwitchPopup chainId={content.failedSwitchNetwork} />
|
||||
}
|
||||
|
||||
const faderStyle = useSpring({
|
||||
|
||||
106
src/components/Popups/SurveyPopup.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowFixed } from 'components/Row'
|
||||
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||
import { useEffect } from 'react'
|
||||
import { MessageCircle, X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { useShowSurveyPopup } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
import BGImage from '../../assets/images/survey-orb.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
|
||||
const Wrapper = styled(AutoColumn)`
|
||||
background: #edeef2;
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
max-width: 360px;
|
||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
|
||||
color: ${({ theme }) => theme.text1};
|
||||
overflow: hidden;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
max-width: 100%;
|
||||
`}
|
||||
`
|
||||
|
||||
const BGOrb = styled.img`
|
||||
position: absolute;
|
||||
right: -64px;
|
||||
top: -64px;
|
||||
width: 180px;
|
||||
z-index: ${Z_INDEX.sticky};
|
||||
`
|
||||
|
||||
const WrappedCloseIcon = styled(X)`
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
stroke: #7c7c80;
|
||||
z-index: ${Z_INDEX.fixed};
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
|
||||
const END_TIMESTAMP = 1642272346 // Jan 15th
|
||||
|
||||
export default function SurveyPopup() {
|
||||
const theme = useTheme()
|
||||
const [showPopup, setShowSurveyPopup] = useShowSurveyPopup()
|
||||
|
||||
// show popup to 1% of users
|
||||
useEffect(() => {
|
||||
// has not visited page during A/B testing if undefined
|
||||
if (showPopup === undefined) {
|
||||
if (Math.random() < 0.01) {
|
||||
setShowSurveyPopup(true)
|
||||
// log a case of succesful view
|
||||
ReactGA.event({
|
||||
category: 'Survey',
|
||||
action: 'Saw Survey',
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [setShowSurveyPopup, showPopup])
|
||||
|
||||
// limit survey to 24 hours based on timestamps
|
||||
const timestamp = useCurrentBlockTimestamp()
|
||||
const durationOver = timestamp ? timestamp.toNumber() > END_TIMESTAMP : false
|
||||
|
||||
return (
|
||||
<>
|
||||
{!showPopup || durationOver ? null : (
|
||||
<Wrapper gap="10px">
|
||||
<WrappedCloseIcon
|
||||
onClick={() => {
|
||||
ReactGA.event({
|
||||
category: 'Survey',
|
||||
action: 'Clicked Survey Link',
|
||||
})
|
||||
setShowSurveyPopup(false)
|
||||
}}
|
||||
/>
|
||||
<BGOrb src={BGImage} />
|
||||
<ExternalLink href="https://www.surveymonkey.com/r/YGWV9VD">
|
||||
<RowFixed>
|
||||
<MessageCircle stroke={theme.black} size="20px" strokeWidth="1px" />
|
||||
<ThemedText.White fontWeight={600} color={theme.black} ml="6px">
|
||||
<Trans>Tell us what you think ↗</Trans>
|
||||
</ThemedText.White>
|
||||
</RowFixed>
|
||||
</ExternalLink>
|
||||
<ThemedText.Black style={{ zIndex: Z_INDEX.fixed }} fontWeight={400} fontSize="12px" color={theme.black}>
|
||||
<Trans>Take a 10 minute survey to help us improve your experience in the Uniswap app.</Trans>
|
||||
</ThemedText.Black>
|
||||
</Wrapper>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useContext } from 'react'
|
||||
import { AlertCircle, CheckCircle } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTransaction } from '../../state/transactions/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme'
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import styled from 'styled-components/macro'
|
||||
import { MEDIA_WIDTHS } from 'theme'
|
||||
|
||||
import { useActivePopups } from '../../state/application/hooks'
|
||||
import { useURLWarningVisible } from '../../state/user/hooks'
|
||||
import { useShowDonationLink, useURLWarningVisible } from '../../state/user/hooks'
|
||||
import { AutoColumn } from '../Column'
|
||||
import ClaimPopup from './ClaimPopup'
|
||||
import DonationLink from './DonationLink'
|
||||
import PopupItem from './PopupItem'
|
||||
|
||||
const MobilePopupWrapper = styled.div<{ height: string | number }>`
|
||||
@@ -14,11 +16,12 @@ const MobilePopupWrapper = styled.div<{ height: string | number }>`
|
||||
max-width: 100%;
|
||||
height: ${({ height }) => height};
|
||||
margin: ${({ height }) => (height ? '0 auto;' : 0)};
|
||||
margin-bottom: ${({ height }) => (height ? '20px' : 0)}};
|
||||
margin-bottom: ${({ height }) => (height ? '20px' : 0)};
|
||||
|
||||
display: none;
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
display: block;
|
||||
padding-top: 20px;
|
||||
`};
|
||||
`
|
||||
|
||||
@@ -65,6 +68,11 @@ export default function Popups() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const isNotOnMainnet = Boolean(chainId && chainId !== SupportedChainId.MAINNET)
|
||||
|
||||
const location = useLocation()
|
||||
const isOnSwapPage = location.pathname.includes('swap')
|
||||
const [donationVisible] = useShowDonationLink()
|
||||
const showDonation = donationVisible && isOnSwapPage
|
||||
|
||||
return (
|
||||
<>
|
||||
<FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}>
|
||||
@@ -72,9 +80,11 @@ export default function Popups() {
|
||||
{activePopups.map((item) => (
|
||||
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
|
||||
))}
|
||||
{showDonation ? <DonationLink /> : null}
|
||||
</FixedPopupColumn>
|
||||
<MobilePopupWrapper height={activePopups?.length > 0 ? 'fit-content' : 0}>
|
||||
<MobilePopupWrapper height={activePopups?.length > 0 || showDonation ? 'fit-content' : 0}>
|
||||
<MobilePopupInner>
|
||||
{showDonation ? <DonationLink /> : null}
|
||||
{activePopups // reverse so new items up front
|
||||
.slice(0)
|
||||
.reverse()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import JSBI from 'jsbi'
|
||||
import { transparentize } from 'polished'
|
||||
import { useState } from 'react'
|
||||
@@ -12,7 +13,6 @@ import styled from 'styled-components/macro'
|
||||
import { BIG_INT_ZERO } from '../../constants/misc'
|
||||
import { useColor } from '../../hooks/useColor'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { currencyId } from '../../utils/currencyId'
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import JSBI from 'jsbi'
|
||||
import { transparentize } from 'polished'
|
||||
import { useState } from 'react'
|
||||
@@ -12,7 +13,6 @@ import styled from 'styled-components/macro'
|
||||
import { BIG_INT_ZERO } from '../../constants/misc'
|
||||
import { useColor } from '../../hooks/useColor'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { currencyId } from '../../utils/currencyId'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ButtonText } from 'components/Button'
|
||||
import PositionListItem from 'components/PositionListItem'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
@@ -14,9 +15,7 @@ const DesktopHeader = styled.div`
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
justify-content: space-between;
|
||||
& > div:last-child {
|
||||
text-align: right;
|
||||
margin-right: 12px;
|
||||
@@ -36,9 +35,15 @@ const MobileHeader = styled.div`
|
||||
|
||||
type PositionListProps = React.PropsWithChildren<{
|
||||
positions: PositionDetails[]
|
||||
setUserHideClosedPositions: any
|
||||
userHideClosedPositions: boolean
|
||||
}>
|
||||
|
||||
export default function PositionList({ positions }: PositionListProps) {
|
||||
export default function PositionList({
|
||||
positions,
|
||||
setUserHideClosedPositions,
|
||||
userHideClosedPositions,
|
||||
}: PositionListProps) {
|
||||
return (
|
||||
<>
|
||||
<DesktopHeader>
|
||||
@@ -46,9 +51,9 @@ export default function PositionList({ positions }: PositionListProps) {
|
||||
<Trans>Your positions</Trans>
|
||||
{positions && ' (' + positions.length + ')'}
|
||||
</div>
|
||||
<div>
|
||||
<Trans>Status</Trans>
|
||||
</div>
|
||||
<ButtonText style={{ opacity: 0.6 }} onClick={() => setUserHideClosedPositions(!userHideClosedPositions)}>
|
||||
<Trans>Hide closed positions</Trans>
|
||||
</ButtonText>
|
||||
</DesktopHeader>
|
||||
<MobileHeader>
|
||||
<Trans>Your positions</Trans>
|
||||
|
||||
@@ -19,7 +19,7 @@ import { PositionDetails } from 'types/position'
|
||||
import { formatTickPrice } from 'utils/formatTickPrice'
|
||||
import { unwrappedToken } from 'utils/unwrappedToken'
|
||||
|
||||
import { DAI, USDC, USDT, WBTC, WETH9_EXTENDED } from '../../constants/tokens'
|
||||
import { DAI, USDC_MAINNET, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||
|
||||
const LinkRow = styled(Link)`
|
||||
align-items: center;
|
||||
@@ -145,7 +145,7 @@ export function getPriceOrderingFromPositionForUI(position?: Position): {
|
||||
const token1 = position.amount1.currency
|
||||
|
||||
// if token0 is a dollar-stable asset, set it as the quote token
|
||||
const stables = [DAI, USDC, USDT]
|
||||
const stables = [DAI, USDC_MAINNET, USDT]
|
||||
if (stables.some((stable) => stable.equals(token0))) {
|
||||
return {
|
||||
priceLower: position.token0PriceUpper.invert(),
|
||||
@@ -156,8 +156,8 @@ export function getPriceOrderingFromPositionForUI(position?: Position): {
|
||||
}
|
||||
|
||||
// if token1 is an ETH-/BTC-stable asset, set it as the base token
|
||||
const bases = [...Object.values(WETH9_EXTENDED), WBTC]
|
||||
if (bases.some((base) => base.equals(token1))) {
|
||||
const bases = [...Object.values(WRAPPED_NATIVE_CURRENCY), WBTC]
|
||||
if (bases.some((base) => base && base.equals(token1))) {
|
||||
return {
|
||||
priceLower: position.token0PriceUpper.invert(),
|
||||
priceUpper: position.token0PriceLower.invert(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Protocol } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { DAI, USDC, WBTC } from 'constants/tokens'
|
||||
import { DAI, USDC_MAINNET, WBTC } from 'constants/tokens'
|
||||
import { render } from 'test-utils'
|
||||
|
||||
import RoutingDiagram, { RoutingDiagramEntry } from './RoutingDiagram'
|
||||
@@ -10,16 +10,16 @@ const percent = (strings: TemplateStringsArray) => new Percent(parseInt(strings[
|
||||
|
||||
const singleRoute: RoutingDiagramEntry = {
|
||||
percent: percent`100`,
|
||||
path: [[USDC, DAI, FeeAmount.LOW]],
|
||||
path: [[USDC_MAINNET, DAI, FeeAmount.LOW]],
|
||||
protocol: Protocol.V3,
|
||||
}
|
||||
|
||||
const multiRoute: RoutingDiagramEntry[] = [
|
||||
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOWEST]], protocol: Protocol.V2 },
|
||||
{ percent: percent`75`, path: [[USDC_MAINNET, DAI, FeeAmount.LOWEST]], protocol: Protocol.V2 },
|
||||
{
|
||||
percent: percent`25`,
|
||||
path: [
|
||||
[USDC, WBTC, FeeAmount.MEDIUM],
|
||||
[USDC_MAINNET, WBTC, FeeAmount.MEDIUM],
|
||||
[WBTC, DAI, FeeAmount.HIGH],
|
||||
],
|
||||
protocol: Protocol.V3,
|
||||
@@ -47,16 +47,16 @@ jest.mock('hooks/useTokenInfoFromActiveList', () => ({
|
||||
}))
|
||||
|
||||
it('renders when no routes are provided', () => {
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={DAI} currencyOut={USDC} routes={[]} />)
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={DAI} currencyOut={USDC_MAINNET} routes={[]} />)
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('renders single route', () => {
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={USDC} currencyOut={DAI} routes={[singleRoute]} />)
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={USDC_MAINNET} currencyOut={DAI} routes={[singleRoute]} />)
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('renders multi route', () => {
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={USDC} currencyOut={DAI} routes={multiRoute} />)
|
||||
const { asFragment } = render(<RoutingDiagram currencyIn={USDC_MAINNET} currencyOut={DAI} routes={multiRoute} />)
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Protocol } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent } from '@uniswap/sdk-core'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import DoubleCurrencyLogo from 'components/DoubleLogo'
|
||||
import Row, { AutoRow } from 'components/Row'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
import { RoutingDiagramEntry } from 'lib/components/Swap/RoutingDiagram/utils'
|
||||
import { Box } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText, Z_INDEX } from 'theme'
|
||||
@@ -14,12 +14,6 @@ import { ThemedText, Z_INDEX } from 'theme'
|
||||
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
|
||||
export interface RoutingDiagramEntry {
|
||||
percent: Percent
|
||||
path: [Currency, Currency, FeeAmount][]
|
||||
protocol: Protocol
|
||||
}
|
||||
|
||||
const Wrapper = styled(Box)`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
@@ -3,45 +3,45 @@
|
||||
exports[`renders multi route 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-i2tbb-0 ivndgC css-vurnku"
|
||||
>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteContainerRow-sc-i2tbb-1 lmTMKd hLLNig hDkZVB"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteRow-sc-i2tbb-2 lmTMKd hLLNig hUDqOH"
|
||||
>
|
||||
<div
|
||||
class="RoutingDiagram__DottedLine-sc-o1ook0-4 kkXINS"
|
||||
class="RoutingDiagram__DottedLine-sc-i2tbb-4 cKqYfU"
|
||||
>
|
||||
<svg
|
||||
class="RoutingDiagram__DotColor-sc-o1ook0-5 kgYqrO"
|
||||
class="RoutingDiagram__DotColor-sc-i2tbb-5 fhSaBA"
|
||||
>
|
||||
dot_line.svg
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__OpaqueBadge-sc-i2tbb-6 knpfHF gGARxH"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__ProtocolBadge-sc-i2tbb-7 knpfHF lbdUti"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-15li2d9"
|
||||
>
|
||||
V2
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
75%
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 Row__AutoRow-sc-u7azg8-3 iqvZFe hLLNig cUhARX"
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
@@ -51,42 +51,42 @@ exports[`renders multi route 1`] = `
|
||||
CurrencyLogo currency=DAI
|
||||
</div>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteContainerRow-sc-i2tbb-1 lmTMKd hLLNig hDkZVB"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteRow-sc-i2tbb-2 lmTMKd hLLNig hUDqOH"
|
||||
>
|
||||
<div
|
||||
class="RoutingDiagram__DottedLine-sc-o1ook0-4 kkXINS"
|
||||
class="RoutingDiagram__DottedLine-sc-i2tbb-4 cKqYfU"
|
||||
>
|
||||
<svg
|
||||
class="RoutingDiagram__DotColor-sc-o1ook0-5 kgYqrO"
|
||||
class="RoutingDiagram__DotColor-sc-i2tbb-5 fhSaBA"
|
||||
>
|
||||
dot_line.svg
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__OpaqueBadge-sc-i2tbb-6 knpfHF gGARxH"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__ProtocolBadge-sc-i2tbb-7 knpfHF lbdUti"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-15li2d9"
|
||||
>
|
||||
V3
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
25%
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 Row__AutoRow-sc-u7azg8-3 iqvZFe hLLNig cUhARX"
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
@@ -102,45 +102,45 @@ exports[`renders multi route 1`] = `
|
||||
exports[`renders single route 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-i2tbb-0 ivndgC css-vurnku"
|
||||
>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteContainerRow-sc-i2tbb-1 lmTMKd hLLNig hDkZVB"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 RoutingDiagram__RouteRow-sc-i2tbb-2 lmTMKd hLLNig hUDqOH"
|
||||
>
|
||||
<div
|
||||
class="RoutingDiagram__DottedLine-sc-o1ook0-4 kkXINS"
|
||||
class="RoutingDiagram__DottedLine-sc-i2tbb-4 cKqYfU"
|
||||
>
|
||||
<svg
|
||||
class="RoutingDiagram__DotColor-sc-o1ook0-5 kgYqrO"
|
||||
class="RoutingDiagram__DotColor-sc-i2tbb-5 fhSaBA"
|
||||
>
|
||||
dot_line.svg
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__OpaqueBadge-sc-i2tbb-6 knpfHF gGARxH"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
class="Badge-sc-3epor3-0 RoutingDiagram__ProtocolBadge-sc-i2tbb-7 knpfHF lbdUti"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-15li2d9"
|
||||
>
|
||||
V3
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
class="theme__TextWrapper-sc-5lu8um-0 chxxqs RoutingDiagram__BadgeText-sc-i2tbb-8 ijjHig css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
100%
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
|
||||
class="sc-bdnxRM Row-sc-u7azg8-0 Row__AutoRow-sc-u7azg8-3 iqvZFe hLLNig cUhARX"
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
@@ -156,7 +156,7 @@ exports[`renders single route 1`] = `
|
||||
exports[`renders when no routes are provided 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-i2tbb-0 ivndgC css-vurnku"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import QuestionHelper from 'components/QuestionHelper'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { COMMON_BASES } from 'constants/routing'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
@@ -46,12 +44,6 @@ export default function CommonBases({
|
||||
|
||||
return bases.length > 0 ? (
|
||||
<MobileWrapper gap="md">
|
||||
<AutoRow>
|
||||
<Text fontWeight={500} fontSize={14}>
|
||||
<Trans>Common bases</Trans>
|
||||
</Text>
|
||||
<QuestionHelper text={<Trans>These tokens are commonly paired with other tokens.</Trans>} />
|
||||
</AutoRow>
|
||||
<AutoRow gap="4px">
|
||||
{bases.map((currency: Currency) => {
|
||||
const isSelected = selectedCurrency?.equals(currency)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { LightGreyCard } from 'components/Card'
|
||||
import QuestionHelper from 'components/QuestionHelper'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
|
||||
import { FixedSizeList } from 'react-window'
|
||||
@@ -10,7 +11,6 @@ import styled from 'styled-components/macro'
|
||||
|
||||
import TokenListLogo from '../../assets/svg/tokenlist.svg'
|
||||
import { useIsUserAddedToken } from '../../hooks/Tokens'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useCombinedActiveList } from '../../state/lists/hooks'
|
||||
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
import { useCurrencyBalance } from '../../state/wallet/hooks'
|
||||
|
||||
@@ -1,30 +1,31 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { Currency, Token } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
|
||||
import { getTokenFilter } from 'lib/hooks/useTokenList/filtering'
|
||||
import { tokenComparator, useSortTokensByQuery } from 'lib/hooks/useTokenList/sorting'
|
||||
import { KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Edit } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import AutoSizer from 'react-virtualized-auto-sizer'
|
||||
import { FixedSizeList } from 'react-window'
|
||||
import { Text } from 'rebass'
|
||||
import { useAllTokenBalances } from 'state/wallet/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ExtendedEther } from '../../constants/tokens'
|
||||
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
|
||||
import { isAddress } from '../../utils'
|
||||
import Column from '../Column'
|
||||
import Row, { RowBetween, RowFixed } from '../Row'
|
||||
import CommonBases from './CommonBases'
|
||||
import CurrencyList from './CurrencyList'
|
||||
import { filterTokens, useSortedTokensByQuery } from './filtering'
|
||||
import ImportRow from './ImportRow'
|
||||
import { useTokenComparator } from './sorting'
|
||||
import { PaddedColumn, SearchInput, Separator } from './styleds'
|
||||
|
||||
const ContentWrapper = styled(Column)`
|
||||
@@ -79,8 +80,6 @@ export function CurrencySearch({
|
||||
const [searchQuery, setSearchQuery] = useState<string>('')
|
||||
const debouncedQuery = useDebounce(searchQuery, 200)
|
||||
|
||||
const [invertSearchOrder] = useState<boolean>(false)
|
||||
|
||||
const allTokens = useAllTokens()
|
||||
|
||||
// if they input an address, use it
|
||||
@@ -100,27 +99,28 @@ export function CurrencySearch({
|
||||
}
|
||||
}, [isAddressSearch])
|
||||
|
||||
const tokenComparator = useTokenComparator(invertSearchOrder)
|
||||
|
||||
const filteredTokens: Token[] = useMemo(() => {
|
||||
return filterTokens(Object.values(allTokens), debouncedQuery)
|
||||
return Object.values(allTokens).filter(getTokenFilter(debouncedQuery))
|
||||
}, [allTokens, debouncedQuery])
|
||||
|
||||
const balances = useAllTokenBalances()
|
||||
const sortedTokens: Token[] = useMemo(() => {
|
||||
return filteredTokens.sort(tokenComparator)
|
||||
}, [filteredTokens, tokenComparator])
|
||||
return filteredTokens.sort(tokenComparator.bind(null, balances))
|
||||
}, [balances, filteredTokens])
|
||||
|
||||
const filteredSortedTokens = useSortedTokensByQuery(sortedTokens, debouncedQuery)
|
||||
const filteredSortedTokens = useSortTokensByQuery(debouncedQuery, sortedTokens)
|
||||
|
||||
const ether = useMemo(() => chainId && ExtendedEther.onChain(chainId), [chainId])
|
||||
const native = useNativeCurrency()
|
||||
|
||||
const filteredSortedTokensWithETH: Currency[] = useMemo(() => {
|
||||
if (!native) return filteredSortedTokens
|
||||
|
||||
const s = debouncedQuery.toLowerCase().trim()
|
||||
if (s === '' || s === 'e' || s === 'et' || s === 'eth') {
|
||||
return ether ? [ether, ...filteredSortedTokens] : filteredSortedTokens
|
||||
if (native.symbol?.toLowerCase()?.indexOf(s) !== -1) {
|
||||
return native ? [native, ...filteredSortedTokens] : filteredSortedTokens
|
||||
}
|
||||
return filteredSortedTokens
|
||||
}, [debouncedQuery, ether, filteredSortedTokens])
|
||||
}, [debouncedQuery, native, filteredSortedTokens])
|
||||
|
||||
const handleCurrencySelect = useCallback(
|
||||
(currency: Currency) => {
|
||||
@@ -148,8 +148,8 @@ export function CurrencySearch({
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
const s = debouncedQuery.toLowerCase().trim()
|
||||
if (s === 'eth' && ether) {
|
||||
handleCurrencySelect(ether)
|
||||
if (s === native?.symbol?.toLowerCase()) {
|
||||
handleCurrencySelect(native)
|
||||
} else if (filteredSortedTokensWithETH.length > 0) {
|
||||
if (
|
||||
filteredSortedTokensWithETH[0].symbol?.toLowerCase() === debouncedQuery.trim().toLowerCase() ||
|
||||
@@ -160,7 +160,7 @@ export function CurrencySearch({
|
||||
}
|
||||
}
|
||||
},
|
||||
[debouncedQuery, ether, filteredSortedTokensWithETH, handleCurrencySelect]
|
||||
[debouncedQuery, native, filteredSortedTokensWithETH, handleCurrencySelect]
|
||||
)
|
||||
|
||||
// menu ui
|
||||
|
||||
@@ -48,7 +48,7 @@ export function ImportToken(props: ImportProps) {
|
||||
<RowBetween>
|
||||
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
|
||||
<ThemedText.MediumHeader>
|
||||
<Plural value={tokens.length} one="Import token" other="Import tokens" />
|
||||
<Plural value={tokens.length} _1="Import token" other="Import tokens" />
|
||||
</ThemedText.MediumHeader>
|
||||
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
|
||||
</RowBetween>
|
||||
|
||||
@@ -16,7 +16,8 @@ import { PaddedColumn, Separator } from './styleds'
|
||||
const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding-bottom: 80px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
`
|
||||
|
||||
const ToggleWrapper = styled(RowBetween)`
|
||||
|
||||
@@ -3,8 +3,10 @@ import { t, Trans } from '@lingui/macro'
|
||||
import { TokenList } from '@uniswap/token-lists'
|
||||
import Card from 'components/Card'
|
||||
import { UNSUPPORTED_LIST_URLS } from 'constants/lists'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useListColor } from 'hooks/useColor'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import parseENSAddress from 'lib/utils/parseENSAddress'
|
||||
import uriToHttp from 'lib/utils/uriToHttp'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { CheckCircle, Settings } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
@@ -20,8 +22,6 @@ import { acceptListUpdate, disableList, enableList, removeList } from '../../sta
|
||||
import { useActiveListUrls, useAllLists, useIsListActive } from '../../state/lists/hooks'
|
||||
import { ExternalLink, IconWrapper, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import listVersionLabel from '../../utils/listVersionLabel'
|
||||
import { parseENSAddress } from '../../utils/parseENSAddress'
|
||||
import uriToHttp from '../../utils/uriToHttp'
|
||||
import { ButtonEmpty, ButtonPrimary } from '../Button'
|
||||
import Column, { AutoColumn } from '../Column'
|
||||
import ListLogo from '../ListLogo'
|
||||
@@ -31,7 +31,8 @@ import { CurrencyModalView } from './CurrencySearchModal'
|
||||
import { PaddedColumn, SearchInput, Separator, SeparatorDark } from './styleds'
|
||||
|
||||
const Wrapper = styled(Column)`
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
`
|
||||
|
||||
const UnpaddedLinkStyledButton = styled(LinkStyledButton)`
|
||||
@@ -229,7 +230,7 @@ const ListContainer = styled.div`
|
||||
padding: 1rem;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding-bottom: 80px;
|
||||
flex: 1;
|
||||
`
|
||||
|
||||
export function ManageLists({
|
||||
|
||||
@@ -5,7 +5,7 @@ import Column from 'components/Column'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import Row, { RowBetween, RowFixed } from 'components/Row'
|
||||
import { useToken } from 'hooks/Tokens'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { RefObject, useCallback, useMemo, useRef, useState } from 'react'
|
||||
import { useRemoveUserAddedToken, useUserAddedTokens } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AutoColumn } from 'components/Column'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import ListLogo from 'components/ListLogo'
|
||||
import { RowFixed } from 'components/Row'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { transparentize } from 'polished'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import { Token } from '@uniswap/sdk-core'
|
||||
import { TokenInfo } from '@uniswap/token-lists'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { isAddress } from '../../utils'
|
||||
|
||||
const alwaysTrue = () => true
|
||||
|
||||
/**
|
||||
* Create a filter function to apply to a token for whether it matches a particular search query
|
||||
* @param search the search query to apply to the token
|
||||
*/
|
||||
export function createTokenFilterFunction<T extends Token | TokenInfo>(search: string): (tokens: T) => boolean {
|
||||
const searchingAddress = isAddress(search)
|
||||
|
||||
if (searchingAddress) {
|
||||
const lower = searchingAddress.toLowerCase()
|
||||
return (t: T) => ('isToken' in t ? searchingAddress === t.address : lower === t.address.toLowerCase())
|
||||
}
|
||||
|
||||
const lowerSearchParts = search
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter((s) => s.length > 0)
|
||||
|
||||
if (lowerSearchParts.length === 0) return alwaysTrue
|
||||
|
||||
const matchesSearch = (s: string): boolean => {
|
||||
const sParts = s
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter((s) => s.length > 0)
|
||||
|
||||
return lowerSearchParts.every((p) => p.length === 0 || sParts.some((sp) => sp.startsWith(p) || sp.endsWith(p)))
|
||||
}
|
||||
|
||||
return ({ name, symbol }: T): boolean => Boolean((symbol && matchesSearch(symbol)) || (name && matchesSearch(name)))
|
||||
}
|
||||
|
||||
export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: string): T[] {
|
||||
return tokens.filter(createTokenFilterFunction(search))
|
||||
}
|
||||
|
||||
export function useSortedTokensByQuery(tokens: Token[] | undefined, searchQuery: string): Token[] {
|
||||
return useMemo(() => {
|
||||
if (!tokens) {
|
||||
return []
|
||||
}
|
||||
|
||||
const symbolMatch = searchQuery
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter((s) => s.length > 0)
|
||||
|
||||
if (symbolMatch.length > 1) {
|
||||
return tokens
|
||||
}
|
||||
|
||||
const exactMatches: Token[] = []
|
||||
const symbolSubtrings: Token[] = []
|
||||
const rest: Token[] = []
|
||||
|
||||
// sort tokens by exact match -> subtring on symbol match -> rest
|
||||
tokens.map((token) => {
|
||||
if (token.symbol?.toLowerCase() === symbolMatch[0]) {
|
||||
return exactMatches.push(token)
|
||||
} else if (token.symbol?.toLowerCase().startsWith(searchQuery.toLowerCase().trim())) {
|
||||
return symbolSubtrings.push(token)
|
||||
} else {
|
||||
return rest.push(token)
|
||||
}
|
||||
})
|
||||
|
||||
return [...exactMatches, ...symbolSubtrings, ...rest]
|
||||
}, [tokens, searchQuery])
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { useAllTokenBalances } from '../../state/wallet/hooks'
|
||||
|
||||
// compare two token amounts with highest one coming first
|
||||
function balanceComparator(balanceA?: CurrencyAmount<Currency>, balanceB?: CurrencyAmount<Currency>) {
|
||||
if (balanceA && balanceB) {
|
||||
return balanceA.greaterThan(balanceB) ? -1 : balanceA.equalTo(balanceB) ? 0 : 1
|
||||
} else if (balanceA && balanceA.greaterThan('0')) {
|
||||
return -1
|
||||
} else if (balanceB && balanceB.greaterThan('0')) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function getTokenComparator(balances: {
|
||||
[tokenAddress: string]: CurrencyAmount<Currency> | undefined
|
||||
}): (tokenA: Token, tokenB: Token) => number {
|
||||
return function sortTokens(tokenA: Token, tokenB: Token): number {
|
||||
// -1 = a is first
|
||||
// 1 = b is first
|
||||
|
||||
// sort by balances
|
||||
const balanceA = balances[tokenA.address]
|
||||
const balanceB = balances[tokenB.address]
|
||||
|
||||
const balanceComp = balanceComparator(balanceA, balanceB)
|
||||
if (balanceComp !== 0) return balanceComp
|
||||
|
||||
if (tokenA.symbol && tokenB.symbol) {
|
||||
// sort by symbol
|
||||
return tokenA.symbol.toLowerCase() < tokenB.symbol.toLowerCase() ? -1 : 1
|
||||
} else {
|
||||
return tokenA.symbol ? -1 : tokenB.symbol ? -1 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useTokenComparator(inverted: boolean): (tokenA: Token, tokenB: Token) => number {
|
||||
const balances = useAllTokenBalances()
|
||||
const comparator = useMemo(() => getTokenComparator(balances ?? {}), [balances])
|
||||
return useMemo(() => {
|
||||
if (inverted) {
|
||||
return (tokenA: Token, tokenB: Token) => comparator(tokenA, tokenB) * -1
|
||||
} else {
|
||||
return comparator
|
||||
}
|
||||
}, [inverted, comparator])
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { AUTO_ROUTER_SUPPORTED_CHAINS } from 'lib/hooks/routing/clientSideSmartOrderRouter'
|
||||
import { useContext, useRef, useState } from 'react'
|
||||
import { Settings, X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { Text } from 'rebass'
|
||||
import { AUTO_ROUTER_SUPPORTED_CHAINS } from 'state/routing/clientSideSmartOrderRouter/constants'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import Badge from 'components/Badge'
|
||||
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
|
||||
import { CHAIN_INFO } from 'constants/chainInfo'
|
||||
import { L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useAddTokenToMetamask from 'hooks/useAddTokenToMetamask'
|
||||
import { ReactNode, useContext } from 'react'
|
||||
import { AlertCircle, AlertTriangle, ArrowUpCircle, CheckCircle } from 'react-feather'
|
||||
@@ -11,7 +13,6 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import MetaMaskLogo from '../../assets/images/metamask.png'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { CloseIcon, CustomLightSpinner } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import ms from 'ms.macro'
|
||||
import { darken } from 'polished'
|
||||
import { useContext, useState } from 'react'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { darken } from 'polished'
|
||||
import styled from 'styled-components/macro'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
|
||||
import { injected } from '../../connectors'
|
||||
import { SUPPORTED_WALLETS } from '../../constants/wallet'
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'
|
||||
import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { PrivacyPolicy } from 'components/PrivacyPolicy'
|
||||
import Row, { AutoRow, RowBetween } from 'components/Row'
|
||||
@@ -10,6 +7,9 @@ import { useEffect, useState } from 'react'
|
||||
import { ArrowLeft, ArrowRight, Info } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import styled from 'styled-components/macro'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
import { UnsupportedChainIdError, useWeb3React } from 'web3-react-core'
|
||||
import { WalletConnectConnector } from 'web3-react-walletconnect-connector'
|
||||
|
||||
import MetamaskIcon from '../../assets/images/metamask.png'
|
||||
import { ReactComponent as Close } from '../../assets/images/x.svg'
|
||||
@@ -111,7 +111,7 @@ const HoverText = styled.div`
|
||||
|
||||
const LinkCard = styled(Card)`
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
color: ${({ theme }) => theme.white};
|
||||
color: ${({ theme }) => theme.text3};
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
@@ -320,7 +320,7 @@ export default function WalletModal({
|
||||
<ContentWrapper>
|
||||
{error instanceof UnsupportedChainIdError ? (
|
||||
<h5>
|
||||
<Trans>Please connect to the appropriate Ethereum network.</Trans>
|
||||
<Trans>Please connect to a supported network in the dropdown menu or in your wallet.</Trans>
|
||||
</h5>
|
||||
) : (
|
||||
<Trans>Error connecting. Try refreshing the page.</Trans>
|
||||
@@ -416,9 +416,9 @@ export default function WalletModal({
|
||||
<RowBetween>
|
||||
<AutoRow gap="4px">
|
||||
<Info size={20} />
|
||||
<ThemedText.White fontSize={14}>
|
||||
<ThemedText.Label fontSize={14}>
|
||||
<Trans>How this app uses APIs</Trans>
|
||||
</ThemedText.White>
|
||||
</ThemedText.Label>
|
||||
</AutoRow>
|
||||
<ArrowRight size={16} />
|
||||
</RowBetween>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useEffect } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { useWeb3React } from 'web3-react-core'
|
||||
|
||||
import { network } from '../../connectors'
|
||||
import { NetworkContextName } from '../../constants/misc'
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'
|
||||
import { Connector } from '@web3-react/types'
|
||||
import { darken } from 'polished'
|
||||
import { useMemo } from 'react'
|
||||
import { Activity } from 'react-feather'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
import { UnsupportedChainIdError, useWeb3React } from 'web3-react-core'
|
||||
|
||||
import { NetworkContextName } from '../../constants/misc'
|
||||
import useENSName from '../../hooks/useENSName'
|
||||
@@ -35,9 +36,12 @@ const Web3StatusGeneric = styled(ButtonSecondary)`
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
padding: 0.5rem;
|
||||
border-radius: 12px;
|
||||
border-radius: 14px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
height: 36px;
|
||||
margin-right: 2px;
|
||||
margin-left: 1px;
|
||||
:focus {
|
||||
outline: none;
|
||||
}
|
||||
@@ -82,7 +86,7 @@ const Web3StatusConnect = styled(Web3StatusGeneric)<{ faded?: boolean }>`
|
||||
`
|
||||
|
||||
const Web3StatusConnected = styled(Web3StatusGeneric)<{ pending?: boolean }>`
|
||||
background-color: ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg0)};
|
||||
background-color: ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg1)};
|
||||
border: 1px solid ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg1)};
|
||||
color: ${({ pending, theme }) => (pending ? theme.white : theme.text1)};
|
||||
font-weight: 500;
|
||||
@@ -127,7 +131,7 @@ function Sock() {
|
||||
)
|
||||
}
|
||||
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<StatusIcon connector={connector} />
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useEffect } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
import { RouteComponentProps } from 'react-router-dom'
|
||||
import { getCLS, getFCP, getFID, getLCP, Metric } from 'web-vitals'
|
||||
|
||||
import { GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY } from './index'
|
||||
|
||||
function reportWebVitals({ name, delta, id }: Metric) {
|
||||
ReactGA.timing({
|
||||
category: 'Web Vitals',
|
||||
@@ -31,5 +33,15 @@ export default function GoogleAnalyticsReporter({ location: { pathname, search }
|
||||
useEffect(() => {
|
||||
ReactGA.pageview(`${pathname}${search}`)
|
||||
}, [pathname, search])
|
||||
|
||||
useEffect(() => {
|
||||
// typed as 'any' in react-ga -.-
|
||||
ReactGA.ga((tracker: any) => {
|
||||
if (!tracker) return
|
||||
|
||||
const clientId = tracker.get('clientId')
|
||||
window.localStorage.setItem(GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY, clientId)
|
||||
})
|
||||
}, [])
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import ReactGA from 'react-ga'
|
||||
import { isMobile } from 'utils/userAgent'
|
||||
|
||||
export const GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY = 'ga_client_id'
|
||||
const GOOGLE_ANALYTICS_ID: string | undefined = process.env.REACT_APP_GOOGLE_ANALYTICS_ID
|
||||
|
||||
const storedClientId = window.localStorage.getItem(GOOGLE_ANALYTICS_CLIENT_ID_STORAGE_KEY)
|
||||
|
||||
if (typeof GOOGLE_ANALYTICS_ID === 'string') {
|
||||
ReactGA.initialize(GOOGLE_ANALYTICS_ID, {
|
||||
gaOptions: {
|
||||
storage: 'none',
|
||||
storeGac: false,
|
||||
clientId: storedClientId ?? undefined,
|
||||
},
|
||||
})
|
||||
ReactGA.set({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useState } from 'react'
|
||||
import { Text } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
@@ -8,7 +9,6 @@ import styled from 'styled-components/macro'
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import tokenLogo from '../../assets/images/token-logo.png'
|
||||
import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useClaimCallback, useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
import { useIsTransactionPending } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import JSBI from 'jsbi'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Text } from 'rebass'
|
||||
@@ -8,7 +9,6 @@ import styled from 'styled-components/macro'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import tokenLogo from '../../assets/images/token-logo.png'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useModalOpen, useToggleSelfClaimModal } from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import StakingRewardsJson from '@uniswap/liquidity-staker/build/StakingRewards.json'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useStakingContract } from '../../hooks/useContract'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useContract } from '../../hooks/useContract'
|
||||
import { StakingInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
@@ -15,6 +16,12 @@ import Modal from '../Modal'
|
||||
import { LoadingView, SubmittedView } from '../ModalViews'
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
const { abi: STAKING_REWARDS_ABI } = StakingRewardsJson
|
||||
|
||||
function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean) {
|
||||
return useContract(stakingAddress, STAKING_REWARDS_ABI, withSignerIfPossible)
|
||||
}
|
||||
|
||||
const ContentWrapper = styled(AutoColumn)`
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import StakingRewardsJson from '@uniswap/liquidity-staker/build/StakingRewards.json'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useV2LiquidityTokenPermit } from 'hooks/useV2LiquidityTokenPermit'
|
||||
import { useCallback, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
||||
import { usePairContract, useStakingContract, useV2RouterContract } from '../../hooks/useContract'
|
||||
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
|
||||
import { useContract, usePairContract, useV2RouterContract } from '../../hooks/useContract'
|
||||
import useTransactionDeadline from '../../hooks/useTransactionDeadline'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { StakingInfo, useDerivedStakeInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
@@ -24,6 +25,12 @@ import { LoadingView, SubmittedView } from '../ModalViews'
|
||||
import ProgressCircles from '../ProgressSteps'
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
const { abi: STAKING_REWARDS_ABI } = StakingRewardsJson
|
||||
|
||||
function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean) {
|
||||
return useContract(stakingAddress, STAKING_REWARDS_ABI, withSignerIfPossible)
|
||||
}
|
||||
|
||||
const HypotheticalRewardRate = styled.div<{ dim: boolean }>`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import StakingRewardsJson from '@uniswap/liquidity-staker/build/StakingRewards.json'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useStakingContract } from '../../hooks/useContract'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useContract } from '../../hooks/useContract'
|
||||
import { StakingInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
@@ -16,6 +17,12 @@ import Modal from '../Modal'
|
||||
import { LoadingView, SubmittedView } from '../ModalViews'
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
const { abi: STAKING_REWARDS_ABI } = StakingRewardsJson
|
||||
|
||||
function useStakingContract(stakingAddress?: string, withSignerIfPossible?: boolean) {
|
||||
return useContract(stakingAddress, STAKING_REWARDS_ABI, withSignerIfPossible)
|
||||
}
|
||||
|
||||
const ContentWrapper = styled(AutoColumn)`
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Trans } from '@lingui/macro'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import Card from 'components/Card'
|
||||
import { LoadingRows } from 'components/Loader/styled'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
@@ -12,7 +13,6 @@ import { computeRealizedLPFeePercent } from '../../utils/prices'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import FormattedPriceImpact from './FormattedPriceImpact'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
|
||||
const StyledCard = styled(Card)`
|
||||
padding: 0;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { tradeMeaningfullyDiffers } from 'utils/tradeMeaningFullyDiffer'
|
||||
|
||||
import TransactionConfirmationModal, {
|
||||
ConfirmationModalContent,
|
||||
@@ -11,23 +12,6 @@ import TransactionConfirmationModal, {
|
||||
import SwapModalFooter from './SwapModalFooter'
|
||||
import SwapModalHeader from './SwapModalHeader'
|
||||
|
||||
/**
|
||||
* Returns true if the trade requires a confirmation of details before we can submit it
|
||||
* @param args either a pair of V2 trades or a pair of V3 trades
|
||||
*/
|
||||
function tradeMeaningfullyDiffers(
|
||||
...args: [Trade<Currency, Currency, TradeType>, Trade<Currency, Currency, TradeType>]
|
||||
): boolean {
|
||||
const [tradeA, tradeB] = args
|
||||
return (
|
||||
tradeA.tradeType !== tradeB.tradeType ||
|
||||
!tradeA.inputAmount.currency.equals(tradeB.inputAmount.currency) ||
|
||||
!tradeA.inputAmount.equalTo(tradeB.inputAmount) ||
|
||||
!tradeA.outputAmount.currency.equals(tradeB.outputAmount.currency) ||
|
||||
!tradeA.outputAmount.equalTo(tradeB.outputAmount)
|
||||
)
|
||||
}
|
||||
|
||||
export default function ConfirmSwapModal({
|
||||
trade,
|
||||
originalTrade,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, TradeType } from '@uniswap/sdk-core'
|
||||
import { ChainId } from '@uniswap/smart-order-router'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer } from 'components/Loader/styled'
|
||||
import { RowFixed } from 'components/Row'
|
||||
@@ -32,8 +31,6 @@ const StyledGasIcon = styled(GasIcon)`
|
||||
}
|
||||
`
|
||||
|
||||
export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = [ChainId.MAINNET]
|
||||
|
||||
export default function GasEstimateBadge({
|
||||
trade,
|
||||
loading,
|
||||
|
||||
@@ -6,7 +6,8 @@ import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer } from 'components/Loader/styled'
|
||||
import Row, { RowBetween, RowFixed } from 'components/Row'
|
||||
import { MouseoverTooltipContent } from 'components/Tooltip'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { darken } from 'polished'
|
||||
import { useState } from 'react'
|
||||
import { ChevronDown, Info } from 'react-feather'
|
||||
@@ -15,7 +16,7 @@ import styled, { keyframes, useTheme } from 'styled-components/macro'
|
||||
import { HideSmall, ThemedText } from 'theme'
|
||||
|
||||
import { AdvancedSwapDetails } from './AdvancedSwapDetails'
|
||||
import GasEstimateBadge, { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
import GasEstimateBadge from './GasEstimateBadge'
|
||||
import { ResponsiveTooltipContainer } from './styleds'
|
||||
import SwapRoute from './SwapRoute'
|
||||
import TradePrice from './TradePrice'
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import { Currency, TradeType } from '@uniswap/sdk-core'
|
||||
import AnimatedDropdown from 'components/AnimatedDropdown'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingRows } from 'components/Loader/styled'
|
||||
import RoutingDiagram, { RoutingDiagramEntry } from 'components/RoutingDiagram/RoutingDiagram'
|
||||
import RoutingDiagram from 'components/RoutingDiagram/RoutingDiagram'
|
||||
import { AutoRow, RowBetween } from 'components/Row'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useAutoRouterSupported from 'hooks/useAutoRouterSupported'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { getTokenPath } from 'lib/components/Swap/RoutingDiagram/utils'
|
||||
import { memo, useState } from 'react'
|
||||
import { Plus } from 'react-feather'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
@@ -16,7 +16,6 @@ import { useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { Separator, ThemedText } from 'theme'
|
||||
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
import { AutoRouterLabel, AutoRouterLogo } from './RouterLabel'
|
||||
|
||||
const Wrapper = styled(AutoColumn)<{ darkMode?: boolean; fixedOpen?: boolean }>`
|
||||
@@ -39,8 +38,6 @@ const OpenCloseIcon = styled(Plus)<{ open?: boolean }>`
|
||||
}
|
||||
`
|
||||
|
||||
const V2_DEFAULT_FEE_TIER = 3000
|
||||
|
||||
interface SwapRouteProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType>
|
||||
syncing: boolean
|
||||
@@ -83,57 +80,29 @@ export default memo(function SwapRoute({ trade, syncing, fixedOpen = false, ...r
|
||||
routes={routes}
|
||||
/>
|
||||
)}
|
||||
<Separator />
|
||||
{autoRouterSupported &&
|
||||
(syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '250px', height: '15px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<ThemedText.Main fontSize={12} width={400} margin={0}>
|
||||
{trade?.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? (
|
||||
<Trans>Best price route costs ~{formattedGasPriceString} in gas. </Trans>
|
||||
) : null}{' '}
|
||||
<Trans>
|
||||
This route optimizes your total output by considering split routes, multiple hops, and the gas cost of
|
||||
each step.
|
||||
</Trans>
|
||||
</ThemedText.Main>
|
||||
))}
|
||||
|
||||
{autoRouterSupported && (
|
||||
<>
|
||||
<Separator />
|
||||
{syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '250px', height: '15px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<ThemedText.Main fontSize={12} width={400} margin={0}>
|
||||
{trade?.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? (
|
||||
<Trans>Best price route costs ~{formattedGasPriceString} in gas. </Trans>
|
||||
) : null}{' '}
|
||||
<Trans>
|
||||
This route optimizes your total output by considering split routes, multiple hops, and the gas cost
|
||||
of each step.
|
||||
</Trans>
|
||||
</ThemedText.Main>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</AutoRow>
|
||||
</AnimatedDropdown>
|
||||
</Wrapper>
|
||||
)
|
||||
})
|
||||
|
||||
function getTokenPath(trade: Trade<Currency, Currency, TradeType>): RoutingDiagramEntry[] {
|
||||
return trade.swaps.map(({ route: { path: tokenPath, pools, protocol }, inputAmount, outputAmount }) => {
|
||||
const portion =
|
||||
trade.tradeType === TradeType.EXACT_INPUT
|
||||
? inputAmount.divide(trade.inputAmount)
|
||||
: outputAmount.divide(trade.outputAmount)
|
||||
|
||||
const percent = new Percent(portion.numerator, portion.denominator)
|
||||
|
||||
const path: RoutingDiagramEntry['path'] = []
|
||||
for (let i = 0; i < pools.length; i++) {
|
||||
const nextPool = pools[i]
|
||||
const tokenIn = tokenPath[i]
|
||||
const tokenOut = tokenPath[i + 1]
|
||||
|
||||
const entry: RoutingDiagramEntry['path'][0] = [
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
nextPool instanceof Pair ? V2_DEFAULT_FEE_TIER : nextPool.fee,
|
||||
]
|
||||
|
||||
path.push(entry)
|
||||
}
|
||||
|
||||
return {
|
||||
percent,
|
||||
path,
|
||||
protocol,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const StyledPriceContainer = styled.button`
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
align-items: center
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AutoColumn } from 'components/Column'
|
||||
import CurrencyLogo from 'components/CurrencyLogo'
|
||||
import Modal from 'components/Modal'
|
||||
import { AutoRow, RowBetween } from 'components/Row'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { CloseIcon, ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useState } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
@@ -7,7 +8,6 @@ import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
import { UNI } from '../../constants/tokens'
|
||||
import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useDelegateCallback } from '../../state/governance/hooks'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
@@ -38,7 +38,7 @@ const EmptyState = ({ HeaderContent, SubHeaderContent }: EmptyStateProps) => (
|
||||
|
||||
export default function ProposalEmptyState() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
if (chainId && L2_CHAIN_IDS.includes(chainId)) {
|
||||
if (chainId && chainId !== SupportedChainId.MAINNET) {
|
||||
return (
|
||||
<EmptyState
|
||||
HeaderContent={() => <Trans>Please connect to Layer 1 Ethereum</Trans>}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useContext, useState } from 'react'
|
||||
import { ArrowUpCircle, X } from 'react-feather'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useUserVotes, useVoteCallback } from '../../state/governance/hooks'
|
||||
import { VoteOption } from '../../state/governance/types'
|
||||
import { CustomLightSpinner, ThemedText } from '../../theme'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FortmaticConnector as FortmaticConnectorCore } from '@web3-react/fortmatic-connector'
|
||||
import { FortmaticConnector as FortmaticConnectorCore } from 'web3-react-fortmatic-connector'
|
||||
|
||||
export const OVERLAY_READY = 'OVERLAY_READY'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { ConnectorUpdate } from '@web3-react/types'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { AbstractConnector } from 'web3-react-abstract-connector'
|
||||
import { ConnectorUpdate } from 'web3-react-types'
|
||||
|
||||
interface NetworkConnectorArguments {
|
||||
urls: { [chainId: number]: string }
|
||||
@@ -36,11 +36,14 @@ class MiniRpcProvider implements AsyncSendable {
|
||||
public readonly path: string
|
||||
public readonly batchWaitTimeMs: number
|
||||
|
||||
private readonly connector: NetworkConnector
|
||||
|
||||
private nextId = 1
|
||||
private batchTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||
private batch: BatchItem[] = []
|
||||
|
||||
constructor(chainId: number, url: string, batchWaitTimeMs?: number) {
|
||||
constructor(connector: NetworkConnector, chainId: number, url: string, batchWaitTimeMs?: number) {
|
||||
this.connector = connector
|
||||
this.chainId = chainId
|
||||
this.url = url
|
||||
const parsed = new URL(url)
|
||||
@@ -52,7 +55,21 @@ class MiniRpcProvider implements AsyncSendable {
|
||||
|
||||
public readonly clearBatch = async () => {
|
||||
console.debug('Clearing batch', this.batch)
|
||||
const batch = this.batch
|
||||
let batch = this.batch
|
||||
|
||||
batch = batch.filter((b) => {
|
||||
if (b.request.method === 'wallet_switchEthereumChain') {
|
||||
try {
|
||||
this.connector.changeChainId(parseInt((b.request.params as [{ chainId: string }])[0].chainId))
|
||||
b.resolve({ id: b.request.id })
|
||||
} catch (error) {
|
||||
b.reject(error)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
this.batch = []
|
||||
this.batchTimeoutId = null
|
||||
let response: Response
|
||||
@@ -148,9 +165,9 @@ export class NetworkConnector extends AbstractConnector {
|
||||
invariant(defaultChainId || Object.keys(urls).length === 1, 'defaultChainId is a required argument with >1 url')
|
||||
super({ supportedChainIds: Object.keys(urls).map((k): number => Number(k)) })
|
||||
|
||||
this.currentChainId = defaultChainId || Number(Object.keys(urls)[0])
|
||||
this.currentChainId = defaultChainId ?? Number(Object.keys(urls)[0])
|
||||
this.providers = Object.keys(urls).reduce<{ [chainId: number]: MiniRpcProvider }>((accumulator, chainId) => {
|
||||
accumulator[Number(chainId)] = new MiniRpcProvider(Number(chainId), urls[Number(chainId)])
|
||||
accumulator[Number(chainId)] = new MiniRpcProvider(this, Number(chainId), urls[Number(chainId)])
|
||||
return accumulator
|
||||
}, {})
|
||||
}
|
||||
@@ -178,4 +195,21 @@ export class NetworkConnector extends AbstractConnector {
|
||||
public deactivate() {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Meant to be called only by MiniRpcProvider
|
||||
* @param chainId the new chain id
|
||||
*/
|
||||
public changeChainId(chainId: number) {
|
||||
if (chainId in this.providers) {
|
||||
this.currentChainId = chainId
|
||||
this.emitUpdate({
|
||||
chainId,
|
||||
account: null,
|
||||
provider: this.providers[chainId],
|
||||
})
|
||||
} else {
|
||||
throw new Error(`Unsupported chain ID: ${chainId}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
import { Web3Provider } from '@ethersproject/providers'
|
||||
import { SafeAppConnector } from '@gnosis.pm/safe-apps-web3-react'
|
||||
import { InjectedConnector } from '@web3-react/injected-connector'
|
||||
import { PortisConnector } from '@web3-react/portis-connector'
|
||||
import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
|
||||
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
|
||||
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
||||
import { INFURA_NETWORK_URLS } from 'constants/infura'
|
||||
import { InjectedConnector } from 'web3-react-injected-connector'
|
||||
import { PortisConnector } from 'web3-react-portis-connector'
|
||||
import { WalletConnectConnector } from 'web3-react-walletconnect-connector'
|
||||
import { WalletLinkConnector } from 'web3-react-walletlink-connector'
|
||||
|
||||
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
|
||||
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from '../constants/chains'
|
||||
import getLibrary from '../utils/getLibrary'
|
||||
import { FortmaticConnector } from './Fortmatic'
|
||||
import { NetworkConnector } from './NetworkConnector'
|
||||
|
||||
const INFURA_KEY = process.env.REACT_APP_INFURA_KEY
|
||||
const FORMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY
|
||||
const PORTIS_ID = process.env.REACT_APP_PORTIS_ID
|
||||
|
||||
if (typeof INFURA_KEY === 'undefined') {
|
||||
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
||||
}
|
||||
|
||||
export const NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
||||
[SupportedChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.GOERLI]: `https://goerli.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.OPTIMISM]: `https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: `https://optimism-kovan.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ARBITRUM_ONE]: `https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: `https://arbitrum-rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||
}
|
||||
|
||||
export const network = new NetworkConnector({
|
||||
urls: NETWORK_URLS,
|
||||
urls: INFURA_NETWORK_URLS,
|
||||
defaultChainId: 1,
|
||||
})
|
||||
|
||||
@@ -49,7 +33,7 @@ export const gnosisSafe = new SafeAppConnector()
|
||||
|
||||
export const walletconnect = new WalletConnectConnector({
|
||||
supportedChainIds: ALL_SUPPORTED_CHAIN_IDS,
|
||||
rpc: NETWORK_URLS,
|
||||
rpc: INFURA_NETWORK_URLS,
|
||||
qrcode: true,
|
||||
})
|
||||
|
||||
@@ -65,9 +49,9 @@ export const portis = new PortisConnector({
|
||||
networks: [1],
|
||||
})
|
||||
|
||||
// mainnet only
|
||||
export const walletlink = new WalletLinkConnector({
|
||||
url: NETWORK_URLS[SupportedChainId.MAINNET],
|
||||
url: INFURA_NETWORK_URLS[SupportedChainId.MAINNET],
|
||||
appName: 'Uniswap',
|
||||
appLogoUrl: UNISWAP_LOGO_URL,
|
||||
supportedChainIds: ALL_SUPPORTED_CHAIN_IDS,
|
||||
})
|
||||
|
||||
@@ -11,6 +11,8 @@ export const MULTICALL_ADDRESS: AddressMap = {
|
||||
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
SupportedChainId.POLYGON,
|
||||
]),
|
||||
[SupportedChainId.ARBITRUM_ONE]: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: '0xa501c031958F579dB7676fF1CE78AD305794d579',
|
||||
@@ -23,12 +25,16 @@ export const V3_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0xE592427A
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
])
|
||||
export const SWAP_ROUTER_ADDRESSES: AddressMap = constructSameAddressMap('0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', [
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
])
|
||||
|
||||
/**
|
||||
@@ -63,12 +69,16 @@ export const V3_CORE_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V3_
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
SupportedChainId.POLYGON,
|
||||
])
|
||||
export const QUOTER_ADDRESSES: AddressMap = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6', [
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
SupportedChainId.POLYGON,
|
||||
])
|
||||
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = constructSameAddressMap(
|
||||
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88',
|
||||
@@ -77,6 +87,8 @@ export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = constructSameA
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
SupportedChainId.POLYGON,
|
||||
]
|
||||
)
|
||||
export const ENS_REGISTRAR_ADDRESSES: AddressMap = {
|
||||
@@ -92,4 +104,11 @@ export const SOCKS_CONTROLLER_ADDRESSES: AddressMap = {
|
||||
export const V3_MIGRATOR_ADDRESSES: AddressMap = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
SupportedChainId.POLYGON,
|
||||
])
|
||||
|
||||
export const TICK_LENS_ADDRESSES: AddressMap = {
|
||||
[SupportedChainId.ARBITRUM_ONE]: '0xbfd8137f7d1516D3ea5cA83523914859ec47F573',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: '0xbfd8137f7d1516D3ea5cA83523914859ec47F573',
|
||||
}
|
||||
|
||||
170
src/constants/chainInfo.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import ethereumLogoUrl from 'assets/images/ethereum-logo.png'
|
||||
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
|
||||
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
|
||||
import polygonMaticLogo from 'assets/svg/polygon-matic-logo.svg'
|
||||
import ms from 'ms.macro'
|
||||
|
||||
import { SupportedChainId, SupportedL1ChainId, SupportedL2ChainId } from './chains'
|
||||
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
|
||||
|
||||
export enum NetworkType {
|
||||
L1,
|
||||
L2,
|
||||
}
|
||||
|
||||
interface BaseChainInfo {
|
||||
readonly networkType: NetworkType
|
||||
readonly blockWaitMsBeforeWarning?: number
|
||||
readonly docs: string
|
||||
readonly bridge?: string
|
||||
readonly explorer: string
|
||||
readonly infoLink: string
|
||||
readonly logoUrl: string
|
||||
readonly label: string
|
||||
readonly helpCenterUrl?: string
|
||||
readonly nativeCurrency: {
|
||||
name: string // e.g. 'Goerli ETH',
|
||||
symbol: string // e.g. 'gorETH',
|
||||
decimals: number // e.g. 18,
|
||||
}
|
||||
}
|
||||
|
||||
export interface L1ChainInfo extends BaseChainInfo {
|
||||
readonly networkType: NetworkType.L1
|
||||
}
|
||||
|
||||
export interface L2ChainInfo extends BaseChainInfo {
|
||||
readonly networkType: NetworkType.L2
|
||||
readonly bridge: string
|
||||
readonly statusPage?: string
|
||||
readonly defaultListUrl: string
|
||||
}
|
||||
|
||||
export type ChainInfoMap = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
|
||||
readonly [chainId in SupportedL2ChainId]: L2ChainInfo
|
||||
} &
|
||||
{ readonly [chainId in SupportedL1ChainId]: L1ChainInfo }
|
||||
|
||||
export const CHAIN_INFO: ChainInfoMap = {
|
||||
[SupportedChainId.MAINNET]: {
|
||||
networkType: NetworkType.L1,
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Ethereum',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.RINKEBY]: {
|
||||
networkType: NetworkType.L1,
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://rinkeby.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Rinkeby',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'Rinkeby Ether', symbol: 'rETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.ROPSTEN]: {
|
||||
networkType: NetworkType.L1,
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://ropsten.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Ropsten',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'Ropsten Ether', symbol: 'ropETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.KOVAN]: {
|
||||
networkType: NetworkType.L1,
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://kovan.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Kovan',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'Kovan Ether', symbol: 'kovETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.GOERLI]: {
|
||||
networkType: NetworkType.L1,
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://goerli.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Görli',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'Görli Ether', symbol: 'görETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.OPTIMISM]: {
|
||||
networkType: NetworkType.L2,
|
||||
blockWaitMsBeforeWarning: ms`25m`,
|
||||
bridge: 'https://gateway.optimism.io/?chainId=1',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'Optimism',
|
||||
logoUrl: optimismLogoUrl,
|
||||
statusPage: 'https://optimism.io/status',
|
||||
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ',
|
||||
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: {
|
||||
networkType: NetworkType.L2,
|
||||
blockWaitMsBeforeWarning: ms`25m`,
|
||||
bridge: 'https://gateway.optimism.io/',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'Optimistic Kovan',
|
||||
logoUrl: optimismLogoUrl,
|
||||
statusPage: 'https://optimism.io/status',
|
||||
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ',
|
||||
nativeCurrency: { name: 'Optimistic Kovan Ether', symbol: 'kovOpETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.ARBITRUM_ONE]: {
|
||||
networkType: NetworkType.L2,
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://arbiscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum',
|
||||
label: 'Arbitrum',
|
||||
logoUrl: arbitrumLogoUrl,
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum',
|
||||
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: {
|
||||
networkType: NetworkType.L2,
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://rinkeby-explorer.arbitrum.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||
label: 'Arbitrum Rinkeby',
|
||||
logoUrl: arbitrumLogoUrl,
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum',
|
||||
nativeCurrency: { name: 'Rinkeby Arbitrum Ether', symbol: 'rinkArbETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.POLYGON]: {
|
||||
networkType: NetworkType.L1,
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://wallet.polygon.technology/bridge',
|
||||
docs: 'https://polygon.io/',
|
||||
explorer: 'https://polygonscan.com/',
|
||||
infoLink: 'https://info.uniswap.org/#/polygon/',
|
||||
label: 'Polygon',
|
||||
logoUrl: polygonMaticLogo,
|
||||
nativeCurrency: { name: 'Polygon Matic', symbol: 'MATIC', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.POLYGON_MUMBAI]: {
|
||||
networkType: NetworkType.L1,
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://wallet.polygon.technology/bridge',
|
||||
docs: 'https://polygon.io/',
|
||||
explorer: 'https://mumbai.polygonscan.com/',
|
||||
infoLink: 'https://info.uniswap.org/#/polygon/',
|
||||
label: 'Polygon Mumbai',
|
||||
logoUrl: polygonMaticLogo,
|
||||
nativeCurrency: { name: 'Polygon Mumbai Matic', symbol: 'mMATIC', decimals: 18 },
|
||||
},
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
import ethereumLogoUrl from 'assets/images/ethereum-logo.png'
|
||||
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
|
||||
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
|
||||
import ms from 'ms.macro'
|
||||
|
||||
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
|
||||
|
||||
/**
|
||||
* List of all the networks supported by the Uniswap Interface
|
||||
*/
|
||||
export enum SupportedChainId {
|
||||
MAINNET = 1,
|
||||
ROPSTEN = 3,
|
||||
@@ -14,33 +10,56 @@ export enum SupportedChainId {
|
||||
|
||||
ARBITRUM_ONE = 42161,
|
||||
ARBITRUM_RINKEBY = 421611,
|
||||
|
||||
OPTIMISM = 10,
|
||||
OPTIMISTIC_KOVAN = 69,
|
||||
|
||||
POLYGON = 137,
|
||||
POLYGON_MUMBAI = 80001,
|
||||
}
|
||||
|
||||
export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = [
|
||||
SupportedChainId.MAINNET,
|
||||
SupportedChainId.ROPSTEN,
|
||||
SupportedChainId.RINKEBY,
|
||||
SupportedChainId.GOERLI,
|
||||
SupportedChainId.KOVAN,
|
||||
export const CHAIN_IDS_TO_NAMES = {
|
||||
[SupportedChainId.MAINNET]: 'mainnet',
|
||||
[SupportedChainId.ROPSTEN]: 'ropsten',
|
||||
[SupportedChainId.RINKEBY]: 'rinkeby',
|
||||
[SupportedChainId.GOERLI]: 'goerli',
|
||||
[SupportedChainId.KOVAN]: 'kovan',
|
||||
[SupportedChainId.POLYGON]: 'polygon',
|
||||
[SupportedChainId.POLYGON_MUMBAI]: 'polygon_mumbai',
|
||||
[SupportedChainId.ARBITRUM_ONE]: 'arbitrum',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: 'arbitrum_rinkeby',
|
||||
[SupportedChainId.OPTIMISM]: 'optimism',
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: 'optimistic_kovan',
|
||||
}
|
||||
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
]
|
||||
/**
|
||||
* Array of all the supported chain IDs
|
||||
*/
|
||||
export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = Object.values(SupportedChainId).filter(
|
||||
(id) => typeof id === 'number'
|
||||
) as SupportedChainId[]
|
||||
|
||||
export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = [SupportedChainId.MAINNET, SupportedChainId.POLYGON]
|
||||
|
||||
/**
|
||||
* All the chain IDs that are running the Ethereum protocol.
|
||||
*/
|
||||
export const L1_CHAIN_IDS = [
|
||||
SupportedChainId.MAINNET,
|
||||
SupportedChainId.ROPSTEN,
|
||||
SupportedChainId.RINKEBY,
|
||||
SupportedChainId.GOERLI,
|
||||
SupportedChainId.KOVAN,
|
||||
SupportedChainId.POLYGON,
|
||||
SupportedChainId.POLYGON_MUMBAI,
|
||||
] as const
|
||||
|
||||
export type SupportedL1ChainId = typeof L1_CHAIN_IDS[number]
|
||||
|
||||
/**
|
||||
* Controls some L2 specific behavior, e.g. slippage tolerance, special UI behavior.
|
||||
* The expectation is that all of these networks have immediate transaction confirmation.
|
||||
*/
|
||||
export const L2_CHAIN_IDS = [
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
@@ -49,120 +68,3 @@ export const L2_CHAIN_IDS = [
|
||||
] as const
|
||||
|
||||
export type SupportedL2ChainId = typeof L2_CHAIN_IDS[number]
|
||||
|
||||
export interface L1ChainInfo {
|
||||
readonly blockWaitMsBeforeWarning?: number
|
||||
readonly docs: string
|
||||
readonly explorer: string
|
||||
readonly infoLink: string
|
||||
readonly label: string
|
||||
readonly logoUrl?: string
|
||||
readonly rpcUrls?: string[]
|
||||
readonly nativeCurrency: {
|
||||
name: string // 'Goerli ETH',
|
||||
symbol: string // 'gorETH',
|
||||
decimals: number //18,
|
||||
}
|
||||
}
|
||||
export interface L2ChainInfo extends L1ChainInfo {
|
||||
readonly bridge: string
|
||||
readonly logoUrl: string
|
||||
readonly statusPage?: string
|
||||
readonly defaultListUrl: string
|
||||
}
|
||||
|
||||
export type ChainInfo = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
|
||||
readonly [chainId in SupportedL2ChainId]: L2ChainInfo
|
||||
} &
|
||||
{ readonly [chainId in SupportedL1ChainId]: L1ChainInfo }
|
||||
|
||||
export const CHAIN_INFO: ChainInfo = {
|
||||
[SupportedChainId.ARBITRUM_ONE]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://arbiscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||
label: 'Arbitrum',
|
||||
logoUrl: arbitrumLogoUrl,
|
||||
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
|
||||
rpcUrls: ['https://arb1.arbitrum.io/rpc'],
|
||||
},
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://rinkeby-explorer.arbitrum.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||
label: 'Arbitrum Rinkeby',
|
||||
logoUrl: arbitrumLogoUrl,
|
||||
nativeCurrency: { name: 'Rinkeby ArbETH', symbol: 'rinkArbETH', decimals: 18 },
|
||||
rpcUrls: ['https://rinkeby.arbitrum.io/rpc'],
|
||||
},
|
||||
[SupportedChainId.MAINNET]: {
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Ethereum',
|
||||
logoUrl: ethereumLogoUrl,
|
||||
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.RINKEBY]: {
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://rinkeby.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Rinkeby',
|
||||
nativeCurrency: { name: 'Rinkeby ETH', symbol: 'rinkETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.ROPSTEN]: {
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://ropsten.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Ropsten',
|
||||
nativeCurrency: { name: 'Ropsten ETH', symbol: 'ropETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.KOVAN]: {
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://kovan.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Kovan',
|
||||
nativeCurrency: { name: 'Kovan ETH', symbol: 'kovETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.GOERLI]: {
|
||||
docs: 'https://docs.uniswap.org/',
|
||||
explorer: 'https://goerli.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/',
|
||||
label: 'Görli',
|
||||
nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.OPTIMISM]: {
|
||||
blockWaitMsBeforeWarning: ms`15m`,
|
||||
bridge: 'https://gateway.optimism.io/',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'OΞ',
|
||||
logoUrl: optimismLogoUrl,
|
||||
nativeCurrency: { name: 'Optimistic ETH', symbol: 'ETH', decimals: 18 },
|
||||
rpcUrls: ['https://mainnet.optimism.io'],
|
||||
},
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: {
|
||||
blockWaitMsBeforeWarning: ms`15m`,
|
||||
bridge: 'https://gateway.optimism.io/',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'Optimistic Kovan',
|
||||
rpcUrls: ['https://kovan.optimism.io'],
|
||||
logoUrl: optimismLogoUrl,
|
||||
nativeCurrency: { name: 'Optimistic kovETH', symbol: 'kovOpETH', decimals: 18 },
|
||||
},
|
||||
}
|
||||
|
||||
export const ARBITRUM_HELP_CENTER_LINK = 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum'
|
||||
export const OPTIMISM_HELP_CENTER_LINK =
|
||||
'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ'
|
||||
|
||||
@@ -12,6 +12,8 @@ export const COMMON_CONTRACT_NAMES: Record<number, { [address: string]: string }
|
||||
[TIMELOCK_ADDRESS[SupportedChainId.MAINNET]]: 'Timelock',
|
||||
[GOVERNANCE_ALPHA_V0_ADDRESSES[SupportedChainId.MAINNET]]: 'Governance (V0)',
|
||||
[GOVERNANCE_ALPHA_V1_ADDRESSES[SupportedChainId.MAINNET]]: 'Governance',
|
||||
'0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e': 'ENS Registry',
|
||||
'0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41': 'ENS Public Resolver',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -21,3 +23,5 @@ export const DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS = 13
|
||||
export const AVERAGE_BLOCK_TIME_IN_SECS: { [chainId: number]: number } = {
|
||||
1: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
|
||||
}
|
||||
|
||||
export const LATEST_GOVERNOR_INDEX = 2
|
||||
|
||||
23
src/constants/infura.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { SupportedChainId } from './chains'
|
||||
|
||||
const INFURA_KEY = process.env.REACT_APP_INFURA_KEY
|
||||
if (typeof INFURA_KEY === 'undefined') {
|
||||
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
||||
}
|
||||
|
||||
/**
|
||||
* These are the network URLs used by the interface when there is not another available source of chain data
|
||||
*/
|
||||
export const INFURA_NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
||||
[SupportedChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.GOERLI]: `https://goerli.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.OPTIMISM]: `https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: `https://optimism-kovan.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ARBITRUM_ONE]: `https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: `https://arbitrum-rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.POLYGON]: `https://polygon-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.POLYGON_MUMBAI]: `https://polygon-mumbai.infura.io/v3/${INFURA_KEY}`,
|
||||
}
|
||||