Compare commits
458 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
82a763f905 | ||
|
|
61e0ce096b | ||
|
|
9e1a775c13 | ||
|
|
642a4177d8 | ||
|
|
37e085763c | ||
|
|
e2baa051c5 | ||
|
|
a5b152da06 | ||
|
|
38cf4f46d7 | ||
|
|
744c313ecf | ||
|
|
b967b1b236 | ||
|
|
596ea03043 | ||
|
|
e81e8a8f71 | ||
|
|
7d343dcfbd | ||
|
|
bf7a40be7a | ||
|
|
097b8361d4 | ||
|
|
82843ff16a | ||
|
|
890471f590 | ||
|
|
478ee7ba14 | ||
|
|
745be977ef | ||
|
|
0e25c055fb | ||
|
|
82a079935e | ||
|
|
876c1539d4 | ||
|
|
f43fd89884 | ||
|
|
efdfdc9083 | ||
|
|
709f0299e2 | ||
|
|
6b57ffe311 | ||
|
|
f7ecdc4332 | ||
|
|
b1009b0e03 | ||
|
|
5a4c7890c6 | ||
|
|
5a3c91f19f | ||
|
|
d5c4ee0342 | ||
|
|
262d984f92 | ||
|
|
7781f5112e | ||
|
|
204e44ac40 | ||
|
|
7c9d9bdb03 | ||
|
|
cb0ea3f14d | ||
|
|
e54ffcc483 | ||
|
|
8a72b374a8 | ||
|
|
3f64415906 | ||
|
|
41a4500f41 | ||
|
|
093dc66cfe | ||
|
|
b10729d217 | ||
|
|
9b0fa8a2c4 | ||
|
|
82c026872f | ||
|
|
222a6d53bc | ||
|
|
0f35f6ee93 | ||
|
|
7b83e3968f | ||
|
|
7938273c0c | ||
|
|
51a4504c75 | ||
|
|
b2697f0077 | ||
|
|
34a58851f7 | ||
|
|
5a20dc82cd | ||
|
|
d1627a6c36 | ||
|
|
55c971892c | ||
|
|
68f8576499 | ||
|
|
d0be3bf222 | ||
|
|
b79fe4b833 | ||
|
|
408c907870 | ||
|
|
8a99bad736 | ||
|
|
5ba3d2f679 | ||
|
|
ec4cd57dc0 | ||
|
|
ccad45d24e | ||
|
|
1903a16097 | ||
|
|
0ea029db4f | ||
|
|
cb41df4cd5 | ||
|
|
659a564db8 | ||
|
|
74c61c0213 | ||
|
|
dc55a21285 | ||
|
|
48cc6811c9 | ||
|
|
ab93d512d3 | ||
|
|
cf4c26a77c | ||
|
|
02296c686f | ||
|
|
60bd0eb86c | ||
|
|
188b321cc9 | ||
|
|
377331c44e | ||
|
|
dfd442cdac | ||
|
|
9561cf54e4 | ||
|
|
714953b50e | ||
|
|
b3844e38d1 | ||
|
|
5dac6a03eb | ||
|
|
d18974480a | ||
|
|
6a90bf3b9d | ||
|
|
5026ebded8 | ||
|
|
02dbed7a75 | ||
|
|
20f462f5a4 | ||
|
|
cf9c6e4b4c | ||
|
|
c0201206cc | ||
|
|
2d2508f681 | ||
|
|
609542c49b | ||
|
|
9a0294f469 | ||
|
|
68e6bc1ba8 | ||
|
|
bbc64f12bb | ||
|
|
06f5fdc6ad | ||
|
|
b4e756ebba | ||
|
|
17439d6fbb | ||
|
|
79d582c72f | ||
|
|
245f8d7279 | ||
|
|
3bf36eade4 | ||
|
|
8eb864426f | ||
|
|
af83399606 | ||
|
|
1d5be31621 | ||
|
|
abe6bf500c | ||
|
|
36cfe627f1 | ||
|
|
aef5d0513a | ||
|
|
5e09a0ced7 | ||
|
|
f768428b9d | ||
|
|
76c9bf84cd | ||
|
|
f26a3306ec | ||
|
|
1846883e56 | ||
|
|
9cacd577e7 | ||
|
|
5e8d725e0e | ||
|
|
c63482b6f7 | ||
|
|
e15a8ddf59 | ||
|
|
1e7dff060f | ||
|
|
244ed38b72 | ||
|
|
87d547ab2b | ||
|
|
0c213be5d9 | ||
|
|
f62d301891 | ||
|
|
902cd343d2 | ||
|
|
a26db9a51d | ||
|
|
b7cb2d24c7 | ||
|
|
aea2bca775 | ||
|
|
93b79be1b6 | ||
|
|
54531b53c6 | ||
|
|
b286c1ba09 | ||
|
|
8dd1be3b47 | ||
|
|
0b8afcff41 | ||
|
|
e4b727f6f0 | ||
|
|
6e0b24cbb1 | ||
|
|
442879ccd9 | ||
|
|
50386f65e7 | ||
|
|
eba8170c46 | ||
|
|
095dbffbca | ||
|
|
4df2824984 | ||
|
|
15345690e3 | ||
|
|
3e36281f77 | ||
|
|
27a868f0cb | ||
|
|
03c3fdef34 | ||
|
|
d37e963f26 | ||
|
|
2e40bef7f0 | ||
|
|
dac87e2299 | ||
|
|
be15604244 | ||
|
|
077570efb4 | ||
|
|
a9ea5c9a1d | ||
|
|
f5b91c9cda | ||
|
|
c0e6388bf8 | ||
|
|
d89d5598a0 | ||
|
|
6f66f5ee77 | ||
|
|
4b8d942da6 | ||
|
|
ef2cb75f6f | ||
|
|
5e0e9be955 | ||
|
|
72a914b0d1 | ||
|
|
c4ce5caf0c | ||
|
|
b87a45b0ba | ||
|
|
80eb394877 | ||
|
|
b47808fcd9 | ||
|
|
e56fdf3eff | ||
|
|
bca70dd46a | ||
|
|
78581d5420 | ||
|
|
896f2fc3c0 | ||
|
|
66e9092d11 | ||
|
|
df397a8a15 | ||
|
|
a7b945a812 | ||
|
|
b71708faee | ||
|
|
7715294bea | ||
|
|
7a57fbe6d9 | ||
|
|
dddd24f1f4 | ||
|
|
13d9f6c29d | ||
|
|
16d8f958b1 | ||
|
|
868242a6b2 | ||
|
|
aa1db580ee | ||
|
|
496a963dcf | ||
|
|
5cb37dc098 | ||
|
|
b58e200eac | ||
|
|
be8b6ccec7 | ||
|
|
d3700882b2 | ||
|
|
31d286c8fa | ||
|
|
77c7dab024 | ||
|
|
ffab1c56c7 | ||
|
|
cd4a2313ac | ||
|
|
81b8afdd3d | ||
|
|
6085284ed6 | ||
|
|
9b56c8db74 | ||
|
|
ea17c7c111 | ||
|
|
52630aa77e | ||
|
|
1fcbd2dcd9 | ||
|
|
d7bf4bbf0d | ||
|
|
23f722cb72 | ||
|
|
2482a10ca8 | ||
|
|
eb09894b73 | ||
|
|
bb3c7ddbe9 | ||
|
|
0aba2701fc | ||
|
|
a9ba79cdbe | ||
|
|
384f674e48 | ||
|
|
8de6bb6d51 | ||
|
|
322c45bef4 | ||
|
|
ffe11f9eda | ||
|
|
d993741713 | ||
|
|
a05aae6c37 | ||
|
|
738fac0c84 | ||
|
|
0099ef6d59 | ||
|
|
8b3da3dbaa | ||
|
|
8bb1983aaa | ||
|
|
afbe846cba | ||
|
|
901e0558b5 | ||
|
|
53da48b646 | ||
|
|
19c3983351 | ||
|
|
45709a5d36 | ||
|
|
fb07919888 | ||
|
|
9fa3b70475 | ||
|
|
91de599f12 | ||
|
|
284a435171 | ||
|
|
9b1903df77 | ||
|
|
ba9ff0dfa5 | ||
|
|
77679026ef | ||
|
|
97ba8fb5b0 | ||
|
|
119c79d623 | ||
|
|
cc9650b74b | ||
|
|
e242faca86 | ||
|
|
1a73f513dc | ||
|
|
c43912df94 | ||
|
|
b07bc40230 | ||
|
|
dabb511ff5 | ||
|
|
6ae632158e | ||
|
|
648e4e02c4 | ||
|
|
9bc00ccaf6 | ||
|
|
2e90561978 | ||
|
|
bea63cd4b4 | ||
|
|
cc8c5712ec | ||
|
|
112b00521c | ||
|
|
1314477a88 | ||
|
|
c6b6e7f0d6 | ||
|
|
c8009ca909 | ||
|
|
2cabd7dc51 | ||
|
|
cd22955817 | ||
|
|
fb33a06861 | ||
|
|
bcf64bcb11 | ||
|
|
c2093ce040 | ||
|
|
308f7d59a0 | ||
|
|
c68d08ac26 | ||
|
|
f826554bd4 | ||
|
|
dc2d1b06d2 | ||
|
|
8ea5cb450a | ||
|
|
58249e3ce2 | ||
|
|
2ee79f74e9 | ||
|
|
24f85d422c | ||
|
|
d98954067e | ||
|
|
58f1193a21 | ||
|
|
88cc20a61a | ||
|
|
442ac8936d | ||
|
|
c563717aae | ||
|
|
15a339a0d7 | ||
|
|
3c371af32a | ||
|
|
5797a6229b | ||
|
|
32212332bb | ||
|
|
f7ac87fa85 | ||
|
|
540ec24e21 | ||
|
|
cd4f19836c | ||
|
|
a20b2ff7fa | ||
|
|
a52b7bf06b | ||
|
|
0ab1e5f144 | ||
|
|
115c72db9e | ||
|
|
2bb695d84c | ||
|
|
3ea6f6e0c8 | ||
|
|
627a5d3a98 | ||
|
|
353c4751b8 | ||
|
|
416a3f9433 | ||
|
|
30cffb7442 | ||
|
|
f59c5f6877 | ||
|
|
4bdf3c191a | ||
|
|
7b829135df | ||
|
|
5831328364 | ||
|
|
6b99740f91 | ||
|
|
f5557a434c | ||
|
|
5dfe44dad4 | ||
|
|
cd50d576d4 | ||
|
|
d922447ef2 | ||
|
|
81b1346937 | ||
|
|
f51335df9d | ||
|
|
13a289f6f1 | ||
|
|
0afeb5acaf | ||
|
|
9e8d08e22c | ||
|
|
299286a0d9 | ||
|
|
00403a4810 | ||
|
|
b8a9191653 | ||
|
|
1304acd8c7 | ||
|
|
8112e48e9a | ||
|
|
f3c400c514 | ||
|
|
c2c7d87ca3 | ||
|
|
db18b486b4 | ||
|
|
1613cc473b | ||
|
|
e1f37b0ec6 | ||
|
|
805af2fdb4 | ||
|
|
b833d07b4f | ||
|
|
ec5da7ec8f | ||
|
|
ff10346b06 | ||
|
|
f15522a47c | ||
|
|
67b66235ba | ||
|
|
7153908935 | ||
|
|
4541e37388 | ||
|
|
3bbcdcb8ae | ||
|
|
2daee152ef | ||
|
|
9af7e0e0c3 | ||
|
|
757741c3df | ||
|
|
a3aa6647e7 | ||
|
|
f463df97bf | ||
|
|
99a282b7b4 | ||
|
|
5a3165358f | ||
|
|
26e334c78f | ||
|
|
bd8192c81e | ||
|
|
ff6bd38992 | ||
|
|
a48b7ce702 | ||
|
|
fc08d1fc6a | ||
|
|
b416603ff4 | ||
|
|
c4dc26e1b2 | ||
|
|
adfe7225a8 | ||
|
|
13e347ee02 | ||
|
|
b527bfbeea |
3
.env
@@ -1,2 +1 @@
|
||||
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_WALLETCONNECT_BRIDGE_URL="https://uniswap.bridge.walletconnect.org"
|
||||
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
@@ -2,3 +2,4 @@ REACT_APP_INFURA_KEY="099fc58e0de9451d80b18d7c74caa7c1"
|
||||
REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236"
|
||||
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID="UA-128182339-4"
|
||||
REACT_APP_FIREBASE_KEY="AIzaSyBcZWwTcTJHj_R6ipZcrJkXdq05PuX0Rs0"
|
||||
|
||||
@@ -8,20 +8,44 @@
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"ignorePatterns": ["node_modules/**/*"],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"src/types/v3",
|
||||
"src/abis/types",
|
||||
"src/locales/**/*.js",
|
||||
"src/locales/**/en-US.po",
|
||||
"src/state/data/generated.ts",
|
||||
"node_modules",
|
||||
"coverage",
|
||||
"build",
|
||||
"dist",
|
||||
".DS_Store",
|
||||
".env.local",
|
||||
".env.development.local",
|
||||
".env.test.local",
|
||||
".env.production.local",
|
||||
".idea/",
|
||||
".vscode/",
|
||||
"package-lock.json",
|
||||
"yarn.lock"
|
||||
],
|
||||
"extends": [
|
||||
"react-app",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"plugins": ["simple-import-sort", "unused-imports"],
|
||||
"rules": {
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
@@ -29,16 +53,34 @@
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"object-shorthand": ["error", "always"],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"name": "ethers",
|
||||
"message": "Please import from '@ethersproject/module' directly to support tree-shaking."
|
||||
},
|
||||
{
|
||||
"name": "styled-components",
|
||||
"message": "Please import from styled-components/macro."
|
||||
},
|
||||
{
|
||||
"name": "@lingui/macro",
|
||||
"importNames": ["t"],
|
||||
"message": "Please use <Trans> instead of t."
|
||||
}
|
||||
],
|
||||
"patterns": ["!styled-components/macro"]
|
||||
"patterns": [
|
||||
{
|
||||
"group": ["**/dist"],
|
||||
"message": "Do not import from dist/ - this is an implementation detail, and breaks tree-shaking."
|
||||
},
|
||||
{
|
||||
"group": ["!styled-components/macro"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
# Files stored in repository root
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
allow:
|
||||
- dependency-name: "@uniswap/token-lists"
|
||||
- dependency-name: "@uniswap/default-token-list"
|
||||
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
|
||||
9
.github/workflows/integration-tests.yaml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
integration-tests:
|
||||
name: Cypress
|
||||
runs-on: ubuntu-16.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -41,11 +41,10 @@ jobs:
|
||||
- run: yarn build
|
||||
env:
|
||||
CI: false
|
||||
REACT_APP_NETWORK_URL: "https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_NETWORK_URL: 'https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847'
|
||||
REACT_APP_SERVICE_WORKER: false
|
||||
|
||||
- run: yarn integration-test
|
||||
- run: yarn test:e2e
|
||||
env:
|
||||
CYPRESS_INTEGRATION_TEST_PRIVATE_KEY: ${{ secrets.CYPRESS_INTEGRATION_TEST_PRIVATE_KEY }}
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
|
||||
|
||||
|
||||
13
.github/workflows/lint.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
@@ -38,10 +38,15 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run linters
|
||||
uses: wearerequired/lint-action@b98b0918aa71490373d2eca9e8e39a9bc1cc2517
|
||||
- name: Run eslint w/ autofix
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
|
||||
uses: wearerequired/lint-action@36c7e6689e80d785d27a22f71d970f3a3b4fcb70
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
eslint: true
|
||||
eslint_extensions: js,jsx,ts,tsx,json
|
||||
eslint_args: "-c .eslintrc.json"
|
||||
auto_fix: true
|
||||
|
||||
- name: Run eslint
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.owner.login != github.repository_owner }}
|
||||
run: yarn eslint .
|
||||
|
||||
3
.github/workflows/release.yaml
vendored
@@ -23,6 +23,7 @@ jobs:
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
release_branches: .*
|
||||
default_bump: false
|
||||
|
||||
create_release:
|
||||
name: Create Release
|
||||
@@ -55,7 +56,7 @@ jobs:
|
||||
pinata-secret-api-key: ${{ secrets.PINATA_API_SECRET_KEY }}
|
||||
|
||||
- name: Pin to Crust
|
||||
uses: crustio/ipfs-crust-action@v1.0.8
|
||||
uses: crustio/ipfs-crust-action@v2.0.3
|
||||
continue-on-error: true
|
||||
timeout-minutes: 2
|
||||
with:
|
||||
|
||||
9
.gitignore
vendored
@@ -3,10 +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/**/*.ts
|
||||
/src/locales/**/*.json
|
||||
/src/locales/**/en-US.po
|
||||
/src/locales/**/pseudo.po
|
||||
/src/state/data/generated.ts
|
||||
|
||||
# dependencies
|
||||
@@ -18,6 +20,9 @@
|
||||
# production
|
||||
/build
|
||||
|
||||
# widgets
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
|
||||
@@ -27,7 +27,7 @@ makes large architectural changes, consider following all the standards.
|
||||
- If something breaks, add automated tests so it doesn't break again
|
||||
- Add integration tests for new pages or flows
|
||||
- Verify that all CI checks pass before merging
|
||||
- Have at least one product manager or designer approve of significant UX changes
|
||||
- Have at least one product manager or designer approve of any significant UX changes
|
||||
|
||||
## Guidelines
|
||||
|
||||
@@ -42,7 +42,7 @@ The following points should help guide your development:
|
||||
- An Ethereum node should be the only critical dependency
|
||||
- All other external dependencies should only enhance the UX ([graceful degradation](https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation))
|
||||
- Accessibility: anyone can use the interface
|
||||
- The interface should be responsive, small and run well on low performance devices (majority of swaps on mobile!)
|
||||
- The interface should be responsive, small and also run well on low performance devices (majority of swaps on mobile!)
|
||||
|
||||
## Release process
|
||||
|
||||
@@ -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!!
|
||||
|
||||
15
README.md
@@ -10,7 +10,7 @@ An open source interface for Uniswap -- a protocol for decentralized exchange of
|
||||
|
||||
- Website: [uniswap.org](https://uniswap.org/)
|
||||
- Interface: [app.uniswap.org](https://app.uniswap.org)
|
||||
- Docs: [uniswap.org/docs/](https://uniswap.org/docs/)
|
||||
- Docs: [uniswap.org/docs/](https://docs.uniswap.org/)
|
||||
- Twitter: [@Uniswap](https://twitter.com/Uniswap)
|
||||
- Reddit: [/r/Uniswap](https://www.reddit.com/r/Uniswap/)
|
||||
- Email: [contact@uniswap.org](mailto:contact@uniswap.org)
|
||||
@@ -26,14 +26,19 @@ To access the Uniswap Interface, use an IPFS gateway link from the
|
||||
[latest release](https://github.com/Uniswap/uniswap-interface/releases/latest),
|
||||
or visit [app.uniswap.org](https://app.uniswap.org).
|
||||
|
||||
## Unsupported tokens
|
||||
|
||||
Check out `useUnsupportedTokenList()` in [src/state/lists/hooks.ts](./src/state/lists/hooks.ts) for blocking tokens in your instance of the interface.
|
||||
|
||||
You can block an entire list of tokens by passing in a tokenlist like [here](./src/constants/lists.ts) or you can block specific tokens by adding them to [unsupported.tokenlist.json](./src/constants/tokenLists/unsupported.tokenlist.json).
|
||||
|
||||
## Contributions
|
||||
|
||||
For steps on local deployment, development, and code contribution, please see [CONTRIBUTING](./CONTRIBUTING.md).
|
||||
|
||||
## Accessing Uniswap V2
|
||||
|
||||
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for
|
||||
Uniswap protocol V2.
|
||||
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for Uniswap protocol V2.
|
||||
|
||||
- Swap on Uniswap V2: https://app.uniswap.org/#/swap?use=v2
|
||||
- View V2 liquidity: https://app.uniswap.org/#/pool/v2
|
||||
@@ -41,6 +46,6 @@ Uniswap protocol V2.
|
||||
- Migrate V2 liquidity to V3: https://app.uniswap.org/#/migrate/v2
|
||||
|
||||
## Accessing Uniswap V1
|
||||
|
||||
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
|
||||
|
||||
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
|
||||
linked from the [v1.0.0 release](https://github.com/Uniswap/uniswap-interface/releases/tag/v1.0.0).
|
||||
|
||||
9
cosmos.config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"watchDirs": [
|
||||
"src"
|
||||
],
|
||||
"webpack": {
|
||||
"configPath": "react-scripts/config/webpack.config",
|
||||
"overridePath": "cosmos.override.js"
|
||||
}
|
||||
}
|
||||
25
cosmos.override.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/* 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,
|
||||
},
|
||||
})
|
||||
}
|
||||
return plugin
|
||||
}),
|
||||
})
|
||||
@@ -5,6 +5,11 @@
|
||||
}
|
||||
},
|
||||
"asToken0": [
|
||||
{
|
||||
"feeTier": "100",
|
||||
"totalValueLockedToken0": "0",
|
||||
"totalValueLockedToken1": "3"
|
||||
},
|
||||
{
|
||||
"feeTier": "500",
|
||||
"totalValueLockedToken0": "0",
|
||||
@@ -13,7 +18,7 @@
|
||||
{
|
||||
"feeTier": "3000",
|
||||
"totalValueLockedToken0": "0",
|
||||
"totalValueLockedToken1": "7"
|
||||
"totalValueLockedToken1": "4"
|
||||
},
|
||||
{
|
||||
"feeTier": "10000",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CyHttpMessages } from 'cypress/types/net-stubbing'
|
||||
|
||||
import { aliasQuery, hasQuery } from '../utils/graphql-test-utils'
|
||||
|
||||
describe('Add Liquidity', () => {
|
||||
@@ -57,7 +58,7 @@ describe('Add Liquidity', () => {
|
||||
cy.wait('@feeTierDistributionQuery')
|
||||
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '70%')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
|
||||
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
|
||||
import { JsonRpcProvider } from '@ethersproject/providers'
|
||||
import { Wallet } from '@ethersproject/wallet'
|
||||
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
|
||||
|
||||
// todo: figure out how env vars actually work in CI
|
||||
// const TEST_PRIVATE_KEY = Cypress.env('INTEGRATION_TEST_PRIVATE_KEY')
|
||||
@@ -74,6 +74,7 @@ class CustomizedBridge extends Eip1193Bridge {
|
||||
}
|
||||
|
||||
// sets up the injected provider to be a mock ethereum provider with the given mnemonic/index
|
||||
// eslint-disable-next-line no-undef
|
||||
Cypress.Commands.overwrite('visit', (original, url, options) => {
|
||||
return original(url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url, {
|
||||
...options,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default {
|
||||
const linguiConfig = {
|
||||
catalogs: [
|
||||
{
|
||||
path: '<rootDir>/src/locales/{locale}',
|
||||
@@ -40,14 +40,19 @@ export default {
|
||||
'ru-RU',
|
||||
'sr-SP',
|
||||
'sv-SE',
|
||||
'sw-TZ',
|
||||
'tr-TR',
|
||||
'uk-UA',
|
||||
'vi-VN',
|
||||
'zh-CN',
|
||||
'zh-TW',
|
||||
'pseudo',
|
||||
],
|
||||
orderBy: 'messageId',
|
||||
rootDir: '.',
|
||||
runtimeConfigModule: ['@lingui/core', 'i18n'],
|
||||
sourceLocale: 'en-US',
|
||||
pseudoLocale: 'pseudo',
|
||||
}
|
||||
|
||||
export default linguiConfig
|
||||
|
||||
166
package.json
@@ -2,6 +2,13 @@
|
||||
"name": "@uniswap/interface",
|
||||
"description": "Uniswap Interface",
|
||||
"homepage": ".",
|
||||
"main": "dist/interface.js",
|
||||
"module": "dist/interface.esm.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"lib",
|
||||
"dist"
|
||||
],
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
@@ -11,25 +18,27 @@
|
||||
"@graphql-codegen/typescript-operations": "^1.18.2",
|
||||
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
|
||||
"@lingui/cli": "^3.9.0",
|
||||
"@lingui/loader": "^3.9.0",
|
||||
"@lingui/macro": "^3.9.0",
|
||||
"@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-eslint": "^8.0.1",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-replace": "^3.0.1",
|
||||
"@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",
|
||||
"@typechain/ethers-v5": "^7.0.0",
|
||||
"@types/array.prototype.flat": "^1.2.1",
|
||||
"@types/array.prototype.flatmap": "^1.2.2",
|
||||
"@types/d3": "^6.7.1",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/lingui__core": "^2.7.1",
|
||||
"@types/lingui__macro": "^2.7.4",
|
||||
"@types/lingui__react": "^2.8.3",
|
||||
"@types/lodash.flatmap": "^4.5.6",
|
||||
"@types/luxon": "^1.24.4",
|
||||
"@types/ms.macro": "^2.0.0",
|
||||
"@types/multicodec": "^1.0.0",
|
||||
"@types/node": "^13.13.5",
|
||||
@@ -47,104 +56,88 @@
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^4.1.0",
|
||||
"@uniswap/default-token-list": "^2.0.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/token-lists": "^1.0.0-beta.25",
|
||||
"@uniswap/v2-core": "1.0.0",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^3.0.0-alpha.2",
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.2.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": "^6.2.0",
|
||||
"@web3-react/walletlink-connector": "^6.2.3",
|
||||
"ajv": "^6.12.3",
|
||||
"cids": "^1.0.0",
|
||||
"@web3-react/walletconnect-connector": "^7.0.2-alpha.0",
|
||||
"@web3-react/walletlink-connector": "^6.2.11",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"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",
|
||||
"ethers": "^5.4.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"firebase": "^9.1.3",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
"inter-ui": "^3.13.1",
|
||||
"jest-styled-components": "^7.0.5",
|
||||
"lodash.flatmap": "^4.5.0",
|
||||
"luxon": "^1.25.0",
|
||||
"ms.macro": "^2.0.0",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashes": "^4.0.2",
|
||||
"node-vibrant": "^3.1.5",
|
||||
"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-device-detect": "^1.6.2",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-cosmos": "^5.6.6",
|
||||
"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-devtools-extension": "^2.13.9",
|
||||
"redux-localstorage-simple": "^2.3.1",
|
||||
"rollup": "^2.63.0",
|
||||
"rollup-plugin-dts": "^4.1.0",
|
||||
"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",
|
||||
"styled-system": "^5.1.5",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.2.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",
|
||||
"workbox-core": "^6.1.0",
|
||||
"workbox-expiration": "^6.1.0",
|
||||
"workbox-precaching": "^6.1.0",
|
||||
"workbox-routing": "^6.1.0",
|
||||
"workbox-strategies": "^6.1.0"
|
||||
"workbox-routing": "^6.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@walletconnect/web3-provider": "1.5.1"
|
||||
"@walletconnect/ethereum-provider": "1.7.1"
|
||||
},
|
||||
"scripts": {
|
||||
"compile-contract-types": "yarn compile-external-abi-types && yarn compile-v3-contract-types",
|
||||
"compile-external-abi-types": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
|
||||
"compile-v3-contract-types": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
|
||||
"build": "yarn compile-contract-types && yarn graphql:generate && yarn i18n:extract && yarn i18n:compile && react-scripts build",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "lingui compile",
|
||||
"integration-test": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
|
||||
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"",
|
||||
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*.json\"",
|
||||
"contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3",
|
||||
"graphql:generate": "graphql-codegen --config codegen.yml",
|
||||
"postinstall": "yarn compile-contract-types",
|
||||
"start": "yarn compile-contract-types && react-scripts start",
|
||||
"prei18n:extract": "touch src/locales/en-US.po",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "yarn i18n:extract && lingui compile",
|
||||
"i18n:pseudo": "lingui extract --locale pseudo && lingui compile",
|
||||
"postinstall": "yarn contracts:compile && yarn graphql:generate && yarn i18n:compile",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=./custom-test-env.js",
|
||||
"prestart": "yarn graphql:generate && touch src/locales/en-US.po"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app",
|
||||
"ignorePatterns": [
|
||||
"node_modules"
|
||||
]
|
||||
"test:e2e": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
|
||||
"widgets:start": "cosmos",
|
||||
"widgets:build": "rollup --config --failAfterWarnings --configPlugin typescript2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -159,5 +152,64 @@
|
||||
]
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {}
|
||||
"dependencies": {
|
||||
"@ethersproject/abi": "^5.4.1",
|
||||
"@ethersproject/abstract-provider": "^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/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",
|
||||
"@lingui/core": "^3.9.0",
|
||||
"@lingui/macro": "^3.9.0",
|
||||
"@lingui/react": "^3.9.0",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@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.7.1",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"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": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-popper": "^2.2.3",
|
||||
"react-redux": "^7.2.2",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
"rebass": "^4.0.7",
|
||||
"redux": "^4.1.2",
|
||||
"styled-components": "^5.3.0",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
"wcag-contrast": "^3.0.0",
|
||||
"wicg-inert": "^3.1.1",
|
||||
"widgets-web3-react/core": "npm:@web3-react/core@8.0.16-alpha.0",
|
||||
"widgets-web3-react/eip1193": "npm:@web3-react/eip1193@8.0.16-alpha.0",
|
||||
"widgets-web3-react/empty": "npm:@web3-react/empty@8.0.17-alpha.0",
|
||||
"widgets-web3-react/metamask": "npm:@web3-react/metamask@8.0.16-alpha.0",
|
||||
"widgets-web3-react/types": "npm:@web3-react/types@8.0.16-alpha.0",
|
||||
"widgets-web3-react/url": "npm:@web3-react/url@8.0.17-alpha.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/fonts/Inter-roman.var.woff2
Normal file
@@ -2,27 +2,31 @@
|
||||
<html translate="no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
%PUBLIC_URL% will be replaced with the URL of the `public` folder during build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="%PUBLIC_URL%/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="%PUBLIC_URL%/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="%PUBLIC_URL%/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#ff007a" />
|
||||
<meta name="fortmatic-site-verification" content="j93LgcVZk79qcgyo" />
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<link rel="preconnect" href="https://www.google-analytics.com/">
|
||||
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Inter-roman.var.woff2" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<style>
|
||||
* {
|
||||
@@ -30,9 +34,23 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Regular';
|
||||
src: url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2 supports variations(gvar)"),
|
||||
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2-variations"),
|
||||
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2");
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter var', sans-serif;
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +67,7 @@
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
@@ -83,8 +102,6 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -92,7 +109,7 @@
|
||||
<!-- The root is the container of the app -->
|
||||
<div id="root">
|
||||
<!-- Triggers the font to load immediately and then is replaced by the app -->
|
||||
<div style="visibility: hidden">X</div>
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="background-radial-gradient"></div>
|
||||
|
||||
63
rollup.config.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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 eslint from '@rollup/plugin-eslint'
|
||||
import json from '@rollup/plugin-json'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import url from '@rollup/plugin-url'
|
||||
import svgr from '@svgr/rollup'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
import sass from 'rollup-plugin-scss'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
|
||||
import { dependencies } from './package.json'
|
||||
|
||||
const deps = Object.keys(dependencies)
|
||||
|
||||
const replacements = {
|
||||
'process.env.REACT_APP_IS_WIDGET': true,
|
||||
}
|
||||
|
||||
const library = {
|
||||
input: 'src/lib/index.tsx',
|
||||
output: [
|
||||
{
|
||||
file: 'dist/widgets.js',
|
||||
format: 'cjs',
|
||||
inlineDynamicImports: true,
|
||||
sourcemap: true,
|
||||
},
|
||||
{
|
||||
file: 'dist/widgets.esm.js',
|
||||
format: 'esm',
|
||||
inlineDynamicImports: true,
|
||||
sourcemap: true,
|
||||
},
|
||||
],
|
||||
// necessary because some nested imports (eg jotai/*) would otherwise not resolve.
|
||||
external: (source: string) => Boolean(deps.find((dep) => source === dep || source.startsWith(dep + '/'))),
|
||||
plugins: [
|
||||
eslint({ include: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'] }),
|
||||
json(), // imports json
|
||||
replace({ ...replacements, preventAssignment: true }),
|
||||
url(), // imports files (including svgs) as data URIs
|
||||
svgr({ exportType: 'named', svgo: false }), // imports svgs as React components
|
||||
sass(), // imports sass styles
|
||||
typescript({ tsconfig: './tsconfig.lib.json', useTsconfigDeclarationDir: true }),
|
||||
],
|
||||
}
|
||||
|
||||
const typings = {
|
||||
input: 'dist/dts/lib/index.d.ts',
|
||||
output: {
|
||||
file: 'dist/widgets.d.ts',
|
||||
format: 'es',
|
||||
},
|
||||
external: (source: string) => source.endsWith('.scss'),
|
||||
plugins: [dts({ compilerOptions: { baseUrl: 'dist/dts' } })],
|
||||
}
|
||||
|
||||
const config = [library, typings]
|
||||
export default config
|
||||
49
src/abis/erc1155.json
Normal file
@@ -0,0 +1,49 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "uri",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
40
src/abis/erc721.json
Normal file
@@ -0,0 +1,40 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "ownerOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "tokenURI",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
1046
src/abis/governor-bravo.json
Normal file
6
src/assets/images/gas-icon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.0047 9.26921H10.2714C11.0078 9.26921 11.6047 9.86617 11.6047 10.6025V12.1359C11.6047 12.7987 12.142 13.3359 12.8047 13.3359C13.4675 13.3359 14.0047 12.7995 14.0047 12.1367V5.22059C14.0047 4.86697 13.7758 4.56227 13.5258 4.31223L10.6714 1.33594M4.00472 2.00254H8.00472C8.7411 2.00254 9.33805 2.59949 9.33805 3.33587V14.0015H2.67139V3.33587C2.67139 2.59949 3.26834 2.00254 4.00472 2.00254ZM14.0047 5.33587C14.0047 6.07225 13.4078 6.66921 12.6714 6.66921C11.935 6.66921 11.3381 6.07225 11.3381 5.33587C11.3381 4.59949 11.935 4.00254 12.6714 4.00254C13.4078 4.00254 14.0047 4.59949 14.0047 5.33587Z" stroke="white"/>
|
||||
<line x1="4" y1="9.99414" x2="8" y2="9.99414" stroke="white"/>
|
||||
<line x1="4" y1="11.9941" x2="8" y2="11.9941" stroke="white"/>
|
||||
<path d="M4 8.16113H8" stroke="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 895 B |
12
src/assets/images/router-icon-grey.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_988_5781)">
|
||||
<path d="M11.3333 12.5C7.33329 12.5 6.66663 8.5 3.99996 8.5M3.99996 8.5C6.66663 8.5 7.33329 4.5 11.3333 4.5M3.99996 8.5H1.66663" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="13.3334" cy="4.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="13.3334" cy="12.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_988_5781">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 733 B |
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 |
10
src/assets/svg/auto_router.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="23" height="20" viewBox="0 0 23 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="gradient1" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(95)">
|
||||
<stop id="stop1" offset="0" stop-color="#2274E2"/>
|
||||
<stop id="stop1" offset="0.5" stop-color="#2274E2"/>
|
||||
<stop id="stop2" offset="1" stop-color="#3FB672" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="M16 16C10 16 9 10 5 10M16 16C16 17.6569 17.3431 19 19 19C20.6569 19 22 17.6569 22 16C22 14.3431 20.6569 13 19 13C17.3431 13 16 14.3431 16 16ZM5 10C9 10 10 4 16 4M5 10H1.5M16 4C16 5.65685 17.3431 7 19 7C20.6569 7 22 5.65685 22 4C22 2.34315 20.6569 1 19 1C17.3431 1 16 2.34315 16 4Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="url(#gradient1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 782 B |
3
src/assets/svg/dot_line.svg
Normal file
@@ -0,0 +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>
|
||||
|
After Width: | Height: | Size: 233 B |
@@ -1,13 +1,13 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="black" xmlns="http://www.w3.org/2000/svg">
|
||||
<g style="mix-blend-mode:darken">
|
||||
<path d="M4.15217 1.55141C3.96412 1.52242 3.95619 1.51902 4.04468 1.5055C4.21427 1.47958 4.61472 1.51491 4.89067 1.58012C5.53489 1.73232 6.12109 2.12221 6.74683 2.81466L6.91307 2.99862L7.15088 2.96062C8.15274 2.8006 9.17194 2.92778 10.0244 3.31918C10.2589 3.42686 10.6287 3.64121 10.6749 3.69629C10.6896 3.71384 10.7166 3.82684 10.7349 3.94742C10.7982 4.36458 10.7665 4.68434 10.6382 4.92317C10.5683 5.05313 10.5644 5.09432 10.6114 5.20554C10.6489 5.2943 10.7534 5.35999 10.8569 5.35985C11.0687 5.35956 11.2968 5.0192 11.4024 4.54561L11.4444 4.3575L11.5275 4.45109C11.9835 4.96459 12.3417 5.66488 12.4032 6.16335L12.4192 6.29332L12.3426 6.17517C12.2107 5.97186 12.0781 5.83346 11.9084 5.72183C11.6024 5.52062 11.2789 5.45215 10.4222 5.40727C9.64839 5.36675 9.21045 5.30106 8.77621 5.16032C8.03738 4.9209 7.66493 4.60204 6.78729 3.4576C6.39748 2.94928 6.15654 2.66804 5.91687 2.44155C5.37228 1.92691 4.83716 1.65701 4.15217 1.55141Z" fill="black"/>
|
||||
<path d="M10.8494 2.68637C10.8689 2.34575 10.9153 2.12108 11.0088 1.9159C11.0458 1.83469 11.0804 1.76822 11.0858 1.76822C11.0911 1.76822 11.075 1.82816 11.05 1.90142C10.9821 2.10054 10.9709 2.3729 11.0177 2.68978C11.0771 3.09184 11.1109 3.14985 11.5385 3.58416C11.739 3.78788 11.9723 4.0448 12.0568 4.15511L12.2106 4.35568L12.0568 4.21234C11.8688 4.03705 11.4364 3.6952 11.3409 3.64633C11.2768 3.61356 11.2673 3.61413 11.2278 3.65321C11.1914 3.68922 11.1837 3.74333 11.1787 3.99915C11.1708 4.39786 11.1161 4.65377 10.9842 4.90965C10.9128 5.04805 10.9015 5.01851 10.9661 4.8623C11.0143 4.74566 11.0192 4.69439 11.0189 4.30842C11.0181 3.53291 10.9255 3.34647 10.3823 3.02709C10.2447 2.94618 10.0179 2.8295 9.87839 2.76778C9.73887 2.70606 9.62805 2.6523 9.63208 2.64828C9.64746 2.63307 10.1772 2.78675 10.3905 2.86828C10.7077 2.98954 10.76 3.00526 10.7985 2.99063C10.8244 2.98082 10.8369 2.90608 10.8494 2.68637Z" fill="black"/>
|
||||
<path d="M4.51745 4.01304C4.13569 3.49066 3.89948 2.68973 3.95062 2.091L3.96643 1.90572L4.05333 1.92148C4.21652 1.95106 4.49789 2.05515 4.62964 2.13469C4.9912 2.35293 5.14773 2.64027 5.30697 3.37811C5.35362 3.59423 5.41482 3.8388 5.44298 3.9216C5.48831 4.05487 5.65962 4.36617 5.7989 4.56834C5.89922 4.71395 5.83258 4.78295 5.61082 4.76305C5.27215 4.73267 4.8134 4.41799 4.51745 4.01304Z" fill="black"/>
|
||||
<path d="M10.3863 7.90088C8.60224 7.18693 7.97389 6.56721 7.97389 5.52157C7.97389 5.36769 7.97922 5.24179 7.98571 5.24179C7.99221 5.24179 8.06124 5.29257 8.1391 5.35465C8.50088 5.64305 8.906 5.76623 10.0275 5.92885C10.6875 6.02455 11.0589 6.10185 11.4015 6.21477C12.4904 6.57371 13.1641 7.30212 13.3248 8.29426C13.3715 8.58255 13.3441 9.12317 13.2684 9.4081C13.2087 9.63315 13.0263 10.0388 12.9779 10.0544C12.9645 10.0587 12.9514 10.0076 12.9479 9.93809C12.9296 9.56554 12.7402 9.20285 12.4221 8.93116C12.0604 8.62227 11.5745 8.37633 10.3863 7.90088Z" fill="black"/>
|
||||
<path d="M9.13385 8.19748C9.11149 8.06527 9.07272 7.89643 9.04769 7.82228L9.00217 7.68748L9.08672 7.7818C9.20374 7.91233 9.2962 8.07937 9.37457 8.30185C9.43438 8.47165 9.44111 8.52215 9.44066 8.79807C9.4402 9.06896 9.43273 9.12575 9.3775 9.27858C9.29042 9.51959 9.18233 9.69048 9.00097 9.87391C8.67507 10.2036 8.25607 10.3861 7.65143 10.4618C7.54633 10.4749 7.24 10.4971 6.97069 10.511C6.292 10.5461 5.84531 10.6186 5.44393 10.7587C5.38623 10.7788 5.3347 10.7911 5.32947 10.7859C5.31323 10.7698 5.58651 10.6079 5.81223 10.4998C6.1305 10.3474 6.44733 10.2643 7.15719 10.1468C7.50785 10.0887 7.86998 10.0183 7.96194 9.99029C8.83033 9.72566 9.27671 9.04276 9.13385 8.19748Z" fill="black"/>
|
||||
<path d="M9.95169 9.64109C9.71465 9.13463 9.66022 8.64564 9.79009 8.18961C9.80399 8.14088 9.82632 8.101 9.83976 8.101C9.85319 8.101 9.90913 8.13105 9.96404 8.16777C10.0733 8.24086 10.2924 8.36395 10.876 8.68023C11.6043 9.0749 12.0196 9.3805 12.302 9.72965C12.5493 10.0354 12.7023 10.3837 12.776 10.8084C12.8177 11.0489 12.7932 11.6277 12.7311 11.8699C12.5353 12.6337 12.0802 13.2336 11.4311 13.5837C11.336 13.635 11.2506 13.6771 11.2414 13.6773C11.2321 13.6775 11.2668 13.5899 11.3184 13.4827C11.5367 13.029 11.5616 12.5877 11.3965 12.0965C11.2954 11.7957 11.0893 11.4287 10.6732 10.8084C10.1893 10.0873 10.0707 9.89539 9.95169 9.64109Z" fill="black"/>
|
||||
<path d="M3.25046 12.3737C3.91252 11.8181 4.73629 11.4234 5.48666 11.3022C5.81005 11.25 6.34877 11.2707 6.64823 11.3469C7.12824 11.469 7.55763 11.7425 7.78094 12.0683C7.99918 12.3867 8.09281 12.6642 8.19029 13.2816C8.22875 13.5252 8.27057 13.7697 8.28323 13.8251C8.35644 14.1451 8.4989 14.4008 8.67544 14.5293C8.95583 14.7333 9.43865 14.7459 9.91362 14.5618C9.99423 14.5305 10.0642 14.5089 10.0691 14.5138C10.0864 14.5308 9.84719 14.6899 9.67847 14.7737C9.45143 14.8864 9.2709 14.93 9.03102 14.93C8.59601 14.93 8.23486 14.7101 7.9335 14.2616C7.87419 14.1733 7.7409 13.909 7.63729 13.6741C7.3191 12.9528 7.16199 12.7331 6.79255 12.4926C6.47104 12.2834 6.05641 12.2459 5.74449 12.3979C5.33475 12.5976 5.22043 13.118 5.51389 13.4478C5.63053 13.5789 5.84803 13.6919 6.02588 13.7139C6.35861 13.7551 6.64455 13.5035 6.64455 13.1696C6.64455 12.9528 6.56071 12.8291 6.34966 12.7344C6.0614 12.6051 5.75156 12.7562 5.75304 13.0254C5.75368 13.1402 5.80396 13.2122 5.91971 13.2643C5.99397 13.2977 5.99569 13.3003 5.93514 13.2878C5.67066 13.2333 5.6087 12.9164 5.82135 12.706C6.07667 12.4535 6.60461 12.5649 6.78591 12.9097C6.86208 13.0545 6.87092 13.3429 6.80451 13.517C6.6559 13.9068 6.22256 14.1117 5.78297 14.0002C5.48368 13.9242 5.36181 13.842 5.00097 13.4726C4.37395 12.8306 4.13053 12.7062 3.22657 12.566L3.05335 12.5391L3.25046 12.3737Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.308383 0.883984C2.40235 3.40996 3.84457 4.45213 4.00484 4.67231C4.13717 4.85412 4.08737 5.01757 3.86067 5.14567C3.7346 5.21689 3.47541 5.28905 3.34564 5.28905C3.19887 5.28905 3.14847 5.23278 3.14847 5.23278C3.06337 5.15255 3.01544 5.16658 2.5784 4.39555C1.97166 3.45981 1.46389 2.68357 1.45004 2.67057C1.41801 2.64052 1.41856 2.64153 2.51654 4.59413C2.69394 5.0011 2.55182 5.15049 2.55182 5.20845C2.55182 5.32636 2.51946 5.38834 2.37311 5.55059C2.12914 5.8211 2.02008 6.12505 1.94135 6.7541C1.8531 7.45926 1.60492 7.95737 0.917156 8.80989C0.514562 9.30893 0.448686 9.4004 0.3471 9.60153C0.219144 9.85482 0.183961 9.99669 0.169701 10.3165C0.154629 10.6547 0.183983 10.8732 0.287934 11.1965C0.378939 11.4796 0.473932 11.6665 0.716778 12.0403C0.926351 12.3629 1.04702 12.6027 1.04702 12.6965C1.04702 12.7711 1.06136 12.7712 1.38611 12.6983C2.16328 12.5239 2.79434 12.2171 3.14925 11.8411C3.36891 11.6084 3.42048 11.4799 3.42215 11.1611C3.42325 10.9525 3.41587 10.9088 3.35914 10.7888C3.2668 10.5935 3.09869 10.4311 2.72817 10.1794C2.2427 9.84953 2.03534 9.58398 1.97807 9.21878C1.93108 8.91913 1.98559 8.70771 2.25416 8.14825C2.53214 7.56916 2.60103 7.32239 2.64763 6.73869C2.67773 6.36158 2.71941 6.21286 2.82842 6.09348C2.94212 5.969 3.04447 5.92684 3.32584 5.88863C3.78457 5.82635 4.07667 5.70839 4.31677 5.48849C4.52505 5.29772 4.61221 5.11391 4.62558 4.8372L4.63574 4.62747L4.51934 4.49259C4.09783 4.00411 0.0261003 0.5 0.000160437 0.5C-0.00538105 0.5 0.133325 0.672804 0.308383 0.883984ZM1.28364 10.6992C1.37894 10.5314 1.3283 10.3158 1.16889 10.2104C1.01827 10.1109 0.78428 10.1578 0.78428 10.2875C0.78428 10.3271 0.806303 10.3559 0.855937 10.3813C0.939514 10.424 0.945581 10.4721 0.879823 10.5703C0.81323 10.6698 0.818604 10.7573 0.894991 10.8167C1.0181 10.9125 1.19237 10.8598 1.28364 10.6992Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.92523 5.99865C4.70988 6.06439 4.50054 6.29124 4.43574 6.5291C4.39621 6.67421 4.41864 6.92875 4.47785 7.00736C4.57351 7.13433 4.66602 7.16778 4.91651 7.16603C5.40693 7.16263 5.83327 6.95358 5.88284 6.69224C5.92347 6.47801 5.73622 6.18112 5.4783 6.05078C5.34521 5.98355 5.06217 5.95688 4.92523 5.99865ZM5.49853 6.44422C5.57416 6.33741 5.54107 6.22198 5.41245 6.14391C5.1675 5.99525 4.79708 6.11827 4.79708 6.34826C4.79708 6.46274 4.99025 6.58765 5.16731 6.58765C5.28516 6.58765 5.44644 6.5178 5.49853 6.44422Z" fill="black"/>
|
||||
<path d="M4.15217 1.55141C3.96412 1.52242 3.95619 1.51902 4.04468 1.5055C4.21427 1.47958 4.61472 1.51491 4.89067 1.58012C5.53489 1.73232 6.12109 2.12221 6.74683 2.81466L6.91307 2.99862L7.15088 2.96062C8.15274 2.8006 9.17194 2.92778 10.0244 3.31918C10.2589 3.42686 10.6287 3.64121 10.6749 3.69629C10.6896 3.71384 10.7166 3.82684 10.7349 3.94742C10.7982 4.36458 10.7665 4.68434 10.6382 4.92317C10.5683 5.05313 10.5644 5.09432 10.6114 5.20554C10.6489 5.2943 10.7534 5.35999 10.8569 5.35985C11.0687 5.35956 11.2968 5.0192 11.4024 4.54561L11.4444 4.3575L11.5275 4.45109C11.9835 4.96459 12.3417 5.66488 12.4032 6.16335L12.4192 6.29332L12.3426 6.17517C12.2107 5.97186 12.0781 5.83346 11.9084 5.72183C11.6024 5.52062 11.2789 5.45215 10.4222 5.40727C9.64839 5.36675 9.21045 5.30106 8.77621 5.16032C8.03738 4.9209 7.66493 4.60204 6.78729 3.4576C6.39748 2.94928 6.15654 2.66804 5.91687 2.44155C5.37228 1.92691 4.83716 1.65701 4.15217 1.55141Z"/>
|
||||
<path d="M10.8494 2.68637C10.8689 2.34575 10.9153 2.12108 11.0088 1.9159C11.0458 1.83469 11.0804 1.76822 11.0858 1.76822C11.0911 1.76822 11.075 1.82816 11.05 1.90142C10.9821 2.10054 10.9709 2.3729 11.0177 2.68978C11.0771 3.09184 11.1109 3.14985 11.5385 3.58416C11.739 3.78788 11.9723 4.0448 12.0568 4.15511L12.2106 4.35568L12.0568 4.21234C11.8688 4.03705 11.4364 3.6952 11.3409 3.64633C11.2768 3.61356 11.2673 3.61413 11.2278 3.65321C11.1914 3.68922 11.1837 3.74333 11.1787 3.99915C11.1708 4.39786 11.1161 4.65377 10.9842 4.90965C10.9128 5.04805 10.9015 5.01851 10.9661 4.8623C11.0143 4.74566 11.0192 4.69439 11.0189 4.30842C11.0181 3.53291 10.9255 3.34647 10.3823 3.02709C10.2447 2.94618 10.0179 2.8295 9.87839 2.76778C9.73887 2.70606 9.62805 2.6523 9.63208 2.64828C9.64746 2.63307 10.1772 2.78675 10.3905 2.86828C10.7077 2.98954 10.76 3.00526 10.7985 2.99063C10.8244 2.98082 10.8369 2.90608 10.8494 2.68637Z"/>
|
||||
<path d="M4.51745 4.01304C4.13569 3.49066 3.89948 2.68973 3.95062 2.091L3.96643 1.90572L4.05333 1.92148C4.21652 1.95106 4.49789 2.05515 4.62964 2.13469C4.9912 2.35293 5.14773 2.64027 5.30697 3.37811C5.35362 3.59423 5.41482 3.8388 5.44298 3.9216C5.48831 4.05487 5.65962 4.36617 5.7989 4.56834C5.89922 4.71395 5.83258 4.78295 5.61082 4.76305C5.27215 4.73267 4.8134 4.41799 4.51745 4.01304Z"/>
|
||||
<path d="M10.3863 7.90088C8.60224 7.18693 7.97389 6.56721 7.97389 5.52157C7.97389 5.36769 7.97922 5.24179 7.98571 5.24179C7.99221 5.24179 8.06124 5.29257 8.1391 5.35465C8.50088 5.64305 8.906 5.76623 10.0275 5.92885C10.6875 6.02455 11.0589 6.10185 11.4015 6.21477C12.4904 6.57371 13.1641 7.30212 13.3248 8.29426C13.3715 8.58255 13.3441 9.12317 13.2684 9.4081C13.2087 9.63315 13.0263 10.0388 12.9779 10.0544C12.9645 10.0587 12.9514 10.0076 12.9479 9.93809C12.9296 9.56554 12.7402 9.20285 12.4221 8.93116C12.0604 8.62227 11.5745 8.37633 10.3863 7.90088Z"/>
|
||||
<path d="M9.13385 8.19748C9.11149 8.06527 9.07272 7.89643 9.04769 7.82228L9.00217 7.68748L9.08672 7.7818C9.20374 7.91233 9.2962 8.07937 9.37457 8.30185C9.43438 8.47165 9.44111 8.52215 9.44066 8.79807C9.4402 9.06896 9.43273 9.12575 9.3775 9.27858C9.29042 9.51959 9.18233 9.69048 9.00097 9.87391C8.67507 10.2036 8.25607 10.3861 7.65143 10.4618C7.54633 10.4749 7.24 10.4971 6.97069 10.511C6.292 10.5461 5.84531 10.6186 5.44393 10.7587C5.38623 10.7788 5.3347 10.7911 5.32947 10.7859C5.31323 10.7698 5.58651 10.6079 5.81223 10.4998C6.1305 10.3474 6.44733 10.2643 7.15719 10.1468C7.50785 10.0887 7.86998 10.0183 7.96194 9.99029C8.83033 9.72566 9.27671 9.04276 9.13385 8.19748Z"/>
|
||||
<path d="M9.95169 9.64109C9.71465 9.13463 9.66022 8.64564 9.79009 8.18961C9.80399 8.14088 9.82632 8.101 9.83976 8.101C9.85319 8.101 9.90913 8.13105 9.96404 8.16777C10.0733 8.24086 10.2924 8.36395 10.876 8.68023C11.6043 9.0749 12.0196 9.3805 12.302 9.72965C12.5493 10.0354 12.7023 10.3837 12.776 10.8084C12.8177 11.0489 12.7932 11.6277 12.7311 11.8699C12.5353 12.6337 12.0802 13.2336 11.4311 13.5837C11.336 13.635 11.2506 13.6771 11.2414 13.6773C11.2321 13.6775 11.2668 13.5899 11.3184 13.4827C11.5367 13.029 11.5616 12.5877 11.3965 12.0965C11.2954 11.7957 11.0893 11.4287 10.6732 10.8084C10.1893 10.0873 10.0707 9.89539 9.95169 9.64109Z"/>
|
||||
<path d="M3.25046 12.3737C3.91252 11.8181 4.73629 11.4234 5.48666 11.3022C5.81005 11.25 6.34877 11.2707 6.64823 11.3469C7.12824 11.469 7.55763 11.7425 7.78094 12.0683C7.99918 12.3867 8.09281 12.6642 8.19029 13.2816C8.22875 13.5252 8.27057 13.7697 8.28323 13.8251C8.35644 14.1451 8.4989 14.4008 8.67544 14.5293C8.95583 14.7333 9.43865 14.7459 9.91362 14.5618C9.99423 14.5305 10.0642 14.5089 10.0691 14.5138C10.0864 14.5308 9.84719 14.6899 9.67847 14.7737C9.45143 14.8864 9.2709 14.93 9.03102 14.93C8.59601 14.93 8.23486 14.7101 7.9335 14.2616C7.87419 14.1733 7.7409 13.909 7.63729 13.6741C7.3191 12.9528 7.16199 12.7331 6.79255 12.4926C6.47104 12.2834 6.05641 12.2459 5.74449 12.3979C5.33475 12.5976 5.22043 13.118 5.51389 13.4478C5.63053 13.5789 5.84803 13.6919 6.02588 13.7139C6.35861 13.7551 6.64455 13.5035 6.64455 13.1696C6.64455 12.9528 6.56071 12.8291 6.34966 12.7344C6.0614 12.6051 5.75156 12.7562 5.75304 13.0254C5.75368 13.1402 5.80396 13.2122 5.91971 13.2643C5.99397 13.2977 5.99569 13.3003 5.93514 13.2878C5.67066 13.2333 5.6087 12.9164 5.82135 12.706C6.07667 12.4535 6.60461 12.5649 6.78591 12.9097C6.86208 13.0545 6.87092 13.3429 6.80451 13.517C6.6559 13.9068 6.22256 14.1117 5.78297 14.0002C5.48368 13.9242 5.36181 13.842 5.00097 13.4726C4.37395 12.8306 4.13053 12.7062 3.22657 12.566L3.05335 12.5391L3.25046 12.3737Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.308383 0.883984C2.40235 3.40996 3.84457 4.45213 4.00484 4.67231C4.13717 4.85412 4.08737 5.01757 3.86067 5.14567C3.7346 5.21689 3.47541 5.28905 3.34564 5.28905C3.19887 5.28905 3.14847 5.23278 3.14847 5.23278C3.06337 5.15255 3.01544 5.16658 2.5784 4.39555C1.97166 3.45981 1.46389 2.68357 1.45004 2.67057C1.41801 2.64052 1.41856 2.64153 2.51654 4.59413C2.69394 5.0011 2.55182 5.15049 2.55182 5.20845C2.55182 5.32636 2.51946 5.38834 2.37311 5.55059C2.12914 5.8211 2.02008 6.12505 1.94135 6.7541C1.8531 7.45926 1.60492 7.95737 0.917156 8.80989C0.514562 9.30893 0.448686 9.4004 0.3471 9.60153C0.219144 9.85482 0.183961 9.99669 0.169701 10.3165C0.154629 10.6547 0.183983 10.8732 0.287934 11.1965C0.378939 11.4796 0.473932 11.6665 0.716778 12.0403C0.926351 12.3629 1.04702 12.6027 1.04702 12.6965C1.04702 12.7711 1.06136 12.7712 1.38611 12.6983C2.16328 12.5239 2.79434 12.2171 3.14925 11.8411C3.36891 11.6084 3.42048 11.4799 3.42215 11.1611C3.42325 10.9525 3.41587 10.9088 3.35914 10.7888C3.2668 10.5935 3.09869 10.4311 2.72817 10.1794C2.2427 9.84953 2.03534 9.58398 1.97807 9.21878C1.93108 8.91913 1.98559 8.70771 2.25416 8.14825C2.53214 7.56916 2.60103 7.32239 2.64763 6.73869C2.67773 6.36158 2.71941 6.21286 2.82842 6.09348C2.94212 5.969 3.04447 5.92684 3.32584 5.88863C3.78457 5.82635 4.07667 5.70839 4.31677 5.48849C4.52505 5.29772 4.61221 5.11391 4.62558 4.8372L4.63574 4.62747L4.51934 4.49259C4.09783 4.00411 0.0261003 0.5 0.000160437 0.5C-0.00538105 0.5 0.133325 0.672804 0.308383 0.883984ZM1.28364 10.6992C1.37894 10.5314 1.3283 10.3158 1.16889 10.2104C1.01827 10.1109 0.78428 10.1578 0.78428 10.2875C0.78428 10.3271 0.806303 10.3559 0.855937 10.3813C0.939514 10.424 0.945581 10.4721 0.879823 10.5703C0.81323 10.6698 0.818604 10.7573 0.894991 10.8167C1.0181 10.9125 1.19237 10.8598 1.28364 10.6992Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.92523 5.99865C4.70988 6.06439 4.50054 6.29124 4.43574 6.5291C4.39621 6.67421 4.41864 6.92875 4.47785 7.00736C4.57351 7.13433 4.66602 7.16778 4.91651 7.16603C5.40693 7.16263 5.83327 6.95358 5.88284 6.69224C5.92347 6.47801 5.73622 6.18112 5.4783 6.05078C5.34521 5.98355 5.06217 5.95688 4.92523 5.99865ZM5.49853 6.44422C5.57416 6.33741 5.54107 6.22198 5.41245 6.14391C5.1675 5.99525 4.79708 6.11827 4.79708 6.34826C4.79708 6.46274 4.99025 6.58765 5.16731 6.58765C5.28516 6.58765 5.44644 6.5178 5.49853 6.44422Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.8 KiB |
@@ -1,11 +0,0 @@
|
||||
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.15217 1.55141C3.96412 1.52242 3.95619 1.51902 4.04468 1.5055C4.21427 1.47958 4.61472 1.51491 4.89067 1.58012C5.53489 1.73232 6.12109 2.12221 6.74683 2.81466L6.91307 2.99862L7.15088 2.96062C8.15274 2.8006 9.17194 2.92778 10.0244 3.31918C10.2589 3.42686 10.6287 3.64121 10.6749 3.69629C10.6896 3.71384 10.7166 3.82684 10.7349 3.94742C10.7982 4.36458 10.7665 4.68434 10.6382 4.92317C10.5683 5.05313 10.5644 5.09432 10.6114 5.20554C10.6489 5.2943 10.7534 5.35999 10.8569 5.35985C11.0687 5.35956 11.2968 5.0192 11.4024 4.54561L11.4444 4.3575L11.5275 4.45109C11.9835 4.96459 12.3417 5.66488 12.4032 6.16335L12.4192 6.29332L12.3426 6.17517C12.2107 5.97186 12.0781 5.83346 11.9084 5.72183C11.6024 5.52062 11.2789 5.45215 10.4222 5.40727C9.64839 5.36675 9.21045 5.30106 8.77621 5.16032C8.03738 4.9209 7.66493 4.60204 6.78729 3.4576C6.39748 2.94928 6.15654 2.66804 5.91687 2.44155C5.37228 1.92691 4.83716 1.65701 4.15217 1.55141Z" fill="white"/>
|
||||
<path d="M10.8494 2.68637C10.8689 2.34575 10.9153 2.12108 11.0088 1.9159C11.0458 1.83469 11.0804 1.76822 11.0858 1.76822C11.0911 1.76822 11.075 1.82816 11.05 1.90142C10.9821 2.10054 10.9709 2.3729 11.0177 2.68978C11.0771 3.09184 11.1109 3.14985 11.5385 3.58416C11.739 3.78788 11.9723 4.0448 12.0568 4.15511L12.2106 4.35568L12.0568 4.21234C11.8688 4.03705 11.4364 3.6952 11.3409 3.64633C11.2768 3.61356 11.2673 3.61413 11.2278 3.65321C11.1914 3.68922 11.1837 3.74333 11.1787 3.99915C11.1708 4.39786 11.1161 4.65377 10.9842 4.90965C10.9128 5.04805 10.9015 5.01851 10.9661 4.8623C11.0143 4.74566 11.0192 4.69439 11.0189 4.30842C11.0181 3.53291 10.9255 3.34647 10.3823 3.02709C10.2447 2.94618 10.0179 2.8295 9.87839 2.76778C9.73887 2.70606 9.62805 2.6523 9.63208 2.64828C9.64746 2.63307 10.1772 2.78675 10.3905 2.86828C10.7077 2.98954 10.76 3.00526 10.7985 2.99063C10.8244 2.98082 10.8369 2.90608 10.8494 2.68637Z" fill="white"/>
|
||||
<path d="M4.51745 4.01304C4.13569 3.49066 3.89948 2.68973 3.95062 2.091L3.96643 1.90572L4.05333 1.92148C4.21652 1.95106 4.49789 2.05515 4.62964 2.13469C4.9912 2.35293 5.14773 2.64027 5.30697 3.37811C5.35362 3.59423 5.41482 3.8388 5.44298 3.9216C5.48831 4.05487 5.65962 4.36617 5.7989 4.56834C5.89922 4.71395 5.83258 4.78295 5.61082 4.76305C5.27215 4.73267 4.8134 4.41799 4.51745 4.01304Z" fill="white"/>
|
||||
<path d="M10.3863 7.90088C8.60224 7.18693 7.97389 6.56721 7.97389 5.52157C7.97389 5.36769 7.97922 5.24179 7.98571 5.24179C7.99221 5.24179 8.06124 5.29257 8.1391 5.35465C8.50088 5.64305 8.906 5.76623 10.0275 5.92885C10.6875 6.02455 11.0589 6.10185 11.4015 6.21477C12.4904 6.57371 13.1641 7.30212 13.3248 8.29426C13.3715 8.58255 13.3441 9.12317 13.2684 9.4081C13.2087 9.63315 13.0263 10.0388 12.9779 10.0544C12.9645 10.0587 12.9514 10.0076 12.9479 9.93809C12.9296 9.56554 12.7402 9.20285 12.4221 8.93116C12.0604 8.62227 11.5745 8.37633 10.3863 7.90088Z" fill="white"/>
|
||||
<path d="M9.13385 8.19748C9.11149 8.06527 9.07272 7.89643 9.04769 7.82228L9.00217 7.68748L9.08672 7.7818C9.20374 7.91233 9.2962 8.07937 9.37457 8.30185C9.43438 8.47165 9.44111 8.52215 9.44066 8.79807C9.4402 9.06896 9.43273 9.12575 9.3775 9.27858C9.29042 9.51959 9.18233 9.69048 9.00097 9.87391C8.67507 10.2036 8.25607 10.3861 7.65143 10.4618C7.54633 10.4749 7.24 10.4971 6.97069 10.511C6.292 10.5461 5.84531 10.6186 5.44393 10.7587C5.38623 10.7788 5.3347 10.7911 5.32947 10.7859C5.31323 10.7698 5.58651 10.6079 5.81223 10.4998C6.1305 10.3474 6.44733 10.2643 7.15719 10.1468C7.50785 10.0887 7.86998 10.0183 7.96194 9.99029C8.83033 9.72566 9.27671 9.04276 9.13385 8.19748Z" fill="white"/>
|
||||
<path d="M9.95169 9.64109C9.71465 9.13463 9.66022 8.64564 9.79009 8.18961C9.80399 8.14088 9.82632 8.101 9.83976 8.101C9.85319 8.101 9.90913 8.13105 9.96404 8.16777C10.0733 8.24086 10.2924 8.36395 10.876 8.68023C11.6043 9.0749 12.0196 9.3805 12.302 9.72965C12.5493 10.0354 12.7023 10.3837 12.776 10.8084C12.8177 11.0489 12.7932 11.6277 12.7311 11.8699C12.5353 12.6337 12.0802 13.2336 11.4311 13.5837C11.336 13.635 11.2506 13.6771 11.2414 13.6773C11.2321 13.6775 11.2668 13.5899 11.3184 13.4827C11.5367 13.029 11.5616 12.5877 11.3965 12.0965C11.2954 11.7957 11.0893 11.4287 10.6732 10.8084C10.1893 10.0873 10.0707 9.89539 9.95169 9.64109Z" fill="white"/>
|
||||
<path d="M3.25046 12.3737C3.91252 11.8181 4.73629 11.4234 5.48666 11.3022C5.81005 11.25 6.34877 11.2707 6.64823 11.3469C7.12824 11.469 7.55763 11.7425 7.78094 12.0683C7.99918 12.3867 8.09281 12.6642 8.19029 13.2816C8.22875 13.5252 8.27057 13.7697 8.28323 13.8251C8.35644 14.1451 8.4989 14.4008 8.67544 14.5293C8.95583 14.7333 9.43865 14.7459 9.91362 14.5618C9.99423 14.5305 10.0642 14.5089 10.0691 14.5138C10.0864 14.5308 9.84719 14.6899 9.67847 14.7737C9.45143 14.8864 9.2709 14.93 9.03102 14.93C8.59601 14.93 8.23486 14.7101 7.9335 14.2616C7.87419 14.1733 7.7409 13.909 7.63729 13.6741C7.3191 12.9528 7.16199 12.7331 6.79255 12.4926C6.47104 12.2834 6.05641 12.2459 5.74449 12.3979C5.33475 12.5976 5.22043 13.118 5.51389 13.4478C5.63053 13.5789 5.84803 13.6919 6.02588 13.7139C6.35861 13.7551 6.64455 13.5035 6.64455 13.1696C6.64455 12.9528 6.56071 12.8291 6.34966 12.7344C6.0614 12.6051 5.75156 12.7562 5.75304 13.0254C5.75368 13.1402 5.80396 13.2122 5.91971 13.2643C5.99397 13.2977 5.99569 13.3003 5.93514 13.2878C5.67066 13.2333 5.6087 12.9164 5.82135 12.706C6.07667 12.4535 6.60461 12.5649 6.78591 12.9097C6.86208 13.0545 6.87092 13.3429 6.80451 13.517C6.6559 13.9068 6.22256 14.1117 5.78297 14.0002C5.48368 13.9242 5.36181 13.842 5.00097 13.4726C4.37395 12.8306 4.13053 12.7062 3.22657 12.566L3.05335 12.5391L3.25046 12.3737Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.308383 0.883984C2.40235 3.40996 3.84457 4.45213 4.00484 4.67231C4.13717 4.85412 4.08737 5.01757 3.86067 5.14567C3.7346 5.21689 3.47541 5.28905 3.34564 5.28905C3.19887 5.28905 3.14847 5.23278 3.14847 5.23278C3.06337 5.15255 3.01544 5.16658 2.5784 4.39555C1.97166 3.45981 1.46389 2.68357 1.45004 2.67057C1.41801 2.64052 1.41856 2.64153 2.51654 4.59413C2.69394 5.0011 2.55182 5.15049 2.55182 5.20845C2.55182 5.32636 2.51946 5.38834 2.37311 5.55059C2.12914 5.8211 2.02008 6.12505 1.94135 6.7541C1.8531 7.45926 1.60492 7.95737 0.917156 8.80989C0.514562 9.30893 0.448686 9.4004 0.3471 9.60153C0.219144 9.85482 0.183961 9.99669 0.169701 10.3165C0.154629 10.6547 0.183983 10.8732 0.287934 11.1965C0.378939 11.4796 0.473932 11.6665 0.716778 12.0403C0.926351 12.3629 1.04702 12.6027 1.04702 12.6965C1.04702 12.7711 1.06136 12.7712 1.38611 12.6983C2.16328 12.5239 2.79434 12.2171 3.14925 11.8411C3.36891 11.6084 3.42048 11.4799 3.42215 11.1611C3.42325 10.9525 3.41587 10.9088 3.35914 10.7888C3.2668 10.5935 3.09869 10.4311 2.72817 10.1794C2.2427 9.84953 2.03534 9.58398 1.97807 9.21878C1.93108 8.91913 1.98559 8.70771 2.25416 8.14825C2.53214 7.56916 2.60103 7.32239 2.64763 6.73869C2.67773 6.36158 2.71941 6.21286 2.82842 6.09348C2.94212 5.969 3.04447 5.92684 3.32584 5.88863C3.78457 5.82635 4.07667 5.70839 4.31677 5.48849C4.52505 5.29772 4.61221 5.11391 4.62558 4.8372L4.63574 4.62747L4.51934 4.49259C4.09783 4.00411 0.0261003 0.5 0.000160437 0.5C-0.00538105 0.5 0.133325 0.672804 0.308383 0.883984ZM1.28364 10.6992C1.37894 10.5314 1.3283 10.3158 1.16889 10.2104C1.01827 10.1109 0.78428 10.1578 0.78428 10.2875C0.78428 10.3271 0.806303 10.3559 0.855937 10.3813C0.939514 10.424 0.945581 10.4721 0.879823 10.5703C0.81323 10.6698 0.818604 10.7573 0.894991 10.8167C1.0181 10.9125 1.19237 10.8598 1.28364 10.6992Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.92523 5.99865C4.70988 6.06439 4.50054 6.29124 4.43574 6.5291C4.39621 6.67421 4.41864 6.92875 4.47785 7.00736C4.57351 7.13433 4.66602 7.16778 4.91651 7.16603C5.40693 7.16263 5.83327 6.95358 5.88284 6.69224C5.92347 6.47801 5.73622 6.18112 5.4783 6.05078C5.34521 5.98355 5.06217 5.95688 4.92523 5.99865ZM5.49853 6.44422C5.57416 6.33741 5.54107 6.22198 5.41245 6.14391C5.1675 5.99525 4.79708 6.11827 4.79708 6.34826C4.79708 6.46274 4.99025 6.58765 5.16731 6.58765C5.28516 6.58765 5.44644 6.5178 5.49853 6.44422Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.9 KiB |
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 |
16
src/assets/svg/optimistic_ethereum.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 1.2 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 |
3
src/assets/svg/static_route.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 18C19 18.5523 18.5523 19 18 19V21C19.6569 21 21 19.6569 21 18H19ZM18 19C17.4477 19 17 18.5523 17 18H15C15 19.6569 16.3431 21 18 21V19ZM17 18C17 17.4477 17.4477 17 18 17V15C16.3431 15 15 16.3431 15 18H17ZM18 17C18.5523 17 19 17.4477 19 18H21C21 16.3431 19.6569 15 18 15V17ZM8 7H16V5H8V7ZM16 11H8V13H16V11ZM8 19H16V17H8V19ZM4 15C4 17.2091 5.79086 19 8 19V17C6.89543 17 6 16.1046 6 15H4ZM8 11C5.79086 11 4 12.7909 4 15H6C6 13.8954 6.89543 13 8 13V11ZM18 9C18 10.1046 17.1046 11 16 11V13C18.2091 13 20 11.2091 20 9H18ZM16 7C17.1046 7 18 7.89543 18 9H20C20 6.79086 18.2091 5 16 5V7ZM7 6C7 6.55228 6.55228 7 6 7V9C7.65685 9 9 7.65685 9 6H7ZM6 7C5.44772 7 5 6.55228 5 6H3C3 7.65685 4.34315 9 6 9V7ZM5 6C5 5.44772 5.44772 5 6 5V3C4.34315 3 3 4.34315 3 6H5ZM6 5C6.55228 5 7 5.44772 7 6H9C9 4.34315 7.65685 3 6 3V5Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 925 B |
@@ -1,10 +1,10 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import useCopyClipboard from '../../hooks/useCopyClipboard'
|
||||
|
||||
import { LinkStyledButton } from '../../theme'
|
||||
import { CheckCircle, Copy } from 'react-feather'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import React from 'react'
|
||||
import { CheckCircle, Copy } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import useCopyClipboard from '../../hooks/useCopyClipboard'
|
||||
import { LinkStyledButton } from '../../theme'
|
||||
|
||||
const CopyIcon = styled(LinkStyledButton)`
|
||||
color: ${({ theme }) => theme.text3};
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { CheckCircle, Triangle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { useAllTransactions } from '../../state/transactions/hooks'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { RowFixed } from '../Row'
|
||||
import Loader from '../Loader'
|
||||
|
||||
const TransactionWrapper = styled.div``
|
||||
import { RowFixed } from '../Row'
|
||||
import { TransactionSummary } from './TransactionSummary'
|
||||
|
||||
const TransactionStatusText = styled.div`
|
||||
margin-right: 0.5rem;
|
||||
@@ -40,26 +39,28 @@ export default function Transaction({ hash }: { hash: string }) {
|
||||
const allTransactions = useAllTransactions()
|
||||
|
||||
const tx = allTransactions?.[hash]
|
||||
const summary = tx?.summary
|
||||
const info = tx?.info
|
||||
const pending = !tx?.receipt
|
||||
const success = !pending && tx && (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined')
|
||||
|
||||
if (!chainId) return null
|
||||
|
||||
return (
|
||||
<TransactionWrapper>
|
||||
<div>
|
||||
<TransactionState
|
||||
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
|
||||
pending={pending}
|
||||
success={success}
|
||||
>
|
||||
<RowFixed>
|
||||
<TransactionStatusText>{summary ?? hash} ↗</TransactionStatusText>
|
||||
<TransactionStatusText>
|
||||
<TransactionSummary info={info} /> ↗
|
||||
</TransactionStatusText>
|
||||
</RowFixed>
|
||||
<IconWrapper pending={pending} success={success}>
|
||||
{pending ? <Loader /> : success ? <CheckCircle size="16" /> : <Triangle size="16" />}
|
||||
</IconWrapper>
|
||||
</TransactionState>
|
||||
</TransactionWrapper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
345
src/components/AccountDetails/TransactionSummary.tsx
Normal file
@@ -0,0 +1,345 @@
|
||||
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'
|
||||
import {
|
||||
AddLiquidityV2PoolTransactionInfo,
|
||||
AddLiquidityV3PoolTransactionInfo,
|
||||
ApproveTransactionInfo,
|
||||
ClaimTransactionInfo,
|
||||
CollectFeesTransactionInfo,
|
||||
CreateV3PoolTransactionInfo,
|
||||
DelegateTransactionInfo,
|
||||
DepositLiquidityStakingTransactionInfo,
|
||||
ExactInputSwapTransactionInfo,
|
||||
ExactOutputSwapTransactionInfo,
|
||||
MigrateV2LiquidityToV3TransactionInfo,
|
||||
RemoveLiquidityV3TransactionInfo,
|
||||
SubmitProposalTransactionInfo,
|
||||
TransactionInfo,
|
||||
TransactionType,
|
||||
VoteTransactionInfo,
|
||||
WithdrawLiquidityStakingTransactionInfo,
|
||||
WrapTransactionInfo,
|
||||
} from '../../state/transactions/actions'
|
||||
|
||||
function formatAmount(amountRaw: string, decimals: number, sigFigs: number): string {
|
||||
return new Fraction(amountRaw, JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(decimals))).toSignificant(sigFigs)
|
||||
}
|
||||
|
||||
function FormattedCurrencyAmount({
|
||||
rawAmount,
|
||||
symbol,
|
||||
decimals,
|
||||
sigFigs,
|
||||
}: {
|
||||
rawAmount: string
|
||||
symbol: string
|
||||
decimals: number
|
||||
sigFigs: number
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{formatAmount(rawAmount, decimals, sigFigs)} {symbol}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function FormattedCurrencyAmountManaged({
|
||||
rawAmount,
|
||||
currencyId,
|
||||
sigFigs = 6,
|
||||
}: {
|
||||
rawAmount: string
|
||||
currencyId: string
|
||||
sigFigs: number
|
||||
}) {
|
||||
const currency = useCurrency(currencyId)
|
||||
return currency ? (
|
||||
<FormattedCurrencyAmount
|
||||
rawAmount={rawAmount}
|
||||
decimals={currency.decimals}
|
||||
sigFigs={sigFigs}
|
||||
symbol={currency.symbol ?? '???'}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
|
||||
function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransactionInfo }) {
|
||||
const { ENSName } = useENSName()
|
||||
return typeof uniAmountRaw === 'string' ? (
|
||||
<Trans>
|
||||
Claim <FormattedCurrencyAmount rawAmount={uniAmountRaw} symbol={'UNI'} decimals={18} sigFigs={4} /> for{' '}
|
||||
{ENSName ?? recipient}
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>Claim UNI reward for {ENSName ?? recipient}</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function SubmitProposalTransactionSummary(_: { info: SubmitProposalTransactionInfo }) {
|
||||
return <Trans>Submit new proposal</Trans>
|
||||
}
|
||||
|
||||
function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) {
|
||||
const token = useToken(info.tokenAddress)
|
||||
|
||||
return <Trans>Approve {token?.symbol}</Trans>
|
||||
}
|
||||
|
||||
function VoteSummary({ info }: { info: VoteTransactionInfo }) {
|
||||
const proposalKey = `${info.governorAddress}/${info.proposalId}`
|
||||
if (info.reason && info.reason.trim().length > 0) {
|
||||
switch (info.decision) {
|
||||
case VoteOption.For:
|
||||
return <Trans>Vote for proposal {proposalKey}</Trans>
|
||||
case VoteOption.Abstain:
|
||||
return <Trans>Vote to abstain on proposal {proposalKey}</Trans>
|
||||
case VoteOption.Against:
|
||||
return <Trans>Vote against proposal {proposalKey}</Trans>
|
||||
}
|
||||
} else {
|
||||
switch (info.decision) {
|
||||
case VoteOption.For:
|
||||
return (
|
||||
<Trans>
|
||||
Vote for proposal {proposalKey} with reason "{info.reason}"
|
||||
</Trans>
|
||||
)
|
||||
case VoteOption.Abstain:
|
||||
return (
|
||||
<Trans>
|
||||
Vote to abstain on proposal {proposalKey} with reason "{info.reason}"
|
||||
</Trans>
|
||||
)
|
||||
case VoteOption.Against:
|
||||
return (
|
||||
<Trans>
|
||||
Vote against proposal {proposalKey} with reason "{info.reason}"
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInfo }) {
|
||||
const { ENSName } = useENSName(delegatee)
|
||||
return <Trans>Delegate voting power to {ENSName ?? delegatee}</Trans>
|
||||
}
|
||||
|
||||
function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
|
||||
const native = chainId ? nativeOnChain(chainId) : undefined
|
||||
|
||||
if (unwrapped) {
|
||||
return (
|
||||
<Trans>
|
||||
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={native?.symbol ?? 'ETH'}
|
||||
decimals={18}
|
||||
sigFigs={6}
|
||||
/>{' '}
|
||||
to {native?.wrapped?.symbol ?? 'WETH'}
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function DepositLiquidityStakingSummary(_: { info: DepositLiquidityStakingTransactionInfo }) {
|
||||
// not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts
|
||||
// todo: deprecate and delete the code paths that allow this, show user more information
|
||||
return <Trans>Deposit liquidity</Trans>
|
||||
}
|
||||
|
||||
function WithdrawLiquidityStakingSummary(_: { info: WithdrawLiquidityStakingTransactionInfo }) {
|
||||
return <Trans>Withdraw deposited liquidity</Trans>
|
||||
}
|
||||
|
||||
function MigrateLiquidityToV3Summary({
|
||||
info: { baseCurrencyId, quoteCurrencyId },
|
||||
}: {
|
||||
info: MigrateV2LiquidityToV3TransactionInfo
|
||||
}) {
|
||||
const baseCurrency = useCurrency(baseCurrencyId)
|
||||
const quoteCurrency = useCurrency(quoteCurrencyId)
|
||||
|
||||
return (
|
||||
<Trans>
|
||||
Migrate {baseCurrency?.symbol}/{quoteCurrency?.symbol} liquidity to V3
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function CreateV3PoolSummary({ info: { quoteCurrencyId, baseCurrencyId } }: { info: CreateV3PoolTransactionInfo }) {
|
||||
const baseCurrency = useCurrency(baseCurrencyId)
|
||||
const quoteCurrency = useCurrency(quoteCurrencyId)
|
||||
|
||||
return (
|
||||
<Trans>
|
||||
Create {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 pool
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function CollectFeesSummary({ info: { currencyId0, currencyId1 } }: { info: CollectFeesTransactionInfo }) {
|
||||
const currency0 = useCurrency(currencyId0)
|
||||
const currency1 = useCurrency(currencyId1)
|
||||
|
||||
return (
|
||||
<Trans>
|
||||
Collect {currency0?.symbol}/{currency1?.symbol} fees
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function RemoveLiquidityV3Summary({
|
||||
info: { baseCurrencyId, quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw },
|
||||
}: {
|
||||
info: RemoveLiquidityV3TransactionInfo
|
||||
}) {
|
||||
return (
|
||||
<Trans>
|
||||
Remove{' '}
|
||||
<FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} /> and{' '}
|
||||
<FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function AddLiquidityV3PoolSummary({
|
||||
info: { createPool, quoteCurrencyId, baseCurrencyId },
|
||||
}: {
|
||||
info: AddLiquidityV3PoolTransactionInfo
|
||||
}) {
|
||||
const baseCurrency = useCurrency(baseCurrencyId)
|
||||
const quoteCurrency = useCurrency(quoteCurrencyId)
|
||||
|
||||
return createPool ? (
|
||||
<Trans>
|
||||
Create pool and add {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 liquidity
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
Add {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 liquidity
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function AddLiquidityV2PoolSummary({
|
||||
info: { quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw, baseCurrencyId },
|
||||
}: {
|
||||
info: AddLiquidityV2PoolTransactionInfo
|
||||
}) {
|
||||
return (
|
||||
<Trans>
|
||||
Add <FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} />{' '}
|
||||
and <FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />{' '}
|
||||
to Uniswap V2
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
|
||||
function SwapSummary({ info }: { info: ExactInputSwapTransactionInfo | ExactOutputSwapTransactionInfo }) {
|
||||
if (info.tradeType === TradeType.EXACT_INPUT) {
|
||||
return (
|
||||
<Trans>
|
||||
Swap exactly{' '}
|
||||
<FormattedCurrencyAmountManaged
|
||||
rawAmount={info.inputCurrencyAmountRaw}
|
||||
currencyId={info.inputCurrencyId}
|
||||
sigFigs={6}
|
||||
/>{' '}
|
||||
for{' '}
|
||||
<FormattedCurrencyAmountManaged
|
||||
rawAmount={info.expectedOutputCurrencyAmountRaw}
|
||||
currencyId={info.outputCurrencyId}
|
||||
sigFigs={6}
|
||||
/>
|
||||
</Trans>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Trans>
|
||||
Swap{' '}
|
||||
<FormattedCurrencyAmountManaged
|
||||
rawAmount={info.expectedInputCurrencyAmountRaw}
|
||||
currencyId={info.inputCurrencyId}
|
||||
sigFigs={6}
|
||||
/>{' '}
|
||||
for exactly{' '}
|
||||
<FormattedCurrencyAmountManaged
|
||||
rawAmount={info.outputCurrencyAmountRaw}
|
||||
currencyId={info.outputCurrencyId}
|
||||
sigFigs={6}
|
||||
/>
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function TransactionSummary({ info }: { info: TransactionInfo }) {
|
||||
switch (info.type) {
|
||||
case TransactionType.ADD_LIQUIDITY_V3_POOL:
|
||||
return <AddLiquidityV3PoolSummary info={info} />
|
||||
|
||||
case TransactionType.ADD_LIQUIDITY_V2_POOL:
|
||||
return <AddLiquidityV2PoolSummary info={info} />
|
||||
|
||||
case TransactionType.CLAIM:
|
||||
return <ClaimSummary info={info} />
|
||||
|
||||
case TransactionType.DEPOSIT_LIQUIDITY_STAKING:
|
||||
return <DepositLiquidityStakingSummary info={info} />
|
||||
|
||||
case TransactionType.WITHDRAW_LIQUIDITY_STAKING:
|
||||
return <WithdrawLiquidityStakingSummary info={info} />
|
||||
|
||||
case TransactionType.SWAP:
|
||||
return <SwapSummary info={info} />
|
||||
|
||||
case TransactionType.APPROVAL:
|
||||
return <ApprovalSummary info={info} />
|
||||
|
||||
case TransactionType.VOTE:
|
||||
return <VoteSummary info={info} />
|
||||
|
||||
case TransactionType.DELEGATE:
|
||||
return <DelegateSummary info={info} />
|
||||
|
||||
case TransactionType.WRAP:
|
||||
return <WrapSummary info={info} />
|
||||
|
||||
case TransactionType.CREATE_V3_POOL:
|
||||
return <CreateV3PoolSummary info={info} />
|
||||
|
||||
case TransactionType.MIGRATE_LIQUIDITY_V3:
|
||||
return <MigrateLiquidityToV3Summary info={info} />
|
||||
|
||||
case TransactionType.COLLECT_FEES:
|
||||
return <CollectFeesSummary info={info} />
|
||||
|
||||
case TransactionType.REMOVE_LIQUIDITY_V3:
|
||||
return <RemoveLiquidityV3Summary info={info} />
|
||||
|
||||
case TransactionType.SUBMIT_PROPOSAL:
|
||||
return <SubmitProposalTransactionSummary info={info} />
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,25 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
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 { Connector } from 'widgets-web3-react/types'
|
||||
|
||||
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'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { ButtonSecondary } from '../Button'
|
||||
import StatusIcon from '../Identicon/StatusIcon'
|
||||
import { AutoRow } from '../Row'
|
||||
import Copy from './Copy'
|
||||
import Transaction from './Transaction'
|
||||
|
||||
import { ReactComponent as Close } from '../../assets/images/x.svg'
|
||||
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||
import Identicon from '../Identicon'
|
||||
import { ButtonSecondary } from '../Button'
|
||||
import { ExternalLink as LinkIcon } from 'react-feather'
|
||||
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
|
||||
const HeaderRow = styled.div`
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
padding: 1rem 1rem;
|
||||
@@ -179,6 +177,23 @@ const IconWrapper = styled.div<{ size?: number }>`
|
||||
`};
|
||||
`
|
||||
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<StatusIcon connector={connector} />
|
||||
{connector === portis && (
|
||||
<MainWalletAction
|
||||
onClick={() => {
|
||||
portis.portis.showPortis()
|
||||
}}
|
||||
>
|
||||
<Trans>Show Portis</Trans>
|
||||
</MainWalletAction>
|
||||
)}
|
||||
</IconWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const TransactionListWrapper = styled.div`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
`
|
||||
@@ -244,50 +259,6 @@ export default function AccountDetails({
|
||||
)
|
||||
}
|
||||
|
||||
function getStatusIcon() {
|
||||
if (connector === injected) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<Identicon />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletconnect) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={WalletConnectIcon} alt={'WalletConnect logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletlink) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={CoinbaseWalletIcon} alt={'Coinbase Wallet logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === fortmatic) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={FortmaticIcon} alt={'Fortmatic logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === portis) {
|
||||
return (
|
||||
<>
|
||||
<IconWrapper size={16}>
|
||||
<img src={PortisIcon} alt={'Portis logo'} />
|
||||
<MainWalletAction
|
||||
onClick={() => {
|
||||
portis.portis.showPortis()
|
||||
}}
|
||||
>
|
||||
<Trans>Show Portis</Trans>
|
||||
</MainWalletAction>
|
||||
</IconWrapper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const clearAllTransactionsCallback = useCallback(() => {
|
||||
if (chainId) dispatch(clearAllTransactions({ chainId }))
|
||||
}, [dispatch, chainId])
|
||||
@@ -332,14 +303,14 @@ export default function AccountDetails({
|
||||
{ENSName ? (
|
||||
<>
|
||||
<div>
|
||||
{getStatusIcon()}
|
||||
{connector && <WrappedStatusIcon connector={connector} />}
|
||||
<p> {ENSName}</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
{getStatusIcon()}
|
||||
{connector && <WrappedStatusIcon connector={connector} />}
|
||||
<p> {account && shortenAddress(account)}</p>
|
||||
</div>
|
||||
</>
|
||||
@@ -408,9 +379,9 @@ export default function AccountDetails({
|
||||
{!!pendingTransactions.length || !!confirmedTransactions.length ? (
|
||||
<LowerSection>
|
||||
<AutoRow mb={'1rem'} style={{ justifyContent: 'space-between' }}>
|
||||
<TYPE.body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Recent Transactions</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<LinkStyledButton onClick={clearAllTransactionsCallback}>
|
||||
<Trans>(clear all)</Trans>
|
||||
</LinkStyledButton>
|
||||
@@ -420,9 +391,9 @@ export default function AccountDetails({
|
||||
</LowerSection>
|
||||
) : (
|
||||
<LowerSection>
|
||||
<TYPE.body color={theme.text1}>
|
||||
<ThemedText.Body color={theme.text1}>
|
||||
<Trans>Your transactions will appear here...</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</LowerSection>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { useContext, useCallback, ReactNode } from 'react'
|
||||
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, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { RowBetween } from '../Row'
|
||||
@@ -105,9 +108,9 @@ export default function AddressInputPanel({
|
||||
<InputContainer>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.black color={theme.text2} fontWeight={500} fontSize={14}>
|
||||
<ThemedText.Black color={theme.text2} fontWeight={500} fontSize={14}>
|
||||
{label ?? <Trans>Recipient</Trans>}
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
{address && chainId && (
|
||||
<ExternalLink
|
||||
href={getExplorerLink(chainId, name ?? address, ExplorerDataType.ADDRESS)}
|
||||
|
||||
34
src/components/AnimatedDropdown/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { animated, useSpring } from 'react-spring'
|
||||
import useResizeObserver from 'use-resize-observer'
|
||||
|
||||
/**
|
||||
* @param open conditional to show content or hide
|
||||
* @returns Wrapper to smoothly hide and expand content
|
||||
*/
|
||||
export default function AnimatedDropdown({ open, children }: React.PropsWithChildren<{ open: boolean }>) {
|
||||
const { ref, height } = useResizeObserver()
|
||||
|
||||
const props = useSpring({
|
||||
height: open ? height ?? 0 : 0,
|
||||
config: {
|
||||
mass: 1.2,
|
||||
tension: 300,
|
||||
friction: 20,
|
||||
clamp: true,
|
||||
velocity: 0.01,
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<animated.div
|
||||
style={{
|
||||
...props,
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
willChange: 'height',
|
||||
}}
|
||||
>
|
||||
<div ref={ref}>{children}</div>
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import Badge, { BadgeVariant } from 'components/Badge'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { MouseoverTooltip } from '../../components/Tooltip'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
|
||||
const BadgeWrapper = styled.div`
|
||||
font-size: 14px;
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
import { ReactNode, useMemo } from 'react'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { ReactNode, useMemo } from 'react'
|
||||
|
||||
// SDN OFAC addresses
|
||||
const BLOCKED_ADDRESSES: string[] = [
|
||||
'0x7Db418b5D567A4e0E8c59Ad71BE1FcE48f3E6107',
|
||||
'0x72a5843cc08275C8171E582972Aa4fDa8C397B2A',
|
||||
'0x7F19720A857F834887FC9A7bC0a0fBe7Fc7f8102',
|
||||
'0xA7e5d5A720f06526557c513402f2e6B5fA20b008',
|
||||
'0x1da5821544e25c636c1417Ba96Ade4Cf6D2f9B5A',
|
||||
'0x9F4cda013E354b8fC285BF4b9A60460cEe7f7Ea9',
|
||||
'0x19Aa5Fe80D33a56D56c78e82eA5E50E5d80b4Dff',
|
||||
'0x2f389cE8bD8ff92De3402FFCe4691d17fC4f6535',
|
||||
'0xe7aa314c77F4233C18C6CC84384A9247c0cf367B',
|
||||
'0x7F367cC41522cE07553e823bf3be79A889DEbe1B',
|
||||
'0xd882cFc20F52f2599D84b8e8D58C7FB62cfE344b',
|
||||
'0x901bb9583b24D97e995513C6778dc6888AB6870e',
|
||||
'0xA7e5d5A720f06526557c513402f2e6B5fA20b008',
|
||||
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
|
||||
'0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963',
|
||||
'0x308eD4B7b49797e1A98D3818bFF6fe5385410370',
|
||||
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B',
|
||||
'0x6f1ca141a28907f78ebaa64fb83a9088b02a83',
|
||||
'0x6acdfba02d390b97ac2b2d42a63e85293bcc1',
|
||||
'0x48549a34ae37b12f6a30566245176994e17c6',
|
||||
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121',
|
||||
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e',
|
||||
'0x3cbded43efdaf0fc77b9c55f6fc9988fcc9b757d',
|
||||
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B6b45',
|
||||
'0x6f1ca141a28907f78ebaa64fb83a9088b02a8352',
|
||||
'0x6acdfba02d390b97ac2b2d42a63e85293bcc160e',
|
||||
'0x48549a34ae37b12f6a30566245176994e17c6b4a',
|
||||
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121b0',
|
||||
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e4a',
|
||||
'0x629e7Da20197a5429d30da36E77d06CdF796b71A',
|
||||
]
|
||||
|
||||
export default function Blocklist({ children }: { children: ReactNode }) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { darken } from 'polished'
|
||||
import { Check, ChevronDown } from 'react-feather'
|
||||
import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { RowBetween } from '../Row'
|
||||
import { ChevronDown, Check } from 'react-feather'
|
||||
import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
|
||||
type ButtonProps = Omit<ButtonPropsOriginal, 'css'>
|
||||
|
||||
const Base = styled(RebassButton)<
|
||||
export const BaseButton = styled(RebassButton)<
|
||||
{
|
||||
padding?: string
|
||||
width?: string
|
||||
@@ -23,7 +23,7 @@ const Base = 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;
|
||||
@@ -33,6 +33,7 @@ const Base = styled(RebassButton)<
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:disabled {
|
||||
opacity: 50%;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -50,7 +51,7 @@ const Base = styled(RebassButton)<
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonPrimary = styled(Base)`
|
||||
export const ButtonPrimary = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.primary1};
|
||||
color: white;
|
||||
&:focus {
|
||||
@@ -67,7 +68,8 @@ export const ButtonPrimary = styled(Base)`
|
||||
&:disabled {
|
||||
background-color: ${({ theme, altDisabledStyle, disabled }) =>
|
||||
altDisabledStyle ? (disabled ? theme.primary1 : theme.bg2) : theme.bg2};
|
||||
color: ${({ theme }) => theme.text2};
|
||||
color: ${({ altDisabledStyle, disabled, theme }) =>
|
||||
altDisabledStyle ? (disabled ? theme.white : theme.text2) : theme.text2};
|
||||
cursor: auto;
|
||||
box-shadow: none;
|
||||
border: 1px solid transparent;
|
||||
@@ -75,7 +77,7 @@ export const ButtonPrimary = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonLight = styled(Base)`
|
||||
export const ButtonLight = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.primary5};
|
||||
color: ${({ theme }) => theme.primaryText1};
|
||||
font-size: 16px;
|
||||
@@ -103,7 +105,7 @@ export const ButtonLight = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonGray = styled(Base)`
|
||||
export const ButtonGray = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
color: ${({ theme }) => theme.text2};
|
||||
font-size: 16px;
|
||||
@@ -117,7 +119,7 @@ export const ButtonGray = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonSecondary = styled(Base)`
|
||||
export const ButtonSecondary = styled(BaseButton)`
|
||||
border: 1px solid ${({ theme }) => theme.primary4};
|
||||
color: ${({ theme }) => theme.primary1};
|
||||
background-color: transparent;
|
||||
@@ -145,7 +147,7 @@ export const ButtonSecondary = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonOutlined = styled(Base)`
|
||||
export const ButtonOutlined = styled(BaseButton)`
|
||||
border: 1px solid ${({ theme }) => theme.bg2};
|
||||
background-color: transparent;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
@@ -164,7 +166,7 @@ export const ButtonOutlined = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonYellow = styled(Base)`
|
||||
export const ButtonYellow = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.yellow3};
|
||||
color: white;
|
||||
&:focus {
|
||||
@@ -185,7 +187,7 @@ export const ButtonYellow = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonEmpty = styled(Base)`
|
||||
export const ButtonEmpty = styled(BaseButton)`
|
||||
background-color: transparent;
|
||||
color: ${({ theme }) => theme.primary1};
|
||||
display: flex;
|
||||
@@ -207,7 +209,7 @@ export const ButtonEmpty = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonText = styled(Base)`
|
||||
export const ButtonText = styled(BaseButton)`
|
||||
padding: 0;
|
||||
width: fit-content;
|
||||
background: none;
|
||||
@@ -229,20 +231,20 @@ export const ButtonText = styled(Base)`
|
||||
}
|
||||
`
|
||||
|
||||
const ButtonConfirmedStyle = styled(Base)`
|
||||
const ButtonConfirmedStyle = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.bg3};
|
||||
color: ${({ theme }) => theme.text1};
|
||||
/* border: 1px solid ${({ theme }) => theme.green1}; */
|
||||
|
||||
&:disabled {
|
||||
/* opacity: 50%; */
|
||||
opacity: 50%;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
color: ${({ theme }) => theme.text2};
|
||||
cursor: auto;
|
||||
}
|
||||
`
|
||||
|
||||
const ButtonErrorStyle = styled(Base)`
|
||||
const ButtonErrorStyle = styled(BaseButton)`
|
||||
background-color: ${({ theme }) => theme.red1};
|
||||
border: 1px solid ${({ theme }) => theme.red1};
|
||||
|
||||
@@ -314,8 +316,8 @@ const ActiveOutlined = styled(ButtonOutlined)`
|
||||
`
|
||||
|
||||
const Circle = styled.div`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
height: 17px;
|
||||
width: 17px;
|
||||
border-radius: 50%;
|
||||
background-color: ${({ theme }) => theme.primary1};
|
||||
display: flex;
|
||||
@@ -324,11 +326,11 @@ const Circle = styled.div`
|
||||
`
|
||||
|
||||
const CheckboxWrapper = styled.div`
|
||||
width: 30px;
|
||||
width: 20px;
|
||||
padding: 0 10px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
top: 11px;
|
||||
right: 15px;
|
||||
`
|
||||
|
||||
const ResponsiveCheck = styled(Check)`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import { Box } from 'rebass/styled-components'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const Card = styled(Box)<{ width?: string; padding?: string; border?: string; $borderRadius?: string }>`
|
||||
width: ${({ width }) => width ?? '100%'};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ReactConfetti from 'react-confetti'
|
||||
|
||||
import { useWindowSize } from '../../hooks/useWindowSize'
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
||||
import { useMemo } from 'react'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { TYPE } from '../../theme'
|
||||
import { warningSeverity } from '../../utils/prices'
|
||||
import HoverInlineText from 'components/HoverInlineText'
|
||||
import { Trans } from '@lingui/macro'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
||||
import HoverInlineText from 'components/HoverInlineText'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { warningSeverity } from '../../utils/prices'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
|
||||
export function FiatValue({
|
||||
fiatValue,
|
||||
@@ -24,10 +28,14 @@ export function FiatValue({
|
||||
}, [priceImpact, theme.green1, theme.red1, theme.text3, theme.yellow1])
|
||||
|
||||
return (
|
||||
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}>
|
||||
<ThemedText.Body fontSize={14} color={fiatValue ? theme.text3 : theme.text4}>
|
||||
{fiatValue ? (
|
||||
<Trans>
|
||||
~$ <HoverInlineText text={fiatValue?.toSignificant(6, { groupSeparator: ',' })} />
|
||||
$
|
||||
<HoverInlineText
|
||||
text={fiatValue?.toSignificant(6, { groupSeparator: ',' })}
|
||||
textColor={fiatValue ? theme.text3 : theme.text4}
|
||||
/>
|
||||
</Trans>
|
||||
) : (
|
||||
''
|
||||
@@ -35,9 +43,11 @@ export function FiatValue({
|
||||
{priceImpact ? (
|
||||
<span style={{ color: priceImpactColor }}>
|
||||
{' '}
|
||||
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
|
||||
<MouseoverTooltip text={t`The estimated difference between the USD values of input and output amounts.`}>
|
||||
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
|
||||
</MouseoverTooltip>
|
||||
</span>
|
||||
) : null}
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
|
||||
import { useState, useCallback, ReactNode } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
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'
|
||||
import styled from 'styled-components/macro'
|
||||
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { useCurrencyBalance } from '../../state/wallet/hooks'
|
||||
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonGray } from '../Button'
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
import DoubleCurrencyLogo from '../DoubleLogo'
|
||||
import { ButtonGray } from '../Button'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import { TYPE } from '../../theme'
|
||||
import { Input as NumericalInput } from '../NumericalInput'
|
||||
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { Lock } from 'react-feather'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
|
||||
import { FiatValue } from './FiatValue'
|
||||
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
|
||||
|
||||
const InputPanel = styled.div<{ hideInput?: boolean }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap}
|
||||
@@ -27,6 +29,8 @@ const InputPanel = styled.div<{ hideInput?: boolean }>`
|
||||
background-color: ${({ theme, hideInput }) => (hideInput ? 'transparent' : theme.bg2)};
|
||||
z-index: 1;
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
transition: height 1s ease;
|
||||
will-change: height;
|
||||
`
|
||||
|
||||
const FixedContainer = styled.div`
|
||||
@@ -34,8 +38,7 @@ const FixedContainer = styled.div`
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border-radius: 20px;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
opacity: 0.95;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -44,7 +47,7 @@ const FixedContainer = styled.div`
|
||||
|
||||
const Container = styled.div<{ hideInput: boolean }>`
|
||||
border-radius: ${({ hideInput }) => (hideInput ? '16px' : '20px')};
|
||||
border: 1px solid ${({ theme, hideInput }) => (hideInput ? ' transparent' : theme.bg2)};
|
||||
border: 1px solid ${({ theme }) => theme.bg0};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
:focus,
|
||||
@@ -53,34 +56,36 @@ const Container = styled.div<{ hideInput: boolean }>`
|
||||
}
|
||||
`
|
||||
|
||||
const CurrencySelect = styled(ButtonGray)<{ selected: boolean; hideInput?: boolean }>`
|
||||
const CurrencySelect = styled(ButtonGray)<{ visible: boolean; selected: boolean; hideInput?: boolean }>`
|
||||
align-items: center;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg0 : theme.primary1)};
|
||||
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
||||
border-radius: 16px;
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : theme.primary1)};
|
||||
box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
outline: none;
|
||||
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
||||
cursor: pointer;
|
||||
border-radius: 16px;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
height: ${({ hideInput }) => (hideInput ? '2.8rem' : '2.4rem')};
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
padding: 0 8px;
|
||||
justify-content: space-between;
|
||||
margin-right: ${({ hideInput }) => (hideInput ? '0' : '12px')};
|
||||
margin-left: ${({ hideInput }) => (hideInput ? '0' : '12px')};
|
||||
:focus,
|
||||
:hover {
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : darken(0.05, theme.primary1))};
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg3 : darken(0.05, theme.primary1))};
|
||||
}
|
||||
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
|
||||
`
|
||||
|
||||
const InputRow = styled.div<{ selected: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap}
|
||||
align-items: center;
|
||||
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 0.75rem 1rem')};
|
||||
justify-content: space-between;
|
||||
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 1rem 1rem')};
|
||||
`
|
||||
|
||||
const LabelRow = styled.div`
|
||||
@@ -124,24 +129,30 @@ const StyledTokenName = styled.span<{ active?: boolean }>`
|
||||
|
||||
const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
|
||||
background-color: transparent;
|
||||
background-color: ${({ theme }) => theme.primary5};
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: ${({ theme }) => theme.primary1};
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
color: ${({ theme }) => theme.primaryText1};
|
||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-left: 0.25rem;
|
||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||
padding: 4px 6px;
|
||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||
|
||||
:hover {
|
||||
opacity: ${({ disabled }) => (!disabled ? 0.8 : 0.4)};
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: none;
|
||||
}
|
||||
`
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToExtraSmall`
|
||||
margin-right: 0.5rem;
|
||||
`};
|
||||
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean }>`
|
||||
${loadingOpacityMixin};
|
||||
text-align: left;
|
||||
`
|
||||
|
||||
interface CurrencyInputPanelProps {
|
||||
@@ -164,6 +175,7 @@ interface CurrencyInputPanelProps {
|
||||
disableNonToken?: boolean
|
||||
renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode
|
||||
locked?: boolean
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
export default function CurrencyInputPanel({
|
||||
@@ -185,6 +197,7 @@ export default function CurrencyInputPanel({
|
||||
pair = null, // used for double token logo
|
||||
hideInput = false,
|
||||
locked = false,
|
||||
loading = false,
|
||||
...rest
|
||||
}: CurrencyInputPanelProps) {
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
@@ -202,15 +215,25 @@ export default function CurrencyInputPanel({
|
||||
<FixedContainer>
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Lock />
|
||||
<TYPE.label fontSize="12px" textAlign="center" padding="0 12px">
|
||||
<ThemedText.Label fontSize="12px" textAlign="center" padding="0 12px">
|
||||
<Trans>The market price is outside your specified price range. Single-asset deposit only.</Trans>
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</AutoColumn>
|
||||
</FixedContainer>
|
||||
)}
|
||||
<Container hideInput={hideInput}>
|
||||
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
|
||||
{!hideInput && (
|
||||
<StyledNumericalInput
|
||||
className="token-amount-input"
|
||||
value={value}
|
||||
onUserInput={onUserInput}
|
||||
$loading={loading}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CurrencySelect
|
||||
visible={currency !== undefined}
|
||||
selected={!!currency}
|
||||
hideInput={hideInput}
|
||||
className="open-currency-select-button"
|
||||
@@ -246,27 +269,19 @@ export default function CurrencyInputPanel({
|
||||
{onCurrencySelect && <StyledDropDown selected={!!currency} />}
|
||||
</Aligner>
|
||||
</CurrencySelect>
|
||||
{!hideInput && (
|
||||
<>
|
||||
<NumericalInput
|
||||
className="token-amount-input"
|
||||
value={value}
|
||||
onUserInput={(val) => {
|
||||
onUserInput(val)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</InputRow>
|
||||
{!hideInput && !hideBalance && (
|
||||
{!hideInput && !hideBalance && currency && (
|
||||
<FiatRow>
|
||||
<RowBetween>
|
||||
<LoadingOpacityContainer $loading={loading}>
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
</LoadingOpacityContainer>
|
||||
{account ? (
|
||||
<RowFixed style={{ height: '17px' }}>
|
||||
<TYPE.body
|
||||
<ThemedText.Body
|
||||
onClick={onMax}
|
||||
color={theme.text2}
|
||||
fontWeight={400}
|
||||
color={theme.text3}
|
||||
fontWeight={500}
|
||||
fontSize={14}
|
||||
style={{ display: 'inline', cursor: 'pointer' }}
|
||||
>
|
||||
@@ -274,22 +289,19 @@ export default function CurrencyInputPanel({
|
||||
renderBalance ? (
|
||||
renderBalance(selectedCurrencyBalance)
|
||||
) : (
|
||||
<Trans>
|
||||
Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)} {currency.symbol}
|
||||
</Trans>
|
||||
<Trans>Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)}</Trans>
|
||||
)
|
||||
) : null}
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
{showMaxButton && selectedCurrencyBalance ? (
|
||||
<StyledBalanceMax onClick={onMax}>
|
||||
<Trans>(Max)</Trans>
|
||||
<Trans>MAX</Trans>
|
||||
</StyledBalanceMax>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
</RowBetween>
|
||||
</FiatRow>
|
||||
)}
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
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'
|
||||
|
||||
export const getTokenLogoURL = (address: string) =>
|
||||
`https://raw.githubusercontent.com/uniswap/assets/master/blockchains/ethereum/assets/${address}/logo.png`
|
||||
|
||||
const StyledEthereumLogo = styled.img<{ size: string }>`
|
||||
const StyledLogo = styled(Logo)<{ size: string; native: boolean }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
border-radius: 24px;
|
||||
`
|
||||
|
||||
const StyledLogo = styled(Logo)<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
border-radius: ${({ size }) => size};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
background-color: ${({ theme }) => theme.white};
|
||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||
border-radius: 50%;
|
||||
-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);
|
||||
`
|
||||
|
||||
export default function CurrencyLogo({
|
||||
@@ -30,28 +22,20 @@ export default function CurrencyLogo({
|
||||
style,
|
||||
...rest
|
||||
}: {
|
||||
currency?: Currency
|
||||
currency?: Currency | null
|
||||
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 = currency.chainId === 1 ? [getTokenLogoURL(currency.address)] : []
|
||||
if (currency instanceof WrappedTokenInfo) {
|
||||
return [...uriLocations, ...defaultUrls]
|
||||
}
|
||||
return defaultUrls
|
||||
}
|
||||
return []
|
||||
}, [currency, uriLocations])
|
||||
|
||||
if (currency?.isNative) {
|
||||
return <StyledEthereumLogo src={EthereumLogo} 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,5 +1,6 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
|
||||
const Wrapper = styled.div<{ margin: boolean; sizeraw: number }>`
|
||||
|
||||
82
src/components/DowntimeWarning/index.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
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;
|
||||
color: black;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 14px;
|
||||
margin: 12px auto;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
max-width: 880px;
|
||||
`
|
||||
const WarningIcon = styled(AlertOctagon)`
|
||||
margin: auto 16px auto 0;
|
||||
min-height: 22px;
|
||||
min-width: 22px;
|
||||
`
|
||||
const ReadMoreLink = styled(ExternalLink)`
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
`
|
||||
|
||||
function Wrapper({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<Root>
|
||||
<WarningIcon />
|
||||
<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
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import React, { ErrorInfo } from 'react'
|
||||
import store, { AppState } from '../../state'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
import styled from 'styled-components/macro'
|
||||
import ReactGA from 'react-ga'
|
||||
import { getUserAgent } from '../../utils/getUserAgent'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import store, { AppState } from '../../state'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { userAgent } from '../../utils/userAgent'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { AutoRow } from '../Row'
|
||||
|
||||
const FallbackWrapper = styled.div`
|
||||
@@ -46,6 +47,8 @@ type ErrorBoundaryState = {
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
const IS_UNISWAP = window.location.hostname === 'app.uniswap.org'
|
||||
|
||||
export default class ErrorBoundary extends React.Component<unknown, ErrorBoundaryState> {
|
||||
constructor(props: unknown) {
|
||||
super(props)
|
||||
@@ -66,6 +69,7 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
|
||||
|
||||
render() {
|
||||
const { error } = this.state
|
||||
|
||||
if (error !== null) {
|
||||
const encodedBody = encodeURIComponent(issueBody(error))
|
||||
return (
|
||||
@@ -73,39 +77,41 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
|
||||
<BodyWrapper>
|
||||
<AutoColumn gap={'md'}>
|
||||
<SomethingWentWrongWrapper>
|
||||
<TYPE.label fontSize={24} fontWeight={600}>
|
||||
<ThemedText.Label fontSize={24} fontWeight={600}>
|
||||
<Trans>Something went wrong</Trans>
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</SomethingWentWrongWrapper>
|
||||
<CodeBlockWrapper>
|
||||
<code>
|
||||
<TYPE.main fontSize={10}>{error.stack}</TYPE.main>
|
||||
<ThemedText.Main fontSize={10}>{error.stack}</ThemedText.Main>
|
||||
</code>
|
||||
</CodeBlockWrapper>
|
||||
<AutoRow>
|
||||
<LinkWrapper>
|
||||
<ExternalLink
|
||||
id="create-github-issue-link"
|
||||
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
|
||||
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
|
||||
)}`}
|
||||
target="_blank"
|
||||
>
|
||||
<TYPE.link fontSize={16}>
|
||||
<Trans>Create an issue on GitHub</Trans>
|
||||
<span>↗</span>
|
||||
</TYPE.link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
<LinkWrapper>
|
||||
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
|
||||
<TYPE.link fontSize={16}>
|
||||
<Trans>Get support on Discord</Trans>
|
||||
<span>↗</span>
|
||||
</TYPE.link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
</AutoRow>
|
||||
{IS_UNISWAP ? (
|
||||
<AutoRow>
|
||||
<LinkWrapper>
|
||||
<ExternalLink
|
||||
id="create-github-issue-link"
|
||||
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
|
||||
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
|
||||
)}`}
|
||||
target="_blank"
|
||||
>
|
||||
<ThemedText.Link fontSize={16}>
|
||||
<Trans>Create an issue on GitHub</Trans>
|
||||
<span>↗</span>
|
||||
</ThemedText.Link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
<LinkWrapper>
|
||||
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
|
||||
<ThemedText.Link fontSize={16}>
|
||||
<Trans>Get support on Discord</Trans>
|
||||
<span>↗</span>
|
||||
</ThemedText.Link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
</AutoRow>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
</BodyWrapper>
|
||||
</FallbackWrapper>
|
||||
@@ -120,7 +126,7 @@ function getRelevantState(): null | keyof AppState {
|
||||
if (!path.startsWith('#/')) {
|
||||
return null
|
||||
}
|
||||
const pieces = path.substring(2).split(/[\/\\?]/)
|
||||
const pieces = path.substring(2).split(/[/\\?]/)
|
||||
switch (pieces[0]) {
|
||||
case 'swap':
|
||||
return 'swap'
|
||||
@@ -136,7 +142,7 @@ function getRelevantState(): null | keyof AppState {
|
||||
|
||||
function issueBody(error: Error): string {
|
||||
const relevantState = getRelevantState()
|
||||
const deviceData = getUserAgent()
|
||||
const deviceData = userAgent
|
||||
return `## URL
|
||||
|
||||
${window.location.href}
|
||||
|
||||
51
src/components/FeeSelector/FeeOption.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ButtonRadioChecked } from 'components/Button'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState } from 'hooks/usePools'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
|
||||
import { FEE_AMOUNT_DETAIL } from './shared'
|
||||
|
||||
const ResponsiveText = styled(ThemedText.Label)`
|
||||
line-height: 16px;
|
||||
font-size: 14px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
`};
|
||||
`
|
||||
|
||||
interface FeeOptionProps {
|
||||
feeAmount: FeeAmount
|
||||
active: boolean
|
||||
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
|
||||
poolState: PoolState
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
export function FeeOption({ feeAmount, active, poolState, distributions, onClick }: FeeOptionProps) {
|
||||
return (
|
||||
<ButtonRadioChecked active={active} onClick={onClick}>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="6px">
|
||||
<ResponsiveText>
|
||||
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}%</Trans>
|
||||
</ResponsiveText>
|
||||
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
{FEE_AMOUNT_DETAIL[feeAmount].description}
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge distributions={distributions} feeAmount={feeAmount} poolState={poolState} />
|
||||
)}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
)
|
||||
}
|
||||
31
src/components/FeeSelector/FeeTierPercentageBadge.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState } from 'hooks/usePools'
|
||||
import React from 'react'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
export function FeeTierPercentageBadge({
|
||||
feeAmount,
|
||||
distributions,
|
||||
poolState,
|
||||
}: {
|
||||
feeAmount: FeeAmount
|
||||
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
|
||||
poolState: PoolState
|
||||
}) {
|
||||
return (
|
||||
<Badge>
|
||||
<ThemedText.Label fontSize={10}>
|
||||
{!distributions || poolState === PoolState.NOT_EXISTS || poolState === PoolState.INVALID ? (
|
||||
<Trans>Not created</Trans>
|
||||
) : distributions[feeAmount] !== undefined ? (
|
||||
<Trans>{distributions[feeAmount]?.toFixed(0)}% select</Trans>
|
||||
) : (
|
||||
<Trans>No data</Trans>
|
||||
)}
|
||||
</ThemedText.Label>
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,24 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { DynamicSection } from 'pages/AddLiquidity/styled'
|
||||
import { TYPE } from 'theme'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import Badge from 'components/Badge'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ButtonGray } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
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 { DynamicSection } from 'pages/AddLiquidity/styled'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
import { Box } from 'rebass'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { FeeOption } from './FeeOption'
|
||||
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
|
||||
import { FEE_AMOUNT_DETAIL } from './shared'
|
||||
|
||||
const pulse = (color: string) => keyframes`
|
||||
0% {
|
||||
@@ -28,45 +33,18 @@ const pulse = (color: string) => keyframes`
|
||||
box-shadow: 0 0 0 0 ${color};
|
||||
}
|
||||
`
|
||||
|
||||
const ResponsiveText = styled(TYPE.label)`
|
||||
line-height: 16px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
`};
|
||||
`
|
||||
|
||||
const FocusedOutlineCard = styled(Card)<{ pulsing: boolean }>`
|
||||
border: 1px solid ${({ theme }) => theme.bg2};
|
||||
animation: ${({ pulsing, theme }) => pulsing && pulse(theme.primary1)} 0.6s linear;
|
||||
align-self: center;
|
||||
`
|
||||
|
||||
const FeeAmountLabel = {
|
||||
[FeeAmount.LOW]: {
|
||||
label: '0.05',
|
||||
description: <Trans>Best for stable pairs.</Trans>,
|
||||
},
|
||||
[FeeAmount.MEDIUM]: {
|
||||
label: '0.3',
|
||||
description: <Trans>Best for most pairs.</Trans>,
|
||||
},
|
||||
[FeeAmount.HIGH]: {
|
||||
label: '1',
|
||||
description: <Trans>Best for exotic pairs.</Trans>,
|
||||
},
|
||||
}
|
||||
|
||||
const FeeTierPercentageBadge = ({ percentage }: { percentage: number | undefined }) => {
|
||||
return (
|
||||
<Badge>
|
||||
<TYPE.label fontSize={12}>
|
||||
{percentage !== undefined ? <Trans>{percentage?.toFixed(0)}% select</Trans> : <Trans>Not created</Trans>}
|
||||
</TYPE.label>
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
const Select = styled.div`
|
||||
align-items: flex-start;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-gap: 8px;
|
||||
`
|
||||
|
||||
export default function FeeSelector({
|
||||
disabled = false,
|
||||
@@ -81,8 +59,39 @@ export default function FeeSelector({
|
||||
currencyA?: Currency | undefined
|
||||
currencyB?: Currency | undefined
|
||||
}) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const { isLoading, isError, largestUsageFeeTier, distributions } = useFeeTierDistribution(currencyA, currencyB)
|
||||
|
||||
// get pool data on-chain for latest states
|
||||
const pools = usePools([
|
||||
[currencyA, currencyB, FeeAmount.LOWEST],
|
||||
[currencyA, currencyB, FeeAmount.LOW],
|
||||
[currencyA, currencyB, FeeAmount.MEDIUM],
|
||||
[currencyA, currencyB, FeeAmount.HIGH],
|
||||
])
|
||||
|
||||
const poolsByFeeTier: Record<FeeAmount, PoolState> = useMemo(
|
||||
() =>
|
||||
pools.reduce(
|
||||
(acc, [curPoolState, curPool]) => {
|
||||
acc = {
|
||||
...acc,
|
||||
...{ [curPool?.fee as FeeAmount]: curPoolState },
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{
|
||||
// default all states to NOT_EXISTS
|
||||
[FeeAmount.LOWEST]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.LOW]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.MEDIUM]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.HIGH]: PoolState.NOT_EXISTS,
|
||||
}
|
||||
),
|
||||
[pools]
|
||||
)
|
||||
|
||||
const [showOptions, setShowOptions] = useState(false)
|
||||
const [pulsing, setPulsing] = useState(false)
|
||||
|
||||
@@ -91,7 +100,7 @@ export default function FeeSelector({
|
||||
const recommended = useRef(false)
|
||||
|
||||
const handleFeePoolSelectWithEvent = useCallback(
|
||||
(fee) => {
|
||||
(fee: FeeAmount) => {
|
||||
ReactGA.event({
|
||||
category: 'FeePoolSelect',
|
||||
action: 'Manual',
|
||||
@@ -140,20 +149,26 @@ export default function FeeSelector({
|
||||
<AutoColumn id="add-liquidity-selected-fee">
|
||||
{!feeAmount ? (
|
||||
<>
|
||||
<TYPE.label>
|
||||
<ThemedText.Label>
|
||||
<Trans>Fee tier</Trans>
|
||||
</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
</ThemedText.Label>
|
||||
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>The % you will earn in fees.</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TYPE.label className="selected-fee-label">
|
||||
<Trans>{FeeAmountLabel[feeAmount].label}% fee tier</Trans>
|
||||
</TYPE.label>
|
||||
<ThemedText.Label className="selected-fee-label">
|
||||
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}% fee tier</Trans>
|
||||
</ThemedText.Label>
|
||||
<Box style={{ width: 'fit-content', marginTop: '8px' }} className="selected-fee-percentage">
|
||||
{distributions && feeAmount && <FeeTierPercentageBadge percentage={distributions[feeAmount]} />}
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge
|
||||
distributions={distributions}
|
||||
feeAmount={feeAmount}
|
||||
poolState={poolsByFeeTier[feeAmount]}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
@@ -165,63 +180,25 @@ export default function FeeSelector({
|
||||
</RowBetween>
|
||||
</FocusedOutlineCard>
|
||||
|
||||
{showOptions && (
|
||||
<RowBetween>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.LOW}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.LOW)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="6px">
|
||||
<ResponsiveText>
|
||||
<Trans>0.05% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for stable pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && <FeeTierPercentageBadge percentage={distributions[FeeAmount.LOW]} />}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.MEDIUM}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.MEDIUM)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="4px">
|
||||
<ResponsiveText>
|
||||
<Trans>0.3% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for most pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && <FeeTierPercentageBadge percentage={distributions[FeeAmount.MEDIUM]} />}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.HIGH}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.HIGH)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="4px">
|
||||
<ResponsiveText>
|
||||
<Trans>1% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for exotic pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && <FeeTierPercentageBadge percentage={distributions[FeeAmount.HIGH]} />}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
</RowBetween>
|
||||
{chainId && showOptions && (
|
||||
<Select>
|
||||
{[FeeAmount.LOWEST, FeeAmount.LOW, FeeAmount.MEDIUM, FeeAmount.HIGH].map((_feeAmount, i) => {
|
||||
const { supportedChains } = FEE_AMOUNT_DETAIL[_feeAmount]
|
||||
if (supportedChains.includes(chainId)) {
|
||||
return (
|
||||
<FeeOption
|
||||
feeAmount={_feeAmount}
|
||||
active={feeAmount === _feeAmount}
|
||||
onClick={() => handleFeePoolSelectWithEvent(_feeAmount)}
|
||||
distributions={distributions}
|
||||
poolState={poolsByFeeTier[_feeAmount]}
|
||||
key={i}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})}
|
||||
</Select>
|
||||
)}
|
||||
</DynamicSection>
|
||||
</AutoColumn>
|
||||
|
||||
30
src/components/FeeSelector/shared.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export const FEE_AMOUNT_DETAIL: Record<
|
||||
FeeAmount,
|
||||
{ label: string; description: ReactNode; supportedChains: SupportedChainId[] }
|
||||
> = {
|
||||
[FeeAmount.LOWEST]: {
|
||||
label: '0.01',
|
||||
description: <Trans>Best for very stable pairs.</Trans>,
|
||||
supportedChains: [SupportedChainId.MAINNET],
|
||||
},
|
||||
[FeeAmount.LOW]: {
|
||||
label: '0.05',
|
||||
description: <Trans>Best for stable pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
[FeeAmount.MEDIUM]: {
|
||||
label: '0.3',
|
||||
description: <Trans>Best for most pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
[FeeAmount.HIGH]: {
|
||||
label: '1',
|
||||
description: <Trans>Best for exotic pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import JSBI from 'jsbi'
|
||||
import { Currency, CurrencyAmount, Fraction } from '@uniswap/sdk-core'
|
||||
import JSBI from 'jsbi'
|
||||
|
||||
const CURRENCY_AMOUNT_MIN = new Fraction(JSBI.BigInt(1), JSBI.BigInt(1000000))
|
||||
|
||||
|
||||
77
src/components/Header/ChainConnectivityWarning.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
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'
|
||||
|
||||
const BodyRow = styled.div`
|
||||
color: ${({ theme }) => theme.black};
|
||||
font-size: 12px;
|
||||
`
|
||||
const CautionIcon = styled(AlertOctagon)`
|
||||
color: ${({ theme }) => theme.black};
|
||||
`
|
||||
const Link = styled(ExternalLink)`
|
||||
color: ${({ theme }) => theme.black};
|
||||
text-decoration: underline;
|
||||
`
|
||||
const TitleRow = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 8px;
|
||||
`
|
||||
const TitleText = styled.div`
|
||||
color: black;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
margin: 0px 12px;
|
||||
`
|
||||
const Wrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.yellow3};
|
||||
border-radius: 12px;
|
||||
bottom: 60px;
|
||||
display: none;
|
||||
max-width: 348px;
|
||||
padding: 16px 20px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
|
||||
export function ChainConnectivityWarning() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const info = CHAIN_INFO[chainId ?? SupportedChainId.MAINNET]
|
||||
const label = info?.label
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<TitleRow>
|
||||
<CautionIcon />
|
||||
<TitleText>
|
||||
<Trans>Network Warning</Trans>
|
||||
</TitleText>
|
||||
</TitleRow>
|
||||
<BodyRow>
|
||||
{chainId === SupportedChainId.MAINNET ? (
|
||||
<Trans>You may have lost your network connection.</Trans>
|
||||
) : (
|
||||
<Trans>You may have lost your network connection, or {label} might be down right now.</Trans>
|
||||
)}{' '}
|
||||
{(info as L2ChainInfo).statusPage !== undefined && (
|
||||
<span>
|
||||
<Trans>Check network status</Trans>{' '}
|
||||
<Link href={(info as L2ChainInfo).statusPage || ''}>
|
||||
<Trans>here.</Trans>
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
</BodyRow>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
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,234 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { YellowCard } from 'components/Card'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { ArrowDownCircle, ChevronDown, ToggleLeft } from 'react-feather'
|
||||
import { ApplicationModal } from 'state/application/actions'
|
||||
import { useModalOpen, useToggleModal } from 'state/application/hooks'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import { ExternalLink } from 'theme'
|
||||
import { switchToNetwork } from 'utils/switchToNetwork'
|
||||
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from '../../constants/chains'
|
||||
|
||||
const BaseWrapper = css`
|
||||
position: relative;
|
||||
margin-right: 8px;
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
justify-self: end;
|
||||
`};
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
margin: 0 0.5rem 0 0;
|
||||
width: initial;
|
||||
text-overflow: ellipsis;
|
||||
flex-shrink: 1;
|
||||
`};
|
||||
`
|
||||
const L2Wrapper = styled.div`
|
||||
${BaseWrapper}
|
||||
`
|
||||
const BaseMenuItem = css`
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border-radius: 12px;
|
||||
color: ${({ theme }) => theme.text2};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
justify-content: space-between;
|
||||
:hover {
|
||||
color: ${({ theme }) => theme.text1};
|
||||
text-decoration: none;
|
||||
}
|
||||
`
|
||||
const DisabledMenuItem = styled.div`
|
||||
${BaseMenuItem}
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
cursor: auto;
|
||||
display: flex;
|
||||
font-size: 10px;
|
||||
font-style: italic;
|
||||
justify-content: center;
|
||||
:hover,
|
||||
:active,
|
||||
:focus {
|
||||
color: ${({ theme }) => theme.text2};
|
||||
}
|
||||
`
|
||||
const FallbackWrapper = styled(YellowCard)`
|
||||
${BaseWrapper}
|
||||
width: auto;
|
||||
border-radius: 12px;
|
||||
padding: 8px 12px;
|
||||
width: 100%;
|
||||
`
|
||||
const Icon = styled.img`
|
||||
width: 16px;
|
||||
margin-right: 2px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
margin-right: 4px;
|
||||
|
||||
`};
|
||||
`
|
||||
|
||||
const MenuFlyout = styled.span`
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
border: 1px solid ${({ 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),
|
||||
0px 24px 32px rgba(0, 0, 0, 0.01);
|
||||
border-radius: 12px;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1rem;
|
||||
position: absolute;
|
||||
left: 0rem;
|
||||
top: 3rem;
|
||||
z-index: 100;
|
||||
width: 237px;
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
|
||||
bottom: unset;
|
||||
top: 4.5em
|
||||
right: 0;
|
||||
|
||||
`};
|
||||
> {
|
||||
padding: 12px;
|
||||
}
|
||||
> :not(:first-child) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
> :not(:last-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
transform: rotate(230deg);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.6;
|
||||
`
|
||||
const MenuItem = styled(ExternalLink)`
|
||||
${BaseMenuItem}
|
||||
`
|
||||
const ButtonMenuItem = styled.button`
|
||||
${BaseMenuItem}
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
color: ${({ theme }) => theme.text2};
|
||||
outline: none;
|
||||
padding: 0;
|
||||
`
|
||||
const NetworkInfo = styled.button<{ chainId: SupportedChainId }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
border-radius: 12px;
|
||||
border: 1px solid ${({ theme }) => theme.bg0};
|
||||
color: ${({ theme }) => theme.text1};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
height: 38px;
|
||||
padding: 0.7rem;
|
||||
|
||||
:hover,
|
||||
:focus {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
border: 1px solid ${({ theme }) => theme.bg3};
|
||||
}
|
||||
`
|
||||
const NetworkName = styled.div<{ chainId: SupportedChainId }>`
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
padding: 0 2px 0.5px 4px;
|
||||
margin: 0 2px;
|
||||
white-space: pre;
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
display: none;
|
||||
`};
|
||||
`
|
||||
|
||||
export default function NetworkCard() {
|
||||
const { chainId, library } = useActiveWeb3React()
|
||||
const node = useRef<HTMLDivElement>(null)
|
||||
const open = useModalOpen(ApplicationModal.ARBITRUM_OPTIONS)
|
||||
const toggle = useToggleModal(ApplicationModal.ARBITRUM_OPTIONS)
|
||||
useOnClickOutside(node, open ? toggle : undefined)
|
||||
|
||||
const [implements3085, setImplements3085] = useState(false)
|
||||
useEffect(() => {
|
||||
// metamask is currently the only known implementer of this EIP
|
||||
// here we proceed w/ a noop feature check to ensure the user's version of metamask supports network switching
|
||||
// if not, we hide the UI
|
||||
if (!library?.provider?.request || !chainId || !library?.provider?.isMetaMask) {
|
||||
return
|
||||
}
|
||||
switchToNetwork({ library, chainId })
|
||||
.then((x) => x ?? setImplements3085(true))
|
||||
.catch(() => setImplements3085(false))
|
||||
}, [library, chainId])
|
||||
|
||||
const info = chainId ? CHAIN_INFO[chainId] : undefined
|
||||
if (!chainId || chainId === SupportedChainId.MAINNET || !info || !library) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (L2_CHAIN_IDS.includes(chainId)) {
|
||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
||||
const isArbitrum = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.ARBITRUM_RINKEBY].includes(chainId)
|
||||
return (
|
||||
<L2Wrapper ref={node}>
|
||||
<NetworkInfo onClick={toggle} chainId={chainId}>
|
||||
<Icon src={info.logoUrl} />
|
||||
<NetworkName chainId={chainId}>{info.label}</NetworkName>
|
||||
<ChevronDown size={16} style={{ marginTop: '2px' }} strokeWidth={2.5} />
|
||||
</NetworkInfo>
|
||||
{open && (
|
||||
<MenuFlyout>
|
||||
<MenuItem href={info.bridge}>
|
||||
<div>{isArbitrum ? <Trans>{info.label} Bridge</Trans> : <Trans>Optimistic L2 Gateway</Trans>}</div>
|
||||
<LinkOutCircle />
|
||||
</MenuItem>
|
||||
<MenuItem href={info.explorer}>
|
||||
{isArbitrum ? <Trans>{info.label} Explorer</Trans> : <Trans>Optimistic Etherscan</Trans>}
|
||||
<LinkOutCircle />
|
||||
</MenuItem>
|
||||
<MenuItem href={info.docs}>
|
||||
<div>
|
||||
<Trans>Learn more</Trans>
|
||||
</div>
|
||||
<LinkOutCircle />
|
||||
</MenuItem>
|
||||
{implements3085 ? (
|
||||
<ButtonMenuItem onClick={() => switchToNetwork({ library, chainId: SupportedChainId.MAINNET })}>
|
||||
<div>
|
||||
<Trans>Switch to L1 (Mainnet)</Trans>
|
||||
</div>
|
||||
<ToggleLeft opacity={0.6} size={16} />
|
||||
</ButtonMenuItem>
|
||||
) : (
|
||||
<DisabledMenuItem>
|
||||
<Trans>Change your network to go back to L1</Trans>
|
||||
</DisabledMenuItem>
|
||||
)}
|
||||
</MenuFlyout>
|
||||
)}
|
||||
</L2Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
return <FallbackWrapper title={info.label}>{info.label}</FallbackWrapper>
|
||||
}
|
||||
327
src/components/Header/NetworkSelector.tsx
Normal file
@@ -0,0 +1,327 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
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 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 { addPopup, ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { replaceURLParam } from 'utils/routes'
|
||||
|
||||
import { useAppDispatch } from '../../state/hooks'
|
||||
import { switchToNetwork } from '../../utils/switchToNetwork'
|
||||
|
||||
const ActiveRowLinkList = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 8px;
|
||||
& > a {
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.text2};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
& > a:first-child {
|
||||
margin: 0;
|
||||
margin-top: 0px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
`
|
||||
const ActiveRowWrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
`
|
||||
const FlyoutHeader = styled.div`
|
||||
color: ${({ theme }) => theme.text2};
|
||||
font-weight: 400;
|
||||
`
|
||||
const FlyoutMenu = 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),
|
||||
0px 24px 32px rgba(0, 0, 0, 0.01);
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
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;
|
||||
background-color: ${({ active, theme }) => (active ? theme.bg1 : 'transparent')};
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
justify-content: space-between;
|
||||
padding: 6px 8px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
`
|
||||
const FlyoutRowActiveIndicator = styled.div`
|
||||
background-color: ${({ theme }) => theme.green1};
|
||||
border-radius: 50%;
|
||||
height: 9px;
|
||||
width: 9px;
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
transform: rotate(230deg);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
`
|
||||
const Logo = styled.img`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 8px;
|
||||
`
|
||||
const NetworkLabel = styled.div`
|
||||
flex: 1 1 auto;
|
||||
`
|
||||
const SelectorLabel = styled(NetworkLabel)`
|
||||
display: none;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
display: block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
`
|
||||
const SelectorControls = styled.div<{ interactive: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
border: 2px solid ${({ theme }) => theme.bg0};
|
||||
border-radius: 16px;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
justify-content: space-between;
|
||||
padding: 6px 8px;
|
||||
`
|
||||
const SelectorLogo = styled(Logo)<{ interactive?: boolean }>`
|
||||
margin-right: ${({ interactive }) => (interactive ? 8 : 0)}px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
`
|
||||
const SelectorWrapper = styled.div`
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
position: relative;
|
||||
}
|
||||
`
|
||||
const StyledChevronDown = styled(ChevronDown)`
|
||||
width: 16px;
|
||||
`
|
||||
const BridgeLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
return <Trans>Arbitrum Bridge</Trans>
|
||||
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 ExplorerLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||
switch (chainId) {
|
||||
case SupportedChainId.ARBITRUM_ONE:
|
||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||
return <Trans>Arbiscan</Trans>
|
||||
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>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 history = useHistory()
|
||||
|
||||
const info = chainId ? CHAIN_INFO[chainId] : undefined
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
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)
|
||||
}
|
||||
}, [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
|
||||
}
|
||||
|
||||
return (
|
||||
<SelectorWrapper ref={node as any}>
|
||||
<SelectorControls onClick={toggle} interactive>
|
||||
<SelectorLogo interactive src={info.logoUrl} />
|
||||
<SelectorLabel>{info.label}</SelectorLabel>
|
||||
<StyledChevronDown />
|
||||
</SelectorControls>
|
||||
{open && (
|
||||
<FlyoutMenu onMouseLeave={toggle}>
|
||||
<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} />
|
||||
</FlyoutMenu>
|
||||
)}
|
||||
</SelectorWrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,40 +1,71 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { RowFixed } from 'components/Row'
|
||||
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 JSBI from 'jsbi'
|
||||
import useBlockNumber from 'lib/hooks/useBlockNumber'
|
||||
import ms from 'ms.macro'
|
||||
import { useEffect, useState } from 'react'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||
|
||||
import { useBlockNumber } from '../../state/application/hooks'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
import { ChainConnectivityWarning } from './ChainConnectivityWarning'
|
||||
|
||||
const StyledPolling = styled.div`
|
||||
const StyledPolling = styled.div<{ warning: boolean }>`
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 1rem;
|
||||
color: ${({ theme }) => theme.green1};
|
||||
color: ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
|
||||
transition: 250ms ease color;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
display: none;
|
||||
`}
|
||||
`
|
||||
const StyledPollingNumber = styled(TYPE.small)<{ breathe: boolean; hovering: boolean }>`
|
||||
const StyledPollingNumber = styled(ThemedText.Small)<{ breathe: boolean; hovering: boolean }>`
|
||||
transition: opacity 0.25s ease;
|
||||
opacity: ${({ breathe, hovering }) => (hovering ? 0.7 : breathe ? 1 : 0.5)};
|
||||
:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
color: unset;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
color: unset;
|
||||
}
|
||||
`
|
||||
const StyledPollingDot = styled.div`
|
||||
const StyledPollingDot = styled.div<{ warning: boolean }>`
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
min-height: 8px;
|
||||
min-width: 8px;
|
||||
margin-left: 0.5rem;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
background-color: ${({ theme }) => theme.green1};
|
||||
background-color: ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
|
||||
transition: 250ms ease background-color;
|
||||
`
|
||||
|
||||
const StyledGasDot = styled.div`
|
||||
background-color: ${({ theme }) => theme.text3};
|
||||
border-radius: 50%;
|
||||
height: 4px;
|
||||
min-height: 4px;
|
||||
min-width: 4px;
|
||||
position: relative;
|
||||
transition: 250ms ease background-color;
|
||||
width: 4px;
|
||||
`
|
||||
|
||||
const rotate360 = keyframes`
|
||||
@@ -46,31 +77,44 @@ const rotate360 = keyframes`
|
||||
}
|
||||
`
|
||||
|
||||
const Spinner = styled.div`
|
||||
const Spinner = styled.div<{ warning: boolean }>`
|
||||
animation: ${rotate360} 1s cubic-bezier(0.83, 0, 0.17, 1) infinite;
|
||||
transform: translateZ(0);
|
||||
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-left: 2px solid ${({ theme }) => theme.green1};
|
||||
border-left: 2px solid ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
|
||||
background: transparent;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
transition: 250ms ease border-color;
|
||||
|
||||
left: -3px;
|
||||
top: -3px;
|
||||
`
|
||||
|
||||
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
|
||||
const NETWORK_HEALTH_CHECK_MS = ms`10s`
|
||||
|
||||
export default function Polling() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const blockNumber = useBlockNumber()
|
||||
|
||||
const [isMounting, setIsMounting] = useState(false)
|
||||
const [isHover, setIsHover] = useState(false)
|
||||
const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
|
||||
const blockTime = useCurrentBlockTimestamp()
|
||||
const theme = useTheme()
|
||||
|
||||
const ethGasPrice = useGasPrice()
|
||||
const priceGwei = ethGasPrice ? JSBI.divide(ethGasPrice, JSBI.BigInt(1000000000)) : undefined
|
||||
|
||||
const waitMsBeforeWarning =
|
||||
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
|
||||
|
||||
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
@@ -90,16 +134,48 @@ export default function Polling() {
|
||||
//if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
|
||||
)
|
||||
|
||||
//TODO - chainlink gas oracle is really slow. Can we get a better data source?
|
||||
|
||||
return (
|
||||
<ExternalLink
|
||||
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
|
||||
>
|
||||
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
|
||||
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
|
||||
{blockNumber}
|
||||
</StyledPollingNumber>
|
||||
<StyledPollingDot>{isMounting && <Spinner />}</StyledPollingDot>
|
||||
</StyledPolling>
|
||||
</ExternalLink>
|
||||
<>
|
||||
<RowFixed>
|
||||
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} warning={warning}>
|
||||
<ExternalLink href={'https://etherscan.io/gastracker'}>
|
||||
{priceGwei ? (
|
||||
<RowFixed style={{ marginRight: '8px' }}>
|
||||
<ThemedText.Main fontSize="11px" mr="8px" color={theme.text3}>
|
||||
<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.
|
||||
</Trans>
|
||||
}
|
||||
>
|
||||
{priceGwei.toString()} <Trans>gwei</Trans>
|
||||
</MouseoverTooltip>
|
||||
</ThemedText.Main>
|
||||
<StyledGasDot />
|
||||
</RowFixed>
|
||||
) : null}
|
||||
</ExternalLink>
|
||||
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
|
||||
<ExternalLink
|
||||
href={
|
||||
chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''
|
||||
}
|
||||
>
|
||||
<MouseoverTooltip
|
||||
text={<Trans>The most recent block number on this network. Prices update on every block.</Trans>}
|
||||
>
|
||||
{blockNumber} 
|
||||
</MouseoverTooltip>
|
||||
</ExternalLink>
|
||||
</StyledPollingNumber>
|
||||
<StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
|
||||
</StyledPolling>
|
||||
{warning && <ChainConnectivityWarning />}
|
||||
</RowFixed>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,143 +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, TYPE, 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>
|
||||
<TYPE.white color="white">
|
||||
<Trans>Your UNI Breakdown</Trans>
|
||||
</TYPE.white>
|
||||
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
|
||||
</RowBetween>
|
||||
</CardSection>
|
||||
<Break />
|
||||
{account && (
|
||||
<>
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md" justify="center">
|
||||
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
|
||||
<TYPE.white fontSize={48} fontWeight={600} color="white">
|
||||
{total?.toFixed(2, { groupSeparator: ',' })}
|
||||
</TYPE.white>
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<Trans>Balance:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</TYPE.white>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<Trans>Unclaimed:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">
|
||||
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
|
||||
{uniToClaim && uniToClaim.greaterThan('0') && (
|
||||
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
|
||||
<Trans>(claim)</Trans>
|
||||
</StyledInternalLink>
|
||||
)}
|
||||
</TYPE.white>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
<Break />
|
||||
</>
|
||||
)}
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<Trans>UNI price:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">${uniPrice?.toFixed(2) ?? '-'}</TYPE.white>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<Trans>UNI in circulation:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<Trans>Total Supply</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
|
||||
</RowBetween>
|
||||
{uni && uni.chainId === 1 ? (
|
||||
<ExternalLink href={`${infoLink}/token/${uni.address}`}>
|
||||
<Trans>View UNI Analytics</Trans>
|
||||
</ExternalLink>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
</ModalUpper>
|
||||
</ContentWrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,29 +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 Logo from '../../assets/svg/logo.svg'
|
||||
import LogoDark from '../../assets/svg/logo_white.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
|
||||
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
||||
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 NetworkCard from './NetworkCard'
|
||||
import UniBalanceContent from './UniBalanceContent'
|
||||
import HolidayOrnament from './HolidayOrnament'
|
||||
import NetworkSelector from './NetworkSelector'
|
||||
|
||||
const HeaderFrame = styled.div<{ showBackground: boolean }>`
|
||||
display: grid;
|
||||
@@ -72,6 +72,10 @@ const HeaderElement = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
/* addresses safari's lack of support for "gap" */
|
||||
& > *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
@@ -86,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;
|
||||
@@ -118,11 +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%;
|
||||
cursor: pointer;
|
||||
height: 40px;
|
||||
|
||||
:focus {
|
||||
border: 1px solid blue;
|
||||
@@ -177,6 +181,8 @@ const UniIcon = styled.div`
|
||||
:hover {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const activeClassName = 'ACTIVE'
|
||||
@@ -198,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,
|
||||
@@ -227,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};
|
||||
}
|
||||
@@ -242,8 +248,9 @@ 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()
|
||||
|
||||
const toggleClaimModal = useToggleSelfClaimModal()
|
||||
|
||||
@@ -251,21 +258,24 @@ 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,
|
||||
addNetworkInfo: {
|
||||
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>
|
||||
<img width={'24px'} src={darkMode ? LogoDark : Logo} alt="logo" />
|
||||
<Logo fill={darkMode ? white : black} width="24px" height="100%" title="logo" />
|
||||
<HolidayOrnament />
|
||||
</UniIcon>
|
||||
</Title>
|
||||
<HeaderLinks>
|
||||
@@ -285,24 +295,26 @@ export default function Header() {
|
||||
>
|
||||
<Trans>Pool</Trans>
|
||||
</StyledNavLink>
|
||||
{chainId && chainId === SupportedChainId.MAINNET && (
|
||||
<StyledNavLink id={`stake-nav-link`} to={'/vote'}>
|
||||
{(!chainId || chainId === SupportedChainId.MAINNET) && (
|
||||
<StyledNavLink id={`vote-nav-link`} to={'/vote'}>
|
||||
<Trans>Vote</Trans>
|
||||
</StyledNavLink>
|
||||
)}
|
||||
<StyledExternalLink id={`stake-nav-link`} href={infoLink}>
|
||||
<StyledExternalLink id={`charts-nav-link`} href={infoLink}>
|
||||
<Trans>Charts</Trans>
|
||||
<sup>↗</sup>
|
||||
</StyledExternalLink>
|
||||
</HeaderLinks>
|
||||
|
||||
<HeaderControls>
|
||||
<NetworkCard />
|
||||
<HeaderElement>
|
||||
<NetworkSelector />
|
||||
</HeaderElement>
|
||||
<HeaderElement>
|
||||
{availableClaim && !showClaimPopup && (
|
||||
<UNIWrapper onClick={toggleClaimModal}>
|
||||
<UNIAmount active={!!account && !availableClaim} style={{ pointerEvents: 'auto' }}>
|
||||
<TYPE.white padding="0 2px">
|
||||
<ThemedText.White padding="0 2px">
|
||||
{claimTxn && !claimTxn?.receipt ? (
|
||||
<Dots>
|
||||
<Trans>Claiming UNI</Trans>
|
||||
@@ -310,19 +322,23 @@ export default function Header() {
|
||||
) : (
|
||||
<Trans>Claim UNI</Trans>
|
||||
)}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</UNIAmount>
|
||||
<CardNoise />
|
||||
</UNIWrapper>
|
||||
)}
|
||||
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
|
||||
<AccountElement active={!!account}>
|
||||
{account && userEthBalance ? (
|
||||
<BalanceText style={{ flexShrink: 0 }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||
<Trans>{userEthBalance?.toSignificant(3)} ETH</Trans>
|
||||
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||
<Trans>
|
||||
{userEthBalance?.toSignificant(3)} {nativeCurrencySymbol}
|
||||
</Trans>
|
||||
</BalanceText>
|
||||
) : null}
|
||||
<Web3Status />
|
||||
</AccountElement>
|
||||
</HeaderElement>
|
||||
<HeaderElement>
|
||||
<Menu />
|
||||
</HeaderElement>
|
||||
</HeaderControls>
|
||||
|
||||
@@ -2,9 +2,15 @@ import Tooltip from 'components/Tooltip'
|
||||
import { useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const TextWrapper = styled.span<{ margin: boolean; link?: boolean; fontSize?: string; adjustSize?: boolean }>`
|
||||
const TextWrapper = styled.span<{
|
||||
margin: boolean
|
||||
link?: boolean
|
||||
fontSize?: string
|
||||
adjustSize?: boolean
|
||||
textColor?: string
|
||||
}>`
|
||||
margin-left: ${({ margin }) => margin && '4px'};
|
||||
color: ${({ theme, link }) => (link ? theme.blue1 : theme.text1)};
|
||||
color: ${({ theme, link, textColor }) => (link ? theme.blue1 : textColor ?? theme.text1)};
|
||||
font-size: ${({ fontSize }) => fontSize ?? 'inherit'};
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
@@ -18,6 +24,7 @@ const HoverInlineText = ({
|
||||
margin = false,
|
||||
adjustSize = false,
|
||||
fontSize,
|
||||
textColor,
|
||||
link,
|
||||
...rest
|
||||
}: {
|
||||
@@ -26,6 +33,7 @@ const HoverInlineText = ({
|
||||
margin?: boolean
|
||||
adjustSize?: boolean
|
||||
fontSize?: string
|
||||
textColor?: string
|
||||
link?: boolean
|
||||
}) => {
|
||||
const [showHover, setShowHover] = useState(false)
|
||||
@@ -42,6 +50,7 @@ const HoverInlineText = ({
|
||||
onMouseLeave={() => setShowHover(false)}
|
||||
margin={margin}
|
||||
adjustSize={adjustSize}
|
||||
textColor={textColor}
|
||||
link={link}
|
||||
fontSize={fontSize}
|
||||
{...rest}
|
||||
@@ -53,7 +62,14 @@ const HoverInlineText = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<TextWrapper margin={margin} adjustSize={adjustSize} link={link} fontSize={fontSize} {...rest}>
|
||||
<TextWrapper
|
||||
margin={margin}
|
||||
adjustSize={adjustSize}
|
||||
link={link}
|
||||
fontSize={fontSize}
|
||||
textColor={textColor}
|
||||
{...rest}
|
||||
>
|
||||
{text}
|
||||
</TextWrapper>
|
||||
)
|
||||
|
||||
26
src/components/Identicon/StatusIcon.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { Connector } from 'widgets-web3-react/types'
|
||||
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||
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 | Connector }) {
|
||||
switch (connector) {
|
||||
case injected:
|
||||
return <Identicon />
|
||||
case walletconnect:
|
||||
return <img src={WalletConnectIcon} alt={'WalletConnect'} />
|
||||
case walletlink:
|
||||
return <img src={CoinbaseWalletIcon} alt={'Coinbase Wallet'} />
|
||||
case fortmatic:
|
||||
return <img src={FortmaticIcon} alt={'Fortmatic'} />
|
||||
case portis:
|
||||
return <img src={PortisIcon} alt={'Portis'} />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,52 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
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'
|
||||
import Jazzicon from '@metamask/jazzicon'
|
||||
|
||||
const StyledIdenticonContainer = styled.div`
|
||||
const StyledIdenticon = styled.div`
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: 1.125rem;
|
||||
background-color: ${({ theme }) => theme.bg4};
|
||||
font-size: initial;
|
||||
`
|
||||
|
||||
const StyledAvatar = styled.img`
|
||||
height: inherit;
|
||||
width: inherit;
|
||||
border-radius: inherit;
|
||||
`
|
||||
|
||||
export default function Identicon() {
|
||||
const ref = useRef<HTMLDivElement>()
|
||||
|
||||
const { account } = useActiveWeb3React()
|
||||
const { avatar } = useENSAvatar(account ?? undefined)
|
||||
const [fetchable, setFetchable] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (account && ref.current) {
|
||||
ref.current.innerHTML = ''
|
||||
ref.current.appendChild(Jazzicon(16, parseInt(account.slice(2, 10), 16)))
|
||||
const icon = useMemo(() => account && jazzicon(16, parseInt(account.slice(2, 10), 16)), [account])
|
||||
const iconRef = useRef<HTMLDivElement>(null)
|
||||
useLayoutEffect(() => {
|
||||
const current = iconRef.current
|
||||
if (icon) {
|
||||
current?.appendChild(icon)
|
||||
return () => {
|
||||
try {
|
||||
current?.removeChild(icon)
|
||||
} catch (e) {
|
||||
console.error('Avatar icon not found')
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [account])
|
||||
return
|
||||
}, [icon, iconRef])
|
||||
|
||||
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
|
||||
return <StyledIdenticonContainer ref={ref as any} />
|
||||
return (
|
||||
<StyledIdenticon>
|
||||
{avatar && fetchable ? (
|
||||
<StyledAvatar alt="avatar" src={avatar} onError={() => setFetchable(false)}></StyledAvatar>
|
||||
) : (
|
||||
<span ref={iconRef} />
|
||||
)}
|
||||
</StyledIdenticon>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { useState, useCallback, useEffect, ReactNode } from 'react'
|
||||
import { OutlineCard } from 'components/Card'
|
||||
import { Input as NumericalInput } from '../NumericalInput'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { ButtonGray } from 'components/Button'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Plus, Minus } from 'react-feather'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ButtonGray } from 'components/Button'
|
||||
import { OutlineCard } from 'components/Card'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { Minus, Plus } from 'react-feather'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { Input as NumericalInput } from '../NumericalInput'
|
||||
|
||||
const pulse = (color: string) => keyframes`
|
||||
0% {
|
||||
@@ -56,13 +57,13 @@ const StyledInput = styled(NumericalInput)<{ usePercent?: boolean }>`
|
||||
`};
|
||||
`
|
||||
|
||||
const InputTitle = styled(TYPE.small)`
|
||||
const InputTitle = styled(ThemedText.Small)`
|
||||
color: ${({ theme }) => theme.text2};
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
`
|
||||
|
||||
const ButtonLabel = styled(TYPE.white)<{ disabled: boolean }>`
|
||||
const ButtonLabel = styled(ThemedText.White)<{ disabled: boolean }>`
|
||||
color: ${({ theme, disabled }) => (disabled ? theme.text2 : theme.text1)} !important;
|
||||
`
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { area, curveStepAfter, ScaleLinear } from 'd3'
|
||||
import React, { useMemo } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ChartEntry } from './types'
|
||||
import inRange from 'lodash/inRange'
|
||||
|
||||
const Path = styled.path<{ fill: string | undefined }>`
|
||||
opacity: 0.5;
|
||||
@@ -35,7 +35,10 @@ export const Area = ({
|
||||
.x((d: unknown) => xScale(xValue(d as ChartEntry)))
|
||||
.y1((d: unknown) => yScale(yValue(d as ChartEntry)))
|
||||
.y0(yScale(0))(
|
||||
series.filter((d) => inRange(xScale(xValue(d)), 0, innerWidth)) as Iterable<[number, number]>
|
||||
series.filter((d) => {
|
||||
const value = xScale(xValue(d))
|
||||
return value > 0 && value <= window.innerWidth
|
||||
}) as Iterable<[number, number]>
|
||||
) ?? undefined
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Axis as d3Axis, axisBottom, NumberValue, ScaleLinear, select } from 'd3'
|
||||
import React, { useMemo } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const StyledGroup = styled.g`
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { BrushBehavior, brushX, D3BrushEvent, ScaleLinear, select } from 'd3'
|
||||
import styled from 'styled-components/macro'
|
||||
import { brushHandleAccentPath, brushHandlePath, OffScreenHandle } from 'components/LiquidityChartRangeInput/svg'
|
||||
import { BrushBehavior, brushX, D3BrushEvent, ScaleLinear, select } from 'd3'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const Handle = styled.path<{ color: string }>`
|
||||
cursor: ew-resize;
|
||||
@@ -43,8 +43,16 @@ const FLIP_HANDLE_THRESHOLD_PX = 20
|
||||
// margin to prevent tick snapping from putting the brush off screen
|
||||
const BRUSH_EXTENT_MARGIN_PX = 2
|
||||
|
||||
const compare = (a1: [number, number], a2: [number, number], xScale: ScaleLinear<number, number>): boolean =>
|
||||
xScale(a1[0]) !== xScale(a2[0]) || xScale(a1[1]) !== xScale(a2[1])
|
||||
/**
|
||||
* Returns true if every element in `a` maps to the
|
||||
* same pixel coordinate as elements in `b`
|
||||
*/
|
||||
const compare = (a: [number, number], b: [number, number], xScale: ScaleLinear<number, number>): boolean => {
|
||||
// normalize pixels to 1 decimals
|
||||
const aNorm = a.map((x) => xScale(x).toFixed(1))
|
||||
const bNorm = b.map((x) => xScale(x).toFixed(1))
|
||||
return aNorm.every((v, i) => v === bNorm[i])
|
||||
}
|
||||
|
||||
export const Brush = ({
|
||||
id,
|
||||
@@ -91,7 +99,7 @@ export const Brush = ({
|
||||
const scaled = (selection as [number, number]).map(xScale.invert) as [number, number]
|
||||
|
||||
// avoid infinite render loop by checking for change
|
||||
if (type === 'end' && compare(brushExtent, scaled, xScale)) {
|
||||
if (type === 'end' && !compare(brushExtent, scaled, xScale)) {
|
||||
setBrushExtent(scaled, mode)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { max, scaleLinear, ZoomTransform } from 'd3'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
|
||||
import { Area } from './Area'
|
||||
import { AxisBottom } from './AxisBottom'
|
||||
import { Brush } from './Brush'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { ScaleLinear } from 'd3'
|
||||
import React, { useMemo } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const StyledLine = styled.line`
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { ButtonGray } from 'components/Button'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ScaleLinear, select, ZoomBehavior, zoom, ZoomTransform, zoomIdentity } from 'd3'
|
||||
import { ScaleLinear, select, zoom, ZoomBehavior, zoomIdentity, ZoomTransform } from 'd3'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { RefreshCcw, ZoomIn, ZoomOut } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { ZoomLevels } from './types'
|
||||
|
||||
const Wrapper = styled.div<{ count: number }>`
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
||||
import { ChartEntry } from './types'
|
||||
import JSBI from 'jsbi'
|
||||
import { TickProcessed, usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
export interface TickProcessed {
|
||||
liquidityActive: JSBI
|
||||
price0: string
|
||||
}
|
||||
import { ChartEntry } from './types'
|
||||
|
||||
export function useDensityChartData({
|
||||
currencyA,
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
import React, { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, Price, Token } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { AutoColumn, ColumnCenter } from 'components/Column'
|
||||
import Loader from 'components/Loader'
|
||||
import { format } from 'd3'
|
||||
import { useColor } from 'hooks/useColor'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { saturate } from 'polished'
|
||||
import { BarChart2, Inbox, CloudOff } from 'react-feather'
|
||||
import React, { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { BarChart2, CloudOff, Inbox } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { batch } from 'react-redux'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from '../../theme'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { Chart } from './Chart'
|
||||
import { useDensityChartData } from './hooks'
|
||||
import { format } from 'd3'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import ReactGA from 'react-ga'
|
||||
import { ZoomLevels } from './types'
|
||||
|
||||
const ZOOM_LEVELS: Record<FeeAmount, ZoomLevels> = {
|
||||
[FeeAmount.LOWEST]: {
|
||||
initialMin: 0.999,
|
||||
initialMax: 1.001,
|
||||
min: 0.00001,
|
||||
max: 1.5,
|
||||
},
|
||||
[FeeAmount.LOW]: {
|
||||
initialMin: 0.999,
|
||||
initialMax: 1.001,
|
||||
@@ -51,9 +58,9 @@ function InfoBox({ message, icon }: { message?: ReactNode; icon: ReactNode }) {
|
||||
<ColumnCenter style={{ height: '100%', justifyContent: 'center' }}>
|
||||
{icon}
|
||||
{message && (
|
||||
<TYPE.mediumHeader padding={10} marginTop="20px" textAlign="center">
|
||||
<ThemedText.MediumHeader padding={10} marginTop="20px" textAlign="center">
|
||||
{message}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
)}
|
||||
</ColumnCenter>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import useHttpLocations from '../../hooks/useHttpLocations'
|
||||
|
||||
import useHttpLocations from '../../hooks/useHttpLocations'
|
||||
import Logo from '../Logo'
|
||||
|
||||
const StyledListLogo = styled(Logo)<{ size: string }>`
|
||||
|
||||
39
src/components/Loader/styled.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import styled, { css, keyframes } from 'styled-components/macro'
|
||||
|
||||
export const loadingAnimation = keyframes`
|
||||
0% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
`
|
||||
|
||||
export const LoadingRows = styled.div`
|
||||
display: grid;
|
||||
|
||||
& > div {
|
||||
animation: ${loadingAnimation} 1.5s infinite;
|
||||
animation-fill-mode: both;
|
||||
background: linear-gradient(
|
||||
to left,
|
||||
${({ theme }) => theme.bg1} 25%,
|
||||
${({ theme }) => theme.bg2} 50%,
|
||||
${({ theme }) => theme.bg1} 75%
|
||||
);
|
||||
background-size: 400%;
|
||||
border-radius: 12px;
|
||||
height: 2.4em;
|
||||
will-change: background-position;
|
||||
}
|
||||
`
|
||||
|
||||
export const loadingOpacityMixin = css<{ $loading: boolean }>`
|
||||
filter: ${({ $loading }) => ($loading ? 'grayscale(1)' : 'none')};
|
||||
opacity: ${({ $loading }) => ($loading ? '0.4' : '1')};
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
`
|
||||
|
||||
export const LoadingOpacityContainer = styled.div<{ $loading: boolean }>`
|
||||
${loadingOpacityMixin}
|
||||
`
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { Slash } from 'react-feather'
|
||||
import { ImageProps } from 'rebass'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
|
||||
const BAD_SRCS: { [tokenAddress: string]: true } = {}
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
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 {
|
||||
BookOpen,
|
||||
Code,
|
||||
Check,
|
||||
ChevronLeft,
|
||||
Coffee,
|
||||
FileText,
|
||||
Globe,
|
||||
HelpCircle,
|
||||
Info,
|
||||
MessageCircle,
|
||||
PieChart,
|
||||
Moon,
|
||||
Sun,
|
||||
ChevronRight,
|
||||
ChevronLeft,
|
||||
Check,
|
||||
} from 'react-feather'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
|
||||
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
import { ApplicationModal } from '../../state/application/actions'
|
||||
import { useModalOpen, useToggleModal } from '../../state/application/hooks'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
|
||||
import { L2_CHAIN_IDS, CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||
import { LOCALE_LABEL, SupportedLocale, SUPPORTED_LOCALES } from 'constants/locales'
|
||||
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
|
||||
export enum FlyoutAlignment {
|
||||
LEFT = 'LEFT',
|
||||
@@ -46,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 {
|
||||
@@ -72,7 +74,6 @@ const UNIbutton = styled(ButtonPrimary)`
|
||||
`
|
||||
|
||||
const StyledMenu = styled.div`
|
||||
margin-left: 0.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -177,8 +178,6 @@ const ToggleMenuItem = styled.button`
|
||||
}
|
||||
`
|
||||
|
||||
const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface'
|
||||
|
||||
function LanguageMenuItem({ locale, active, key }: { locale: SupportedLocale; active: boolean; key: string }) {
|
||||
const { to, onClick } = useLocationLinkProps(locale)
|
||||
|
||||
@@ -212,11 +211,11 @@ export default function Menu() {
|
||||
|
||||
const node = useRef<HTMLDivElement>()
|
||||
const open = useModalOpen(ApplicationModal.MENU)
|
||||
const toggle = useToggleModal(ApplicationModal.MENU)
|
||||
useOnClickOutside(node, open ? toggle : undefined)
|
||||
const toggleMenu = useToggleModal(ApplicationModal.MENU)
|
||||
useOnClickOutside(node, open ? toggleMenu : undefined)
|
||||
const togglePrivacyPolicy = useToggleModal(ApplicationModal.PRIVACY_POLICY)
|
||||
const openClaimModal = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
|
||||
const showUNIClaimOption = Boolean(!!account && !!chainId && !L2_CHAIN_IDS.includes(chainId))
|
||||
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||
|
||||
const [darkMode, toggleDarkMode] = useDarkModeManager()
|
||||
|
||||
@@ -227,77 +226,86 @@ export default function Menu() {
|
||||
}, [open])
|
||||
|
||||
return (
|
||||
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
|
||||
<StyledMenu ref={node as any}>
|
||||
<StyledMenuButton onClick={toggle}>
|
||||
<StyledMenuIcon />
|
||||
</StyledMenuButton>
|
||||
<>
|
||||
{/* // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451 */}
|
||||
<StyledMenu ref={node as any}>
|
||||
<StyledMenuButton onClick={toggleMenu} aria-label={t`Menu`}>
|
||||
<StyledMenuIcon />
|
||||
</StyledMenuButton>
|
||||
|
||||
{open &&
|
||||
(() => {
|
||||
switch (menu) {
|
||||
case 'lang':
|
||||
return <LanguageMenu close={() => setMenu('main')} />
|
||||
case 'main':
|
||||
default:
|
||||
return (
|
||||
<MenuFlyout>
|
||||
<MenuItem href="https://uniswap.org/">
|
||||
<div>
|
||||
<Trans>About</Trans>
|
||||
</div>
|
||||
<Info opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://docs.uniswap.org/">
|
||||
<div>
|
||||
<Trans>Docs</Trans>
|
||||
</div>
|
||||
<BookOpen opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href={CODE_LINK}>
|
||||
<div>
|
||||
<Trans>Code</Trans>
|
||||
</div>
|
||||
<Code opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://discord.gg/FCfyBSbCU5">
|
||||
<div>
|
||||
<Trans>Discord</Trans>
|
||||
</div>
|
||||
<MessageCircle opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href={infoLink}>
|
||||
<div>
|
||||
<Trans>Analytics</Trans>
|
||||
</div>
|
||||
<PieChart opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<ToggleMenuItem onClick={() => setMenu('lang')}>
|
||||
<div>
|
||||
<Trans>Language</Trans>
|
||||
</div>
|
||||
<ChevronRight size={16} opacity={0.6} />
|
||||
</ToggleMenuItem>
|
||||
<ToggleMenuItem onClick={() => toggleDarkMode()}>
|
||||
<div>{darkMode ? <Trans>Light Theme</Trans> : <Trans>Dark Theme</Trans>}</div>
|
||||
{darkMode ? <Moon opacity={0.6} size={16} /> : <Sun opacity={0.6} size={16} />}
|
||||
</ToggleMenuItem>
|
||||
{showUNIClaimOption && (
|
||||
<UNIbutton
|
||||
onClick={openClaimModal}
|
||||
padding="8px 16px"
|
||||
width="100%"
|
||||
$borderRadius="12px"
|
||||
mt="0.5rem"
|
||||
>
|
||||
<Trans>Claim UNI</Trans>
|
||||
</UNIbutton>
|
||||
)}
|
||||
</MenuFlyout>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
</StyledMenu>
|
||||
{open &&
|
||||
(() => {
|
||||
switch (menu) {
|
||||
case 'lang':
|
||||
return <LanguageMenu close={() => setMenu('main')} />
|
||||
case 'main':
|
||||
default:
|
||||
return (
|
||||
<MenuFlyout>
|
||||
<MenuItem href="https://uniswap.org/">
|
||||
<div>
|
||||
<Trans>About</Trans>
|
||||
</div>
|
||||
<Info opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://help.uniswap.org/">
|
||||
<div>
|
||||
<Trans>Help Center</Trans>
|
||||
</div>
|
||||
<HelpCircle opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://uniswap.canny.io/feature-requests">
|
||||
<div>
|
||||
<Trans>Request Features</Trans>
|
||||
</div>
|
||||
<Coffee opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://discord.gg/FCfyBSbCU5">
|
||||
<div>
|
||||
<Trans>Discord</Trans>
|
||||
</div>
|
||||
<MessageCircle opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<ToggleMenuItem onClick={() => setMenu('lang')}>
|
||||
<div>
|
||||
<Trans>Language</Trans>
|
||||
</div>
|
||||
<Globe opacity={0.6} size={16} />
|
||||
</ToggleMenuItem>
|
||||
<ToggleMenuItem onClick={() => toggleDarkMode()}>
|
||||
<div>{darkMode ? <Trans>Light Theme</Trans> : <Trans>Dark Theme</Trans>}</div>
|
||||
{darkMode ? <Moon opacity={0.6} size={16} /> : <Sun opacity={0.6} size={16} />}
|
||||
</ToggleMenuItem>
|
||||
<MenuItem href="https://docs.uniswap.org/">
|
||||
<div>
|
||||
<Trans>Docs</Trans>
|
||||
</div>
|
||||
<BookOpen opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<ToggleMenuItem onClick={() => togglePrivacyPolicy()}>
|
||||
<div>
|
||||
<Trans>Legal & Privacy</Trans>
|
||||
</div>
|
||||
<FileText opacity={0.6} size={16} />
|
||||
</ToggleMenuItem>
|
||||
{showUNIClaimOption && (
|
||||
<UNIbutton
|
||||
onClick={openClaimModal}
|
||||
padding="8px 16px"
|
||||
width="100%"
|
||||
$borderRadius="12px"
|
||||
mt="0.5rem"
|
||||
>
|
||||
<Trans>Claim UNI</Trans>
|
||||
</UNIbutton>
|
||||
)}
|
||||
</MenuFlyout>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
</StyledMenu>
|
||||
<PrivacyPolicyModal />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import { animated, useTransition, useSpring } from 'react-spring'
|
||||
import { DialogOverlay, DialogContent } from '@reach/dialog'
|
||||
import { isMobile } from 'react-device-detect'
|
||||
import { DialogContent, DialogOverlay } from '@reach/dialog'
|
||||
import { transparentize } from 'polished'
|
||||
import React from 'react'
|
||||
import { animated, useSpring, useTransition } from 'react-spring'
|
||||
import { useGesture } from 'react-use-gesture'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
|
||||
import { isMobile } from '../../utils/userAgent'
|
||||
|
||||
const AnimatedDialogOverlay = animated(DialogOverlay)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { useContext } from 'react'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
|
||||
import { AutoColumn, ColumnCenter } from '../Column'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import { RowBetween } from '../Row'
|
||||
import { TYPE, CloseIcon, CustomLightSpinner } from '../../theme'
|
||||
import { ArrowUpCircle } from 'react-feather'
|
||||
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 { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { AutoColumn, ColumnCenter } from '../Column'
|
||||
import { RowBetween } from '../Row'
|
||||
|
||||
const ConfirmOrLoadingWrapper = styled.div`
|
||||
width: 100%;
|
||||
@@ -33,9 +32,9 @@ export function LoadingView({ children, onDismiss }: { children: any; onDismiss:
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
{children}
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>Confirm this transaction in your wallet</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</AutoColumn>
|
||||
</ConfirmOrLoadingWrapper>
|
||||
)
|
||||
@@ -69,9 +68,9 @@ export function SubmittedView({
|
||||
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
|
||||
style={{ marginLeft: '4px' }}
|
||||
>
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>View transaction on Explorer</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</AutoColumn>
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import { darken } from 'polished'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { NavLink, Link as HistoryLink, useLocation } from 'react-router-dom'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { darken } from 'polished'
|
||||
import { ReactNode } from 'react'
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import Row, { RowBetween } from '../Row'
|
||||
import SettingsTab from '../Settings'
|
||||
|
||||
import { Link as HistoryLink, NavLink, useLocation } from 'react-router-dom'
|
||||
import { Box } from 'rebass'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import { resetMintState } from 'state/mint/actions'
|
||||
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
|
||||
import { TYPE } from 'theme'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { ReactNode } from 'react'
|
||||
import { Box } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import Row, { RowBetween } from '../Row'
|
||||
import SettingsTab from '../Settings'
|
||||
|
||||
const Tabs = styled.div`
|
||||
${({ theme }) => theme.flexRowNoWrap}
|
||||
@@ -137,7 +136,7 @@ export function AddRemoveTabs({
|
||||
>
|
||||
<StyledArrowLeft stroke={theme.text2} />
|
||||
</StyledHistoryLink>
|
||||
<TYPE.mediumHeader
|
||||
<ThemedText.MediumHeader
|
||||
fontWeight={500}
|
||||
fontSize={20}
|
||||
style={{ flex: '1', margin: 'auto', textAlign: children ? 'start' : 'center' }}
|
||||
@@ -149,7 +148,7 @@ export function AddRemoveTabs({
|
||||
) : (
|
||||
<Trans>Remove Liquidity</Trans>
|
||||
)}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<Box style={{ marginRight: '.5rem' }}>{children}</Box>
|
||||
<SettingsTab placeholderSlippage={defaultSlippage} />
|
||||
</RowBetween>
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import {
|
||||
ArbitrumWrapperBackgroundDarkMode,
|
||||
ArbitrumWrapperBackgroundLightMode,
|
||||
OptimismWrapperBackgroundDarkMode,
|
||||
OptimismWrapperBackgroundLightMode,
|
||||
} from 'components/NetworkAlert/NetworkAlert'
|
||||
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { ArrowDownCircle } from 'react-feather'
|
||||
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { ReadMoreLink } from './styles'
|
||||
|
||||
const L2Icon = styled.img`
|
||||
display: none;
|
||||
height: 40px;
|
||||
margin: auto 20px auto 4px;
|
||||
width: 40px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
const DesktopTextBreak = styled.div`
|
||||
display: none;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
const Wrapper = styled.div<{ chainId: SupportedL2ChainId; darkMode: boolean; logoUrl: string }>`
|
||||
${({ chainId, darkMode }) =>
|
||||
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? darkMode
|
||||
? OptimismWrapperBackgroundDarkMode
|
||||
: OptimismWrapperBackgroundLightMode
|
||||
: darkMode
|
||||
? ArbitrumWrapperBackgroundDarkMode
|
||||
: ArbitrumWrapperBackgroundLightMode};
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
:before {
|
||||
background-image: url(${({ logoUrl }) => logoUrl});
|
||||
background-repeat: no-repeat;
|
||||
background-size: 300px;
|
||||
content: '';
|
||||
height: 300px;
|
||||
opacity: 0.1;
|
||||
position: absolute;
|
||||
transform: rotate(25deg) translate(-90px, -40px);
|
||||
width: 300px;
|
||||
z-index: -1;
|
||||
}
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
flex-direction: row;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
`
|
||||
const Body = styled.div`
|
||||
font-size: 12px;
|
||||
line-height: 143%;
|
||||
margin: 12px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
flex: 1 1 auto;
|
||||
margin: auto 0;
|
||||
}
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
transform: rotate(230deg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-left: 12px;
|
||||
`
|
||||
const LinkOutToBridge = styled(ExternalLink)`
|
||||
align-items: center;
|
||||
background-color: black;
|
||||
border-radius: 16px;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
max-height: 47px;
|
||||
padding: 16px 12px;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
:hover,
|
||||
:focus,
|
||||
:active {
|
||||
background-color: black;
|
||||
}
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
margin: auto 0 auto auto;
|
||||
padding: 14px 16px;
|
||||
min-width: 226px;
|
||||
}
|
||||
`
|
||||
export function AddLiquidityNetworkAlert() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [arbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
|
||||
|
||||
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged) {
|
||||
return null
|
||||
}
|
||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
||||
const depositUrl = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? `${info.bridge}?chainId=1`
|
||||
: info.bridge
|
||||
return (
|
||||
<Wrapper darkMode={darkMode} chainId={chainId} logoUrl={info.logoUrl}>
|
||||
<L2Icon src={info.logoUrl} />
|
||||
<Body>
|
||||
<Trans>This is an alpha release of Uniswap on the {info.label} network.</Trans>
|
||||
<DesktopTextBreak /> <Trans>You must bridge L1 assets to the network to use them.</Trans>{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism">
|
||||
<Trans>Read more</Trans>
|
||||
</ReadMoreLink>
|
||||
</Body>
|
||||
<LinkOutToBridge href={depositUrl}>
|
||||
<Trans>Deposit to {info.label}</Trans>
|
||||
<LinkOutCircle />
|
||||
</LinkOutToBridge>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import {
|
||||
ArbitrumWrapperBackgroundDarkMode,
|
||||
ArbitrumWrapperBackgroundLightMode,
|
||||
OptimismWrapperBackgroundDarkMode,
|
||||
OptimismWrapperBackgroundLightMode,
|
||||
} from 'components/NetworkAlert/NetworkAlert'
|
||||
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { ArrowDownCircle } from 'react-feather'
|
||||
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||
import { ReadMoreLink } from './styles'
|
||||
|
||||
const L2Icon = styled.img`
|
||||
display: none;
|
||||
height: 40px;
|
||||
margin: auto 20px auto 4px;
|
||||
width: 40px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
const DesktopTextBreak = styled.div`
|
||||
display: none;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
const Wrapper = styled.div<{ chainId: SupportedL2ChainId; darkMode: boolean; logoUrl: string }>`
|
||||
${({ chainId, darkMode }) =>
|
||||
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? darkMode
|
||||
? OptimismWrapperBackgroundDarkMode
|
||||
: OptimismWrapperBackgroundLightMode
|
||||
: darkMode
|
||||
? ArbitrumWrapperBackgroundDarkMode
|
||||
: ArbitrumWrapperBackgroundLightMode};
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
:before {
|
||||
background-image: url(${({ logoUrl }) => logoUrl});
|
||||
background-repeat: no-repeat;
|
||||
background-size: 300px;
|
||||
content: '';
|
||||
height: 300px;
|
||||
opacity: 0.1;
|
||||
position: absolute;
|
||||
transform: rotate(25deg) translate(-90px, -40px);
|
||||
width: 300px;
|
||||
z-index: -1;
|
||||
}
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
flex-direction: row;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
`
|
||||
const Body = styled.div`
|
||||
font-size: 12px;
|
||||
line-height: 143%;
|
||||
margin: 12px;
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
flex: 1 1 auto;
|
||||
margin: auto 0;
|
||||
}
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
transform: rotate(230deg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-left: 12px;
|
||||
`
|
||||
const LinkOutToBridge = styled(ExternalLink)`
|
||||
align-items: center;
|
||||
background-color: black;
|
||||
border-radius: 16px;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
max-height: 47px;
|
||||
padding: 16px 8px;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
:hover,
|
||||
:focus,
|
||||
:active {
|
||||
background-color: black;
|
||||
}
|
||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||
margin: auto 0 auto auto;
|
||||
padding: 14px 17px;
|
||||
min-width: 226px;
|
||||
}
|
||||
`
|
||||
export function MinimalNetworkAlert() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [arbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
|
||||
|
||||
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged) {
|
||||
return null
|
||||
}
|
||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
||||
const depositUrl = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? `${info.bridge}?chainId=1`
|
||||
: info.bridge
|
||||
return (
|
||||
<Wrapper darkMode={darkMode} chainId={chainId} logoUrl={info.logoUrl}>
|
||||
<L2Icon src={info.logoUrl} />
|
||||
<Body>
|
||||
<Trans>This is an alpha release of Uniswap on the {info.label} network.</Trans>
|
||||
<DesktopTextBreak /> <Trans>You must bridge L1 assets to the network to use them.</Trans>{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism">
|
||||
<Trans>Read more</Trans>
|
||||
</ReadMoreLink>
|
||||
</Body>
|
||||
<LinkOutToBridge href={depositUrl}>
|
||||
<Trans>Deposit to {info.label}</Trans>
|
||||
<LinkOutCircle />
|
||||
</LinkOutToBridge>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,68 +1,89 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { ArrowDownCircle, X } from 'react-feather'
|
||||
import { useArbitrumAlphaAlert, useDarkModeManager } 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/chains'
|
||||
import { ReadMoreLink } from './styles'
|
||||
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 { AutoRow } from '../Row'
|
||||
|
||||
const L2Icon = styled.img`
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
justify-self: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 16px;
|
||||
`
|
||||
const CloseIcon = styled(X)`
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
`
|
||||
const ContentWrapper = styled.div`
|
||||
|
||||
export const Controls = 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;
|
||||
}
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding: 0 20px 20px 20px;
|
||||
`
|
||||
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);
|
||||
|
||||
const BodyText = styled.div`
|
||||
color: ${({ color }) => color};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 8px;
|
||||
font-size: 14px;
|
||||
`
|
||||
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);
|
||||
const RootWrapper = styled.div`
|
||||
position: relative;
|
||||
margin-top: 16px;
|
||||
`
|
||||
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 RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string }>`
|
||||
${({ 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%;
|
||||
@@ -82,87 +103,71 @@ const RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; l
|
||||
`
|
||||
const Header = styled.h2`
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding-right: 30px;
|
||||
`
|
||||
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;
|
||||
}
|
||||
`
|
||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||
transform: rotate(230deg);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
`
|
||||
|
||||
const LinkOutToBridge = styled(ExternalLink)`
|
||||
align-items: center;
|
||||
background-color: black;
|
||||
border-radius: 16px;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 44px;
|
||||
justify-content: space-between;
|
||||
margin: 0 20px 20px 20px;
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
width: auto;
|
||||
:hover,
|
||||
:focus,
|
||||
:active {
|
||||
background-color: black;
|
||||
}
|
||||
padding: 6px 8px;
|
||||
margin-right: 12px;
|
||||
text-decoration: none !important;
|
||||
width: 100%;
|
||||
`
|
||||
export function NetworkAlert() {
|
||||
const { account, chainId } = useActiveWeb3React()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
|
||||
const [locallyDismissed, setLocallyDimissed] = useState(false)
|
||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
||||
|
||||
const dismiss = useCallback(() => {
|
||||
if (userEthBalance?.greaterThan(0)) {
|
||||
setArbitrumAlphaAcknowledged(true)
|
||||
} else {
|
||||
setLocallyDimissed(true)
|
||||
}
|
||||
}, [setArbitrumAlphaAcknowledged, userEthBalance])
|
||||
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged || locallyDismissed) {
|
||||
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',
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
if (!shouldShowAlert(chainId)) {
|
||||
return null
|
||||
}
|
||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
||||
const depositUrl = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
||||
? `${info.bridge}?chainId=1`
|
||||
: info.bridge
|
||||
|
||||
return (
|
||||
<RootWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl}>
|
||||
<CloseIcon onClick={dismiss} />
|
||||
<ContentWrapper>
|
||||
<L2Icon src={info.logoUrl} />
|
||||
<Header>
|
||||
<Trans>Uniswap on {info.label}</Trans>
|
||||
</Header>
|
||||
<Body>
|
||||
<Trans>
|
||||
This is an alpha release of Uniswap on the {info.label} network. You must bridge L1 assets to the network to
|
||||
swap them.
|
||||
</Trans>{' '}
|
||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism">
|
||||
<Trans>Read more</Trans>
|
||||
</ReadMoreLink>
|
||||
</Body>
|
||||
const { label, logoUrl, bridge } = CHAIN_INFO[chainId]
|
||||
const textColor = TEXT_COLORS[chainId]
|
||||
|
||||
return bridge ? (
|
||||
<RootWrapper>
|
||||
<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>
|
||||
<LinkOutToBridge href={depositUrl}>
|
||||
<Trans>Deposit to {info.label}</Trans>
|
||||
<LinkOutCircle />
|
||||
</LinkOutToBridge>
|
||||
</RootWrapper>
|
||||
)
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink } from 'theme'
|
||||
|
||||
export const ReadMoreLink = styled(ExternalLink)`
|
||||
color: ${({ theme }) => theme.text1};
|
||||
text-decoration: underline;
|
||||
`
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { escapeRegExp } from '../../utils'
|
||||
|
||||
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`
|
||||
@@ -11,7 +12,7 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s
|
||||
border: none;
|
||||
flex: 1 1 auto;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
font-size: ${({ fontSize }) => fontSize ?? '24px'};
|
||||
font-size: ${({ fontSize }) => fontSize ?? '28px'};
|
||||
text-align: ${({ align }) => align && align};
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { AlertOctagon } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink } from 'theme'
|
||||
|
||||
const Root = styled.div`
|
||||
background-color: ${({ theme }) => theme.yellow3};
|
||||
border-radius: 18px;
|
||||
color: black;
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
max-width: 880px;
|
||||
`
|
||||
const WarningIcon = styled(AlertOctagon)`
|
||||
margin: 0 8px 0 0;
|
||||
`
|
||||
const TitleRow = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 25px;
|
||||
`
|
||||
const Body = styled.div`
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
margin: 8px 0 0 0;
|
||||
`
|
||||
const ReadMoreLink = styled(ExternalLink)`
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
`
|
||||
|
||||
export default function OptimismDowntimeWarning() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
if (!chainId || ![SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<TitleRow>
|
||||
<WarningIcon />
|
||||
<Trans>Optimism Planned Downtime</Trans>
|
||||
</TitleRow>
|
||||
<Body>
|
||||
<Trans>
|
||||
Optimism expects planned downtime in the near future. Unplanned downtime may also occur. While the network is
|
||||
down, fees will not be generated 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>
|
||||
</Body>
|
||||
</Root>
|
||||
)
|
||||
}
|
||||
@@ -1,21 +1,16 @@
|
||||
import { Placement } from '@popperjs/core'
|
||||
import { transparentize } from 'polished'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
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'
|
||||
import Portal from '@reach/portal'
|
||||
|
||||
const PopoverContainer = styled.div<{ show: boolean }>`
|
||||
z-index: 9999;
|
||||
visibility: ${(props) => (props.show ? 'visible' : 'hidden')};
|
||||
opacity: ${(props) => (props.show ? 1 : 0)};
|
||||
transition: visibility 150ms linear, opacity 150ms linear;
|
||||
background: ${({ theme }) => theme.bg2};
|
||||
border: 1px solid ${({ theme }) => theme.bg3};
|
||||
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.9, theme.shadow1)};
|
||||
color: ${({ theme }) => theme.text2};
|
||||
border-radius: 8px;
|
||||
`
|
||||
|
||||
const ReferenceElement = styled.div`
|
||||
@@ -34,9 +29,9 @@ const Arrow = styled.div`
|
||||
z-index: 9998;
|
||||
|
||||
content: '';
|
||||
border: 1px solid ${({ theme }) => theme.bg3};
|
||||
border: 1px solid ${({ theme }) => theme.bg2};
|
||||
transform: rotate(45deg);
|
||||
background: ${({ theme }) => theme.bg2};
|
||||
background: ${({ theme }) => theme.bg0};
|
||||
}
|
||||
|
||||
&.arrow-top {
|
||||
@@ -84,14 +79,22 @@ export default function Popover({ content, show, children, placement = 'auto' }:
|
||||
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null)
|
||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null)
|
||||
const [arrowElement, setArrowElement] = useState<HTMLDivElement | null>(null)
|
||||
const { styles, update, attributes } = usePopper(referenceElement, popperElement, {
|
||||
placement,
|
||||
strategy: 'fixed',
|
||||
modifiers: [
|
||||
{ name: 'offset', options: { offset: [8, 8] } },
|
||||
{ name: 'arrow', options: { element: arrowElement } },
|
||||
],
|
||||
})
|
||||
|
||||
const options = useMemo(
|
||||
(): Options => ({
|
||||
placement,
|
||||
strategy: 'fixed',
|
||||
modifiers: [
|
||||
{ name: 'offset', options: { offset: [8, 8] } },
|
||||
{ name: 'arrow', options: { element: arrowElement } },
|
||||
{ name: 'preventOverflow', options: { padding: 8 } },
|
||||
],
|
||||
}),
|
||||
[arrowElement, placement]
|
||||
)
|
||||
|
||||
const { styles, update, attributes } = usePopper(referenceElement, popperElement, options)
|
||||
|
||||
const updateCallback = useCallback(() => {
|
||||
update && update()
|
||||
}, [update])
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
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 { ButtonPrimary } from '../../components/Button'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ApplicationModal } from '../../state/application/actions'
|
||||
import {
|
||||
useModalOpen,
|
||||
useShowClaimPopup,
|
||||
useToggleSelfClaimModal,
|
||||
useToggleShowClaimPopup,
|
||||
} from '../../state/application/hooks'
|
||||
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { CardBGImage, CardNoise } from '../earn/styled'
|
||||
|
||||
@@ -98,10 +98,10 @@ export default function ClaimPopup() {
|
||||
<StyledClose stroke="white" onClick={toggleShowClaimPopup} />
|
||||
<AutoColumn style={{ padding: '2rem 0', zIndex: 10 }} justify="center">
|
||||
<UniToken width="48px" src={tokenLogo} />{' '}
|
||||
<TYPE.white style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
|
||||
<ThemedText.White style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
|
||||
{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI
|
||||
</TYPE.white>
|
||||
<TYPE.white style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
|
||||
</ThemedText.White>
|
||||
<ThemedText.White style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
|
||||
<span role="img" aria-label="party">
|
||||
🎉
|
||||
</span>{' '}
|
||||
@@ -109,12 +109,12 @@ export default function ClaimPopup() {
|
||||
<span role="img" aria-label="party">
|
||||
🎉
|
||||
</span>
|
||||
</TYPE.white>
|
||||
<TYPE.subHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
|
||||
</ThemedText.White>
|
||||
<ThemedText.SubHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
|
||||
<Trans>
|
||||
Thanks for being part of the Uniswap community <Heart size={12} />
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</AutoColumn>
|
||||
<AutoColumn style={{ zIndex: 10 }} justify="center">
|
||||
<ButtonPrimary padding="8px" $borderRadius="8px" width={'fit-content'} onClick={handleToggleSelfClaimModal}>
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useCallback, useContext, useEffect } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import { animated } from 'react-spring'
|
||||
import { useSpring } from 'react-spring/web'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import { animated } from 'react-spring'
|
||||
import { PopupContent } from '../../state/application/actions'
|
||||
|
||||
import { useRemovePopup } from '../../state/application/hooks'
|
||||
import { PopupContent } from '../../state/application/reducer'
|
||||
import FailedNetworkSwitchPopup from './FailedNetworkSwitchPopup'
|
||||
import TransactionPopup from './TransactionPopup'
|
||||
|
||||
const StyledClose = styled(X)`
|
||||
@@ -73,9 +75,11 @@ export default function PopupItem({
|
||||
let popupContent
|
||||
if ('txn' in content) {
|
||||
const {
|
||||
txn: { hash, success, summary },
|
||||
txn: { hash },
|
||||
} = content
|
||||
popupContent = <TransactionPopup hash={hash} success={success} summary={summary} />
|
||||
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,10 +1,13 @@
|
||||
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 { TYPE } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
|
||||
import { useTransaction } from '../../state/transactions/hooks'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { AutoRow } from '../Row'
|
||||
|
||||
@@ -12,26 +15,24 @@ const RowNoFlex = styled(AutoRow)`
|
||||
flex-wrap: nowrap;
|
||||
`
|
||||
|
||||
export default function TransactionPopup({
|
||||
hash,
|
||||
success,
|
||||
summary,
|
||||
}: {
|
||||
hash: string
|
||||
success?: boolean
|
||||
summary?: string
|
||||
}) {
|
||||
export default function TransactionPopup({ hash }: { hash: string }) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const tx = useTransaction(hash)
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
if (!tx) return null
|
||||
const success = Boolean(tx.receipt && tx.receipt.status === 1)
|
||||
|
||||
return (
|
||||
<RowNoFlex>
|
||||
<div style={{ paddingRight: 16 }}>
|
||||
{success ? <CheckCircle color={theme.green1} size={24} /> : <AlertCircle color={theme.red1} size={24} />}
|
||||
</div>
|
||||
<AutoColumn gap="8px">
|
||||
<TYPE.body fontWeight={500}>{summary ?? 'Hash: ' + hash.slice(0, 8) + '...' + hash.slice(58, 65)}</TYPE.body>
|
||||
<ThemedText.Body fontWeight={500}>
|
||||
<TransactionSummary info={tx.info} />
|
||||
</ThemedText.Body>
|
||||
{chainId && (
|
||||
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
|
||||
View on Explorer
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import styled from 'styled-components/macro'
|
||||
import { useActivePopups } from '../../state/application/hooks'
|
||||
import { AutoColumn } from '../Column'
|
||||
import PopupItem from './PopupItem'
|
||||
import ClaimPopup from './ClaimPopup'
|
||||
import { useURLWarningVisible } from '../../state/user/hooks'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import styled from 'styled-components/macro'
|
||||
import { MEDIA_WIDTHS } from 'theme'
|
||||
|
||||
import { useActivePopups } from '../../state/application/hooks'
|
||||
import { useURLWarningVisible } from '../../state/user/hooks'
|
||||
import { AutoColumn } from '../Column'
|
||||
import ClaimPopup from './ClaimPopup'
|
||||
import PopupItem from './PopupItem'
|
||||
|
||||
const MobilePopupWrapper = styled.div<{ height: string | number }>`
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Token } from '@uniswap/sdk-core'
|
||||
import Badge, { BadgeVariant } from 'components/Badge'
|
||||
import { transparentize } from 'polished'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Text } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import { Trans } from '@lingui/macro'
|
||||
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
import { ButtonEmpty } from '../Button'
|
||||
import { transparentize } from 'polished'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
|
||||
import { useColor } from '../../hooks/useColor'
|
||||
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
import { ButtonEmpty } from '../Button'
|
||||
import { LightCard } from '../Card'
|
||||
import { AutoColumn } from '../Column'
|
||||
import DoubleCurrencyLogo from '../DoubleLogo'
|
||||
import { RowFixed, AutoRow } from '../Row'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
import { AutoRow, RowFixed } from '../Row'
|
||||
import { Dots } from '../swap/styleds'
|
||||
import { FixedHeightRow } from '.'
|
||||
import Badge, { BadgeVariant } from 'components/Badge'
|
||||
|
||||
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`
|
||||
border: none;
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
import JSBI from 'jsbi'
|
||||
import { useState } from 'react'
|
||||
import { Percent, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
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'
|
||||
import { ChevronDown, ChevronUp } from 'react-feather'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Text } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import { Trans } from '@lingui/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { BIG_INT_ZERO } from '../../constants/misc'
|
||||
import { useColor } from '../../hooks/useColor'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { currencyId } from '../../utils/currencyId'
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
import { ButtonPrimary, ButtonSecondary, ButtonEmpty } from '../Button'
|
||||
import { transparentize } from 'polished'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
|
||||
import { useColor } from '../../hooks/useColor'
|
||||
|
||||
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
|
||||
import { LightCard } from '../Card'
|
||||
import { AutoColumn } from '../Column'
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
import DoubleCurrencyLogo from '../DoubleLogo'
|
||||
import { RowBetween, RowFixed, AutoRow } from '../Row'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
import { AutoRow, RowBetween, RowFixed } from '../Row'
|
||||
import { Dots } from '../swap/styleds'
|
||||
import { BIG_INT_ZERO } from '../../constants/misc'
|
||||
import { FixedHeightRow } from '.'
|
||||
|
||||
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`
|
||||
|
||||