Compare commits

...

86 Commits

Author SHA1 Message Date
Will Hennessy
744c313ecf feat: Add learn more link in TRM description (#2919)
* Add learn more link in TRM description

* Update src/components/PrivacyPolicy/index.tsx

Co-authored-by: Justin Domingue <judo@uniswap.org>
2021-12-06 12:26:33 -05:00
Noah Zinsmeister
b967b1b236 fix: introduce safeNamehash (#2925)
* namehash -> safeNamehash where necessary

* cleanup

* address comment
2021-12-03 16:45:33 -05:00
J M Rossy
596ea03043 refactor: Replace multicall implementation with library (#2768)
- Replace the local implementation of multicall with the new redux-multicall lib
- Create wrappers for redux-multicall hooks to inject block number and chainId
2021-12-03 06:29:39 -05:00
Zach Pomerantz
e81e8a8f71 fix: inadvertent merges/reverts (#2915)
* Revert "Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)"

This reverts commit 7d343dcfbd.

* Revert "deleted files"

This reverts commit 097b8361d4.
2021-12-02 10:35:39 -08:00
Justin Domingue
7d343dcfbd Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)
This reverts commit bf7a40be7a, reversing
changes made to 097b8361d4.
2021-12-02 13:12:22 -05:00
Justin Domingue
bf7a40be7a Merge branch 'main' of https://github.com/Uniswap/interface 2021-12-02 11:15:09 -05:00
Justin Domingue
097b8361d4 deleted files 2021-12-02 11:14:41 -05:00
Carlos Diaz-Padron
82843ff16a fix: typo in arweave URI recognition (#2901) 2021-12-01 13:26:46 -05:00
Moody Salem
890471f590 fix: fix layout of proposal list items on the vote page on mobile (#2898)
* fix: fixing layout from using grid to flexbox

* fix: setting WrapSmall to nowrap due to layout issue on mobile

* fix: using width auto instead of disabling flex wrap

Co-authored-by: Julian Anderson <juliancanderson@gmail.com>
2021-12-01 10:23:02 -05:00
Dmitri Tsumak
478ee7ba14 fix: Add routes for stakewise tokens (#2832)
* Add additional routes for stakewise tokens

* Reference StakeWise addresses with sdk tokens

* Sort token imports
2021-11-30 15:25:50 -05:00
Moody Salem
745be977ef fix(lint): clean up the eslint config (#2886)
* fix(lint): clean up the eslint config

* Fix code style issues with ESLint

* fix the linter errors that arose from using the proper config

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-11-30 15:20:59 -05:00
Justin Domingue
0e25c055fb add more tests for tryParseTick (#2110) 2021-11-30 11:44:40 -05:00
dependabot[bot]
82a079935e chore(deps): bump url-parse from 1.5.1 to 1.5.3 (#2504)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-30 11:40:15 -05:00
dependabot[bot]
876c1539d4 chore(deps): bump ws from 5.2.2 to 5.2.3 (#2759)
Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-30 11:38:15 -05:00
Crowdin Bot
f43fd89884 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-30 02:11:35 +00:00
Zach Pomerantz
efdfdc9083 refactor: use ref for jazzicon (#2874) 2021-11-29 15:49:01 -08:00
Zach Pomerantz
709f0299e2 fix: remove orphaned node (#2863)
* fix: remove orphaned node

* fix: react cleanup
2021-11-29 12:15:08 -08:00
Moody Salem
6b57ffe311 fix: do not show urls if issue is not occurring on app.uniswap.org (#2855)
* fix: do not show urls if issue is not occurring on app.uniswap.org

fixes https://github.com/Uniswap/interface/issues/2572

* address comment
2021-11-29 12:44:14 -05:00
Moody Salem
f7ecdc4332 chore: run linters with auto_fix = false for forks (#2852) 2021-11-28 12:30:58 -05:00
Moody Salem
b1009b0e03 chore: fix the build blocking linter error 2021-11-28 12:07:51 -05:00
Crowdin Bot
5a4c7890c6 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-25 20:06:51 +00:00
Kimmo S
5a3c91f19f Update locales.ts (#2825)
update Finnish from person (Suomalainen) to language (suomi)
2021-11-23 10:04:14 -05:00
Zach Pomerantz
d5c4ee0342 feat: display an ENS avatar (#2806)
* feat: ens avatar resolution

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

* fix: pass memoized args to multicall
2021-11-22 10:55:25 -08:00
Jordan Frankfurt
262d984f92 check for support on all connectors, and disable when the connector (or lack thereof) no longer supports 3085 (#2824) 2021-11-22 12:33:52 -05:00
Lint Action
7781f5112e Fix code style issues with ESLint 2021-11-22 16:08:21 +00:00
Jordan Frankfurt
204e44ac40 fix(L2): block L2 tokens explicitly linked to L1 tokens that are blocked (#2721)
* block L2 tokens explicitly linked to L1 tokens that are blocked
2021-11-22 11:04:36 -05:00
Will Hennessy
7c9d9bdb03 Add trailing slash to L2 info links (#2696)
Some links were broken. For example on /pools/ page click the 'Top Pools' CTA. It would mistakenly direct you to info.uniswap.org/optimismpools instead of optimism/pools
2021-11-22 09:32:34 -05:00
Justin Domingue
cb0ea3f14d log an event on max click (#2827) 2021-11-22 09:27:29 -05:00
Crowdin Bot
e54ffcc483 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-19 16:06:45 +00:00
Justin Domingue
8a72b374a8 fix: fix #2818 2021-11-19 10:10:45 -05:00
Crowdin Bot
3f64415906 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-18 19:06:37 +00:00
Lint Action
41a4500f41 Fix code style issues with ESLint 2021-11-18 18:27:24 +00:00
Ali Eray Kısabacak
093dc66cfe Fixing #2818 (#2820) 2021-11-18 13:23:13 -05:00
Moody Salem
b10729d217 feat: set the auto slippage tolerance by the dollar value of gas (#2815)
* feat: set the auto slippage tolerance by the dollar value of gas

* comments

* min/max at 0.5% to 25%

* oops on constant

* address review feedback
2021-11-18 13:05:29 -05:00
Brendan Weinstein
9b0fa8a2c4 fix: Enable 3085 requests for coinbase wallet (#2753)
enable 3085 requests for coinbase wallet
2021-11-18 12:29:56 -05:00
Crowdin Bot
82c026872f chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-18 06:11:55 +00:00
Sam Chen
222a6d53bc perf: lazy load vote related routes (#2468)
* perf: lazy load vote related routes

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

* fix
2021-11-17 22:01:45 -08:00
Matthew Salamon
0f35f6ee93 chore: update typechain scripts for Windows (#2707)
There are two errors when deploying on Windows system:
1. Using single quotes in path argument doesn't seem to be accepted in typechain command
2. `?(v3-core|v3-periphery)` operator doesn't work

Here are fixes/workarounds.
2021-11-17 21:00:37 -08:00
Ikko Ashimine
7b83e3968f chore: fix typo in useAllCurrencyCombinations.ts (#2778)
occurence -> occurrence
2021-11-17 20:40:58 -08:00
Raj
7938273c0c fix: broken link to docs (#2816) 2021-11-17 20:30:54 -08:00
Crowdin Bot
51a4504c75 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-18 03:06:35 +00:00
Zach Pomerantz
b2697f0077 fix: format date using Date.toLocaleString (#2459)
* fix: format date using Date.toLocaleString

Fixes #2458

* fix: date typings
2021-11-16 16:20:46 -08:00
Crowdin Bot
34a58851f7 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-14 14:06:34 +00:00
Will Hennessy
5a20dc82cd change not created font size to 10 (#2785) 2021-11-12 15:23:15 -05:00
Jordan Frankfurt
d1627a6c36 fix(L2): remove redux from chain connectivity (#2781)
* remove redux from chain connectivity

* useMachineTimeMs instead of Date.now to force updates, useCurrentBlockTimestamp

* use useInterval
2021-11-12 13:24:45 -06:00
Crowdin Bot
55c971892c chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-12 17:09:58 +00:00
Moody Salem
68f8576499 fix: copy in network alert 2021-11-12 11:50:07 -05:00
Jordan Frankfurt
d0be3bf222 fix(L2): update block warning updater to check most recent block timestamp (#2777)
* update block warning updater to check most recent block timestamp

* stop doing dumb state manipulation
2021-11-12 10:18:25 -05:00
Crowdin Bot
b79fe4b833 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-12 15:06:38 +00:00
Justin Domingue
408c907870 feat: add support for 0.01% tier (#2769)
* chore: add support for 0.01% tier

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

* merge main and only consider lowest tier for mainnet
2021-11-12 09:46:26 -05:00
Crowdin Bot
8a99bad736 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-12 09:07:00 +00:00
Crowdin Bot
5ba3d2f679 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-12 01:27:47 +00:00
Crowdin Bot
ec4cd57dc0 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-11 21:07:22 +00:00
Moody Salem
ccad45d24e fix(optimism): Optimism regenesis support (#2703)
* feat(optimism): optimistic kovan local regenesis changes

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

* remove the optimism mainnet specific code and point to the mainnet regenesis rpc url

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

* specific version of v3-sdk
2021-11-11 15:40:12 -05:00
Justin Domingue
1903a16097 fix: lint error (#2775) 2021-11-11 13:12:09 -05:00
Justin Domingue
0ea029db4f add protocols param to quote endpoint (#2774)
* add protocols param to quote endpoint

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-11-11 11:42:17 -05:00
Crowdin Bot
cb41df4cd5 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-11 16:07:15 +00:00
Jordan Frankfurt
659a564db8 no unused imports eslint rule (#2773) 2021-11-11 10:53:14 -05:00
Will Hennessy
74c61c0213 feat: Menu update. Add help center & feature requests. Remove analytics & github. (#2709)
* Add help center, remove analytics from menu

* Add canny feature requests link, remove github link

* add coffee icon
2021-11-11 10:31:08 -05:00
Will Hennessy
dc55a21285 fix: remove deprecated optimism status url (#2771) 2021-11-10 16:41:00 -05:00
Moody Salem
48cc6811c9 fix: bump to latest token list including ENS token 2021-11-08 23:46:50 -05:00
Ben Krochta
ab93d512d3 fix: #2741 Increase liquidity form off center (#2746) 2021-11-05 10:29:55 -04:00
Crowdin Bot
cf4c26a77c chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-03 22:06:57 +00:00
Crowdin Bot
02296c686f chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-03 18:11:33 +00:00
Noah Zinsmeister
60bd0eb86c add proposal start time (#2738) 2021-11-03 13:57:56 -04:00
Noah Zinsmeister
188b321cc9 fix: Parse latest proposal description correctly 2021-11-03 13:12:39 -04:00
Brendan Weinstein
377331c44e fix: Update walletlink-connector to 6.2.8 (#2655)
* Update walletlink-connector to 6.2.5 which has a walletlink update to support addEthereumChain+switchEthereumChain requests

* Update walletlink-connector to 6.2.7

* Update walletlink-connector to 6.2.8
2021-11-03 10:56:54 -04:00
Jordan Frankfurt
dfd442cdac try cd1 for custom dimension (#2734) 2021-11-02 22:50:47 -04:00
Jordan Frankfurt
9561cf54e4 don't overwrite localstorage lists when fetch throws (#2723) 2021-11-02 16:31:25 -05:00
Ian Lapham
714953b50e add token to unsupported list (#2732) 2021-11-02 14:46:14 -04:00
Ian Lapham
b3844e38d1 feat: update cmc list link (#2710)
* update cmc lists

* update CMC url
2021-11-02 10:39:40 -04:00
Crowdin Bot
5dac6a03eb chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-01 21:06:15 +00:00
Moody Salem
d18974480a fix: memoize the list stuff so the tokens are consistently clickable (#2724) 2021-11-01 14:01:41 -04:00
Will Hennessy
6a90bf3b9d chore: update unsupported token list (#2689)
* chore: update unsupported token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-11-01 13:43:55 -04:00
M0kY
5026ebded8 fix: walletconnect modal re-open after user rejection (#2693)
Co-authored-by: M0kY <moky@example.com>
2021-11-01 13:42:16 -04:00
Crowdin Bot
02dbed7a75 chore(i18n): synchronize translations from crowdin [skip ci] 2021-11-01 15:09:04 +00:00
Crowdin Bot
20f462f5a4 chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-27 19:06:32 +00:00
Jordan Frankfurt
cf9c6e4b4c try out 'dimension1' (#2704) 2021-10-27 12:49:42 -04:00
Crowdin Bot
c0201206cc chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-27 13:10:19 +00:00
dependabot[bot]
2d2508f681 chore(deps-dev): bump @uniswap/token-lists (#2699) 2021-10-27 07:15:50 -04:00
Crowdin Bot
609542c49b chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-27 06:07:13 +00:00
Crowdin Bot
9a0294f469 chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-26 22:06:20 +00:00
Jordan Frankfurt
68e6bc1ba8 block import of unsupported tokens (#2673)
generalize custom import token block ui
2021-10-26 17:38:59 -04:00
Justin Domingue
bbc64f12bb fix: back arrow bug in wallet modal and fill tx for wallet (#2687)
* add tx to wallet connect

* remove id from env

* restore env
2021-10-26 12:46:10 -04:00
Crowdin Bot
06f5fdc6ad chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-26 09:07:10 +00:00
Crowdin Bot
b4e756ebba chore(i18n): synchronize translations from crowdin [skip ci] 2021-10-26 08:07:05 +00:00
201 changed files with 4329 additions and 5276 deletions

View File

@@ -8,21 +8,42 @@
"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"],
"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",

View File

@@ -7,3 +7,4 @@ updates:
interval: "daily"
allow:
- dependency-name: "@uniswap/token-lists"
- dependency-name: "@uniswap/default-token-list"

View File

@@ -11,7 +11,6 @@ on:
jobs:
run-linters:
name: Run linters
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
runs-on: ubuntu-latest
steps:
@@ -39,10 +38,15 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run linters
- 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 .

View File

@@ -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)

View File

@@ -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",

View File

@@ -58,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%')
})
})
})

View File

@@ -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,

View File

@@ -1,4 +1,4 @@
export default {
const linguiConfig = {
catalogs: [
{
path: '<rootDir>/src/locales/{locale}',
@@ -52,3 +52,5 @@ export default {
runtimeConfigModule: ['@lingui/core', 'i18n'],
sourceLocale: 'en-US',
}
export default linguiConfig

View File

@@ -11,7 +11,6 @@
],
"private": true,
"devDependencies": {
"@davatar/react": "1.8.1",
"@ethersproject/experimental": "^5.4.0",
"@gnosis.pm/safe-apps-web3-react": "^0.6.0",
"@graphql-codegen/cli": "1.21.5",
@@ -21,6 +20,7 @@
"@lingui/cli": "^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",
@@ -37,7 +37,6 @@
"@types/lingui__core": "^2.7.1",
"@types/lingui__macro": "^2.7.4",
"@types/lingui__react": "^2.8.3",
"@types/luxon": "^1.24.4",
"@types/ms.macro": "^2.0.0",
"@types/multicodec": "^1.0.0",
"@types/node": "^13.13.5",
@@ -55,24 +54,25 @@
"@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": "^2.1.0",
"@uniswap/governance": "^1.0.2",
"@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "1.0.1",
"@uniswap/redux-multicall": "^1.0.0",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/token-lists": "^1.0.0-beta.26",
"@uniswap/token-lists": "^1.0.0-beta.27",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v2-sdk": "^3.0.0-alpha.2",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "^1.1.1",
"@uniswap/v3-sdk": "^3.4.1",
"@uniswap/v3-sdk": "^3.7.1",
"@web3-react/core": "^6.0.9",
"@web3-react/fortmatic-connector": "^6.0.9",
"@web3-react/injected-connector": "^6.0.7",
"@web3-react/portis-connector": "^6.0.9",
"@web3-react/walletconnect-connector": "^7.0.2-alpha.0",
"@web3-react/walletlink-connector": "^6.2.3",
"@web3-react/walletlink-connector": "^6.2.8",
"ajv": "^6.12.3",
"array.prototype.flat": "^1.2.4",
"array.prototype.flatmap": "^1.2.4",
@@ -87,13 +87,13 @@
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.0.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"ethers": "^5.4.6",
"firebase": "^9.1.3",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
"inter-ui": "^3.13.1",
"jest-styled-components": "^7.0.5",
"luxon": "^1.25.0",
"microbundle": "^0.13.3",
"ms.macro": "^2.0.0",
"multicodec": "^3.0.1",
@@ -138,8 +138,8 @@
"@walletconnect/ethereum-provider": "1.6.5"
},
"scripts": {
"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/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
"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",
"prei18n:extract": "touch src/locales/en-US.po",
@@ -153,12 +153,6 @@
"bundle": "microbundle --tsconfig tsconfig.lib.json src/lib/index.tsx --format esm,cjs",
"cosmos": "open http://localhost:5000 && cross-env FAST_REFRESH=false cosmos"
},
"eslintConfig": {
"extends": "react-app",
"ignorePatterns": [
"node_modules"
]
},
"browserslist": {
"production": [
">0.2%",

49
src/abis/erc1155.json Normal file
View 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
View 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"
}
]

View File

@@ -80,7 +80,7 @@ function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransa
)
}
function SubmitProposalTransactionSummary({}: { info: SubmitProposalTransactionInfo }) {
function SubmitProposalTransactionSummary(_: { info: SubmitProposalTransactionInfo }) {
return <Trans>Submit new proposal</Trans>
}
@@ -147,13 +147,13 @@ function WrapSummary({ info: { currencyAmountRaw, unwrapped } }: { info: WrapTra
}
}
function DepositLiquidityStakingSummary({}: { info: DepositLiquidityStakingTransactionInfo }) {
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 }) {
function WithdrawLiquidityStakingSummary(_: { info: WithdrawLiquidityStakingTransactionInfo }) {
return <Trans>Withdraw deposited liquidity</Trans>
}

View File

@@ -1,23 +1,20 @@
import { Trans } from '@lingui/macro'
import { AbstractConnector } from '@web3-react/abstract-connector'
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 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 { ReactComponent as Close } from '../../assets/images/x.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
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, TYPE } from '../../theme'
import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
import { shortenAddress } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonSecondary } from '../Button'
import Identicon from '../Identicon'
import StatusIcon from '../Identicon/StatusIcon'
import { AutoRow } from '../Row'
import Copy from './Copy'
import Transaction from './Transaction'
@@ -179,6 +176,23 @@ const IconWrapper = styled.div<{ size?: number }>`
`};
`
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
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 +258,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 +302,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 +378,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 +390,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>
)}
</>

View File

@@ -1,11 +1,12 @@
import { Trans } from '@lingui/macro'
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { t } from '@lingui/macro'
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'
@@ -107,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)}

View File

@@ -315,8 +315,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;
@@ -325,11 +325,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)`

View File

@@ -4,7 +4,7 @@ import HoverInlineText from 'components/HoverInlineText'
import { useMemo } from 'react'
import useTheme from '../../hooks/useTheme'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { warningSeverity } from '../../utils/prices'
export function FiatValue({
@@ -25,7 +25,7 @@ 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.text2 : theme.text4}>
{fiatValue ? (
<Trans>
~$ <HoverInlineText text={fiatValue?.toSignificant(6, { groupSeparator: ',' })} />
@@ -39,6 +39,6 @@ export function FiatValue({
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
</span>
) : null}
</TYPE.body>
</ThemedText.Body>
)
}

View File

@@ -13,7 +13,7 @@ import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import useTheme from '../../hooks/useTheme'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { ButtonGray } from '../Button'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
@@ -212,9 +212,9 @@ 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>
)}
@@ -271,7 +271,7 @@ export default function CurrencyInputPanel({
<RowBetween>
{account ? (
<RowFixed style={{ height: '17px' }}>
<TYPE.body
<ThemedText.Body
onClick={onMax}
color={theme.text2}
fontWeight={400}
@@ -287,7 +287,7 @@ export default function CurrencyInputPanel({
</Trans>
)
) : null}
</TYPE.body>
</ThemedText.Body>
{showMaxButton && selectedCurrencyBalance ? (
<StyledBalanceMax onClick={onMax}>
<Trans>(Max)</Trans>

View File

@@ -4,7 +4,7 @@ import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import store, { AppState } from '../../state'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { userAgent } from '../../utils/userAgent'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
@@ -47,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)
@@ -67,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 (
@@ -74,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>
@@ -121,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'

View 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>
)
}

View 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>
)
}

View File

@@ -1,20 +1,24 @@
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
import { ButtonGray } from 'components/Button'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import { RowBetween } from 'components/Row'
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
import { PoolState, usePools } from 'hooks/usePools'
import usePrevious from 'hooks/usePrevious'
import { useActiveWeb3React } from 'hooks/web3'
import { DynamicSection } from 'pages/AddLiquidity/styled'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import ReactGA from 'react-ga'
import { Box } from 'rebass'
import styled, { keyframes } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { FeeOption } from './FeeOption'
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
import { FEE_AMOUNT_DETAIL } from './shared'
const pulse = (color: string) => keyframes`
0% {
@@ -29,60 +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>,
},
}
function FeeTierPercentageBadge({
feeAmount,
distributions,
poolState,
}: {
feeAmount: FeeAmount
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
poolState: PoolState
}) {
return (
<Badge>
<TYPE.label fontSize={12}>
{!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>
)}
</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,
@@ -97,16 +59,19 @@ 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 = useMemo(
const poolsByFeeTier: Record<FeeAmount, PoolState> = useMemo(
() =>
pools.reduce(
(acc, [curPoolState, curPool]) => {
@@ -118,6 +83,7 @@ export default function FeeSelector({
},
{
// 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,
@@ -134,7 +100,7 @@ export default function FeeSelector({
const recommended = useRef(false)
const handleFeePoolSelectWithEvent = useCallback(
(fee) => {
(fee: FeeAmount) => {
ReactGA.event({
category: 'FeePoolSelect',
action: 'Manual',
@@ -183,18 +149,18 @@ 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 && (
<FeeTierPercentageBadge
@@ -214,81 +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
{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}
feeAmount={FeeAmount.LOW}
poolState={poolsByFeeTier[FeeAmount.LOW]}
poolState={poolsByFeeTier[_feeAmount]}
key={i}
/>
)}
</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
distributions={distributions}
feeAmount={FeeAmount.MEDIUM}
poolState={poolsByFeeTier[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
distributions={distributions}
feeAmount={FeeAmount.HIGH}
poolState={poolsByFeeTier[FeeAmount.HIGH]}
/>
)}
</AutoColumn>
</ButtonRadioChecked>
</RowBetween>
)
}
return null
})}
</Select>
)}
</DynamicSection>
</AutoColumn>

View 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,
},
}

View File

@@ -1,11 +1,14 @@
import { CHAIN_INFO } from 'constants/chains'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useMachineTimeMs from 'hooks/useMachineTime'
import { useActiveWeb3React } from 'hooks/web3'
import ms from 'ms.macro'
import { useEffect, useState } from 'react'
import { useAppSelector } from 'state/hooks'
import { useBlockNumber } from 'state/application/hooks'
import styled, { keyframes } from 'styled-components/macro'
import { ExternalLink, ThemedText } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import { useActiveWeb3React } from '../../hooks/web3'
import { useBlockNumber } from '../../state/application/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ChainConnectivityWarning } from './ChainConnectivityWarning'
const StyledPolling = styled.div<{ warning: boolean }>`
@@ -22,7 +25,7 @@ const StyledPolling = styled.div<{ warning: boolean }>`
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 {
@@ -68,12 +71,21 @@ const Spinner = styled.div<{ warning: boolean }>`
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 chainConnectivityWarning = useAppSelector((state) => state.application.chainConnectivityWarning)
const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
const blockTime = useCurrentBlockTimestamp()
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(
() => {
@@ -98,20 +110,14 @@ export default function Polling() {
<ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
>
<StyledPolling
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
warning={chainConnectivityWarning}
>
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} warning={warning}>
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}&ensp;
</StyledPollingNumber>
<StyledPollingDot warning={chainConnectivityWarning}>
{isMounting && <Spinner warning={chainConnectivityWarning} />}
</StyledPollingDot>{' '}
<StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
</StyledPolling>
</ExternalLink>
{chainConnectivityWarning && <ChainConnectivityWarning />}
{warning && <ChainConnectivityWarning />}
</>
)
}

View File

@@ -14,7 +14,7 @@ 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 { ExternalLink, StyledInternalLink, ThemedText, UniTokenAnimated } from '../../theme'
import { computeUniCirculation } from '../../utils/computeUniCirculation'
import { AutoColumn } from '../Column'
import { Break, CardBGImage, CardNoise, CardSection, DataCard } from '../earn/styled'
@@ -70,9 +70,9 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
<CardNoise />
<CardSection gap="md">
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>Your UNI Breakdown</Trans>
</TYPE.white>
</ThemedText.White>
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
</RowBetween>
</CardSection>
@@ -82,29 +82,29 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
<CardSection gap="sm">
<AutoColumn gap="md" justify="center">
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
<TYPE.white fontSize={48} fontWeight={600} color="white">
<ThemedText.White fontSize={48} fontWeight={600} color="white">
{total?.toFixed(2, { groupSeparator: ',' })}
</TYPE.white>
</ThemedText.White>
</AutoColumn>
<AutoColumn gap="md">
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>Balance:</Trans>
</TYPE.white>
<TYPE.white color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</TYPE.white>
</ThemedText.White>
<ThemedText.White color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</ThemedText.White>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>Unclaimed:</Trans>
</TYPE.white>
<TYPE.white color="white">
</ThemedText.White>
<ThemedText.White color="white">
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
{uniToClaim && uniToClaim.greaterThan('0') && (
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
<Trans>(claim)</Trans>
</StyledInternalLink>
)}
</TYPE.white>
</ThemedText.White>
</RowBetween>
</AutoColumn>
</CardSection>
@@ -114,22 +114,22 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
<CardSection gap="sm">
<AutoColumn gap="md">
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>UNI price:</Trans>
</TYPE.white>
<TYPE.white color="white">${uniPrice?.toFixed(2) ?? '-'}</TYPE.white>
</ThemedText.White>
<ThemedText.White color="white">${uniPrice?.toFixed(2) ?? '-'}</ThemedText.White>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>UNI in circulation:</Trans>
</TYPE.white>
<TYPE.white color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
</ThemedText.White>
<ThemedText.White color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<ThemedText.White color="white">
<Trans>Total Supply</Trans>
</TYPE.white>
<TYPE.white color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
</ThemedText.White>
<ThemedText.White color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
</RowBetween>
{uni && uni.chainId === 1 ? (
<ExternalLink href={`${infoLink}/token/${uni.address}`}>

View File

@@ -15,7 +15,7 @@ import styled from 'styled-components/macro'
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import ClaimModal from '../claim/ClaimModal'
import { CardNoise } from '../earn/styled'
import Menu from '../Menu'
@@ -309,7 +309,7 @@ export default function Header() {
{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>
@@ -317,7 +317,7 @@ export default function Header() {
) : (
<Trans>Claim UNI</Trans>
)}
</TYPE.white>
</ThemedText.White>
</UNIAmount>
<CardNoise />
</UNIWrapper>

View File

@@ -0,0 +1,25 @@
import { AbstractConnector } from '@web3-react/abstract-connector'
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 }) {
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
}
}

View File

@@ -1,32 +1,49 @@
import Davatar, { Image } from '@davatar/react'
import { useMemo } from 'react'
import jazzicon from '@metamask/jazzicon'
import useENSAvatar from 'hooks/useENSAvatar'
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
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 { account, library } = useActiveWeb3React()
const { account } = useActiveWeb3React()
const { avatar } = useENSAvatar(account ?? undefined)
const [fetchable, setFetchable] = useState(true)
// restrict usage of Davatar until it stops sending 3p requests
// see https://github.com/metaphor-xyz/davatar-helpers/issues/18
const supportsENS = useMemo(() => {
return ([1, 3, 4, 5] as Array<number | undefined>).includes(library?.network?.chainId)
}, [library])
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 () => {
current?.removeChild(icon)
}
}
return
}, [icon, iconRef])
return (
<StyledIdenticonContainer>
{account && supportsENS ? (
<Davatar address={account} size={16} provider={library} />
<StyledIdenticon>
{avatar && fetchable ? (
<StyledAvatar alt="avatar" src={avatar} onError={() => setFetchable(false)}></StyledAvatar>
) : (
<Image address={account} size={16} />
<span ref={iconRef} />
)}
</StyledIdenticonContainer>
</StyledIdenticon>
)
}

View File

@@ -6,7 +6,7 @@ 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 { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { Input as NumericalInput } from '../NumericalInput'
@@ -57,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;
`

View File

@@ -37,7 +37,7 @@ export const Area = ({
.y0(yScale(0))(
series.filter((d) => {
const value = xScale(xValue(d))
return value > 0 && value <= innerWidth
return value > 0 && value <= window.innerWidth
}) as Iterable<[number, number]>
) ?? undefined
}

View File

@@ -14,12 +14,18 @@ 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 { 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,
@@ -52,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>
)

View File

@@ -1,7 +1,7 @@
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { L2_CHAIN_IDS } from 'constants/chains'
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
import { useActiveLocale } from 'hooks/useActiveLocale'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
@@ -10,13 +10,13 @@ import {
BookOpen,
Check,
ChevronLeft,
Code,
Coffee,
FileText,
Globe,
HelpCircle,
Info,
MessageCircle,
Moon,
PieChart,
Sun,
} from 'react-feather'
import { Link } from 'react-router-dom'
@@ -179,8 +179,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)
@@ -219,7 +217,6 @@ export default function Menu() {
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()
@@ -252,17 +249,17 @@ export default function Menu() {
</div>
<Info opacity={0.6} size={16} />
</MenuItem>
<MenuItem href="https://docs.uniswap.org/">
<MenuItem href="https://help.uniswap.org/">
<div>
<Trans>Docs</Trans>
<Trans>Help Center</Trans>
</div>
<BookOpen opacity={0.6} size={16} />
<HelpCircle opacity={0.6} size={16} />
</MenuItem>
<MenuItem href={CODE_LINK}>
<MenuItem href="https://uniswap.canny.io/feature-requests">
<div>
<Trans>Code</Trans>
<Trans>Request Features</Trans>
</div>
<Code opacity={0.6} size={16} />
<Coffee opacity={0.6} size={16} />
</MenuItem>
<MenuItem href="https://discord.gg/FCfyBSbCU5">
<div>
@@ -270,12 +267,6 @@ export default function Menu() {
</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>
@@ -286,6 +277,12 @@ export default function Menu() {
<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>

View File

@@ -5,7 +5,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { CloseIcon, CustomLightSpinner, TYPE } from '../../theme'
import { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn, ColumnCenter } from '../Column'
@@ -32,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>
)
@@ -68,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>

View File

@@ -10,7 +10,7 @@ import { useAppDispatch } from 'state/hooks'
import { resetMintState } from 'state/mint/actions'
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import Row, { RowBetween } from '../Row'
import SettingsTab from '../Settings'
@@ -136,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' }}
@@ -148,7 +148,7 @@ export function AddRemoveTabs({
) : (
<Trans>Remove Liquidity</Trans>
)}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<Box style={{ marginRight: '.5rem' }}>{children}</Box>
<SettingsTab placeholderSlippage={defaultSlippage} />
</RowBetween>

View File

@@ -260,7 +260,7 @@ export function NetworkAlert(props: NetworkAlertProps) {
</Header>
<Body>
<Trans>
To starting trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
To start trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
release and learn about the risks before using {info.label}.
</Trans>
</Body>

View File

@@ -6,7 +6,6 @@ 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 {
useModalOpen,
@@ -16,7 +15,8 @@ import {
} 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}>

View File

@@ -4,8 +4,8 @@ import styled, { ThemeContext } from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTransaction } from '../../state/transactions/hooks'
import { TYPE } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { ThemedText } from '../../theme'
import { ExternalLink } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
import { AutoColumn } from '../Column'
@@ -30,9 +30,9 @@ export default function TransactionPopup({ hash }: { hash: string }) {
{success ? <CheckCircle color={theme.green1} size={24} /> : <AlertCircle color={theme.red1} size={24} />}
</div>
<AutoColumn gap="8px">
<TYPE.body fontWeight={500}>
<ThemedText.Body fontWeight={500}>
<TransactionSummary info={tx.info} />
</TYPE.body>
</ThemedText.Body>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
View on Explorer

View File

@@ -14,7 +14,7 @@ import { useColor } from '../../hooks/useColor'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
@@ -142,7 +142,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
</GreyCard>
) : (
<LightCard>
<TYPE.subHeader style={{ textAlign: 'center' }}>
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
<span role="img" aria-label="wizard-icon">
</span>{' '}
@@ -150,7 +150,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
By adding liquidity you&apos;ll earn 0.3% of all trades on this pair proportional to your share of the
pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
</Trans>{' '}
</TYPE.subHeader>
</ThemedText.SubHeader>
</LightCard>
)}
</>

View File

@@ -13,7 +13,7 @@ import JSBI from 'jsbi'
import { ReactNode, useCallback, useContext, useState } from 'react'
import { Bound } from 'state/mint/v3/actions'
import { ThemeContext } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/unwrappedToken'
@@ -70,9 +70,9 @@ export const PositionPreview = ({
size={24}
margin={true}
/>
<TYPE.label ml="10px" fontSize="24px">
<ThemedText.Label ml="10px" fontSize="24px">
{currency0?.symbol} / {currency1?.symbol}
</TYPE.label>
</ThemedText.Label>
</RowFixed>
<RangeBadge removed={removed} inRange={inRange} />
</RowBetween>
@@ -82,36 +82,36 @@ export const PositionPreview = ({
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currency0} />
<TYPE.label ml="8px">{currency0?.symbol}</TYPE.label>
<ThemedText.Label ml="8px">{currency0?.symbol}</ThemedText.Label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{position.amount0.toSignificant(4)}</TYPE.label>
<ThemedText.Label mr="8px">{position.amount0.toSignificant(4)}</ThemedText.Label>
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currency1} />
<TYPE.label ml="8px">{currency1?.symbol}</TYPE.label>
<ThemedText.Label ml="8px">{currency1?.symbol}</ThemedText.Label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{position.amount1.toSignificant(4)}</TYPE.label>
<ThemedText.Label mr="8px">{position.amount1.toSignificant(4)}</ThemedText.Label>
</RowFixed>
</RowBetween>
<Break />
<RowBetween>
<TYPE.label>
<ThemedText.Label>
<Trans>Fee Tier</Trans>
</TYPE.label>
<TYPE.label>
</ThemedText.Label>
<ThemedText.Label>
<Trans>{position?.pool?.fee / 10000}%</Trans>
</TYPE.label>
</ThemedText.Label>
</RowBetween>
</AutoColumn>
</LightCard>
<AutoColumn gap="md">
<RowBetween>
{title ? <TYPE.main>{title}</TYPE.main> : <div />}
{title ? <ThemedText.Main>{title}</ThemedText.Main> : <div />}
<RateToggle
currencyA={sorted ? currency0 : currency1}
currencyB={sorted ? currency1 : currency0}
@@ -122,57 +122,57 @@ export const PositionPreview = ({
<RowBetween>
<LightCard width="48%" padding="8px">
<AutoColumn gap="4px" justify="center">
<TYPE.main fontSize="12px">
<ThemedText.Main fontSize="12px">
<Trans>Min Price</Trans>
</TYPE.main>
<TYPE.mediumHeader textAlign="center">{`${formatTickPrice(
</ThemedText.Main>
<ThemedText.MediumHeader textAlign="center">{`${formatTickPrice(
priceLower,
ticksAtLimit,
Bound.LOWER
)}`}</TYPE.mediumHeader>
<TYPE.main textAlign="center" fontSize="12px">
)}`}</ThemedText.MediumHeader>
<ThemedText.Main textAlign="center" fontSize="12px">
<Trans>
{quoteCurrency.symbol} per {baseCurrency.symbol}
</Trans>
</TYPE.main>
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
</ThemedText.Main>
<ThemedText.Small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
<Trans>Your position will be 100% composed of {baseCurrency?.symbol} at this price</Trans>
</TYPE.small>
</ThemedText.Small>
</AutoColumn>
</LightCard>
<LightCard width="48%" padding="8px">
<AutoColumn gap="4px" justify="center">
<TYPE.main fontSize="12px">
<ThemedText.Main fontSize="12px">
<Trans>Max Price</Trans>
</TYPE.main>
<TYPE.mediumHeader textAlign="center">{`${formatTickPrice(
</ThemedText.Main>
<ThemedText.MediumHeader textAlign="center">{`${formatTickPrice(
priceUpper,
ticksAtLimit,
Bound.UPPER
)}`}</TYPE.mediumHeader>
<TYPE.main textAlign="center" fontSize="12px">
)}`}</ThemedText.MediumHeader>
<ThemedText.Main textAlign="center" fontSize="12px">
<Trans>
{quoteCurrency.symbol} per {baseCurrency.symbol}
</Trans>
</TYPE.main>
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
</ThemedText.Main>
<ThemedText.Small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
<Trans>Your position will be 100% composed of {quoteCurrency?.symbol} at this price</Trans>
</TYPE.small>
</ThemedText.Small>
</AutoColumn>
</LightCard>
</RowBetween>
<LightCard padding="12px ">
<AutoColumn gap="4px" justify="center">
<TYPE.main fontSize="12px">
<ThemedText.Main fontSize="12px">
<Trans>Current price</Trans>
</TYPE.main>
<TYPE.mediumHeader>{`${price.toSignificant(5)} `}</TYPE.mediumHeader>
<TYPE.main textAlign="center" fontSize="12px">
</ThemedText.Main>
<ThemedText.MediumHeader>{`${price.toSignificant(5)} `}</ThemedText.MediumHeader>
<ThemedText.Main textAlign="center" fontSize="12px">
<Trans>
{quoteCurrency.symbol} per {baseCurrency.symbol}
</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoColumn>
</LightCard>
</AutoColumn>

View File

@@ -5,7 +5,7 @@ import { useEffect, useRef } from 'react'
import { ArrowDown, Info, X } from 'react-feather'
import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import { ExternalLink, TYPE } from 'theme'
import { ExternalLink, ThemedText } from 'theme'
import { isMobile } from 'utils/userAgent'
import { useModalOpen, useTogglePrivacyPolicy } from '../../state/application/hooks'
@@ -58,9 +58,15 @@ const EXTERNAL_APIS = [
{
name: 'TRM Labs',
description: (
<Trans>
The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.
</Trans>
<>
<Trans>
The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance
reasons.
</Trans>{' '}
<ExternalLink href="https://help.uniswap.org/en/articles/5675203-terms-of-service-faq">
<Trans>Learn more</Trans>
</ExternalLink>
</>
),
},
{
@@ -91,9 +97,9 @@ export function PrivacyPolicyModal() {
<Modal isOpen={open} onDismiss={() => toggle()}>
<AutoColumn gap="12px" ref={node as any}>
<RowBetween padding="1rem 1rem 0.5rem 1rem">
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Legal & Privacy</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<HoverText onClick={() => toggle()}>
<X size={24} />
</HoverText>
@@ -122,9 +128,9 @@ export function PrivacyPolicy() {
<RowBetween>
<AutoRow gap="4px">
<Info size={20} />
<TYPE.main fontSize={14} color={'primaryText1'}>
<ThemedText.Main fontSize={14} color={'primaryText1'}>
<Trans>Uniswap Labs&apos; Terms of Service</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoRow>
<StyledLinkOut size={20} />
</RowBetween>
@@ -135,29 +141,29 @@ export function PrivacyPolicy() {
<RowBetween>
<AutoRow gap="4px">
<Info size={20} />
<TYPE.main fontSize={14} color={'primaryText1'}>
<ThemedText.Main fontSize={14} color={'primaryText1'}>
<Trans>Protocol Disclaimer</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoRow>
<StyledLinkOut size={20} />
</RowBetween>
</ExternalLink>
</StyledExternalCard>
</AutoColumn>
<TYPE.main fontSize={14}>
<ThemedText.Main fontSize={14}>
<Trans>This app uses the following third-party APIs:</Trans>
</TYPE.main>
</ThemedText.Main>
<AutoColumn gap="12px">
{EXTERNAL_APIS.map(({ name, description }, i) => (
<DarkGreyCard key={i}>
<AutoColumn gap="8px">
<AutoRow gap="4px">
<Info size={18} />
<TYPE.main fontSize={14} color={'text1'}>
<ThemedText.Main fontSize={14} color={'text1'}>
{name}
</TYPE.main>
</ThemedText.Main>
</AutoRow>
<TYPE.main fontSize={14}>{description}</TYPE.main>
<ThemedText.Main fontSize={14}>{description}</ThemedText.Main>
</AutoColumn>
</DarkGreyCard>
))}

View File

@@ -2,7 +2,7 @@ import { useContext } from 'react'
import styled from 'styled-components/macro'
import { ThemeContext } from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
const Wrapper = styled(AutoColumn)`
@@ -65,7 +65,7 @@ export default function ProgressCircles({ steps, disabled = false, ...rest }: Pr
<Circle confirmed={step} disabled={disabled || (!steps[i - 1] && i !== 0)}>
{step ? '✓' : i + 1 + '.'}
</Circle>
<TYPE.main color={theme.text4}>|</TYPE.main>
<ThemedText.Main color={theme.text4}>|</ThemedText.Main>
</CircleRow>
)
})}

View File

@@ -4,7 +4,7 @@ import { AutoRow } from 'components/Row'
import React from 'react'
import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
const Button = styled(ButtonOutlined).attrs(() => ({
padding: '8px',
@@ -26,9 +26,9 @@ export default function PresetsButtons({ setFullRange }: { setFullRange: () => v
})
}}
>
<TYPE.body fontSize={12}>
<ThemedText.Body fontSize={12}>
<Trans>Full Range</Trans>
</TYPE.body>
</ThemedText.Body>
</Button>
</AutoRow>
)

View File

@@ -10,7 +10,7 @@ const percent = (strings: TemplateStringsArray) => new Percent(parseInt(strings[
const singleRoute: RoutingDiagramEntry = { percent: percent`100`, path: [[USDC, DAI, FeeAmount.LOW]] }
const multiRoute: RoutingDiagramEntry[] = [
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOW]] },
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOWEST]] },
{
percent: percent`25`,
path: [

View File

@@ -7,7 +7,7 @@ import Row, { AutoRow } from 'components/Row'
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
import { Box } from 'rebass'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
@@ -93,9 +93,9 @@ function Route({ percent, path }: { percent: RoutingDiagramEntry['percent']; pat
<DotColor />
</DottedLine>
<OpaqueBadge>
<TYPE.small fontSize={12} style={{ wordBreak: 'normal' }}>
<ThemedText.Small fontSize={12} style={{ wordBreak: 'normal' }}>
{percent.toSignificant(2)}%
</TYPE.small>
</ThemedText.Small>
</OpaqueBadge>
<AutoRow gap="1px" width="100%" style={{ justifyContent: 'space-evenly', zIndex: 2 }}>
@@ -116,7 +116,7 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren
<Box margin="0 5px 0 10px">
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
</Box>
<TYPE.small fontSize={12}>{feeAmount / 10000}%</TYPE.small>
<ThemedText.Small fontSize={12}>{feeAmount / 10000}%</ThemedText.Small>
</PoolBadge>
)
}

View File

@@ -47,7 +47,7 @@ exports[`renders multi route 1`] = `
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
>
0.05%
0.01%
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import { ButtonPrimary } from 'components/Button'
import { AlertCircle, ArrowLeft } from 'react-feather'
import styled from 'styled-components/macro'
import { CloseIcon, ThemedText } from 'theme'
import TokenImportCard from './TokenImportCard'
const Wrapper = styled.div`
align-items: center;
display: flex;
flex-direction: column;
flex: 1 1 auto;
height: 100%;
width: 100%;
`
const Button = styled(ButtonPrimary)`
margin-top: 1em;
padding: 10px 1em;
`
const Content = styled.div`
padding: 1em;
`
const Copy = styled(ThemedText.Body)`
text-align: center;
margin: 0 2em 1em !important;
font-weight: 400;
font-size: 16px;
`
const Header = styled.div`
align-items: center;
display: flex;
gap: 14px;
justify-content: space-between;
padding: 20px;
width: 100%;
`
const Icon = styled(AlertCircle)`
stroke: ${({ theme }) => theme.text2};
width: 48px;
height: 48px;
`
interface BlockedTokenProps {
onBack: (() => void) | undefined
onDismiss: (() => void) | undefined
blockedTokens: Token[]
}
const BlockedToken = ({ onBack, onDismiss, blockedTokens }: BlockedTokenProps) => (
<Wrapper>
<Header>
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
<ThemedText.MediumHeader>
<Trans>Token not supported</Trans>
</ThemedText.MediumHeader>
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
</Header>
<Icon />
<Content>
<Copy>
<Trans>This token is not supported in the Uniswap Labs app</Trans>
</Copy>
<TokenImportCard token={blockedTokens[0]} />
<Button disabled>
<Trans>Import</Trans>
</Button>
</Content>
</Wrapper>
)
export default BlockedToken

View File

@@ -14,7 +14,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
import { useCombinedActiveList } from '../../state/lists/hooks'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { isTokenOnList } from '../../utils'
import Column from '../Column'
import CurrencyLogo from '../CurrencyLogo'
@@ -135,13 +135,13 @@ function CurrencyRow({
<Text title={currency.name} fontWeight={500}>
{currency.symbol}
</Text>
<TYPE.darkGray ml="0px" fontSize={'12px'} fontWeight={300}>
<ThemedText.DarkGray ml="0px" fontSize={'12px'} fontWeight={300}>
{!currency.isNative && !isOnSelectedList && customAdded ? (
<Trans>{currency.name} Added by user</Trans>
) : (
currency.name
)}
</TYPE.darkGray>
</ThemedText.DarkGray>
</Column>
<TokenTags currency={currency} />
{showCurrencyAmount && (
@@ -167,9 +167,9 @@ function BreakLineComponent({ style }: { style: CSSProperties }) {
<RowBetween>
<RowFixed>
<TokenListLogoWrapper src={TokenListLogo} />
<TYPE.main ml="6px" fontSize="12px" color={theme.text1}>
<ThemedText.Main ml="6px" fontSize="12px" color={theme.text1}>
<Trans>Expanded results from inactive Token Lists</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
<QuestionHelper
text={

View File

@@ -16,7 +16,7 @@ import styled from 'styled-components/macro'
import { ExtendedEther } from '../../constants/tokens'
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
import { useActiveWeb3React } from '../../hooks/web3'
import { ButtonText, CloseIcon, IconWrapper, TYPE } from '../../theme'
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
import { isAddress } from '../../utils'
import Column from '../Column'
import Row, { RowBetween, RowFixed } from '../Row'
@@ -224,9 +224,9 @@ export function CurrencySearch({
</div>
) : (
<Column style={{ padding: '20px', height: '100%' }}>
<TYPE.main color={theme.text3} textAlign="center" mb="20px">
<ThemedText.Main color={theme.text3} textAlign="center" mb="20px">
<Trans>No results found.</Trans>
</TYPE.main>
</ThemedText.Main>
</Column>
)}
<Footer>
@@ -236,9 +236,9 @@ export function CurrencySearch({
<IconWrapper size="16px" marginRight="6px" stroke={theme.primaryText1}>
<Edit />
</IconWrapper>
<TYPE.main color={theme.primaryText1}>
<ThemedText.Main color={theme.primaryText1}>
<Trans>Manage Token Lists</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
</ButtonText>
</Row>

View File

@@ -66,12 +66,19 @@ export default function CurrencySearchModal({
const [importList, setImportList] = useState<TokenList | undefined>()
const [listURL, setListUrl] = useState<string | undefined>()
const showImportView = useCallback(() => setModalView(CurrencyModalView.importToken), [setModalView])
const showManageView = useCallback(() => setModalView(CurrencyModalView.manage), [setModalView])
const handleBackImport = useCallback(
() => setModalView(prevView && prevView !== CurrencyModalView.importToken ? prevView : CurrencyModalView.search),
[setModalView, prevView]
)
// change min height if not searching
const minHeight = modalView === CurrencyModalView.importToken || modalView === CurrencyModalView.importList ? 40 : 80
return (
<Modal isOpen={isOpen} onDismiss={onDismiss} maxHeight={80} minHeight={minHeight}>
{modalView === CurrencyModalView.search ? (
let content = null
switch (modalView) {
case CurrencyModalView.search:
content = (
<CurrencySearch
isOpen={isOpen}
onDismiss={onDismiss}
@@ -81,23 +88,32 @@ export default function CurrencySearchModal({
showCommonBases={showCommonBases}
showCurrencyAmount={showCurrencyAmount}
disableNonToken={disableNonToken}
showImportView={() => setModalView(CurrencyModalView.importToken)}
showImportView={showImportView}
setImportToken={setImportToken}
showManageView={() => setModalView(CurrencyModalView.manage)}
showManageView={showManageView}
/>
) : modalView === CurrencyModalView.importToken && importToken ? (
<ImportToken
tokens={[importToken]}
onDismiss={onDismiss}
list={importToken instanceof WrappedTokenInfo ? importToken.list : undefined}
onBack={() =>
setModalView(prevView && prevView !== CurrencyModalView.importToken ? prevView : CurrencyModalView.search)
}
handleCurrencySelect={handleCurrencySelect}
/>
) : modalView === CurrencyModalView.importList && importList && listURL ? (
<ImportList list={importList} listURL={listURL} onDismiss={onDismiss} setModalView={setModalView} />
) : modalView === CurrencyModalView.manage ? (
)
break
case CurrencyModalView.importToken:
if (importToken) {
content = (
<ImportToken
tokens={[importToken]}
onDismiss={onDismiss}
list={importToken instanceof WrappedTokenInfo ? importToken.list : undefined}
onBack={handleBackImport}
handleCurrencySelect={handleCurrencySelect}
/>
)
}
break
case CurrencyModalView.importList:
if (importList && listURL) {
content = <ImportList list={importList} listURL={listURL} onDismiss={onDismiss} setModalView={setModalView} />
}
break
case CurrencyModalView.manage:
content = (
<Manage
onDismiss={onDismiss}
setModalView={setModalView}
@@ -105,9 +121,12 @@ export default function CurrencySearchModal({
setImportList={setImportList}
setListUrl={setListUrl}
/>
) : (
''
)}
)
break
}
return (
<Modal isOpen={isOpen} onDismiss={onDismiss} maxHeight={80} minHeight={minHeight}>
{content}
</Modal>
)
}

View File

@@ -16,9 +16,9 @@ import { useAppDispatch } from 'state/hooks'
import { enableList, removeList } from 'state/lists/actions'
import { useAllLists } from 'state/lists/hooks'
import styled from 'styled-components/macro'
import { CloseIcon, TYPE } from 'theme'
import { CloseIcon, ThemedText } from 'theme'
import { ExternalLink } from '../../theme/components'
import { ExternalLink } from '../../theme'
import { CurrencyModalView } from './CurrencySearchModal'
import { Checkbox, PaddedColumn, TextDot } from './styleds'
@@ -81,9 +81,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
<PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
<RowBetween>
<ArrowLeft style={{ cursor: 'pointer' }} onClick={() => setModalView(CurrencyModalView.manage)} />
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Import List</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<CloseIcon onClick={onDismiss} />
</RowBetween>
</PaddedColumn>
@@ -96,18 +96,18 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
{list.logoURI && <ListLogo logoURI={list.logoURI} size="40px" />}
<AutoColumn gap="sm" style={{ marginLeft: '20px' }}>
<RowFixed>
<TYPE.body fontWeight={600} mr="6px">
<ThemedText.Body fontWeight={600} mr="6px">
{list.name}
</TYPE.body>
</ThemedText.Body>
<TextDot />
<TYPE.main fontSize={'16px'} ml="6px">
<ThemedText.Main fontSize={'16px'} ml="6px">
<Trans>{list.tokens.length} tokens</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
<ExternalLink href={`https://tokenlists.org/token-list?url=${listURL}`}>
<TYPE.main fontSize={'12px'} color={theme.blue1}>
<ThemedText.Main fontSize={'12px'} color={theme.blue1}>
{listURL}
</TYPE.main>
</ThemedText.Main>
</ExternalLink>
</AutoColumn>
</RowFixed>
@@ -116,22 +116,22 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
<Card style={{ backgroundColor: transparentize(0.8, theme.red1) }}>
<AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
<AlertTriangle stroke={theme.red1} size={32} />
<TYPE.body fontWeight={500} fontSize={20} color={theme.red1}>
<ThemedText.Body fontWeight={500} fontSize={20} color={theme.red1}>
<Trans>Import at your own risk</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
<AutoColumn style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
<TYPE.body fontWeight={500} color={theme.red1}>
<ThemedText.Body fontWeight={500} color={theme.red1}>
<Trans>
By adding this list you are implicitly trusting that the data is correct. Anyone can create a list,
including creating fake versions of existing lists and lists that claim to represent projects that do
not have one.
</Trans>
</TYPE.body>
<TYPE.body fontWeight={600} color={theme.red1}>
</ThemedText.Body>
<ThemedText.Body fontWeight={600} color={theme.red1}>
<Trans>If you purchase a token from this list, you may not be able to sell it back.</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
<AutoRow justify="center" style={{ cursor: 'pointer' }} onClick={() => setConfirmed(!confirmed)}>
<Checkbox
@@ -140,9 +140,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
checked={confirmed}
onChange={() => setConfirmed(!confirmed)}
/>
<TYPE.body ml="10px" fontSize="16px" color={theme.red1} fontWeight={500}>
<ThemedText.Body ml="10px" fontSize="16px" color={theme.red1} fontWeight={500}>
<Trans>I understand</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoRow>
</Card>
@@ -156,9 +156,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
<Trans>Import</Trans>
</ButtonPrimary>
{addError ? (
<TYPE.error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
<ThemedText.Error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
{addError}
</TYPE.error>
</ThemedText.Error>
) : null}
</AutoColumn>
{/* </Card> */}

View File

@@ -10,7 +10,7 @@ import useTheme from 'hooks/useTheme'
import { CSSProperties } from 'react'
import { CheckCircle } from 'react-feather'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
@@ -67,16 +67,16 @@ export default function ImportRow({
<CurrencyLogo currency={token} size={'24px'} style={{ opacity: dim ? '0.6' : '1' }} />
<AutoColumn gap="4px" style={{ opacity: dim ? '0.6' : '1' }}>
<AutoRow>
<TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
<TYPE.darkGray ml="8px" fontWeight={300}>
<ThemedText.Body fontWeight={500}>{token.symbol}</ThemedText.Body>
<ThemedText.DarkGray ml="8px" fontWeight={300}>
<NameOverflow title={token.name}>{token.name}</NameOverflow>
</TYPE.darkGray>
</ThemedText.DarkGray>
</AutoRow>
{list && list.logoURI && (
<RowFixed>
<TYPE.small mr="4px" color={theme.text3}>
<ThemedText.Small mr="4px" color={theme.text3}>
<Trans>via {list.name} </Trans>
</TYPE.small>
</ThemedText.Small>
<ListLogo logoURI={list.logoURI} size="12px" />
</RowFixed>
)}
@@ -97,9 +97,9 @@ export default function ImportRow({
) : (
<RowFixed style={{ minWidth: 'fit-content' }}>
<CheckIcon />
<TYPE.main color={theme.green1}>
<ThemedText.Main color={theme.green1}>
<Trans>Active</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
)}
</TokenSection>

View File

@@ -2,23 +2,19 @@ import { Plural, Trans } from '@lingui/macro'
import { Currency, Token } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists'
import { ButtonPrimary } from 'components/Button'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import ListLogo from 'components/ListLogo'
import { RowBetween, RowFixed } from 'components/Row'
import { RowBetween } from 'components/Row'
import { SectionBreak } from 'components/swap/styleds'
import { useUnsupportedTokens } from 'hooks/Tokens'
import useTheme from 'hooks/useTheme'
import { useActiveWeb3React } from 'hooks/web3'
import { transparentize } from 'polished'
import { AlertCircle, ArrowLeft } from 'react-feather'
import { useAddUserToken } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { CloseIcon, TYPE } from 'theme'
import { CloseIcon, ThemedText } from 'theme'
import { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import BlockedToken from './BlockedToken'
import { PaddedColumn } from './styleds'
import TokenImportCard from './TokenImportCard'
const Wrapper = styled.div`
position: relative;
@@ -26,21 +22,6 @@ const Wrapper = styled.div`
overflow: auto;
`
const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
background-color: ${({ theme, highWarning }) =>
highWarning ? transparentize(0.8, theme.red1) : transparentize(0.8, theme.yellow2)};
width: fit-content;
`
const AddressText = styled(TYPE.blue)`
font-size: 12px;
word-break: break-all;
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 10px;
`}
`
interface ImportProps {
tokens: Token[]
list?: TokenList
@@ -49,21 +30,26 @@ interface ImportProps {
handleCurrencySelect?: (currency: Currency) => void
}
export function ImportToken({ tokens, list, onBack, onDismiss, handleCurrencySelect }: ImportProps) {
export function ImportToken(props: ImportProps) {
const { tokens, list, onBack, onDismiss, handleCurrencySelect } = props
const theme = useTheme()
const { chainId } = useActiveWeb3React()
const addToken = useAddUserToken()
const unsupportedTokens = useUnsupportedTokens()
const unsupportedSet = new Set(Object.keys(unsupportedTokens))
const intersection = new Set(tokens.filter((token) => unsupportedSet.has(token.address)))
if (intersection.size > 0) {
return <BlockedToken onBack={onBack} onDismiss={onDismiss} blockedTokens={Array.from(intersection)} />
}
return (
<Wrapper>
<PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
<RowBetween>
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Plural value={tokens.length} one="Import token" other="Import tokens" />
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
</RowBetween>
</PaddedColumn>
@@ -71,59 +57,16 @@ export function ImportToken({ tokens, list, onBack, onDismiss, handleCurrencySel
<AutoColumn gap="md" style={{ marginBottom: '32px', padding: '1rem' }}>
<AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', padding: '1rem' }}>
<AlertCircle size={48} stroke={theme.text2} strokeWidth={1} />
<TYPE.body fontWeight={400} fontSize={16}>
<ThemedText.Body fontWeight={400} fontSize={16}>
<Trans>
This token doesn&apos;t appear on the active token list(s). Make sure this is the token that you want to
trade.
</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
{tokens.map((token) => {
return (
<Card
backgroundColor={theme.bg2}
key={'import' + token.address}
className=".token-warning-container"
padding="2rem"
>
<AutoColumn gap="10px" justify="center">
<CurrencyLogo currency={token} size={'32px'} />
<AutoColumn gap="4px" justify="center">
<TYPE.body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
{token.symbol}
</TYPE.body>
<TYPE.darkGray fontWeight={400} fontSize={14}>
{token.name}
</TYPE.darkGray>
</AutoColumn>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<AddressText fontSize={12}>{token.address}</AddressText>
</ExternalLink>
)}
{list !== undefined ? (
<RowFixed>
{list.logoURI && <ListLogo logoURI={list.logoURI} size="16px" />}
<TYPE.small ml="6px" fontSize={14} color={theme.text3}>
<Trans>via {list.name} token list</Trans>
</TYPE.small>
</RowFixed>
) : (
<WarningWrapper $borderRadius="4px" padding="4px" highWarning={true}>
<RowFixed>
<AlertCircle stroke={theme.red1} size="10px" />
<TYPE.body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
<Trans>Unknown Source</Trans>
</TYPE.body>
</RowFixed>
</WarningWrapper>
)}
</AutoColumn>
</Card>
)
})}
{tokens.map((token) => (
<TokenImportCard token={token} list={list} key={'import' + token.address} />
))}
<ButtonPrimary
altDisabledStyle={true}
$borderRadius="20px"

View File

@@ -18,7 +18,7 @@ import useTheme from '../../hooks/useTheme'
import useToggle from '../../hooks/useToggle'
import { acceptListUpdate, disableList, enableList, removeList } from '../../state/lists/actions'
import { useActiveListUrls, useAllLists, useIsListActive } from '../../state/lists/hooks'
import { ExternalLink, IconWrapper, LinkStyledButton, TYPE } from '../../theme'
import { ExternalLink, IconWrapper, LinkStyledButton, ThemedText } from '../../theme'
import listVersionLabel from '../../utils/listVersionLabel'
import { parseENSAddress } from '../../utils/parseENSAddress'
import uriToHttp from '../../utils/uriToHttp'
@@ -75,7 +75,7 @@ const StyledTitleText = styled.div<{ active: boolean }>`
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
`
const StyledListUrlText = styled(TYPE.main)<{ active: boolean }>`
const StyledListUrlText = styled(ThemedText.Main)<{ active: boolean }>`
font-size: 12px;
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
`
@@ -361,9 +361,9 @@ export function ManageLists({
/>
</Row>
{addError ? (
<TYPE.error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
<ThemedText.Error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
{addError}
</TYPE.error>
</ThemedText.Error>
) : null}
</PaddedColumn>
{tempList && (
@@ -373,10 +373,10 @@ export function ManageLists({
<RowFixed>
{tempList.logoURI && <ListLogo logoURI={tempList.logoURI} size="40px" />}
<AutoColumn gap="4px" style={{ marginLeft: '20px' }}>
<TYPE.body fontWeight={600}>{tempList.name}</TYPE.body>
<TYPE.main fontSize={'12px'}>
<ThemedText.Body fontWeight={600}>{tempList.name}</ThemedText.Body>
<ThemedText.Main fontSize={'12px'}>
<Trans>{tempList.tokens.length} tokens</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoColumn>
</RowFixed>
{isImported ? (
@@ -384,9 +384,9 @@ export function ManageLists({
<IconWrapper stroke={theme.text2} size="16px" marginRight={'10px'}>
<CheckCircle />
</IconWrapper>
<TYPE.body color={theme.text2}>
<ThemedText.Body color={theme.text2}>
<Trans>Loaded</Trans>
</TYPE.body>
</ThemedText.Body>
</RowFixed>
) : (
<ButtonPrimary

View File

@@ -9,7 +9,7 @@ import { useActiveWeb3React } from 'hooks/web3'
import { RefObject, useCallback, useMemo, useRef, useState } from 'react'
import { useRemoveUserAddedToken, useUserAddedTokens } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ButtonText, ExternalLink, ExternalLinkIcon, TrashIcon, TYPE } from 'theme'
import { ButtonText, ExternalLink, ExternalLinkIcon, ThemedText, TrashIcon } from 'theme'
import { isAddress } from 'utils'
import useTheme from '../../hooks/useTheme'
@@ -81,9 +81,9 @@ export default function ManageTokens({
<RowFixed>
<CurrencyLogo currency={token} size={'20px'} />
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<TYPE.main ml={'10px'} fontWeight={600}>
<ThemedText.Main ml={'10px'} fontWeight={600}>
{token.symbol}
</TYPE.main>
</ThemedText.Main>
</ExternalLink>
</RowFixed>
<RowFixed>
@@ -111,9 +111,9 @@ export default function ManageTokens({
/>
</Row>
{searchQuery !== '' && !isAddressSearch && (
<TYPE.error error={true}>
<ThemedText.Error error={true}>
<Trans>Enter valid token address</Trans>
</TYPE.error>
</ThemedText.Error>
)}
{searchToken && (
<Card backgroundColor={theme.bg2} padding="10px 0">
@@ -129,14 +129,14 @@ export default function ManageTokens({
<Separator />
<PaddedColumn gap="lg" style={{ overflow: 'auto', marginBottom: '10px' }}>
<RowBetween>
<TYPE.main fontWeight={600}>
<ThemedText.Main fontWeight={600}>
<Trans>{userAddedTokens?.length} Custom Tokens</Trans>
</TYPE.main>
</ThemedText.Main>
{userAddedTokens.length > 0 && (
<ButtonText onClick={handleRemoveAll}>
<TYPE.blue>
<ThemedText.Blue>
<Trans>Clear all</Trans>
</TYPE.blue>
</ThemedText.Blue>
</ButtonText>
)}
</RowBetween>
@@ -144,9 +144,9 @@ export default function ManageTokens({
</PaddedColumn>
</Column>
<Footer>
<TYPE.darkGray>
<ThemedText.DarkGray>
<Trans>Tip: Custom tokens are stored locally in your browser</Trans>
</TYPE.darkGray>
</ThemedText.DarkGray>
</Footer>
</Wrapper>
)

View File

@@ -0,0 +1,76 @@
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import ListLogo from 'components/ListLogo'
import { RowFixed } from 'components/Row'
import { useActiveWeb3React } from 'hooks/web3'
import { transparentize } from 'polished'
import { AlertCircle } from 'react-feather'
import styled, { useTheme } from 'styled-components/macro'
import { ExternalLink, ThemedText } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
background-color: ${({ theme, highWarning }) =>
highWarning ? transparentize(0.8, theme.red1) : transparentize(0.8, theme.yellow2)};
width: fit-content;
`
const AddressText = styled(ThemedText.Blue)`
font-size: 12px;
word-break: break-all;
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 10px;
`}
`
interface TokenImportCardProps {
list?: TokenList
token: Token
}
const TokenImportCard = ({ list, token }: TokenImportCardProps) => {
const theme = useTheme()
const { chainId } = useActiveWeb3React()
return (
<Card backgroundColor={theme.bg2} padding="2rem">
<AutoColumn gap="10px" justify="center">
<CurrencyLogo currency={token} size={'32px'} />
<AutoColumn gap="4px" justify="center">
<ThemedText.Body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
{token.symbol}
</ThemedText.Body>
<ThemedText.DarkGray fontWeight={400} fontSize={14}>
{token.name}
</ThemedText.DarkGray>
</AutoColumn>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
<AddressText fontSize={12}>{token.address}</AddressText>
</ExternalLink>
)}
{list !== undefined ? (
<RowFixed>
{list.logoURI && <ListLogo logoURI={list.logoURI} size="16px" />}
<ThemedText.Small ml="6px" fontSize={14} color={theme.text3}>
<Trans>via {list.name} token list</Trans>
</ThemedText.Small>
</RowFixed>
) : (
<WarningWrapper $borderRadius="4px" padding="4px" highWarning={true}>
<RowFixed>
<AlertCircle stroke={theme.red1} size="10px" />
<ThemedText.Body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
<Trans>Unknown Source</Trans>
</ThemedText.Body>
</RowFixed>
</WarningWrapper>
)}
</AutoColumn>
</Card>
)
}
export default TokenImportCard

View File

@@ -13,7 +13,7 @@ import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { useModalOpen, useToggleSettingsMenu } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { useClientSideRouter, useExpertModeManager } from '../../state/user/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { ButtonError } from '../Button'
import { AutoColumn } from '../Column'
import Modal from '../Modal'
@@ -203,9 +203,9 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
{chainId === SupportedChainId.MAINNET && (
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Auto Router</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={<Trans>Use the Uniswap Labs API to get better pricing through a more efficient route.</Trans>}
/>
@@ -226,9 +226,9 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Expert Mode</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={
<Trans>Allow high price impact trades and skip the confirm screen. Use at your own risk.</Trans>

View File

@@ -5,9 +5,9 @@ import styled from 'styled-components/macro'
import { DEFAULT_LOCALE, LOCALE_LABEL, SupportedLocale } from '../../constants/locales'
import { navigatorLocale, useActiveLocale } from '../../hooks/useActiveLocale'
import { StyledInternalLink, TYPE } from '../../theme'
import { StyledInternalLink, ThemedText } from '../../theme'
const Container = styled(TYPE.small)`
const Container = styled(ThemedText.Small)`
opacity: 0.6;
:hover {
opacity: 1;

View File

@@ -1,7 +1,7 @@
import { Trans } from '@lingui/macro'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean }>`
border-radius: 20px;
@@ -25,7 +25,7 @@ const ToggleElement = styled.span<{ isActive?: boolean; bgColor?: string }>`
}
`
const StatusText = styled(TYPE.main)<{ isActive?: boolean }>`
const StatusText = styled(ThemedText.Main)<{ isActive?: boolean }>`
margin: 0 10px;
width: 24px;
color: ${({ theme, isActive }) => (isActive ? theme.text1 : theme.text3)};

View File

@@ -13,7 +13,7 @@ import Circle from '../../assets/images/blue-loader.svg'
import MetaMaskLogo from '../../assets/images/metamask.png'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink } from '../../theme'
import { CloseIcon, CustomLightSpinner } from '../../theme/components'
import { CloseIcon, CustomLightSpinner } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
import { ButtonLight, ButtonPrimary } from '../Button'
@@ -284,11 +284,11 @@ function L2Content({
</Text>
</ExternalLink>
) : (
<div style={{ height: '17px' }}></div>
<div style={{ height: '17px' }} />
)}
<Text color={theme.text3} style={{ margin: '20px 0 0 0' }} fontSize={'14px'}>
{!secondsToConfirm ? (
<div style={{ height: '24px' }}></div>
<div style={{ height: '24px' }} />
) : (
<div>
<Trans>Transaction completed in </Trans>

View File

@@ -8,7 +8,7 @@ import { useContext, useState } from 'react'
import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
import QuestionHelper from '../QuestionHelper'
import { RowBetween, RowFixed } from '../Row'
@@ -160,9 +160,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
<AutoColumn gap="md">
<AutoColumn gap="sm">
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Slippage tolerance</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={
<Trans>Your transaction will revert if the price changes unfavorably by more than this percentage.</Trans>
@@ -229,9 +229,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
{showCustomDeadlineRow && (
<AutoColumn gap="sm">
<RowFixed>
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
<ThemedText.Black fontSize={14} fontWeight={400} color={theme.text2}>
<Trans>Transaction deadline</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={<Trans>Your transaction will revert if it is pending for more than this period of time.</Trans>}
/>
@@ -255,9 +255,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
color={deadlineError ? 'red' : ''}
/>
</OptionCustom>
<TYPE.body style={{ paddingLeft: '8px' }} fontSize={14}>
<ThemedText.Body style={{ paddingLeft: '8px' }} fontSize={14}>
<Trans>minutes</Trans>
</TYPE.body>
</ThemedText.Body>
</RowFixed>
</AutoColumn>
)}

View File

@@ -19,7 +19,7 @@ import { SUPPORTED_WALLETS } from '../../constants/wallet'
import usePrevious from '../../hooks/usePrevious'
import { useModalOpen, useWalletModalToggle } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { isMobile } from '../../utils/userAgent'
import AccountDetails from '../AccountDetails'
import Card, { LightCard } from '../Card'
@@ -195,7 +195,7 @@ export default function WalletModal({
setWalletView(WALLET_VIEWS.PENDING)
// if the connector is walletconnect and the user has already tried to connect, manually reset the connector
if (connector instanceof WalletConnectConnector && connector.walletConnectProvider?.wc?.uri) {
if (connector instanceof WalletConnectConnector) {
connector.walletConnectProvider = undefined
}
@@ -335,15 +335,18 @@ export default function WalletModal({
<HeaderRow>
<HoverText
onClick={() => {
setWalletView(previousWalletView ?? WALLET_VIEWS.ACCOUNT)
setWalletView(
(previousWalletView === WALLET_VIEWS.LEGAL ? WALLET_VIEWS.ACCOUNT : previousWalletView) ??
WALLET_VIEWS.ACCOUNT
)
}}
>
<ArrowLeft />
</HoverText>
<Row justify="center">
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Legal & Privacy</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
</Row>
</HeaderRow>
<PrivacyPolicy />
@@ -389,23 +392,23 @@ export default function WalletModal({
<AutoColumn gap="16px">
<LightCard>
<AutoRow style={{ flexWrap: 'nowrap' }}>
<TYPE.black fontSize={14}>
<ThemedText.Black fontSize={14}>
<Trans>
By connecting a wallet, you agree to Uniswap Labs{' '}
<ExternalLink href="https://uniswap.org/terms-of-service/">Terms of Service</ExternalLink> and
acknowledge that you have read and understand the Uniswap{' '}
<ExternalLink href="https://uniswap.org/disclaimer/">Protocol Disclaimer</ExternalLink>.
</Trans>
</TYPE.black>
</ThemedText.Black>
</AutoRow>
</LightCard>
<LinkCard padding=".5rem" $borderRadius=".75rem" onClick={() => setWalletView(WALLET_VIEWS.LEGAL)}>
<RowBetween>
<AutoRow gap="4px">
<Info size={20} />
<TYPE.white fontSize={14}>
<ThemedText.White fontSize={14}>
<Trans>How this app uses APIs</Trans>
</TYPE.white>
</ThemedText.White>
</AutoRow>
<ArrowRight size={16} />
</RowBetween>

View File

@@ -7,11 +7,6 @@ import { useMemo } from 'react'
import { Activity } from 'react-feather'
import styled, { css } from 'styled-components/macro'
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 { NetworkContextName } from '../../constants/misc'
import useENSName from '../../hooks/useENSName'
import { useHasSocks } from '../../hooks/useSocksBalance'
@@ -20,7 +15,7 @@ import { isTransactionRecent, useAllTransactions } from '../../state/transaction
import { TransactionDetails } from '../../state/transactions/reducer'
import { shortenAddress } from '../../utils'
import { ButtonSecondary } from '../Button'
import Identicon from '../Identicon'
import StatusIcon from '../Identicon/StatusIcon'
import Loader from '../Loader'
import { RowBetween } from '../Row'
import WalletModal from '../WalletModal'
@@ -132,36 +127,12 @@ function Sock() {
)
}
// eslint-disable-next-line react/prop-types
function StatusIcon({ connector }: { connector: AbstractConnector }) {
if (connector === injected) {
return <Identicon />
} else if (connector === walletconnect) {
return (
<IconWrapper size={16}>
<img src={WalletConnectIcon} alt={'WalletConnect'} />
</IconWrapper>
)
} else if (connector === walletlink) {
return (
<IconWrapper size={16}>
<img src={CoinbaseWalletIcon} alt={'CoinbaseWallet'} />
</IconWrapper>
)
} else if (connector === fortmatic) {
return (
<IconWrapper size={16}>
<img src={FortmaticIcon} alt={'Fortmatic'} />
</IconWrapper>
)
} else if (connector === portis) {
return (
<IconWrapper size={16}>
<img src={PortisIcon} alt={'Portis'} />
</IconWrapper>
)
}
return null
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
return (
<IconWrapper size={16}>
<StatusIcon connector={connector} />
</IconWrapper>
)
}
function Web3StatusInner() {
@@ -198,7 +169,7 @@ function Web3StatusInner() {
<Text>{ENSName || shortenAddress(account)}</Text>
</>
)}
{!hasPendingTransactions && connector && <StatusIcon connector={connector} />}
{!hasPendingTransactions && connector && <WrappedStatusIcon connector={connector} />}
</Web3StatusConnected>
)
} else if (error) {

View File

@@ -24,7 +24,8 @@ export default function GoogleAnalyticsReporter({ location: { pathname, search }
const { chainId } = useActiveWeb3React()
useEffect(() => {
ReactGA.set({ ['Chain ID']: chainId ?? 0 })
// cd1 - custom dimension 1 - chainId
ReactGA.set({ cd1: chainId ?? 0 })
}, [chainId])
useEffect(() => {

View File

@@ -11,7 +11,7 @@ import useENS from '../../hooks/useENS'
import { useActiveWeb3React } from '../../hooks/web3'
import { useClaimCallback, useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { useIsTransactionPending } from '../../state/transactions/hooks'
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
import { shortenAddress } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import AddressInputPanel from '../AddressInputPanel'
@@ -105,29 +105,29 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
<CardNoise />
<CardSection gap="md">
<RowBetween>
<TYPE.white fontWeight={500}>
<ThemedText.White fontWeight={500}>
<Trans>Claim UNI Token</Trans>
</TYPE.white>
</ThemedText.White>
<CloseIcon onClick={wrappedOnDismiss} style={{ zIndex: 99 }} stroke="white" />
</RowBetween>
<TYPE.white fontWeight={700} fontSize={36}>
<ThemedText.White fontWeight={700} fontSize={36}>
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
</TYPE.white>
</ThemedText.White>
</CardSection>
<Break />
</ModalUpper>
<AutoColumn gap="md" style={{ padding: '1rem', paddingTop: '0' }} justify="center">
<TYPE.subHeader fontWeight={500}>
<ThemedText.SubHeader fontWeight={500}>
<Trans>
Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on
submission.
</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
<AddressInputPanel value={typed} onChange={handleRecipientType} />
{parsedAddress && !hasAvailableClaim && (
<TYPE.error error={true}>
<ThemedText.Error error={true}>
<Trans>Address has no available claim</Trans>
</TYPE.error>
</ThemedText.Error>
)}
<ButtonPrimary
disabled={!isAddress(parsedAddress ?? '') || !hasAvailableClaim}
@@ -159,23 +159,23 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
</ConfirmedIcon>
<AutoColumn gap="100px" justify={'center'}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader fontWeight={600} color="black">
<ThemedText.LargeHeader fontWeight={600} color="black">
{claimConfirmed ? <Trans>Claimed</Trans> : <Trans>Claiming</Trans>}
</TYPE.largeHeader>
</ThemedText.LargeHeader>
{!claimConfirmed && (
<Text fontSize={36} color={'#ff007a'} fontWeight={800}>
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
</Text>
)}
{parsedAddress && (
<TYPE.largeHeader fontWeight={600} color="black">
<ThemedText.LargeHeader fontWeight={600} color="black">
<Trans>for {shortenAddress(parsedAddress)}</Trans>
</TYPE.largeHeader>
</ThemedText.LargeHeader>
)}
</AutoColumn>
{claimConfirmed && (
<>
<TYPE.subHeader fontWeight={500} color="black">
<ThemedText.SubHeader fontWeight={500} color="black">
<span role="img" aria-label="party-hat">
🎉{' '}
</span>
@@ -183,13 +183,13 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
<span role="img" aria-label="party-hat">
🎉
</span>
</TYPE.subHeader>
</ThemedText.SubHeader>
</>
)}
{attempting && !hash && (
<TYPE.subHeader color="black">
<ThemedText.SubHeader color="black">
<Trans>Confirm this transaction in your wallet</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
)}
{attempting && hash && !claimConfirmed && chainId && hash && (
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)} style={{ zIndex: 99 }}>

View File

@@ -13,7 +13,7 @@ import { useModalOpen, useToggleSelfClaimModal } from '../../state/application/h
import { ApplicationModal } from '../../state/application/reducer'
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { useUserHasSubmittedClaim } from '../../state/transactions/hooks'
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonPrimary } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
@@ -100,63 +100,63 @@ export default function ClaimModal() {
<CardNoise />
<CardSection gap="md">
<RowBetween>
<TYPE.white fontWeight={500}>
<ThemedText.White fontWeight={500}>
<Trans>Claim UNI</Trans>
</TYPE.white>
</ThemedText.White>
<CloseIcon onClick={toggleClaimModal} style={{ zIndex: 99 }} color="white" />
</RowBetween>
<TYPE.white fontWeight={700} fontSize={36}>
<ThemedText.White fontWeight={700} fontSize={36}>
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
</TYPE.white>
</ThemedText.White>
</CardSection>
<Break />
<CardSection gap="sm">
{userClaimData?.flags?.isSOCKS && (
<RowBetween>
<TYPE.subHeader color="white">SOCKS</TYPE.subHeader>
<TYPE.subHeader color="white">
<ThemedText.SubHeader color="white">SOCKS</ThemedText.SubHeader>
<ThemedText.SubHeader color="white">
<Trans>{SOCKS_AMOUNT} UNI</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowBetween>
)}
{userClaimData?.flags?.isLP &&
unclaimedAmount &&
JSBI.greaterThanOrEqual(unclaimedAmount.quotient, nonLPAmount) && (
<RowBetween>
<TYPE.subHeader color="white">
<ThemedText.SubHeader color="white">
<Trans>Liquidity</Trans>
</TYPE.subHeader>
<TYPE.subHeader color="white">
</ThemedText.SubHeader>
<ThemedText.SubHeader color="white">
<Trans>
{unclaimedAmount
.subtract(CurrencyAmount.fromRawAmount(unclaimedAmount.currency, nonLPAmount))
.toFixed(0, { groupSeparator: ',' })}{' '}
UNI
</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowBetween>
)}
{userClaimData?.flags?.isUser && (
<RowBetween>
<TYPE.subHeader color="white">
<ThemedText.SubHeader color="white">
<Trans>User</Trans>
</TYPE.subHeader>
<TYPE.subHeader color="white">
</ThemedText.SubHeader>
<ThemedText.SubHeader color="white">
<Trans>{USER_AMOUNT} UNI</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowBetween>
)}
</CardSection>
</ModalUpper>
<AutoColumn gap="md" style={{ padding: '1rem', paddingTop: '0' }} justify="center">
<TYPE.subHeader fontWeight={500}>
<ThemedText.SubHeader fontWeight={500}>
<Trans>
As a member of the Uniswap community you may claim UNI to be used for voting and governance.
<br />
<br />
<ExternalLink href="https://uniswap.org/blog/uni">Read more about UNI</ExternalLink>
</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
<ButtonPrimary
disabled={!isAddress(account ?? '')}
padding="16px 16px"
@@ -187,9 +187,9 @@ export default function ClaimModal() {
</ConfirmedIcon>
<AutoColumn gap="100px" justify={'center'}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader fontWeight={600} color="black">
<ThemedText.LargeHeader fontWeight={600} color="black">
{claimConfirmed ? <Trans>Claimed!</Trans> : <Trans>Claiming</Trans>}
</TYPE.largeHeader>
</ThemedText.LargeHeader>
{!claimConfirmed && (
<Text fontSize={36} color={'#ff007a'} fontWeight={800}>
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
@@ -198,7 +198,7 @@ export default function ClaimModal() {
</AutoColumn>
{claimConfirmed && (
<>
<TYPE.subHeader fontWeight={500} color="black">
<ThemedText.SubHeader fontWeight={500} color="black">
<Trans>
<span role="img" aria-label="party-hat">
🎉{' '}
@@ -208,13 +208,13 @@ export default function ClaimModal() {
🎉
</span>
</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</>
)}
{attempting && !claimSubmitted && (
<TYPE.subHeader color="black">
<ThemedText.SubHeader color="black">
<Trans>Confirm this transaction in your wallet</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
)}
{attempting && claimSubmitted && !claimConfirmed && chainId && claimTxn?.hash && (
<ExternalLink

View File

@@ -8,7 +8,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
import { StakingInfo } from '../../state/stake/hooks'
import { TransactionType } from '../../state/transactions/actions'
import { useTransactionAdder } from '../../state/transactions/hooks'
import { CloseIcon, TYPE } from '../../theme'
import { CloseIcon, ThemedText } from '../../theme'
import { ButtonError } from '../Button'
import { AutoColumn } from '../Column'
import Modal from '../Modal'
@@ -74,24 +74,24 @@ export default function ClaimRewardModal({ isOpen, onDismiss, stakingInfo }: Sta
{!attempting && !hash && (
<ContentWrapper gap="lg">
<RowBetween>
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Claim</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<CloseIcon onClick={wrappedOnDismiss} />
</RowBetween>
{stakingInfo?.earnedAmount && (
<AutoColumn justify="center" gap="md">
<TYPE.body fontWeight={600} fontSize={36}>
<ThemedText.Body fontWeight={600} fontSize={36}>
{stakingInfo?.earnedAmount?.toSignificant(6)}
</TYPE.body>
<TYPE.body>
</ThemedText.Body>
<ThemedText.Body>
<Trans>Unclaimed UNI</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
)}
<TYPE.subHeader style={{ textAlign: 'center' }}>
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
<Trans>When you claim without withdrawing your liquidity remains in the mining pool.</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
<ButtonError disabled={!!error} error={!!error && !!stakingInfo?.stakedAmount} onClick={onClaimReward}>
{error ?? <Trans>Claim</Trans>}
</ButtonError>
@@ -100,21 +100,21 @@ export default function ClaimRewardModal({ isOpen, onDismiss, stakingInfo }: Sta
{attempting && !hash && (
<LoadingView onDismiss={wrappedOnDismiss}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.body fontSize={20}>
<ThemedText.Body fontSize={20}>
<Trans>Claiming {stakingInfo?.earnedAmount?.toSignificant(6)} UNI</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</LoadingView>
)}
{hash && (
<SubmittedView onDismiss={wrappedOnDismiss} hash={hash}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Transaction Submitted</Trans>
</TYPE.largeHeader>
<TYPE.body fontSize={20}>
</ThemedText.LargeHeader>
<ThemedText.Body fontSize={20}>
<Trans>Claimed UNI!</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</SubmittedView>
)}

View File

@@ -9,7 +9,7 @@ import { useTotalSupply } from '../../hooks/useTotalSupply'
import useUSDCPrice from '../../hooks/useUSDCPrice'
import { useV2Pair } from '../../hooks/useV2Pairs'
import { StakingInfo } from '../../state/stake/hooks'
import { StyledInternalLink, TYPE } from '../../theme'
import { StyledInternalLink, ThemedText } from '../../theme'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonPrimary } from '../Button'
@@ -115,9 +115,9 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
<TopSection>
<DoubleCurrencyLogo currency0={currency0} currency1={currency1} size={24} />
<TYPE.white fontWeight={600} fontSize={24} style={{ marginLeft: '8px' }}>
<ThemedText.White fontWeight={600} fontSize={24} style={{ marginLeft: '8px' }}>
{currency0.symbol}-{currency1.symbol}
</TYPE.white>
</ThemedText.White>
<StyledInternalLink to={`/uni/${currencyId(currency0)}/${currencyId(currency1)}`} style={{ width: '100%' }}>
<ButtonPrimary padding="8px" $borderRadius="8px">
@@ -128,22 +128,22 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
<StatContainer>
<RowBetween>
<TYPE.white>
<ThemedText.White>
<Trans>Total deposited</Trans>
</TYPE.white>
<TYPE.white>
</ThemedText.White>
<ThemedText.White>
{valueOfTotalStakedAmountInUSDC ? (
<Trans>${valueOfTotalStakedAmountInUSDC.toFixed(0, { groupSeparator: ',' })}</Trans>
) : (
<Trans>{valueOfTotalStakedAmountInWETH?.toSignificant(4, { groupSeparator: ',' }) ?? '-'} ETH</Trans>
)}
</TYPE.white>
</ThemedText.White>
</RowBetween>
<RowBetween>
<TYPE.white>
<ThemedText.White>
<Trans>Pool rate</Trans>
</TYPE.white>
<TYPE.white>
</ThemedText.White>
<ThemedText.White>
{stakingInfo ? (
stakingInfo.active ? (
<Trans>
@@ -156,7 +156,7 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
) : (
'-'
)}
</TYPE.white>
</ThemedText.White>
</RowBetween>
</StatContainer>
@@ -164,13 +164,13 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
<>
<Break />
<BottomSection showBackground={true}>
<TYPE.black color={'white'} fontWeight={500}>
<ThemedText.Black color={'white'} fontWeight={500}>
<span>
<Trans>Your rate</Trans>
</span>
</TYPE.black>
</ThemedText.Black>
<TYPE.black style={{ textAlign: 'right' }} color={'white'} fontWeight={500}>
<ThemedText.Black style={{ textAlign: 'right' }} color={'white'} fontWeight={500}>
<span role="img" aria-label="wizard-icon" style={{ marginRight: '0.5rem' }}>
</span>
@@ -188,7 +188,7 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
) : (
'-'
)}
</TYPE.black>
</ThemedText.Black>
</BottomSection>
</>
)}

View File

@@ -13,7 +13,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
import { StakingInfo, useDerivedStakeInfo } from '../../state/stake/hooks'
import { TransactionType } from '../../state/transactions/actions'
import { useTransactionAdder } from '../../state/transactions/hooks'
import { CloseIcon, TYPE } from '../../theme'
import { CloseIcon, ThemedText } from '../../theme'
import { formatCurrencyAmount } from '../../utils/formatCurrencyAmount'
import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { ButtonConfirmed, ButtonError } from '../Button'
@@ -159,9 +159,9 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
{!attempting && !hash && (
<ContentWrapper gap="lg">
<RowBetween>
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Deposit</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<CloseIcon onClick={wrappedOnDismiss} />
</RowBetween>
<CurrencyInputPanel
@@ -178,19 +178,19 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
<HypotheticalRewardRate dim={!hypotheticalRewardRate.greaterThan('0')}>
<div>
<TYPE.black fontWeight={600}>
<ThemedText.Black fontWeight={600}>
<Trans>Weekly Rewards</Trans>
</TYPE.black>
</ThemedText.Black>
</div>
<TYPE.black>
<ThemedText.Black>
<Trans>
{hypotheticalRewardRate
.multiply((60 * 60 * 24 * 7).toString())
.toSignificant(4, { groupSeparator: ',' })}{' '}
UNI / week
</Trans>
</TYPE.black>
</ThemedText.Black>
</HypotheticalRewardRate>
<RowBetween>
@@ -216,24 +216,24 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
{attempting && !hash && (
<LoadingView onDismiss={wrappedOnDismiss}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Depositing Liquidity</Trans>
</TYPE.largeHeader>
<TYPE.body fontSize={20}>
</ThemedText.LargeHeader>
<ThemedText.Body fontSize={20}>
<Trans>{parsedAmount?.toSignificant(4)} UNI-V2</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</LoadingView>
)}
{attempting && hash && (
<SubmittedView onDismiss={wrappedOnDismiss} hash={hash}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Transaction Submitted</Trans>
</TYPE.largeHeader>
<TYPE.body fontSize={20}>
</ThemedText.LargeHeader>
<ThemedText.Body fontSize={20}>
<Trans>Deposited {parsedAmount?.toSignificant(4)} UNI-V2</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</SubmittedView>
)}

View File

@@ -8,7 +8,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
import { StakingInfo } from '../../state/stake/hooks'
import { TransactionType } from '../../state/transactions/actions'
import { useTransactionAdder } from '../../state/transactions/hooks'
import { CloseIcon, TYPE } from '../../theme'
import { CloseIcon, ThemedText } from '../../theme'
import { ButtonError } from '../Button'
import { AutoColumn } from '../Column'
import FormattedCurrencyAmount from '../FormattedCurrencyAmount'
@@ -76,34 +76,34 @@ export default function UnstakingModal({ isOpen, onDismiss, stakingInfo }: Staki
{!attempting && !hash && (
<ContentWrapper gap="lg">
<RowBetween>
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Withdraw</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<CloseIcon onClick={wrappedOndismiss} />
</RowBetween>
{stakingInfo?.stakedAmount && (
<AutoColumn justify="center" gap="md">
<TYPE.body fontWeight={600} fontSize={36}>
<ThemedText.Body fontWeight={600} fontSize={36}>
{<FormattedCurrencyAmount currencyAmount={stakingInfo.stakedAmount} />}
</TYPE.body>
<TYPE.body>
</ThemedText.Body>
<ThemedText.Body>
<Trans>Deposited liquidity:</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
)}
{stakingInfo?.earnedAmount && (
<AutoColumn justify="center" gap="md">
<TYPE.body fontWeight={600} fontSize={36}>
<ThemedText.Body fontWeight={600} fontSize={36}>
{<FormattedCurrencyAmount currencyAmount={stakingInfo?.earnedAmount} />}
</TYPE.body>
<TYPE.body>
</ThemedText.Body>
<ThemedText.Body>
<Trans>Unclaimed UNI</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
)}
<TYPE.subHeader style={{ textAlign: 'center' }}>
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
<Trans>When you withdraw, your UNI is claimed and your liquidity is removed from the mining pool.</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
<ButtonError disabled={!!error} error={!!error && !!stakingInfo?.stakedAmount} onClick={onWithdraw}>
{error ?? <Trans>Withdraw & Claim</Trans>}
</ButtonError>
@@ -112,27 +112,27 @@ export default function UnstakingModal({ isOpen, onDismiss, stakingInfo }: Staki
{attempting && !hash && (
<LoadingView onDismiss={wrappedOndismiss}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.body fontSize={20}>
<ThemedText.Body fontSize={20}>
<Trans>Withdrawing {stakingInfo?.stakedAmount?.toSignificant(4)} UNI-V2</Trans>
</TYPE.body>
<TYPE.body fontSize={20}>
</ThemedText.Body>
<ThemedText.Body fontSize={20}>
<Trans>Claiming {stakingInfo?.earnedAmount?.toSignificant(4)} UNI</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</LoadingView>
)}
{hash && (
<SubmittedView onDismiss={wrappedOndismiss} hash={hash}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Transaction Submitted</Trans>
</TYPE.largeHeader>
<TYPE.body fontSize={20}>
</ThemedText.LargeHeader>
<ThemedText.Body fontSize={20}>
<Trans>Withdrew UNI-V2!</Trans>
</TYPE.body>
<TYPE.body fontSize={20}>
</ThemedText.Body>
<ThemedText.Body fontSize={20}>
<Trans>Claimed UNI!</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</SubmittedView>
)}

View File

@@ -6,7 +6,7 @@ import { LoadingRows } from 'components/Loader/styled'
import { useContext, useMemo } from 'react'
import { ThemeContext } from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { computeRealizedLPFeePercent } from '../../utils/prices'
import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row'
@@ -56,55 +56,55 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
</TransactionDetailsLabel>
<RowBetween>
<RowFixed>
<TYPE.subHeader color={theme.text1}>
<ThemedText.SubHeader color={theme.text1}>
<Trans>Liquidity Provider Fee</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={65}>
<TYPE.black textAlign="right" fontSize={14}>
<ThemedText.Black textAlign="right" fontSize={14}>
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${realizedLPFee.currency.symbol}` : '-'}
</TYPE.black>
</ThemedText.Black>
</TextWithLoadingPlaceholder>
</RowBetween>
<RowBetween>
<RowFixed>
<TYPE.subHeader color={theme.text1}>
<ThemedText.SubHeader color={theme.text1}>
<Trans>Price Impact</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={50}>
<TYPE.black textAlign="right" fontSize={14}>
<ThemedText.Black textAlign="right" fontSize={14}>
<FormattedPriceImpact priceImpact={priceImpact} />
</TYPE.black>
</ThemedText.Black>
</TextWithLoadingPlaceholder>
</RowBetween>
<RowBetween>
<RowFixed>
<TYPE.subHeader color={theme.text1}>
<ThemedText.SubHeader color={theme.text1}>
<Trans>Allowed Slippage</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={45}>
<TYPE.black textAlign="right" fontSize={14}>
<ThemedText.Black textAlign="right" fontSize={14}>
{allowedSlippage.toFixed(2)}%
</TYPE.black>
</ThemedText.Black>
</TextWithLoadingPlaceholder>
</RowBetween>
<RowBetween>
<RowFixed>
<TYPE.subHeader color={theme.text1}>
<ThemedText.SubHeader color={theme.text1}>
{trade.tradeType === TradeType.EXACT_INPUT ? <Trans>Minimum received</Trans> : <Trans>Maximum sent</Trans>}
</TYPE.subHeader>
</ThemedText.SubHeader>
</RowFixed>
<TextWithLoadingPlaceholder syncing={syncing} width={70}>
<TYPE.black textAlign="right" fontSize={14}>
<ThemedText.Black textAlign="right" fontSize={14}>
{trade.tradeType === TradeType.EXACT_INPUT
? `${trade.minimumAmountOut(allowedSlippage).toSignificant(6)} ${trade.outputAmount.currency.symbol}`
: `${trade.maximumAmountIn(allowedSlippage).toSignificant(6)} ${trade.inputAmount.currency.symbol}`}
</TYPE.black>
</ThemedText.Black>
</TextWithLoadingPlaceholder>
</RowBetween>
</AutoColumn>

View File

@@ -1,7 +1,7 @@
import { Trans } from '@lingui/macro'
import { useRoutingAPIEnabled } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { ReactComponent as AutoRouterIcon } from '../../assets/svg/auto_router.svg'
import { ReactComponent as StaticRouterIcon } from '../../assets/svg/static_route.svg'
@@ -26,7 +26,7 @@ const StyledStaticRouterIcon = styled(StaticRouterIcon)`
}
`
const StyledAutoRouterLabel = styled(TYPE.black)`
const StyledAutoRouterLabel = styled(ThemedText.Black)`
line-height: 1rem;
/* fallback color */
@@ -51,8 +51,8 @@ export function AutoRouterLabel() {
return routingAPIEnabled ? (
<StyledAutoRouterLabel fontSize={14}>Auto Router</StyledAutoRouterLabel>
) : (
<TYPE.black fontSize={14}>
<ThemedText.Black fontSize={14}>
<Trans>Trade Route</Trans>
</TYPE.black>
</ThemedText.Black>
)
}

View File

@@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { RowBetween, RowFixed } from '../Row'
import SettingsTab from '../Settings'
@@ -17,9 +17,9 @@ export default function SwapHeader({ allowedSlippage }: { allowedSlippage: Perce
<StyledSwapHeader>
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={500} fontSize={16} style={{ marginRight: '8px' }}>
<ThemedText.Black fontWeight={500} fontSize={16} style={{ marginRight: '8px' }}>
<Trans>Swap</Trans>
</TYPE.black>
</ThemedText.Black>
</RowFixed>
<RowFixed>
<SettingsTab placeholderSlippage={allowedSlippage} />

View File

@@ -8,7 +8,7 @@ import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components/macro'
import { useUSDCValue } from '../../hooks/useUSDCPrice'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { isAddress, shortenAddress } from '../../utils'
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
import { ButtonPrimary } from '../Button'
@@ -64,9 +64,9 @@ export default function SwapModalHeader({
<LightCard padding="0.75rem 1rem">
<AutoColumn gap={'8px'}>
<RowBetween>
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
<ThemedText.Body color={theme.text3} fontWeight={500} fontSize={14}>
<Trans>From</Trans>
</TYPE.body>
</ThemedText.Body>
<FiatValue fiatValue={fiatValueInput} />
</RowBetween>
<RowBetween align="center">
@@ -94,15 +94,15 @@ export default function SwapModalHeader({
<LightCard padding="0.75rem 1rem" style={{ marginBottom: '0.25rem' }}>
<AutoColumn gap={'8px'}>
<RowBetween>
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
<ThemedText.Body color={theme.text3} fontWeight={500} fontSize={14}>
<Trans>To</Trans>
</TYPE.body>
<TYPE.body fontSize={14} color={theme.text3}>
</ThemedText.Body>
<ThemedText.Body fontSize={14} color={theme.text3}>
<FiatValue
fiatValue={fiatValueOutput}
priceImpact={computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)}
/>
</TYPE.body>
</ThemedText.Body>
</RowBetween>
<RowBetween align="flex-end">
<RowFixed gap={'0px'}>
@@ -120,9 +120,9 @@ export default function SwapModalHeader({
</AutoColumn>
</LightCard>
<RowBetween style={{ marginTop: '0.25rem', padding: '0 1rem' }}>
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
<ThemedText.Body color={theme.text2} fontWeight={500} fontSize={14}>
<Trans>Price</Trans>
</TYPE.body>
</ThemedText.Body>
<TradePrice price={trade.executionPrice} showInverted={showInverted} setShowInverted={setShowInverted} />
</RowBetween>
@@ -135,9 +135,9 @@ export default function SwapModalHeader({
<RowBetween>
<RowFixed>
<AlertTriangle size={20} style={{ marginRight: '8px', minWidth: 24 }} />
<TYPE.main color={theme.primary1}>
<ThemedText.Main color={theme.primary1}>
<Trans>Price Updated</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
<ButtonPrimary
style={{ padding: '.5rem', width: 'fit-content', fontSize: '0.825rem', borderRadius: '12px' }}
@@ -151,7 +151,7 @@ export default function SwapModalHeader({
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '.75rem 1rem' }}>
{trade.tradeType === TradeType.EXACT_INPUT ? (
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
<ThemedText.Italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
<Trans>
Output is estimated. You will receive at least{' '}
<b>
@@ -159,9 +159,9 @@ export default function SwapModalHeader({
</b>{' '}
or the transaction will revert.
</Trans>
</TYPE.italic>
</ThemedText.Italic>
) : (
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
<ThemedText.Italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
<Trans>
Input is estimated. You will sell at most{' '}
<b>
@@ -169,17 +169,17 @@ export default function SwapModalHeader({
</b>{' '}
or the transaction will revert.
</Trans>
</TYPE.italic>
</ThemedText.Italic>
)}
</AutoColumn>
{recipient !== null ? (
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
<TYPE.main>
<ThemedText.Main>
<Trans>
Output will be sent to{' '}
<b title={recipient}>{isAddress(recipient) ? shortenAddress(recipient) : recipient}</b>
</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoColumn>
) : null}
</AutoColumn>

View File

@@ -11,7 +11,7 @@ import { Version } from 'hooks/useToggledVersion'
import { memo } from 'react'
import { useRoutingAPIEnabled } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { getTradeVersion } from 'utils/getTradeVersion'
import { AutoRouterLabel, AutoRouterLogo } from './RouterLabel'
@@ -46,9 +46,9 @@ export default memo(function SwapRoute({
</LoadingRows>
) : (
<Badge>
<TYPE.black fontSize={12}>
<ThemedText.Black fontSize={12}>
{getTradeVersion(trade) === Version.v2 ? <Trans>V2</Trans> : <Trans>V3</Trans>}
</TYPE.black>
</ThemedText.Black>
</Badge>
)}
</RowBetween>
@@ -65,9 +65,9 @@ export default memo(function SwapRoute({
/>
)}
{routingAPIEnabled && (
<TYPE.main fontSize={12} width={400}>
<ThemedText.Main fontSize={12} width={400}>
<Trans>This route optimizes your price by considering split routes, multiple hops, and gas costs.</Trans>
</TYPE.main>
</ThemedText.Main>
)}
</AutoColumn>
)

View File

@@ -4,7 +4,7 @@ import useUSDCPrice from 'hooks/useUSDCPrice'
import { useCallback, useContext } from 'react'
import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
interface TradePriceProps {
price: Price<Currency, Currency>
@@ -49,9 +49,9 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
{text}
</Text>{' '}
{usdcPrice && (
<TYPE.darkGray>
<ThemedText.DarkGray>
<Trans>(${usdcPrice.toSignificant(6, { groupSeparator: ',' })})</Trans>
</TYPE.darkGray>
</ThemedText.DarkGray>
)}
</StyledPriceContainer>
)

View File

@@ -1,5 +1,5 @@
import { Trans } from '@lingui/macro'
import { Currency, Token } from '@uniswap/sdk-core'
import { Currency } from '@uniswap/sdk-core'
import { ButtonEmpty } from 'components/Button'
import Card, { OutlineCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
@@ -9,7 +9,7 @@ import { AutoRow, RowBetween } from 'components/Row'
import { useActiveWeb3React } from 'hooks/web3'
import { useState } from 'react'
import styled from 'styled-components/macro'
import { CloseIcon, ExternalLink, TYPE, Z_INDEX } from 'theme'
import { CloseIcon, ExternalLink, ThemedText, Z_INDEX } from 'theme'
import { useUnsupportedTokens } from '../../hooks/Tokens'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
@@ -37,7 +37,7 @@ const StyledButtonEmpty = styled(ButtonEmpty)`
text-decoration: none;
`
const AddressText = styled(TYPE.blue)`
const AddressText = styled(ThemedText.Blue)`
font-size: 12px;
${({ theme }) => theme.mediaWidth.upToSmall`
@@ -62,7 +62,7 @@ export default function UnsupportedCurrencyFooter({
})
: []
const unsupportedTokens: { [address: string]: Token } = useUnsupportedTokens()
const unsupportedTokens = useUnsupportedTokens()
return (
<DetailsFooter show={show}>
@@ -70,9 +70,9 @@ export default function UnsupportedCurrencyFooter({
<Card padding="2rem">
<AutoColumn gap="lg">
<RowBetween>
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Unsupported Assets</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<CloseIcon onClick={() => setShowDetails(false)} />
</RowBetween>
{tokens.map((token) => {
@@ -84,7 +84,7 @@ export default function UnsupportedCurrencyFooter({
<AutoColumn gap="10px">
<AutoRow gap="5px" align="center">
<CurrencyLogo currency={token} size={'24px'} />
<TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
<ThemedText.Body fontWeight={500}>{token.symbol}</ThemedText.Body>
</AutoRow>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
@@ -97,20 +97,20 @@ export default function UnsupportedCurrencyFooter({
)
})}
<AutoColumn gap="lg">
<TYPE.body fontWeight={500}>
<ThemedText.Body fontWeight={500}>
<Trans>
Some assets are not available through this interface because they may not work well with the smart
contracts or we are unable to allow trading for legal reasons.
</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
</AutoColumn>
</Card>
</Modal>
<StyledButtonEmpty padding={'0'} onClick={() => setShowDetails(true)}>
<TYPE.blue>
<ThemedText.Blue>
<Trans>Read more about unsupported assets</Trans>
</TYPE.blue>
</ThemedText.Blue>
</StyledButtonEmpty>
</DetailsFooter>
)

View File

@@ -5,8 +5,8 @@ import { ReactNode } from 'react'
import { AlertTriangle } from 'react-feather'
import { Text } from 'rebass'
import styled, { css } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
import TradePrice from './TradePrice'
@@ -133,7 +133,7 @@ export const SwapShowAcceptChanges = styled(AutoColumn)`
margin-top: 8px;
`
export const TransactionDetailsLabel = styled(TYPE.black)`
export const TransactionDetailsLabel = styled(ThemedText.Black)`
border-bottom: 1px solid ${({ theme }) => theme.bg2};
padding-bottom: 0.5rem;
`

View File

@@ -10,7 +10,7 @@ import useENS from '../../hooks/useENS'
import { useActiveWeb3React } from '../../hooks/web3'
import { useDelegateCallback } from '../../state/governance/hooks'
import { useTokenBalance } from '../../state/wallet/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import AddressInputPanel from '../AddressInputPanel'
import { ButtonPrimary } from '../Button'
import { AutoColumn } from '../Column'
@@ -95,23 +95,25 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro
<ContentWrapper gap="lg">
<AutoColumn gap="lg" justify="center">
<RowBetween>
<TYPE.mediumHeader fontWeight={500}>{title}</TYPE.mediumHeader>
<ThemedText.MediumHeader fontWeight={500}>{title}</ThemedText.MediumHeader>
<StyledClosed stroke="black" onClick={wrappedOndismiss} />
</RowBetween>
<TYPE.body>
<ThemedText.Body>
<Trans>Earned UNI tokens represent voting shares in Uniswap governance.</Trans>
</TYPE.body>
<TYPE.body>
</ThemedText.Body>
<ThemedText.Body>
<Trans>You can either vote on each proposal yourself or delegate your votes to a third party.</Trans>
</TYPE.body>
</ThemedText.Body>
{usingDelegate && <AddressInputPanel value={typed} onChange={handleRecipientType} />}
<ButtonPrimary disabled={!isAddress(parsedAddress ?? '')} onClick={onDelegate}>
<TYPE.mediumHeader color="white">
<ThemedText.MediumHeader color="white">
{usingDelegate ? <Trans>Delegate Votes</Trans> : <Trans>Self Delegate</Trans>}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
</ButtonPrimary>
<TextButton onClick={() => setUsingDelegate(!usingDelegate)}>
<TYPE.blue>{usingDelegate ? <Trans>Remove Delegate</Trans> : <Trans>Add Delegate +</Trans>}</TYPE.blue>
<ThemedText.Blue>
{usingDelegate ? <Trans>Remove Delegate</Trans> : <Trans>Add Delegate +</Trans>}
</ThemedText.Blue>
</TextButton>
</AutoColumn>
</ContentWrapper>
@@ -119,20 +121,20 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro
{attempting && !hash && (
<LoadingView onDismiss={wrappedOndismiss}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
{usingDelegate ? <Trans>Delegating votes</Trans> : <Trans>Unlocking Votes</Trans>}
</TYPE.largeHeader>
<TYPE.main fontSize={36}> {formatCurrencyAmount(uniBalance, 4)}</TYPE.main>
</ThemedText.LargeHeader>
<ThemedText.Main fontSize={36}> {formatCurrencyAmount(uniBalance, 4)}</ThemedText.Main>
</AutoColumn>
</LoadingView>
)}
{hash && (
<SubmittedView onDismiss={wrappedOndismiss} hash={hash}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Transaction Submitted</Trans>
</TYPE.largeHeader>
<TYPE.main fontSize={36}>{formatCurrencyAmount(uniBalance, 4)}</TYPE.main>
</ThemedText.LargeHeader>
<ThemedText.Main fontSize={36}>{formatCurrencyAmount(uniBalance, 4)}</ThemedText.Main>
</AutoColumn>
</SubmittedView>
)}

View File

@@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
import { L2_CHAIN_IDS } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
const EmptyProposals = styled.div`
border: 1px solid ${({ theme }) => theme.text4};
@@ -25,14 +25,14 @@ interface EmptyStateProps {
}
const EmptyState = ({ HeaderContent, SubHeaderContent }: EmptyStateProps) => (
<EmptyProposals>
<TYPE.body style={{ marginBottom: '8px' }}>
<ThemedText.Body style={{ marginBottom: '8px' }}>
<HeaderContent />
</TYPE.body>
<TYPE.subHeader>
</ThemedText.Body>
<ThemedText.SubHeader>
<Sub>
<SubHeaderContent />
</Sub>
</TYPE.subHeader>
</ThemedText.SubHeader>
</EmptyProposals>
)

View File

@@ -8,8 +8,8 @@ import Circle from '../../assets/images/blue-loader.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { useUserVotes, useVoteCallback } from '../../state/governance/hooks'
import { VoteOption } from '../../state/governance/types'
import { CustomLightSpinner, TYPE } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { CustomLightSpinner, ThemedText } from '../../theme'
import { ExternalLink } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonPrimary } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
@@ -85,7 +85,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
<ContentWrapper gap="lg">
<AutoColumn gap="lg" justify="center">
<RowBetween>
<TYPE.mediumHeader fontWeight={500}>
<ThemedText.MediumHeader fontWeight={500}>
{voteOption === VoteOption.Against ? (
<Trans>Vote against proposal {proposalId}</Trans>
) : voteOption === VoteOption.For ? (
@@ -93,14 +93,14 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
) : (
<Trans>Vote to abstain on proposal {proposalId}</Trans>
)}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<StyledClosed stroke="black" onClick={wrappedOndismiss} />
</RowBetween>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>{formatCurrencyAmount(availableVotes, 4)} Votes</Trans>
</TYPE.largeHeader>
</ThemedText.LargeHeader>
<ButtonPrimary onClick={onVote}>
<TYPE.mediumHeader color="white">
<ThemedText.MediumHeader color="white">
{voteOption === VoteOption.Against ? (
<Trans>Vote against proposal {proposalId}</Trans>
) : voteOption === VoteOption.For ? (
@@ -108,7 +108,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
) : (
<Trans>Vote to abstain on proposal {proposalId}</Trans>
)}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
</ButtonPrimary>
</AutoColumn>
</ContentWrapper>
@@ -124,13 +124,13 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
</ConfirmedIcon>
<AutoColumn gap="100px" justify={'center'}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Submitting Vote</Trans>
</TYPE.largeHeader>
</ThemedText.LargeHeader>
</AutoColumn>
<TYPE.subHeader>
<ThemedText.SubHeader>
<Trans>Confirm this transaction in your wallet</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</AutoColumn>
</ConfirmOrLoadingWrapper>
)}
@@ -145,18 +145,18 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
</ConfirmedIcon>
<AutoColumn gap="100px" justify={'center'}>
<AutoColumn gap="12px" justify={'center'}>
<TYPE.largeHeader>
<ThemedText.LargeHeader>
<Trans>Transaction Submitted</Trans>
</TYPE.largeHeader>
</ThemedText.LargeHeader>
</AutoColumn>
{chainId && (
<ExternalLink
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>

View File

@@ -5,10 +5,10 @@ export const OVERLAY_READY = 'OVERLAY_READY'
type FormaticSupportedChains = 1 | 3 | 4 | 42
const CHAIN_ID_NETWORK_ARGUMENT: { readonly [chainId in FormaticSupportedChains]: string | undefined } = {
[1]: undefined,
[3]: 'ropsten',
[4]: 'rinkeby',
[42]: 'kovan',
1: undefined,
3: 'ropsten',
4: 'rinkeby',
42: 'kovan',
}
export class FortmaticConnector extends FortmaticConnectorCore {

View File

@@ -8,8 +8,10 @@ type AddressMap = { [chainId: number]: string }
export const UNI_ADDRESS: AddressMap = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
export const MULTICALL_ADDRESS: AddressMap = {
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [SupportedChainId.OPTIMISTIC_KOVAN]),
[SupportedChainId.OPTIMISM]: '0x90f872b3d8f33f305e0250db6A2761B354f7710A',
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [
SupportedChainId.OPTIMISTIC_KOVAN,
SupportedChainId.OPTIMISM,
]),
[SupportedChainId.ARBITRUM_ONE]: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB',
[SupportedChainId.ARBITRUM_RINKEBY]: '0xa501c031958F579dB7676fF1CE78AD305794d579',
}

View File

@@ -3,6 +3,8 @@ import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
import ms from 'ms.macro'
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
export enum SupportedChainId {
MAINNET = 1,
ROPSTEN = 3,
@@ -66,6 +68,7 @@ export interface L2ChainInfo extends L1ChainInfo {
readonly bridge: string
readonly logoUrl: string
readonly statusPage?: string
readonly defaultListUrl: string
}
export type ChainInfo = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
@@ -77,9 +80,10 @@ export const CHAIN_INFO: ChainInfo = {
[SupportedChainId.ARBITRUM_ONE]: {
blockWaitMsBeforeWarning: ms`10m`,
bridge: 'https://bridge.arbitrum.io/',
defaultListUrl: ARBITRUM_LIST,
docs: 'https://offchainlabs.com/',
explorer: 'https://arbiscan.io/',
infoLink: 'https://info.uniswap.org/#/arbitrum',
infoLink: 'https://info.uniswap.org/#/arbitrum/',
label: 'Arbitrum',
logoUrl: arbitrumLogoUrl,
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
@@ -88,6 +92,7 @@ export const CHAIN_INFO: ChainInfo = {
[SupportedChainId.ARBITRUM_RINKEBY]: {
blockWaitMsBeforeWarning: ms`10m`,
bridge: 'https://bridge.arbitrum.io/',
defaultListUrl: ARBITRUM_LIST,
docs: 'https://offchainlabs.com/',
explorer: 'https://rinkeby-explorer.arbitrum.io/',
infoLink: 'https://info.uniswap.org/#/arbitrum/',
@@ -133,28 +138,28 @@ export const CHAIN_INFO: ChainInfo = {
nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 },
},
[SupportedChainId.OPTIMISM]: {
blockWaitMsBeforeWarning: ms`10m`,
blockWaitMsBeforeWarning: ms`15m`,
bridge: 'https://gateway.optimism.io/',
defaultListUrl: OPTIMISM_LIST,
docs: 'https://optimism.io/',
explorer: 'https://optimistic.etherscan.io/',
infoLink: 'https://info.uniswap.org/#/optimism',
infoLink: 'https://info.uniswap.org/#/optimism/',
label: 'OΞ',
logoUrl: optimismLogoUrl,
nativeCurrency: { name: 'Optimistic ETH', symbol: 'ETH', decimals: 18 },
rpcUrls: ['https://mainnet.optimism.io'],
statusPage: 'https://optimism.io/status',
},
[SupportedChainId.OPTIMISTIC_KOVAN]: {
blockWaitMsBeforeWarning: ms`10m`,
blockWaitMsBeforeWarning: ms`15m`,
bridge: 'https://gateway.optimism.io/',
defaultListUrl: OPTIMISM_LIST,
docs: 'https://optimism.io/',
explorer: 'https://optimistic.etherscan.io/',
infoLink: 'https://info.uniswap.org/#/optimism',
infoLink: 'https://info.uniswap.org/#/optimism/',
label: 'Optimistic Kovan',
rpcUrls: ['https://kovan.optimism.io'],
logoUrl: optimismLogoUrl,
nativeCurrency: { name: 'Optimistic kovETH', symbol: 'kovOpETH', decimals: 18 },
statusPage: 'https://optimism.io/status',
},
}

View File

@@ -19,5 +19,5 @@ export const DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS = 13
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
export const AVERAGE_BLOCK_TIME_IN_SECS: { [chainId: number]: number } = {
[1]: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
1: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
}

View File

@@ -1,7 +1,6 @@
const AAVE_LIST = 'tokenlist.aave.eth'
const BA_LIST = 'https://raw.githubusercontent.com/The-Blockchain-Association/sec-notice-list/master/ba-sec-list.json'
const CMC_ALL_LIST = 'defi.cmc.eth'
const CMC_STABLECOIN = 'stablecoin.cmc.eth'
const CMC_ALL_LIST = 'https://api.coinmarketcap.com/data-api/v3/uniswap/all.json'
const COINGECKO_LIST = 'https://tokens.coingecko.com/uniswap/all.json'
const COMPOUND_LIST = 'https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json'
const GEMINI_LIST = 'https://www.gemini.com/uniswap/manifest.json'
@@ -20,15 +19,14 @@ const DEFAULT_LIST_OF_LISTS_TO_DISPLAY: string[] = [
COMPOUND_LIST,
AAVE_LIST,
CMC_ALL_LIST,
CMC_STABLECOIN,
COINGECKO_LIST,
KLEROS_LIST,
GEMINI_LIST,
WRAPPED_LIST,
SET_LIST,
ROLL_LIST,
COINGECKO_LIST,
KLEROS_LIST,
ARBITRUM_LIST,
OPTIMISM_LIST,
GEMINI_LIST,
]
export const DEFAULT_LIST_OF_LISTS: string[] = [

View File

@@ -49,7 +49,7 @@ export const LOCALE_LABEL: { [locale in SupportedLocale]: string } = {
'el-GR': 'ελληνικά',
'en-US': 'English',
'es-ES': 'Español',
'fi-FI': 'Suomalainen',
'fi-FI': 'suomi',
'fr-FR': 'français',
'he-IL': 'עִברִית',
'hu-HU': 'Magyar',

View File

@@ -1,2 +1,3 @@
export const UNISWAP_GRANTS_START_BLOCK = 11473815
export const BRAVO_START_BLOCK = 13059344
export const ONE_BIP_START_BLOCK = 13551293

View File

@@ -13,6 +13,9 @@ import {
FRAX,
FXS,
renBTC,
rETH2,
sETH2,
SWISE,
TRIBE,
USDC,
USDC_ARBITRUM,
@@ -53,6 +56,8 @@ export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
[SupportedChainId.MAINNET]: {
'0xF16E4d813f4DcfDe4c5b44f305c908742De84eF0': [ETH2X_FLI],
[rETH2.address]: [sETH2],
[SWISE.address]: [sETH2],
[FEI.address]: [TRIBE],
[TRIBE.address]: [FEI],
[FRAX.address]: [FXS],

View File

@@ -1080,6 +1080,20 @@
"name": "Shatner",
"symbol": "SHAT",
"decimals": 18
},
{
"chainId": 1,
"address": "0x7277a44D1325D81Ac58893002a1B40a41bea43fe",
"name": "FAANG Index",
"symbol": "FAANG",
"decimals": 18
},
{
"chainId": 1,
"address": "0x76175599887730786bdA1545D0D7AcE8737fEBB1",
"name": "ENS DAO",
"symbol": "ENS",
"decimals": 18
}
]
}

View File

@@ -136,6 +136,27 @@ export const ETH2X_FLI = new Token(
'ETH2x-FLI',
'ETH 2x Flexible Leverage Index'
)
export const sETH2 = new Token(
SupportedChainId.MAINNET,
'0xFe2e637202056d30016725477c5da089Ab0A043A',
18,
'sETH2',
'StakeWise Staked ETH2'
)
export const rETH2 = new Token(
SupportedChainId.MAINNET,
'0x20BC832ca081b91433ff6c17f85701B6e92486c5',
18,
'rETH2',
'StakeWise Reward ETH2'
)
export const SWISE = new Token(
SupportedChainId.MAINNET,
'0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2',
18,
'SWISE',
'StakeWise'
)
export const UNI: { [chainId: number]: Token } = {
[SupportedChainId.MAINNET]: new Token(SupportedChainId.MAINNET, UNI_ADDRESS[1], 18, 'UNI', 'Uniswap'),
[SupportedChainId.RINKEBY]: new Token(SupportedChainId.RINKEBY, UNI_ADDRESS[4], 18, 'UNI', 'Uniswap'),

View File

@@ -1,7 +1,7 @@
import { arrayify } from '@ethersproject/bytes'
import { parseBytes32String } from '@ethersproject/strings'
import { Currency, Token } from '@uniswap/sdk-core'
import { SupportedChainId } from 'constants/chains'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
import { useMemo } from 'react'
import { createTokenFilterFunction } from '../components/SearchModal/filtering'
@@ -57,9 +57,56 @@ export function useAllTokens(): { [address: string]: Token } {
return useTokensFromMap(allTokens, true)
}
type BridgeInfo = Record<
SupportedChainId,
{
tokenAddress: string
originBridgeAddress: string
destBridgeAddress: string
}
>
export function useUnsupportedTokens(): { [address: string]: Token } {
const { chainId } = useActiveWeb3React()
const listsByUrl = useAllLists()
const unsupportedTokensMap = useUnsupportedTokenList()
return useTokensFromMap(unsupportedTokensMap, false)
const unsupportedTokens = useTokensFromMap(unsupportedTokensMap, false)
// checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
if (!chainId || !L2_CHAIN_IDS.includes(chainId)) {
return {}
}
if (!listsByUrl) {
return {}
}
const listUrl = CHAIN_INFO[chainId as SupportedL2ChainId].defaultListUrl
const { current: list } = listsByUrl[listUrl]
if (!list) {
return {}
}
const unsupportedSet = new Set(Object.keys(unsupportedTokens))
return list.tokens.reduce((acc, tokenInfo) => {
const bridgeInfo = tokenInfo.extensions?.bridgeInfo as unknown as BridgeInfo
if (
bridgeInfo &&
bridgeInfo[SupportedChainId.MAINNET] &&
bridgeInfo[SupportedChainId.MAINNET].tokenAddress &&
unsupportedSet.has(bridgeInfo[SupportedChainId.MAINNET].tokenAddress)
) {
const address = bridgeInfo[SupportedChainId.MAINNET].tokenAddress
// don't rely on decimals--it's possible that a token could be bridged w/ different decimals on the L2
return { ...acc, [address]: new Token(SupportedChainId.MAINNET, address, tokenInfo.decimals) }
}
return acc
}, {})
}, [chainId, listsByUrl, unsupportedTokens])
return { ...unsupportedTokens, ...l2InferredBlockedTokens }
}
export function useSearchInactiveTokenLists(search: string | undefined, minResults = 10): WrappedTokenInfo[] {

View File

@@ -48,7 +48,7 @@ export function useAllCurrencyCombinations(currencyA?: Currency, currencyB?: Cur
const firstIndexInOtherPairs = otherPairs.findIndex(([t0Other, t1Other]) => {
return (t0.equals(t0Other) && t1.equals(t1Other)) || (t0.equals(t1Other) && t1.equals(t0Other))
})
// only accept the first occurence of the same 2 tokens
// only accept the first occurrence of the same 2 tokens
return firstIndexInOtherPairs === i
})
// optionally filter out some pairs for tokens with custom bases defined

View File

@@ -87,7 +87,7 @@ export function useApproveCallback(
return tokenContract
.approve(spender, useExact ? amountToApprove.quotient.toString() : MaxUint256, {
gasLimit: calculateGasMargin(chainId, estimatedGas),
gasLimit: calculateGasMargin(estimatedGas),
})
.then((response: TransactionResponse) => {
addTransaction(response, { type: TransactionType.APPROVAL, tokenAddress: token.address, spender })

View File

@@ -11,8 +11,6 @@ import { useV3Quoter } from './useContract'
import { useActiveWeb3React } from './web3'
const QUOTE_GAS_OVERRIDES: { [chainId: number]: number } = {
[SupportedChainId.OPTIMISM]: 6_000_000,
[SupportedChainId.OPTIMISTIC_KOVAN]: 6_000_000,
[SupportedChainId.ARBITRUM_ONE]: 25_000_000,
[SupportedChainId.ARBITRUM_RINKEBY]: 25_000_000,
}

View File

@@ -15,6 +15,8 @@ import ENS_PUBLIC_RESOLVER_ABI from 'abis/ens-public-resolver.json'
import ENS_ABI from 'abis/ens-registrar.json'
import ERC20_ABI from 'abis/erc20.json'
import ERC20_BYTES32_ABI from 'abis/erc20_bytes32.json'
import ERC721_ABI from 'abis/erc721.json'
import ERC1155_ABI from 'abis/erc1155.json'
import GOVERNOR_BRAVO_ABI from 'abis/governor-bravo.json'
import WETH_ABI from 'abis/weth.json'
import {
@@ -35,7 +37,7 @@ import { NonfungiblePositionManager, Quoter, UniswapInterfaceMulticall } from 't
import { V3Migrator } from 'types/v3/V3Migrator'
import { getContract } from 'utils'
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Weth } from '../abis/types'
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Erc721, Erc1155, Weth } from '../abis/types'
import { UNI, WETH9_EXTENDED } from '../constants/tokens'
import { useActiveWeb3React } from './web3'
@@ -75,6 +77,14 @@ export function useWETHContract(withSignerIfPossible?: boolean) {
return useContract<Weth>(chainId ? WETH9_EXTENDED[chainId]?.address : undefined, WETH_ABI, withSignerIfPossible)
}
export function useERC721Contract(nftAddress?: string) {
return useContract<Erc721>(nftAddress, ERC721_ABI, false)
}
export function useERC1155Contract(nftAddress?: string) {
return useContract<Erc1155>(nftAddress, ERC1155_ABI, false)
}
export function useArgentWalletDetectorContract() {
return useContract<ArgentWalletDetector>(ARGENT_WALLET_DETECTOR_ADDRESS, ARGENT_WALLET_DETECTOR_ABI, false)
}

View File

@@ -1,5 +1,5 @@
import { namehash } from '@ethersproject/hash'
import { useMemo } from 'react'
import { safeNamehash } from 'utils/safeNamehash'
import { useSingleCallResult } from '../state/multicall/hooks'
import isZero from '../utils/isZero'
@@ -11,14 +11,10 @@ import useDebounce from './useDebounce'
*/
export default function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } {
const debouncedName = useDebounce(ensName, 200)
const ensNodeArgument = useMemo(() => {
if (!debouncedName) return [undefined]
try {
return debouncedName ? [namehash(debouncedName)] : [undefined]
} catch (error) {
return [undefined]
}
}, [debouncedName])
const ensNodeArgument = useMemo(
() => [debouncedName === null ? undefined : safeNamehash(debouncedName)],
[debouncedName]
)
const registrarContract = useENSRegistrarContract(false)
const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
const resolverAddressResult = resolverAddress.result?.[0]

129
src/hooks/useENSAvatar.ts Normal file
View File

@@ -0,0 +1,129 @@
import { namehash } from '@ethersproject/hash'
import { useEffect, useMemo, useState } from 'react'
import { safeNamehash } from 'utils/safeNamehash'
import uriToHttp from 'utils/uriToHttp'
import { useSingleCallResult } from '../state/multicall/hooks'
import { isAddress } from '../utils'
import isZero from '../utils/isZero'
import { useENSRegistrarContract, useENSResolverContract, useERC721Contract, useERC1155Contract } from './useContract'
import useDebounce from './useDebounce'
import useENSName from './useENSName'
import { useActiveWeb3React } from './web3'
/**
* Returns the ENS avatar URI, if available.
* Spec: https://gist.github.com/Arachnid/9db60bd75277969ee1689c8742b75182.
*/
export default function useENSAvatar(
address?: string,
enforceOwnership = true
): { avatar: string | null; loading: boolean } {
const debouncedAddress = useDebounce(address, 200)
const node = useMemo(() => {
if (!debouncedAddress || !isAddress(debouncedAddress)) return undefined
return namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)
}, [debouncedAddress])
const addressAvatar = useAvatarFromNode(node)
const ENSName = useENSName(address).ENSName
const nameAvatar = useAvatarFromNode(ENSName === null ? undefined : safeNamehash(ENSName))
let avatar = addressAvatar.avatar || nameAvatar.avatar
const nftAvatar = useAvatarFromNFT(avatar, enforceOwnership)
avatar = nftAvatar.avatar || avatar
const http = avatar && uriToHttp(avatar)[0]
const changed = debouncedAddress !== address
return {
avatar: changed ? null : http ?? null,
loading: changed || addressAvatar.loading || nameAvatar.loading || nftAvatar.loading,
}
}
function useAvatarFromNode(node?: string): { avatar?: string; loading: boolean } {
const nodeArgument = useMemo(() => [node], [node])
const textArgument = useMemo(() => [node, 'avatar'], [node])
const registrarContract = useENSRegistrarContract(false)
const resolverAddress = useSingleCallResult(registrarContract, 'resolver', nodeArgument)
const resolverAddressResult = resolverAddress.result?.[0]
const resolverContract = useENSResolverContract(
resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined,
false
)
const avatar = useSingleCallResult(resolverContract, 'text', textArgument)
return {
avatar: avatar.result?.[0],
loading: resolverAddress.loading || avatar.loading,
}
}
function useAvatarFromNFT(nftUri = '', enforceOwnership: boolean): { avatar?: string; loading: boolean } {
const parts = nftUri.toLowerCase().split(':')
const protocol = parts[0]
// ignore the chain from eip155
// TODO: when we are able, pull only from the specified chain
const [, erc] = parts[1]?.split('/') ?? []
const [contractAddress, id] = parts[2]?.split('/') ?? []
const isERC721 = protocol === 'eip155' && erc === 'erc721'
const isERC1155 = protocol === 'eip155' && erc === 'erc1155'
const erc721 = useERC721Uri(isERC721 ? contractAddress : undefined, id, enforceOwnership)
const erc1155 = useERC1155Uri(isERC1155 ? contractAddress : undefined, id, enforceOwnership)
const uri = erc721.uri || erc1155.uri
const http = uri && uriToHttp(uri)[0]
const [loading, setLoading] = useState(false)
const [avatar, setAvatar] = useState(undefined)
useEffect(() => {
setAvatar(undefined)
if (http) {
setLoading(true)
fetch(http)
.then((res) => res.json())
.then(({ image }) => {
setAvatar(image)
})
.catch((e) => console.warn(e))
.finally(() => {
setLoading(false)
})
}
}, [http])
return { avatar, loading: erc721.loading || erc1155.loading || loading }
}
function useERC721Uri(
contractAddress: string | undefined,
id: string | undefined,
enforceOwnership: boolean
): { uri?: string; loading: boolean } {
const idArgument = useMemo(() => [id], [id])
const { account } = useActiveWeb3React()
const contract = useERC721Contract(contractAddress)
const owner = useSingleCallResult(contract, 'ownerOf', idArgument)
const uri = useSingleCallResult(contract, 'tokenURI', idArgument)
return {
uri: !enforceOwnership || account === owner.result?.[0] ? uri.result?.[0] : undefined,
loading: owner.loading || uri.loading,
}
}
function useERC1155Uri(
contractAddress: string | undefined,
id: string | undefined,
enforceOwnership: boolean
): { uri?: string; loading: boolean } {
const { account } = useActiveWeb3React()
const idArgument = useMemo(() => [id], [id])
const accountArgument = useMemo(() => [account || '', id], [account, id])
const contract = useERC1155Contract(contractAddress)
const balance = useSingleCallResult(contract, 'balanceOf', accountArgument)
const uri = useSingleCallResult(contract, 'uri', idArgument)
return {
uri: !enforceOwnership || balance.result?.[0] > 0 ? uri.result?.[0] : undefined,
loading: balance.loading || uri.loading,
}
}

View File

@@ -1,5 +1,5 @@
import { namehash } from '@ethersproject/hash'
import { useMemo } from 'react'
import { safeNamehash } from 'utils/safeNamehash'
import { useSingleCallResult } from '../state/multicall/hooks'
import isZero from '../utils/isZero'
@@ -9,14 +9,7 @@ import { useENSRegistrarContract, useENSResolverContract } from './useContract'
* Does a lookup for an ENS name to find its contenthash.
*/
export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } {
const ensNodeArgument = useMemo(() => {
if (!ensName) return [undefined]
try {
return ensName ? [namehash(ensName)] : [undefined]
} catch (error) {
return [undefined]
}
}, [ensName])
const ensNodeArgument = useMemo(() => [ensName === null ? undefined : safeNamehash(ensName)], [ensName])
const registrarContract = useENSRegistrarContract(false)
const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
const resolverAddress = resolverAddressResult.result?.[0]

View File

@@ -15,11 +15,7 @@ export default function useENSName(address?: string): { ENSName: string | null;
const debouncedAddress = useDebounce(address, 200)
const ensNodeArgument = useMemo(() => {
if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined]
try {
return debouncedAddress ? [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] : [undefined]
} catch (error) {
return [undefined]
}
return [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)]
}, [debouncedAddress])
const registrarContract = useENSRegistrarContract(false)
const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)

View File

@@ -34,23 +34,23 @@ const PERMITTABLE_TOKENS: {
[checksummedTokenAddress: string]: PermitInfo
}
} = {
[1]: {
1: {
[USDC.address]: { type: PermitType.AMOUNT, name: 'USD Coin', version: '2' },
[DAI.address]: { type: PermitType.ALLOWED, name: 'Dai Stablecoin', version: '1' },
[UNI[1].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
},
[4]: {
['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735']: { type: PermitType.ALLOWED, name: 'Dai Stablecoin', version: '1' },
4: {
'0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735': { type: PermitType.ALLOWED, name: 'Dai Stablecoin', version: '1' },
[UNI[4].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
},
[3]: {
3: {
[UNI[3].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
['0x07865c6E87B9F70255377e024ace6630C1Eaa37F']: { type: PermitType.AMOUNT, name: 'USD Coin', version: '2' },
'0x07865c6E87B9F70255377e024ace6630C1Eaa37F': { type: PermitType.AMOUNT, name: 'USD Coin', version: '2' },
},
[5]: {
5: {
[UNI[5].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
},
[42]: {
42: {
[UNI[42].address]: { type: PermitType.AMOUNT, name: 'Uniswap' },
},
}

View File

@@ -19,11 +19,7 @@ interface FeeTierDistribution {
largestUsageFeeTier?: FeeAmount | undefined
// distributions as percentages of overall liquidity
distributions?: {
[FeeAmount.LOW]: number | undefined
[FeeAmount.MEDIUM]: number | undefined
[FeeAmount.HIGH]: number | undefined
}
distributions?: Record<FeeAmount, number | undefined>
}
export function useFeeTierDistribution(
@@ -36,6 +32,7 @@ export function useFeeTierDistribution(
)
// fetch all pool states to determine pool state
const [poolStateVeryLow] = usePool(currencyA, currencyB, FeeAmount.LOWEST)
const [poolStateLow] = usePool(currencyA, currencyB, FeeAmount.LOW)
const [poolStateMedium] = usePool(currencyA, currencyB, FeeAmount.MEDIUM)
const [poolStateHigh] = usePool(currencyA, currencyB, FeeAmount.HIGH)
@@ -58,10 +55,13 @@ export function useFeeTierDistribution(
!isLoading &&
!isError &&
distributions &&
poolStateVeryLow !== PoolState.LOADING &&
poolStateLow !== PoolState.LOADING &&
poolStateMedium !== PoolState.LOADING &&
poolStateHigh !== PoolState.LOADING
? {
[FeeAmount.LOWEST]:
poolStateVeryLow === PoolState.EXISTS ? (distributions[FeeAmount.LOWEST] ?? 0) * 100 : undefined,
[FeeAmount.LOW]: poolStateLow === PoolState.EXISTS ? (distributions[FeeAmount.LOW] ?? 0) * 100 : undefined,
[FeeAmount.MEDIUM]:
poolStateMedium === PoolState.EXISTS ? (distributions[FeeAmount.MEDIUM] ?? 0) * 100 : undefined,
@@ -76,7 +76,17 @@ export function useFeeTierDistribution(
distributions: percentages,
largestUsageFeeTier: largestUsageFeeTier === -1 ? undefined : largestUsageFeeTier,
}
}, [isLoading, isFetching, isUninitialized, isError, distributions, poolStateLow, poolStateMedium, poolStateHigh])
}, [
isLoading,
isFetching,
isUninitialized,
isError,
distributions,
poolStateVeryLow,
poolStateLow,
poolStateMedium,
poolStateHigh,
])
}
function usePoolTVL(token0: Token | undefined, token1: Token | undefined) {
@@ -124,10 +134,11 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) {
return acc
},
{
[FeeAmount.LOWEST]: [undefined, undefined],
[FeeAmount.LOW]: [undefined, undefined],
[FeeAmount.MEDIUM]: [undefined, undefined],
[FeeAmount.HIGH]: [undefined, undefined],
}
} as Record<FeeAmount, [number | undefined, number | undefined]>
)
// sum total tvl for token0 and token1
@@ -144,7 +155,13 @@ function usePoolTVL(token0: Token | undefined, token1: Token | undefined) {
const mean = (tvl0: number | undefined, sumTvl0: number, tvl1: number | undefined, sumTvl1: number) =>
tvl0 === undefined && tvl1 === undefined ? undefined : ((tvl0 ?? 0) + (tvl1 ?? 0)) / (sumTvl0 + sumTvl1) || 0
const distributions = {
const distributions: Record<FeeAmount, number | undefined> = {
[FeeAmount.LOWEST]: mean(
tvlByFeeTier[FeeAmount.LOWEST][0],
sumToken0Tvl,
tvlByFeeTier[FeeAmount.LOWEST][1],
sumToken1Tvl
),
[FeeAmount.LOW]: mean(tvlByFeeTier[FeeAmount.LOW][0], sumToken0Tvl, tvlByFeeTier[FeeAmount.LOW][1], sumToken1Tvl),
[FeeAmount.MEDIUM]: mean(
tvlByFeeTier[FeeAmount.MEDIUM][0],

Some files were not shown because too many files have changed in this diff Show More