Compare commits

..

55 Commits

Author SHA1 Message Date
dependabot[bot]
ffe11f9eda chore(deps-dev): bump @uniswap/token-lists (#2425)
Bumps [@uniswap/token-lists](https://github.com/Uniswap/token-lists) from 1.0.0-beta.25 to 1.0.0-beta.26.
- [Release notes](https://github.com/Uniswap/token-lists/releases)
- [Commits](https://github.com/Uniswap/token-lists/compare/v1.0.0-beta.25...v1.0.0-beta.26)

---
updated-dependencies:
- dependency-name: "@uniswap/token-lists"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-22 17:32:47 -05:00
Crowdin Bot
d993741713 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-22 19:04:51 +00:00
Crowdin Bot
a05aae6c37 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-22 18:05:15 +00:00
Moody Salem
738fac0c84 chore(ci): configure dependabot to automatically update token lists 2021-09-22 12:52:11 -05:00
Ian Lapham
0099ef6d59 update SDN list (#2423) 2021-09-22 13:37:30 -04:00
Justin Domingue
8b3da3dbaa fix: infinite loop when brushing (#2422)
* refine comparison method

* adjust comment
2021-09-22 12:42:53 -04:00
Zach Pomerantz
8bb1983aaa chore: dedup @ethersproject (#2415)
Saves 20kb of gzipped payload.
2021-09-22 09:15:44 -07:00
Crowdin Bot
afbe846cba chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-22 02:15:59 +00:00
Crowdin Bot
901e0558b5 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-22 01:26:53 +00:00
Moody Salem
53da48b646 refactor: add an import sorting plugin (#2417)
* refactor: add an import sorting plugin

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-09-21 18:21:28 -05:00
Moody Salem
19c3983351 chore: update the linter to skip running on forks and update the version 2021-09-21 18:15:59 -05:00
Crowdin Bot
45709a5d36 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-21 22:05:23 +00:00
Moody Salem
fb07919888 refactor: transaction info is translated in the appropriate places (#2380)
* refactor: transaction info is translated in the appropriate places

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

* getting closer

* more work

* finished, finally

* bit more refactoring

* move summary into its own file

* little more cleanup in the transaction summary file

* fix bad copy

* fix the migrate notification

* missing translation

* fix the language for vote and address other pr comments

* fix typo

* - remove old transactions with this update
- change to present tense
- show ens name where appropriate

* add a test that shows we don't clear old ones
2021-09-21 16:45:24 -05:00
Zach Pomerantz
9fa3b70475 perf(font): serve inter var from public (#2403)
* perf(font): load Inter var from HTML, not JS

* perf(font): use font-display block

Prevents FOUT.

* perf(font): preload font

Further removes font from the critical render path.
2021-09-21 12:44:20 -07:00
Justin Domingue
91de599f12 fix: de-duplicate intermediate pairs (#2396)
* make useAllCurrencyCombinations return uniques

* consolidate useBestV3Trade* functions

* consolidate useBestV2Trade

* typo

* reverted changes to trade hooks

* reverted changes to trade hooks

Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
2021-09-21 15:42:30 -04:00
Justin Domingue
284a435171 chore: initial support for Swahili (Tanzanian) (#2397)
* initial support for Swahili (Tanzania)

* remove sw-KE
2021-09-21 15:41:58 -04:00
Zach Pomerantz
9b1903df77 perf(i18n): bundle default locale with main chunk (#2405)
* fix(i18n): do not defer render on locale

Do not defer render on locale load. This delays the initial render of the page, effectively delaying to LCP.
Lingui allows the page to render with no text while a locale is loading. A fallback locale is only used when loading a locale fails - not while it is pending.

* perf(i18n): include default language in initial bundle
2021-09-21 12:20:53 -07:00
dependabot[bot]
ba9ff0dfa5 chore(deps): bump tmpl from 1.0.4 to 1.0.5 (#2407)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-21 15:06:02 -04:00
Crowdin Bot
77679026ef chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-21 19:04:48 +00:00
Jordan Frankfurt
97ba8fb5b0 feat(L2-beta-launch): network selector (#2129)
* fix an issue with optimism/arbitrum alert distinction, add a prompt to switch to Optimism on mainnet

* only prompt to switch networks if the user has a wallet connected

* add readmore link styles

* add network to the user's wallet if it hasn't been added already

* network selector

* hide arbitrum until it launches

* add arbitrum for testing

* update copy and some margins

* fix alert opacity issue

* remove the launch alert :(

* adjust icon position and add curvier corners

* lighten some colors

* keep the selector around even if the user's wallet doesn't support the eip when they're on L2, just hide all other networks

* copy updates and some other small tweaks

* better mobile experience

* shrink on mobile

* fix some links and css

* differentiate between selector and row logos

* fix some copy

* remove network alert from add liquidity pages, update copy and buttons on swap page, remove close option if no eth, persist close state otherwise

* design polish

* update read more links

* update downtime warning to be less intense

* oe logo
'

* design polish sesh

* fix a couple bugs
2021-09-21 14:57:29 -04:00
Moody Salem
119c79d623 fix: improve the meta tags (#2412) 2021-09-21 13:14:58 -05:00
Justin Domingue
cc9650b74b refactor: simplify trade hooks (#2371)
* merge tradeExactIn|Out

* cleanup

* reset polling interval

* polish

* improved types and fixed client side

* rename combined to bestv3
2021-09-21 13:51:50 -04:00
Zach Pomerantz
e242faca86 perf: render components on first frame (#2404)
* fix(nav): render Vote link while awaiting connection

Minimizes layout shift in the normal case.

* perf: inline logo svg

* perf: display connect button for web3 initial state
2021-09-20 16:03:57 -07:00
Crowdin Bot
1a73f513dc chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-20 15:38:09 +00:00
Crowdin Bot
c43912df94 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-20 10:05:15 +00:00
Crowdin Bot
b07bc40230 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-20 08:05:20 +00:00
Crowdin Bot
dabb511ff5 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-18 18:05:22 +00:00
Moody Salem
6ae632158e fix: bump walletconnect to fix android deep linking (#2384) 2021-09-17 15:56:08 -05:00
Justin Domingue
648e4e02c4 ignore v3 state when only v2 only (#2383) 2021-09-17 16:29:08 -04:00
Crowdin Bot
9bc00ccaf6 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-17 18:05:12 +00:00
Crowdin Bot
2e90561978 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-17 17:08:27 +00:00
Zach Pomerantz
bea63cd4b4 feat: report web-vitals to ga (#2363) 2021-09-17 09:14:45 -07:00
Carlos Diaz-Padron
cc8c5712ec feat: add @davatar/react for robust avatar support (#2321)
* add @davatar/react for robust avatar support

* remove @metamask/jazzicon, unused

* move @davatar/react to devDependencies

* pin exact version for @davatar/react
2021-09-16 16:04:11 -04:00
Justin Domingue
112b00521c fix: flip token logos in routing diagram (#2375)
* flip token logos in route

* update snapshot
2021-09-16 14:50:51 -04:00
Justin Domingue
1314477a88 add static route svg (#2373) 2021-09-16 14:16:19 -04:00
Crowdin Bot
c6b6e7f0d6 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-16 17:07:45 +00:00
Crowdin Bot
c8009ca909 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-16 16:05:14 +00:00
Crowdin Bot
2cabd7dc51 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-16 15:04:55 +00:00
Justin Domingue
cd22955817 feat: routing api integration (#2116)
* initial routing api integration

* add routing api slice

* display route in dialog

* addressed pr feedback

* improved routing

* switch to `get`

* first pass at integration new MultiRouteTrade

* initial implementation of RoutingDiagram

* add RoutingDiagram tests

* improve tests in RoutingDiagram

* integrate with v3-sdk 3.3.1

* removed references to MultiRouteTrade

* revert swapcallback

* fix abi compilation error

* added useRoute hook to build a Route from edges and nodes

* added react-hooks-testing-library

* integrated latest changes

* renamed router hook to routerTrade

* improve integration

* fixed routing

* usability

* mock RoutingDiagram children to reduce size

* undo mocked children

* adjust ui

* better support long routes

* use routing api logo and adjust ux

* set default percent to 0

* added intermediary hook to combine local and routing api trades

* added intermediary hook to combine local and routing api trades

* make account optional

* improve ux

* improve router

* fixed duplicate pool bug and inputAmount undefined bug

* extract input/outputAmounts from routes

* add todo

* fixed uninitialized issue and added %

* fixed tests

* fix duplicate pool bug

* added routing api setting

* change router label based on router version

* improve useRoutes and fix duplicate pool bug

* debounce routing api/local routing

* removed single hop setting

* fix bug when moving between v2/v3

* consider isUnitialized non loading

* ui fixes

* reverted change to usedebounce

* use new route schema

* visual updates

* log quoteId for polish session

* fix: persist advanced swap details toggle state

* fix no route found

* poll every 10s

* derive currencies from pool rather than input

* polish query status handling in useRouterTrade

* removed RouterVersion

* update ui

* update ui

* update loading state

* animate auto router

* apply loading treatment to out

* disable routing api on l2 and support auto slippage

* use opacity on the whole element

* show loading card when syncing

* updated gradient

* polished ui

* create routerlabel component

* disable router on all bu mainnet

* polish

* feat: [draft] routing api polish (#2224)

* show loading card when syncing

* updated gradient

* polished ui

* create routerlabel component

* disable router on all bu mainnet

* polish

* polished loading state

* add dashes

* fixed tooltip styles

* fixed merge conflict

* few updates

* polish

* updated yarn.lock

* fixed styles

* updated routing diagram

* Fix code style issues with ESLint

* routing api enabled without localstorage upgrade

* fixed lint error

* Fix code style issues with ESLint

* refined mocks in routing diagram tests

* addressed pr feedback

* polish

* revert sending eth

* improved loading animation

* handle stale routing api

* Fix code style issues with ESLint

* updated yarn.lock

* support native eth

* Compute gas adjusted quote for V2 trade and compare to V3 gas adjusted quote

* Incorporate approval gas cost estimate

* feat: simplify routing api ux (#2258)

* support native eth

* simplified ui

* perf optimization

* implement realized lp fee

* improved route realized lp fee

* fix lp realized fee

* fix auto router gradient

* initial route overlay

* add auto router svg

* adjusted ux to mocks

* fix lp fee

* upddated routing diagram

* optimize tradeBetter hook

* adjust type and name

* add useBetterTrade

* useBetterTrade takes gasEstimateWei

* implement gasEstimateForApproval

* import state from react

* use gas estimate

* improve integration with gas estimate comparison

* remove dependency on account

* fix currency switch bug

* improve syncing state

* add loadingbar

* style tooltip container

* updated tooltip styles

* increase opacity range

* always keep dependent currency input interactable

* show placeholders in tooltips

* Revert v2 gas estimates and approval estimates

* Add debug logs

* refactor

* fix bug

* removed comment

* update engish key

* add try-catch

* addressed pr feedback

* remove loading bar for price impact

* addressed pr feedback and bug bash feedback

* fix: use url to force version

* addressed pr feedback and bug bash feedback

* stop fetching when losing focus

* only show auto router label when activated

* avoid showing syncing status

* move V3TradeSTate to own file

* make useRoutes a function rather than hook

* use logo from active list when possible

* renamed and refactored hook

* renamed and refactored hook

* update status

* polish

* remove unused import

* fixed merge error

* updated combined trade tests

* remove priceimpact while loading

* Design tweaks

* polish latest design

* removed some styles

* log gaevent on tooltip open and clean up origin

* Small tweaks

* addressed pr feedback

* wrap route length in a loading container

* renamed local to clientside

* fix percent and token logo

* addressed pr feedback

* avoid comparing trades when v3 not ready

* some refactor

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Will Pote <will@uniswap.org>
Co-authored-by: Callil Capuozzo <callil.capuozzo@gmail.com>
2021-09-16 10:50:58 -04:00
Crowdin Bot
fb33a06861 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-16 03:04:54 +00:00
Jordan Frankfurt
bcf64bcb11 feat(chain-connectivity): warn when the user is not receiving blocks (#2123)
* logic for tracking time since last block

* add polling times to chain info

* pr feedback

* add gui for chain connectivity warning

* add arb support

* update title of warning to indicate internet connectivity issues may be the problem

* pr review

* clean up useBlockWarningTimer

* softer language on mainnet

* only show warning if user has the window visible
2021-09-15 22:20:28 -04:00
Zach Pomerantz
c2093ce040 feat: lazily load token list validator (#2342)
Removes 125kb from main chunk. Moves ~90ms off of the critical pageload path.
2021-09-15 13:23:17 -07:00
Zach Pomerantz
308f7d59a0 fix: avoid replaceAll (#2361) 2021-09-15 13:20:14 -07:00
Zach Pomerantz
c68d08ac26 fix: shim array-flat (#2346)
* chore: remove @types/lodash.flatmap

* fix: shim array-flat
2021-09-15 11:03:12 -07:00
Crowdin Bot
f826554bd4 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-15 17:06:46 +00:00
Crowdin Bot
dc2d1b06d2 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-15 16:05:05 +00:00
Patrick
8ea5cb450a style: Fix letter case consistency (#2353)
* Fix letter case consistency

Fixed lower case to upper case to be consistent with:

src/pages/AddLiquidityV2/index.tsx
src/pages/RemoveLiquidity/index.tsx
src/pages/Swap/index.tsx
src/state/burn/hooks.ts
src/state/burn/v3/hooks.ts
src/state/mint/hooks.ts
src/state/mint/v3/hooks.ts
src/state/stake/hooks.ts
src/state/swap/hooks.ts

* style: Fix case to be consistent
2021-09-15 11:03:56 -04:00
Patrick
58249e3ce2 Fix letter case consistency (#2352)
Fixed upper case to lower case to be consistent with src/components/SearchModal/ImportList.tsx
2021-09-15 10:42:57 -04:00
Crowdin Bot
2ee79f74e9 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-15 11:04:52 +00:00
Crowdin Bot
24f85d422c chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-15 09:05:18 +00:00
Crowdin Bot
d98954067e chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-14 20:17:38 +00:00
Zach Pomerantz
58f1193a21 fix: add deps to try safe effect (#2349) 2021-09-14 11:20:52 -07:00
Zach Pomerantz
88cc20a61a feat(i18n): initialize locale before React (#2343)
* feat: initialize locale before React

* chore: explain react-router-dom hash/search usage
2021-09-14 10:17:56 -07:00
Zach Pomerantz
442ac8936d chore: use ubuntu-latest for integration tests (#2348) 2021-09-14 10:04:15 -07:00
Crowdin Bot
c563717aae chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-14 14:06:02 +00:00
336 changed files with 15687 additions and 7129 deletions

View File

@@ -21,7 +21,10 @@
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"plugins": ["simple-import-sort"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"prettier/prettier": "error",
"@typescript-eslint/no-explicit-any": "off",

9
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: npm
# Files stored in repository root
directory: "/"
schedule:
interval: "daily"
allow:
- dependency-name: "@uniswap/token-lists"

View File

@@ -11,7 +11,7 @@ on:
jobs:
integration-tests:
name: Cypress
runs-on: ubuntu-16.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

View File

@@ -4,13 +4,14 @@ on:
push:
branches:
- main
pull_request_target:
pull_request:
branches:
- main
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,7 +40,7 @@ jobs:
run: yarn install --frozen-lockfile
- name: Run linters
uses: wearerequired/lint-action@b98b0918aa71490373d2eca9e8e39a9bc1cc2517
uses: wearerequired/lint-action@36c7e6689e80d785d27a22f71d970f3a3b4fcb70
with:
github_token: ${{ secrets.github_token }}
eslint: true

2
.gitignore vendored
View File

@@ -4,8 +4,6 @@
/src/types/v3
/src/abis/types
/src/locales/**/*.js
/src/locales/**/*.ts
/src/locales/**/*.json
/src/locales/**/en-US.po
/src/state/data/generated.ts

View File

@@ -1,4 +1,5 @@
import { CyHttpMessages } from 'cypress/types/net-stubbing'
import { aliasQuery, hasQuery } from '../utils/graphql-test-utils'
describe('Add Liquidity', () => {

View File

@@ -4,9 +4,9 @@
// https://on.cypress.io/custom-commands
// ***********************************************
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
import { JsonRpcProvider } from '@ethersproject/providers'
import { Wallet } from '@ethersproject/wallet'
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
// todo: figure out how env vars actually work in CI
// const TEST_PRIVATE_KEY = Cypress.env('INTEGRATION_TEST_PRIVATE_KEY')

View File

@@ -40,6 +40,7 @@ export default {
'ru-RU',
'sr-SP',
'sv-SE',
'sw-TZ',
'tr-TR',
'uk-UA',
'vi-VN',

View File

@@ -4,6 +4,7 @@
"homepage": ".",
"private": true,
"devDependencies": {
"@davatar/react": "1.1.0",
"@ethersproject/experimental": "^5.4.0",
"@gnosis.pm/safe-apps-web3-react": "^0.6.0",
"@graphql-codegen/cli": "1.21.5",
@@ -11,10 +12,8 @@
"@graphql-codegen/typescript-operations": "^1.18.2",
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
"@lingui/cli": "^3.9.0",
"@lingui/loader": "^3.9.0",
"@lingui/macro": "^3.9.0",
"@lingui/react": "^3.9.0",
"@metamask/jazzicon": "^2.0.0",
"@popperjs/core": "^2.4.4",
"@reach/dialog": "^0.10.3",
"@reach/portal": "^0.10.3",
@@ -22,13 +21,15 @@
"@reduxjs/toolkit": "^1.6.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^7.0.2",
"@typechain/ethers-v5": "^7.0.0",
"@types/array.prototype.flat": "^1.2.1",
"@types/array.prototype.flatmap": "^1.2.2",
"@types/d3": "^6.7.1",
"@types/jest": "^25.2.1",
"@types/lingui__core": "^2.7.1",
"@types/lingui__macro": "^2.7.4",
"@types/lingui__react": "^2.8.3",
"@types/lodash.flatmap": "^4.5.6",
"@types/luxon": "^1.24.4",
"@types/ms.macro": "^2.0.0",
"@types/multicodec": "^1.0.0",
@@ -52,7 +53,7 @@
"@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "1.0.1",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/token-lists": "^1.0.0-beta.25",
"@uniswap/token-lists": "^1.0.0-beta.26",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v2-sdk": "^3.0.0-alpha.2",
@@ -66,6 +67,8 @@
"@web3-react/walletconnect-connector": "^7.0.2-alpha.0",
"@web3-react/walletlink-connector": "^6.2.3",
"ajv": "^6.12.3",
"array.prototype.flat": "^1.2.4",
"array.prototype.flatmap": "^1.2.4",
"cids": "^1.0.0",
"copy-to-clipboard": "^3.2.0",
"cypress": "^7.7.0",
@@ -75,6 +78,7 @@
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.0.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"ethers": "^5.4.6",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
@@ -115,26 +119,28 @@
"ua-parser-js": "^0.7.28",
"use-count-up": "^2.2.5",
"wcag-contrast": "^3.0.0",
"web-vitals": "^2.1.0",
"workbox-core": "^6.1.0",
"workbox-precaching": "^6.1.0",
"workbox-routing": "^6.1.0"
},
"resolutions": {
"@walletconnect/ethereum-provider": "1.6.4"
"@walletconnect/ethereum-provider": "1.6.5"
},
"scripts": {
"compile-contract-types": "yarn compile-external-abi-types && yarn compile-v3-contract-types",
"compile-external-abi-types": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
"compile-v3-contract-types": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
"build": "yarn compile-contract-types && yarn graphql:generate && yarn i18n:extract && react-scripts build",
"build": "yarn compile-contract-types && yarn graphql:generate && yarn i18n:extract && yarn i18n:compile && react-scripts build",
"i18n:extract": "lingui extract --locale en-US",
"i18n:compile": "lingui compile",
"integration-test": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
"graphql:generate": "graphql-codegen --config codegen.yml",
"postinstall": "yarn compile-contract-types",
"start": "yarn compile-contract-types && react-scripts start",
"test": "react-scripts test --env=./custom-test-env.js",
"prei18n:extract": "touch src/locales/en-US.po",
"prestart": "yarn graphql:generate && yarn prei18n:extract"
"prestart": "yarn graphql:generate && yarn prei18n:extract && yarn i18n:compile"
},
"eslintConfig": {
"extends": "react-app",

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<title>Uniswap Interface</title>
<meta name="description" content="Uniswap Interface" />
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
<!--
%PUBLIC_URL% will be replaced with the URL of the `public` folder during build.
@@ -14,7 +14,7 @@
<link rel="apple-touch-icon" sizes="192x192" href="%PUBLIC_URL%/images/192x192_App_Icon.png" />
<link rel="apple-touch-icon" sizes="512x512" href="%PUBLIC_URL%/images/512x512_App_Icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="theme-color" content="#ff007a" />
<meta name="fortmatic-site-verification" content="j93LgcVZk79qcgyo" />
@@ -26,15 +26,31 @@
<link rel="preconnect" href="https://www.google-analytics.com/">
<link rel="preload" href="%PUBLIC_URL%/fonts/Inter-roman.var.woff2" as="font" type="font/woff2" crossorigin>
<style>
* {
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
font-named-instance: 'Regular';
src: url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2 supports variations(gvar)"),
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2-variations"),
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2");
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Inter var', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@@ -92,7 +108,7 @@
<!-- The root is the container of the app -->
<div id="root">
<!-- Triggers the font to load immediately and then is replaced by the app -->
<div style="visibility: hidden">X</div>
<div>&emsp;</div>
</div>
<div id="background-radial-gradient"></div>

View File

@@ -0,0 +1,10 @@
<svg width="23" height="20" viewBox="0 0 23 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="gradient1" x1="0" y1="0" x2="1" y2="0" gradientTransform="rotate(95)">
<stop id="stop1" offset="0" stop-color="#2274E2"/>
<stop id="stop1" offset="0.5" stop-color="#2274E2"/>
<stop id="stop2" offset="1" stop-color="#3FB672" />
</linearGradient>
</defs>
<path d="M16 16C10 16 9 10 5 10M16 16C16 17.6569 17.3431 19 19 19C20.6569 19 22 17.6569 22 16C22 14.3431 20.6569 13 19 13C17.3431 13 16 14.3431 16 16ZM5 10C9 10 10 4 16 4M5 10H1.5M16 4C16 5.65685 17.3431 7 19 7C20.6569 7 22 5.65685 22 4C22 2.34315 20.6569 1 19 1C17.3431 1 16 2.34315 16 4Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="url(#gradient1)" />
</svg>

After

Width:  |  Height:  |  Size: 782 B

View File

@@ -0,0 +1,16 @@
<svg width="170" height="168" viewBox="0 0 170 168" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path opacity="0.6" d="M85.05 168C132.022 168 170.1 130.105 170.1 83.3593C170.1 36.6135 0 36.6135 0 83.3593C0 130.105 38.0782 168 85.05 168Z" fill="#FF505F"/>
<path opacity="0.6" d="M85.05 168C132.022 168 170.1 130.105 170.1 83.3593C170.1 36.6135 0 36.6135 0 83.3593C0 130.105 38.0782 168 85.05 168Z" fill="#FF0320"/>
<path d="M85.05 0C132.022 0 170.1 37.8949 170.1 84.6407C170.1 131.386 0 131.386 0 84.6407C0 37.8949 38.0782 0 85.05 0Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.665 64.0394L112.444 12.3742L89.0263 78.9477L144.665 64.0394Z" fill="#FF4E65"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M143.777 64.215L112.444 12.3742L165.349 58.4347L143.777 64.215Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M144.551 63.613L142.479 124.467L88.912 78.5213L144.551 63.613Z" fill="#D0001A"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M143.663 63.7886L142.479 124.467L165.235 58.0083L143.663 63.7886Z" fill="#FF697B"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="170" height="168" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 18C19 18.5523 18.5523 19 18 19V21C19.6569 21 21 19.6569 21 18H19ZM18 19C17.4477 19 17 18.5523 17 18H15C15 19.6569 16.3431 21 18 21V19ZM17 18C17 17.4477 17.4477 17 18 17V15C16.3431 15 15 16.3431 15 18H17ZM18 17C18.5523 17 19 17.4477 19 18H21C21 16.3431 19.6569 15 18 15V17ZM8 7H16V5H8V7ZM16 11H8V13H16V11ZM8 19H16V17H8V19ZM4 15C4 17.2091 5.79086 19 8 19V17C6.89543 17 6 16.1046 6 15H4ZM8 11C5.79086 11 4 12.7909 4 15H6C6 13.8954 6.89543 13 8 13V11ZM18 9C18 10.1046 17.1046 11 16 11V13C18.2091 13 20 11.2091 20 9H18ZM16 7C17.1046 7 18 7.89543 18 9H20C20 6.79086 18.2091 5 16 5V7ZM7 6C7 6.55228 6.55228 7 6 7V9C7.65685 9 9 7.65685 9 6H7ZM6 7C5.44772 7 5 6.55228 5 6H3C3 7.65685 4.34315 9 6 9V7ZM5 6C5 5.44772 5.44772 5 6 5V3C4.34315 3 3 4.34315 3 6H5ZM6 5C6.55228 5 7 5.44772 7 6H9C9 4.34315 7.65685 3 6 3V5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@@ -1,10 +1,10 @@
import React from 'react'
import styled from 'styled-components/macro'
import useCopyClipboard from '../../hooks/useCopyClipboard'
import { LinkStyledButton } from '../../theme'
import { CheckCircle, Copy } from 'react-feather'
import { Trans } from '@lingui/macro'
import React from 'react'
import { CheckCircle, Copy } from 'react-feather'
import styled from 'styled-components/macro'
import useCopyClipboard from '../../hooks/useCopyClipboard'
import { LinkStyledButton } from '../../theme'
const CopyIcon = styled(LinkStyledButton)`
color: ${({ theme }) => theme.text3};

View File

@@ -1,14 +1,13 @@
import styled from 'styled-components/macro'
import { CheckCircle, Triangle } from 'react-feather'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink } from '../../theme'
import { useAllTransactions } from '../../state/transactions/hooks'
import { ExternalLink } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { RowFixed } from '../Row'
import Loader from '../Loader'
const TransactionWrapper = styled.div``
import { RowFixed } from '../Row'
import { TransactionSummary } from './TransactionSummary'
const TransactionStatusText = styled.div`
margin-right: 0.5rem;
@@ -40,26 +39,28 @@ export default function Transaction({ hash }: { hash: string }) {
const allTransactions = useAllTransactions()
const tx = allTransactions?.[hash]
const summary = tx?.summary
const info = tx?.info
const pending = !tx?.receipt
const success = !pending && tx && (tx.receipt?.status === 1 || typeof tx.receipt?.status === 'undefined')
if (!chainId) return null
return (
<TransactionWrapper>
<div>
<TransactionState
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
pending={pending}
success={success}
>
<RowFixed>
<TransactionStatusText>{summary ?? hash} </TransactionStatusText>
<TransactionStatusText>
<TransactionSummary info={info} />
</TransactionStatusText>
</RowFixed>
<IconWrapper pending={pending} success={success}>
{pending ? <Loader /> : success ? <CheckCircle size="16" /> : <Triangle size="16" />}
</IconWrapper>
</TransactionState>
</TransactionWrapper>
</div>
)
}

View File

@@ -0,0 +1,329 @@
import { Trans } from '@lingui/macro'
import { Fraction, TradeType } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import { useCurrency, useToken } from '../../hooks/Tokens'
import useENSName from '../../hooks/useENSName'
import { VoteOption } from '../../state/governance/types'
import {
AddLiquidityV2PoolTransactionInfo,
AddLiquidityV3PoolTransactionInfo,
ApproveTransactionInfo,
ClaimTransactionInfo,
CollectFeesTransactionInfo,
CreateV3PoolTransactionInfo,
DelegateTransactionInfo,
DepositLiquidityStakingTransactionInfo,
ExactInputSwapTransactionInfo,
ExactOutputSwapTransactionInfo,
MigrateV2LiquidityToV3TransactionInfo,
RemoveLiquidityV3TransactionInfo,
SubmitProposalTransactionInfo,
TransactionInfo,
TransactionType,
VoteTransactionInfo,
WithdrawLiquidityStakingTransactionInfo,
WrapTransactionInfo,
} from '../../state/transactions/actions'
function formatAmount(amountRaw: string, decimals: number, sigFigs: number): string {
return new Fraction(amountRaw, JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(decimals))).toSignificant(sigFigs)
}
function FormattedCurrencyAmount({
rawAmount,
symbol,
decimals,
sigFigs,
}: {
rawAmount: string
symbol: string
decimals: number
sigFigs: number
}) {
return (
<>
{formatAmount(rawAmount, decimals, sigFigs)} {symbol}
</>
)
}
function FormattedCurrencyAmountManaged({
rawAmount,
currencyId,
sigFigs = 6,
}: {
rawAmount: string
currencyId: string
sigFigs: number
}) {
const currency = useCurrency(currencyId)
return currency ? (
<FormattedCurrencyAmount
rawAmount={rawAmount}
decimals={currency.decimals}
sigFigs={sigFigs}
symbol={currency.symbol ?? '???'}
/>
) : null
}
function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransactionInfo }) {
const { ENSName } = useENSName()
return typeof uniAmountRaw === 'string' ? (
<Trans>
Claim <FormattedCurrencyAmount rawAmount={uniAmountRaw} symbol={'UNI'} decimals={18} sigFigs={4} /> for{' '}
{ENSName ?? recipient}
</Trans>
) : (
<Trans>Claim UNI reward for {ENSName ?? recipient}</Trans>
)
}
function SubmitProposalTransactionSummary({}: { info: SubmitProposalTransactionInfo }) {
return <Trans>Submit new proposal</Trans>
}
function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) {
const token = useToken(info.tokenAddress)
return <Trans>Approve {token?.symbol}</Trans>
}
function VoteSummary({ info }: { info: VoteTransactionInfo }) {
const proposalKey = `${info.governorAddress}/${info.proposalId}`
if (info.reason && info.reason.trim().length > 0) {
switch (info.decision) {
case VoteOption.For:
return <Trans>Vote for proposal {proposalKey}</Trans>
case VoteOption.Abstain:
return <Trans>Vote to abstain on proposal {proposalKey}</Trans>
case VoteOption.Against:
return <Trans>Vote against proposal {proposalKey}</Trans>
}
} else {
switch (info.decision) {
case VoteOption.For:
return (
<Trans>
Vote for proposal {proposalKey} with reason &quot;{info.reason}&quot;
</Trans>
)
case VoteOption.Abstain:
return (
<Trans>
Vote to abstain on proposal {proposalKey} with reason &quot;{info.reason}&quot;
</Trans>
)
case VoteOption.Against:
return (
<Trans>
Vote against proposal {proposalKey} with reason &quot;{info.reason}&quot;
</Trans>
)
}
}
}
function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInfo }) {
const { ENSName } = useENSName(delegatee)
return <Trans>Delegate voting power to {ENSName ?? delegatee}</Trans>
}
function WrapSummary({ info: { currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
if (unwrapped) {
return (
<Trans>
Unwrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'WETH'} decimals={18} sigFigs={6} /> to
ETH
</Trans>
)
} else {
return (
<Trans>
Wrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'ETH'} decimals={18} sigFigs={6} /> to WETH
</Trans>
)
}
}
function DepositLiquidityStakingSummary({}: { info: DepositLiquidityStakingTransactionInfo }) {
// not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts
// todo: deprecate and delete the code paths that allow this, show user more information
return <Trans>Deposit liquidity</Trans>
}
function WithdrawLiquidityStakingSummary({}: { info: WithdrawLiquidityStakingTransactionInfo }) {
return <Trans>Withdraw deposited liquidity</Trans>
}
function MigrateLiquidityToV3Summary({
info: { baseCurrencyId, quoteCurrencyId },
}: {
info: MigrateV2LiquidityToV3TransactionInfo
}) {
const baseCurrency = useCurrency(baseCurrencyId)
const quoteCurrency = useCurrency(quoteCurrencyId)
return (
<Trans>
Migrate {baseCurrency?.symbol}/{quoteCurrency?.symbol} liquidity to V3
</Trans>
)
}
function CreateV3PoolSummary({ info: { quoteCurrencyId, baseCurrencyId } }: { info: CreateV3PoolTransactionInfo }) {
const baseCurrency = useCurrency(baseCurrencyId)
const quoteCurrency = useCurrency(quoteCurrencyId)
return (
<Trans>
Create {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 pool
</Trans>
)
}
function CollectFeesSummary({ info: { currencyId0, currencyId1 } }: { info: CollectFeesTransactionInfo }) {
const currency0 = useCurrency(currencyId0)
const currency1 = useCurrency(currencyId1)
return (
<Trans>
Collect {currency0?.symbol}/{currency1?.symbol} fees
</Trans>
)
}
function RemoveLiquidityV3Summary({
info: { baseCurrencyId, quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw },
}: {
info: RemoveLiquidityV3TransactionInfo
}) {
return (
<Trans>
Remove{' '}
<FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} /> and{' '}
<FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />
</Trans>
)
}
function AddLiquidityV3PoolSummary({
info: { createPool, quoteCurrencyId, baseCurrencyId },
}: {
info: AddLiquidityV3PoolTransactionInfo
}) {
const baseCurrency = useCurrency(baseCurrencyId)
const quoteCurrency = useCurrency(quoteCurrencyId)
return createPool ? (
<Trans>
Create pool and add {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 liquidity
</Trans>
) : (
<Trans>
Add {baseCurrency?.symbol}/{quoteCurrency?.symbol} V3 liquidity
</Trans>
)
}
function AddLiquidityV2PoolSummary({
info: { quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw, baseCurrencyId },
}: {
info: AddLiquidityV2PoolTransactionInfo
}) {
return (
<Trans>
Add <FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} />{' '}
and <FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />{' '}
to Uniswap V2
</Trans>
)
}
function SwapSummary({ info }: { info: ExactInputSwapTransactionInfo | ExactOutputSwapTransactionInfo }) {
if (info.tradeType === TradeType.EXACT_INPUT) {
return (
<Trans>
Swap exactly{' '}
<FormattedCurrencyAmountManaged
rawAmount={info.inputCurrencyAmountRaw}
currencyId={info.inputCurrencyId}
sigFigs={6}
/>{' '}
for{' '}
<FormattedCurrencyAmountManaged
rawAmount={info.expectedOutputCurrencyAmountRaw}
currencyId={info.outputCurrencyId}
sigFigs={6}
/>
</Trans>
)
} else {
return (
<Trans>
Swap{' '}
<FormattedCurrencyAmountManaged
rawAmount={info.expectedInputCurrencyAmountRaw}
currencyId={info.inputCurrencyId}
sigFigs={6}
/>{' '}
for exactly{' '}
<FormattedCurrencyAmountManaged
rawAmount={info.outputCurrencyAmountRaw}
currencyId={info.outputCurrencyId}
sigFigs={6}
/>
</Trans>
)
}
}
export function TransactionSummary({ info }: { info: TransactionInfo }) {
switch (info.type) {
case TransactionType.ADD_LIQUIDITY_V3_POOL:
return <AddLiquidityV3PoolSummary info={info} />
case TransactionType.ADD_LIQUIDITY_V2_POOL:
return <AddLiquidityV2PoolSummary info={info} />
case TransactionType.CLAIM:
return <ClaimSummary info={info} />
case TransactionType.DEPOSIT_LIQUIDITY_STAKING:
return <DepositLiquidityStakingSummary info={info} />
case TransactionType.WITHDRAW_LIQUIDITY_STAKING:
return <WithdrawLiquidityStakingSummary info={info} />
case TransactionType.SWAP:
return <SwapSummary info={info} />
case TransactionType.APPROVAL:
return <ApprovalSummary info={info} />
case TransactionType.VOTE:
return <VoteSummary info={info} />
case TransactionType.DELEGATE:
return <DelegateSummary info={info} />
case TransactionType.WRAP:
return <WrapSummary info={info} />
case TransactionType.CREATE_V3_POOL:
return <CreateV3PoolSummary info={info} />
case TransactionType.MIGRATE_LIQUIDITY_V3:
return <MigrateLiquidityToV3Summary info={info} />
case TransactionType.COLLECT_FEES:
return <CollectFeesSummary info={info} />
case TransactionType.REMOVE_LIQUIDITY_V3:
return <RemoveLiquidityV3Summary info={info} />
case TransactionType.SUBMIT_PROPOSAL:
return <SubmitProposalTransactionSummary info={info} />
}
}

View File

@@ -1,27 +1,27 @@
import { Trans } from '@lingui/macro'
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 { SUPPORTED_WALLETS } from '../../constants/wallet'
import { useActiveWeb3React } from '../../hooks/web3'
import { clearAllTransactions } from '../../state/transactions/actions'
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
import { shortenAddress } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonSecondary } from '../Button'
import Identicon from '../Identicon'
import { AutoRow } from '../Row'
import Copy from './Copy'
import Transaction from './Transaction'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
import PortisIcon from '../../assets/images/portisIcon.png'
import Identicon from '../Identicon'
import { ButtonSecondary } from '../Button'
import { ExternalLink as LinkIcon } from 'react-feather'
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
import { Trans } from '@lingui/macro'
import { useAppDispatch } from 'state/hooks'
const HeaderRow = styled.div`
${({ theme }) => theme.flexRowNoWrap};
padding: 1rem 1rem;

View File

@@ -1,6 +1,7 @@
import { t, Trans } from '@lingui/macro'
import { useContext, useCallback, ReactNode } from 'react'
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'

View File

@@ -1,9 +1,9 @@
import { Trans } from '@lingui/macro'
import Badge, { BadgeVariant } from 'components/Badge'
import { AlertCircle } from 'react-feather'
import styled from 'styled-components/macro'
import { MouseoverTooltip } from '../../components/Tooltip'
import { Trans } from '@lingui/macro'
import { AlertCircle } from 'react-feather'
const BadgeWrapper = styled.div`
font-size: 14px;

View File

@@ -1,6 +1,7 @@
import { ReactNode, useMemo } from 'react'
import { useActiveWeb3React } from '../../hooks/web3'
import { Trans } from '@lingui/macro'
import { ReactNode, useMemo } from 'react'
import { useActiveWeb3React } from '../../hooks/web3'
// SDN OFAC addresses
const BLOCKED_ADDRESSES: string[] = [
@@ -10,6 +11,7 @@ const BLOCKED_ADDRESSES: string[] = [
'0xA7e5d5A720f06526557c513402f2e6B5fA20b008',
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
'0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963',
'0x9f4cda013e354b8fc285bf4b9a60460cee7f7ea9',
]
export default function Blocklist({ children }: { children: ReactNode }) {

View File

@@ -1,14 +1,14 @@
import styled from 'styled-components/macro'
import useTheme from 'hooks/useTheme'
import { darken } from 'polished'
import { Check, ChevronDown } from 'react-feather'
import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components'
import styled from 'styled-components/macro'
import { RowBetween } from '../Row'
import { ChevronDown, Check } from 'react-feather'
import { Button as RebassButton, ButtonProps as ButtonPropsOriginal } from 'rebass/styled-components'
import useTheme from 'hooks/useTheme'
type ButtonProps = Omit<ButtonPropsOriginal, 'css'>
const Base = styled(RebassButton)<
export const BaseButton = styled(RebassButton)<
{
padding?: string
width?: string
@@ -50,7 +50,7 @@ const Base = styled(RebassButton)<
}
`
export const ButtonPrimary = styled(Base)`
export const ButtonPrimary = styled(BaseButton)`
background-color: ${({ theme }) => theme.primary1};
color: white;
&:focus {
@@ -67,7 +67,8 @@ export const ButtonPrimary = styled(Base)`
&:disabled {
background-color: ${({ theme, altDisabledStyle, disabled }) =>
altDisabledStyle ? (disabled ? theme.primary1 : theme.bg2) : theme.bg2};
color: ${({ theme }) => theme.text2};
color: ${({ altDisabledStyle, disabled, theme }) =>
altDisabledStyle ? (disabled ? theme.white : theme.text2) : theme.text2};
cursor: auto;
box-shadow: none;
border: 1px solid transparent;
@@ -75,7 +76,7 @@ export const ButtonPrimary = styled(Base)`
}
`
export const ButtonLight = styled(Base)`
export const ButtonLight = styled(BaseButton)`
background-color: ${({ theme }) => theme.primary5};
color: ${({ theme }) => theme.primaryText1};
font-size: 16px;
@@ -103,7 +104,7 @@ export const ButtonLight = styled(Base)`
}
`
export const ButtonGray = styled(Base)`
export const ButtonGray = styled(BaseButton)`
background-color: ${({ theme }) => theme.bg1};
color: ${({ theme }) => theme.text2};
font-size: 16px;
@@ -117,7 +118,7 @@ export const ButtonGray = styled(Base)`
}
`
export const ButtonSecondary = styled(Base)`
export const ButtonSecondary = styled(BaseButton)`
border: 1px solid ${({ theme }) => theme.primary4};
color: ${({ theme }) => theme.primary1};
background-color: transparent;
@@ -145,7 +146,7 @@ export const ButtonSecondary = styled(Base)`
}
`
export const ButtonOutlined = styled(Base)`
export const ButtonOutlined = styled(BaseButton)`
border: 1px solid ${({ theme }) => theme.bg2};
background-color: transparent;
color: ${({ theme }) => theme.text1};
@@ -164,7 +165,7 @@ export const ButtonOutlined = styled(Base)`
}
`
export const ButtonYellow = styled(Base)`
export const ButtonYellow = styled(BaseButton)`
background-color: ${({ theme }) => theme.yellow3};
color: white;
&:focus {
@@ -185,7 +186,7 @@ export const ButtonYellow = styled(Base)`
}
`
export const ButtonEmpty = styled(Base)`
export const ButtonEmpty = styled(BaseButton)`
background-color: transparent;
color: ${({ theme }) => theme.primary1};
display: flex;
@@ -207,7 +208,7 @@ export const ButtonEmpty = styled(Base)`
}
`
export const ButtonText = styled(Base)`
export const ButtonText = styled(BaseButton)`
padding: 0;
width: fit-content;
background: none;
@@ -229,7 +230,7 @@ export const ButtonText = styled(Base)`
}
`
const ButtonConfirmedStyle = styled(Base)`
const ButtonConfirmedStyle = styled(BaseButton)`
background-color: ${({ theme }) => theme.bg3};
color: ${({ theme }) => theme.text1};
/* border: 1px solid ${({ theme }) => theme.green1}; */
@@ -242,7 +243,7 @@ const ButtonConfirmedStyle = styled(Base)`
}
`
const ButtonErrorStyle = styled(Base)`
const ButtonErrorStyle = styled(BaseButton)`
background-color: ${({ theme }) => theme.red1};
border: 1px solid ${({ theme }) => theme.red1};

View File

@@ -1,5 +1,5 @@
import styled from 'styled-components/macro'
import { Box } from 'rebass/styled-components'
import styled from 'styled-components/macro'
const Card = styled(Box)<{ width?: string; padding?: string; border?: string; $borderRadius?: string }>`
width: ${({ width }) => width ?? '100%'};

View File

@@ -1,4 +1,5 @@
import ReactConfetti from 'react-confetti'
import { useWindowSize } from '../../hooks/useWindowSize'
// eslint-disable-next-line react/prop-types

View File

@@ -1,10 +1,11 @@
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import HoverInlineText from 'components/HoverInlineText'
import { useMemo } from 'react'
import useTheme from '../../hooks/useTheme'
import { TYPE } from '../../theme'
import { warningSeverity } from '../../utils/prices'
import HoverInlineText from 'components/HoverInlineText'
import { Trans } from '@lingui/macro'
export function FiatValue({
fiatValue,

View File

@@ -1,24 +1,26 @@
import { Pair } from '@uniswap/v2-sdk'
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { useState, useCallback, ReactNode } from 'react'
import styled from 'styled-components/macro'
import { Pair } from '@uniswap/v2-sdk'
import { AutoColumn } from 'components/Column'
import { LoadingOpacityContainer, loadingOpacityMixin } from 'components/Loader/styled'
import { darken } from 'polished'
import { ReactNode, useCallback, useState } from 'react'
import { Lock } from 'react-feather'
import styled from 'styled-components/macro'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import useTheme from '../../hooks/useTheme'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
import { TYPE } from '../../theme'
import { ButtonGray } from '../Button'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { ButtonGray } from '../Button'
import { RowBetween, RowFixed } from '../Row'
import { TYPE } from '../../theme'
import { Input as NumericalInput } from '../NumericalInput'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { Trans } from '@lingui/macro'
import useTheme from '../../hooks/useTheme'
import { Lock } from 'react-feather'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed } from '../Row'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
import { FiatValue } from './FiatValue'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
const InputPanel = styled.div<{ hideInput?: boolean }>`
${({ theme }) => theme.flexColumnNoWrap}
@@ -81,6 +83,7 @@ const CurrencySelect = styled(ButtonGray)<{ visible: boolean; selected: boolean;
const InputRow = styled.div<{ selected: boolean }>`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
justify-content: space-between;
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 0.75rem 1rem')};
`
@@ -145,6 +148,10 @@ const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
`};
`
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean }>`
${loadingOpacityMixin}
`
interface CurrencyInputPanelProps {
value: string
onUserInput: (value: string) => void
@@ -165,6 +172,7 @@ interface CurrencyInputPanelProps {
disableNonToken?: boolean
renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode
locked?: boolean
loading?: boolean
}
export default function CurrencyInputPanel({
@@ -186,6 +194,7 @@ export default function CurrencyInputPanel({
pair = null, // used for double token logo
hideInput = false,
locked = false,
loading = false,
...rest
}: CurrencyInputPanelProps) {
const [modalOpen, setModalOpen] = useState(false)
@@ -249,15 +258,12 @@ export default function CurrencyInputPanel({
</Aligner>
</CurrencySelect>
{!hideInput && (
<>
<NumericalInput
className="token-amount-input"
value={value}
onUserInput={(val) => {
onUserInput(val)
}}
/>
</>
<StyledNumericalInput
className="token-amount-input"
value={value}
onUserInput={onUserInput}
$loading={loading}
/>
)}
</InputRow>
{!hideInput && !hideBalance && (
@@ -291,7 +297,9 @@ export default function CurrencyInputPanel({
) : (
<span />
)}
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
<LoadingOpacityContainer $loading={loading}>
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
</LoadingOpacityContainer>
</RowBetween>
</FiatRow>
)}

View File

@@ -1,6 +1,7 @@
import { Currency } from '@uniswap/sdk-core'
import React, { useMemo } from 'react'
import styled from 'styled-components/macro'
import EthereumLogo from '../../assets/images/ethereum-logo.png'
import useHttpLocations from '../../hooks/useHttpLocations'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'

View File

@@ -1,5 +1,6 @@
import { Currency } from '@uniswap/sdk-core'
import styled from 'styled-components/macro'
import CurrencyLogo from '../CurrencyLogo'
const Wrapper = styled.div<{ margin: boolean; sizeraw: number }>`

View File

@@ -0,0 +1,77 @@
import { Trans } from '@lingui/macro'
import { L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { AlertOctagon } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink } from 'theme'
const Root = styled.div`
background-color: ${({ theme }) => (theme.darkMode ? '#888D9B' : '#CED0D9')};
border-radius: 18px;
color: black;
display: flex;
flex-direction: row;
font-size: 14px;
margin: 12px auto;
padding: 16px;
width: 100%;
max-width: 880px;
`
const WarningIcon = styled(AlertOctagon)`
display: block;
margin: auto 16px auto 0;
min-height: 22px;
min-width: 22px;
`
const ReadMoreLink = styled(ExternalLink)`
color: black;
text-decoration: underline;
`
export default function DowntimeWarning() {
const { chainId } = useActiveWeb3React()
if (!chainId || !L2_CHAIN_IDS.includes(chainId)) {
return null
}
const Content = () => {
switch (chainId) {
case SupportedChainId.OPTIMISM:
case SupportedChainId.OPTIMISTIC_KOVAN:
return (
<div>
<Trans>
Optimistic Ethereum is in Beta and may experience downtime. Optimism expects planned downtime to upgrade
the network in the near future. During downtime, your position will not earn fees and you will be unable
to remove liquidity.{' '}
<ReadMoreLink href="https://help.uniswap.org/en/articles/5406082-what-happens-if-the-optimistic-ethereum-network-experiences-downtime">
Read more.
</ReadMoreLink>
</Trans>
</div>
)
case SupportedChainId.ARBITRUM_ONE:
case SupportedChainId.ARBITRUM_RINKEBY:
return (
<div>
<Trans>
Arbitrum is in Beta and may experience downtime. During downtime, your position will not earn fees and you
will be unable to remove liquidity.{' '}
<ReadMoreLink href="https://help.uniswap.org/en/articles/5576122-arbitrum-network-downtime">
Read more.
</ReadMoreLink>
</Trans>
</div>
)
default:
return null
}
}
return (
<Root>
<WarningIcon />
<Content />
</Root>
)
}

View File

@@ -1,11 +1,12 @@
import { Trans } from '@lingui/macro'
import React, { ErrorInfo } from 'react'
import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import store, { AppState } from '../../state'
import { ExternalLink, TYPE } from '../../theme'
import { AutoColumn } from '../Column'
import styled from 'styled-components/macro'
import ReactGA from 'react-ga'
import { getUserAgent } from '../../utils/getUserAgent'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
const FallbackWrapper = styled.div`

View File

@@ -1,19 +1,19 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { FeeAmount } from '@uniswap/v3-sdk'
import { Currency } from '@uniswap/sdk-core'
import { Trans } from '@lingui/macro'
import { AutoColumn } from 'components/Column'
import { DynamicSection } from 'pages/AddLiquidity/styled'
import { TYPE } from 'theme'
import { RowBetween } from 'components/Row'
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
import styled, { keyframes } from 'styled-components/macro'
import { Currency } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
import Card from 'components/Card'
import usePrevious from 'hooks/usePrevious'
import { AutoColumn } from 'components/Column'
import { RowBetween } from 'components/Row'
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
import usePrevious from 'hooks/usePrevious'
import { DynamicSection } from 'pages/AddLiquidity/styled'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import ReactGA from 'react-ga'
import { Box } from 'rebass'
import styled, { keyframes } from 'styled-components/macro'
import { TYPE } from 'theme'
const pulse = (color: string) => keyframes`
0% {

View File

@@ -1,5 +1,5 @@
import JSBI from 'jsbi'
import { Currency, CurrencyAmount, Fraction } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
const CURRENCY_AMOUNT_MIN = new Fraction(JSBI.BigInt(1), JSBI.BigInt(1000000))

View File

@@ -0,0 +1,76 @@
import { Trans } from '@lingui/macro'
import { CHAIN_INFO, L2ChainInfo, SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { AlertOctagon } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
const BodyRow = styled.div`
color: ${({ theme }) => theme.black};
font-size: 12px;
`
const CautionIcon = styled(AlertOctagon)`
color: ${({ theme }) => theme.black};
`
const Link = styled(ExternalLink)`
color: ${({ theme }) => theme.black};
text-decoration: underline;
`
const TitleRow = styled.div`
align-items: center;
display: flex;
justify-content: flex-start;
margin-bottom: 8px;
`
const TitleText = styled.div`
color: black;
font-weight: 600;
font-size: 16px;
line-height: 20px;
margin: 0px 12px;
`
const Wrapper = styled.div`
background-color: ${({ theme }) => theme.yellow3};
border-radius: 12px;
bottom: 60px;
display: none;
max-width: 348px;
padding: 16px 20px;
position: absolute;
right: 16px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
export function ChainConnectivityWarning() {
const { chainId } = useActiveWeb3React()
const info = CHAIN_INFO[chainId ?? SupportedChainId.MAINNET]
const label = info?.label
return (
<Wrapper>
<TitleRow>
<CautionIcon />
<TitleText>
<Trans>Network Warning</Trans>
</TitleText>
</TitleRow>
<BodyRow>
{chainId === SupportedChainId.MAINNET ? (
<Trans>You may have lost your network connection.</Trans>
) : (
<Trans>You may have lost your network connection, or {label} might be down right now.</Trans>
)}{' '}
{(info as L2ChainInfo).statusPage !== undefined && (
<span>
<Trans>Check network status</Trans>{' '}
<Link href={(info as L2ChainInfo).statusPage || ''}>
<Trans>here.</Trans>
</Link>
</span>
)}
</BodyRow>
</Wrapper>
)
}

View File

@@ -1,235 +0,0 @@
import { Trans } from '@lingui/macro'
import { YellowCard } from 'components/Card'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { useEffect, useRef, useState } from 'react'
import { ArrowDownCircle, ChevronDown, ToggleLeft } from 'react-feather'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleModal } from 'state/application/hooks'
import styled, { css } from 'styled-components/macro'
import { ExternalLink } from 'theme'
import { switchToNetwork } from 'utils/switchToNetwork'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from '../../constants/chains'
const BaseWrapper = css`
position: relative;
margin-right: 8px;
${({ theme }) => theme.mediaWidth.upToMedium`
justify-self: end;
`};
${({ theme }) => theme.mediaWidth.upToSmall`
margin: 0 0.5rem 0 0;
width: initial;
text-overflow: ellipsis;
flex-shrink: 1;
`};
`
const L2Wrapper = styled.div`
${BaseWrapper}
`
const BaseMenuItem = css`
align-items: center;
background-color: transparent;
border-radius: 12px;
color: ${({ theme }) => theme.text2};
cursor: pointer;
display: flex;
flex: 1;
flex-direction: row;
font-size: 16px;
font-weight: 400;
justify-content: space-between;
:hover {
color: ${({ theme }) => theme.text1};
text-decoration: none;
}
`
const DisabledMenuItem = styled.div`
${BaseMenuItem}
align-items: center;
background-color: ${({ theme }) => theme.bg2};
cursor: auto;
display: flex;
font-size: 10px;
font-style: italic;
justify-content: center;
:hover,
:active,
:focus {
color: ${({ theme }) => theme.text2};
}
`
const FallbackWrapper = styled(YellowCard)`
${BaseWrapper}
width: auto;
border-radius: 12px;
padding: 8px 12px;
width: 100%;
user-select: none;
`
const Icon = styled.img`
width: 16px;
margin-right: 2px;
${({ theme }) => theme.mediaWidth.upToSmall`
margin-right: 4px;
`};
`
const MenuFlyout = styled.span`
background-color: ${({ theme }) => theme.bg1};
border: 1px solid ${({ theme }) => theme.bg0};
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 12px;
padding: 1rem;
display: flex;
flex-direction: column;
font-size: 1rem;
position: absolute;
left: 0rem;
top: 3rem;
z-index: 100;
width: 237px;
${({ theme }) => theme.mediaWidth.upToMedium`
bottom: unset;
top: 4.5em
right: 0;
`};
> {
padding: 12px;
}
> :not(:first-child) {
margin-top: 8px;
}
> :not(:last-child) {
margin-bottom: 8px;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 16px;
height: 16px;
opacity: 0.6;
`
const MenuItem = styled(ExternalLink)`
${BaseMenuItem}
`
const ButtonMenuItem = styled.button`
${BaseMenuItem}
border: none;
box-shadow: none;
color: ${({ theme }) => theme.text2};
outline: none;
padding: 0;
`
const NetworkInfo = styled.button<{ chainId: SupportedChainId }>`
align-items: center;
background-color: ${({ theme }) => theme.bg0};
border-radius: 12px;
border: 1px solid ${({ theme }) => theme.bg0};
color: ${({ theme }) => theme.text1};
display: flex;
flex-direction: row;
font-weight: 500;
font-size: 12px;
height: 100%;
margin: 0;
height: 38px;
padding: 0.7rem;
:hover,
:focus {
cursor: pointer;
outline: none;
border: 1px solid ${({ theme }) => theme.bg3};
}
`
const NetworkName = styled.div<{ chainId: SupportedChainId }>`
border-radius: 6px;
font-size: 16px;
font-weight: 500;
padding: 0 2px 0.5px 4px;
margin: 0 2px;
white-space: pre;
${({ theme }) => theme.mediaWidth.upToSmall`
display: none;
`};
`
export default function NetworkCard() {
const { chainId, library } = useActiveWeb3React()
const node = useRef<HTMLDivElement>(null)
const open = useModalOpen(ApplicationModal.ARBITRUM_OPTIONS)
const toggle = useToggleModal(ApplicationModal.ARBITRUM_OPTIONS)
useOnClickOutside(node, open ? toggle : undefined)
const [implements3085, setImplements3085] = useState(false)
useEffect(() => {
// metamask is currently the only known implementer of this EIP
// here we proceed w/ a noop feature check to ensure the user's version of metamask supports network switching
// if not, we hide the UI
if (!library?.provider?.request || !chainId || !library?.provider?.isMetaMask) {
return
}
switchToNetwork({ library, chainId })
.then((x) => x ?? setImplements3085(true))
.catch(() => setImplements3085(false))
}, [library, chainId])
const info = chainId ? CHAIN_INFO[chainId] : undefined
if (!chainId || chainId === SupportedChainId.MAINNET || !info || !library) {
return null
}
if (L2_CHAIN_IDS.includes(chainId)) {
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const isArbitrum = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.ARBITRUM_RINKEBY].includes(chainId)
return (
<L2Wrapper ref={node}>
<NetworkInfo onClick={toggle} chainId={chainId}>
<Icon src={info.logoUrl} />
<NetworkName chainId={chainId}>{info.label}</NetworkName>
<ChevronDown size={16} style={{ marginTop: '2px' }} strokeWidth={2.5} />
</NetworkInfo>
{open && (
<MenuFlyout>
<MenuItem href={info.bridge}>
<div>{isArbitrum ? <Trans>{info.label} Bridge</Trans> : <Trans>Optimistic L2 Gateway</Trans>}</div>
<LinkOutCircle />
</MenuItem>
<MenuItem href={info.explorer}>
{isArbitrum ? <Trans>{info.label} Explorer</Trans> : <Trans>Optimistic Etherscan</Trans>}
<LinkOutCircle />
</MenuItem>
<MenuItem href={info.docs}>
<div>
<Trans>Learn more</Trans>
</div>
<LinkOutCircle />
</MenuItem>
{implements3085 ? (
<ButtonMenuItem onClick={() => switchToNetwork({ library, chainId: SupportedChainId.MAINNET })}>
<div>
<Trans>Switch to L1 (Mainnet)</Trans>
</div>
<ToggleLeft opacity={0.6} size={16} />
</ButtonMenuItem>
) : (
<DisabledMenuItem>
<Trans>Change your network to go back to L1</Trans>
</DisabledMenuItem>
)}
</MenuFlyout>
)}
</L2Wrapper>
)
}
return <FallbackWrapper title={info.label}>{info.label}</FallbackWrapper>
}

View File

@@ -0,0 +1,249 @@
import { Trans } from '@lingui/macro'
import {
ARBITRUM_HELP_CENTER_LINK,
CHAIN_INFO,
L2_CHAIN_IDS,
OPTIMISM_HELP_CENTER_LINK,
SupportedChainId,
SupportedL2ChainId,
} from 'constants/chains'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useRef } from 'react'
import { ArrowDownCircle, ChevronDown } from 'react-feather'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleModal } from 'state/application/hooks'
import { useAppSelector } from 'state/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { switchToNetwork } from 'utils/switchToNetwork'
const ActiveRowLinkList = styled.div`
display: flex;
flex-direction: column;
padding: 0 8px;
& > a {
align-items: center;
color: ${({ theme }) => theme.text2};
display: flex;
flex-direction: row;
font-size: 14px;
font-weight: 500;
justify-content: space-between;
padding: 8px 0 4px;
text-decoration: none;
}
& > a:first-child {
border-top: 1px solid ${({ theme }) => theme.text2};
margin: 0;
margin-top: 6px;
padding-top: 10px;
}
`
const ActiveRowWrapper = styled.div`
background-color: ${({ theme }) => theme.bg2};
border-radius: 8px;
cursor: pointer;
padding: 8px 0 8px 0;
width: 100%;
`
const FlyoutHeader = styled.div`
color: ${({ theme }) => theme.text2};
font-weight: 400;
`
const FlyoutMenu = styled.div`
align-items: flex-start;
background-color: ${({ theme }) => theme.bg1};
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 20px;
display: flex;
flex-direction: column;
font-size: 16px;
overflow: auto;
padding: 16px;
position: absolute;
top: 64px;
width: 272px;
z-index: 99;
& > *:not(:last-child) {
margin-bottom: 12px;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
top: 50px;
}
`
const FlyoutRow = styled.div<{ active: boolean }>`
align-items: center;
background-color: ${({ active, theme }) => (active ? theme.bg2 : 'transparent')};
border-radius: 8px;
cursor: pointer;
display: flex;
font-weight: 500;
justify-content: space-between;
padding: 6px 8px;
text-align: left;
width: 100%;
`
const FlyoutRowActiveIndicator = styled.div`
background-color: ${({ theme }) => theme.green1};
border-radius: 50%;
height: 9px;
width: 9px;
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 16px;
height: 16px;
`
const Logo = styled.img`
height: 20px;
width: 20px;
margin-right: 8px;
`
const NetworkLabel = styled.div`
flex: 1 1 auto;
`
const SelectorLabel = styled(NetworkLabel)`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
display: block;
margin-right: 8px;
}
`
const SelectorControls = styled.div<{ interactive: boolean }>`
align-items: center;
background-color: ${({ theme }) => theme.bg1};
border: 2px solid ${({ theme }) => theme.bg1};
border-radius: 12px;
color: ${({ theme }) => theme.text1};
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
display: flex;
font-weight: 500;
justify-content: space-between;
padding: 6px 8px;
`
const SelectorLogo = styled(Logo)<{ interactive?: boolean }>`
margin-right: ${({ interactive }) => (interactive ? 8 : 0)}px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
margin-right: 8px;
}
`
const SelectorWrapper = styled.div`
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
position: relative;
}
`
const StyledChevronDown = styled(ChevronDown)`
width: 12px;
`
const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
switch (chainId) {
case SupportedChainId.ARBITRUM_ONE:
case SupportedChainId.ARBITRUM_RINKEBY:
return <Trans>Arbitrum Bridge</Trans>
case SupportedChainId.OPTIMISM:
case SupportedChainId.OPTIMISTIC_KOVAN:
return <Trans>Optimism Gateway</Trans>
default:
return <Trans>Bridge</Trans>
}
}
const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
switch (chainId) {
case SupportedChainId.ARBITRUM_ONE:
case SupportedChainId.ARBITRUM_RINKEBY:
return <Trans>Arbiscan</Trans>
case SupportedChainId.OPTIMISM:
case SupportedChainId.OPTIMISTIC_KOVAN:
return <Trans>Optimistic Etherscan</Trans>
default:
return <Trans>Explorer</Trans>
}
}
export default function NetworkSelector() {
const { chainId, library } = useActiveWeb3React()
const node = useRef<HTMLDivElement>()
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
useOnClickOutside(node, open ? toggle : undefined)
const implements3085 = useAppSelector((state) => state.application.implements3085)
const info = chainId ? CHAIN_INFO[chainId] : undefined
const isOnL2 = chainId ? L2_CHAIN_IDS.includes(chainId) : false
const showSelector = Boolean(implements3085 || isOnL2)
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]
const conditionalToggle = useCallback(() => {
if (showSelector) {
toggle()
}
}, [showSelector, toggle])
if (!chainId || !info || !library) {
return null
}
function Row({ targetChain }: { targetChain: number }) {
if (!library || !chainId || (!implements3085 && targetChain !== chainId)) {
return null
}
const handleRowClick = () => {
switchToNetwork({ library, chainId: targetChain })
toggle()
}
const active = chainId === targetChain
const hasExtendedInfo = L2_CHAIN_IDS.includes(targetChain)
const isOptimism = targetChain === SupportedChainId.OPTIMISM
const rowText = `${CHAIN_INFO[targetChain].label}${isOptimism ? ' (Optimism)' : ''}`
const RowContent = () => (
<FlyoutRow onClick={handleRowClick} active={active}>
<Logo src={CHAIN_INFO[targetChain].logoUrl} />
<NetworkLabel>{rowText}</NetworkLabel>
{chainId === targetChain && <FlyoutRowActiveIndicator />}
</FlyoutRow>
)
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
if (active && hasExtendedInfo) {
return (
<ActiveRowWrapper>
<RowContent />
<ActiveRowLinkList>
<ExternalLink href={CHAIN_INFO[targetChain as SupportedL2ChainId].bridge}>
<BridgeText chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
<ExternalLink href={CHAIN_INFO[targetChain].explorer}>
<ExplorerText chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
<ExternalLink href={helpCenterLink}>
<Trans>Help Center</Trans> <LinkOutCircle />
</ExternalLink>
</ActiveRowLinkList>
</ActiveRowWrapper>
)
}
return <RowContent />
}
return (
<SelectorWrapper ref={node as any}>
<SelectorControls onClick={conditionalToggle} interactive={showSelector}>
<SelectorLogo interactive={showSelector} src={info.logoUrl || mainnetInfo.logoUrl} />
<SelectorLabel>{info.label}</SelectorLabel>
{showSelector && <StyledChevronDown />}
</SelectorControls>
{open && (
<FlyoutMenu>
<FlyoutHeader>
<Trans>Select a network</Trans>
</FlyoutHeader>
<Row targetChain={SupportedChainId.MAINNET} />
<Row targetChain={SupportedChainId.OPTIMISM} />
<Row targetChain={SupportedChainId.ARBITRUM_ONE} />
</FlyoutMenu>
)}
</SelectorWrapper>
)
}

View File

@@ -1,19 +1,22 @@
import { useEffect, useState } from 'react'
import { useAppSelector } from 'state/hooks'
import styled, { keyframes } from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
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`
const StyledPolling = styled.div<{ warning: boolean }>`
position: fixed;
display: flex;
align-items: center;
right: 0;
bottom: 0;
padding: 1rem;
color: ${({ theme }) => theme.green1};
color: ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
transition: 250ms ease color;
${({ theme }) => theme.mediaWidth.upToMedium`
display: none;
@@ -26,14 +29,15 @@ const StyledPollingNumber = styled(TYPE.small)<{ breathe: boolean; hovering: boo
opacity: 1;
}
`
const StyledPollingDot = styled.div`
const StyledPollingDot = styled.div<{ warning: boolean }>`
width: 8px;
height: 8px;
min-height: 8px;
min-width: 8px;
border-radius: 50%;
position: relative;
background-color: ${({ theme }) => theme.green1};
background-color: ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
transition: 250ms ease background-color;
`
const rotate360 = keyframes`
@@ -45,19 +49,20 @@ const rotate360 = keyframes`
}
`
const Spinner = styled.div`
const Spinner = styled.div<{ warning: boolean }>`
animation: ${rotate360} 1s cubic-bezier(0.83, 0, 0.17, 1) infinite;
transform: translateZ(0);
border-top: 1px solid transparent;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
border-left: 2px solid ${({ theme }) => theme.green1};
border-left: 2px solid ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
background: transparent;
width: 14px;
height: 14px;
border-radius: 50%;
position: relative;
transition: 250ms ease border-color;
left: -3px;
top: -3px;
@@ -65,11 +70,10 @@ const Spinner = styled.div`
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)
useEffect(
() => {
@@ -90,15 +94,24 @@ export default function Polling() {
)
return (
<ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
>
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}&ensp;
</StyledPollingNumber>
<StyledPollingDot>{isMounting && <Spinner />}</StyledPollingDot>
</StyledPolling>
</ExternalLink>
<>
<ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
>
<StyledPolling
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
warning={chainConnectivityWarning}
>
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}&ensp;
</StyledPollingNumber>
<StyledPollingDot warning={chainConnectivityWarning}>
{isMounting && <Spinner warning={chainConnectivityWarning} />}
</StyledPollingDot>{' '}
</StyledPolling>
</ExternalLink>
{chainConnectivityWarning && <ChainConnectivityWarning />}
</>
)
}

View File

@@ -4,6 +4,7 @@ import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
import { useMemo } from 'react'
import { X } from 'react-feather'
import styled from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { UNI } from '../../constants/tokens'
import { useMerkleDistributorContract } from '../../hooks/useContract'

View File

@@ -11,8 +11,9 @@ import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
import { useDarkModeManager } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import styled from 'styled-components/macro'
import Logo from '../../assets/svg/logo.svg'
import LogoDark from '../../assets/svg/logo_white.svg'
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
import { ReactComponent as LogoDark } from '../../assets/svg/logo_white.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink, TYPE } from '../../theme'
import ClaimModal from '../claim/ClaimModal'
@@ -22,7 +23,7 @@ import Modal from '../Modal'
import Row from '../Row'
import { Dots } from '../swap/styleds'
import Web3Status from '../Web3Status'
import NetworkCard from './NetworkCard'
import NetworkSelector from './NetworkSelector'
import UniBalanceContent from './UniBalanceContent'
const HeaderFrame = styled.div<{ showBackground: boolean }>`
@@ -72,6 +73,10 @@ const HeaderElement = styled.div`
display: flex;
align-items: center;
&:not(:first-child) {
margin-left: 0.5em;
}
/* addresses safari's lack of support for "gap" */
& > *:not(:first-child) {
margin-left: 8px;
@@ -264,7 +269,11 @@ export default function Header() {
</Modal>
<Title href=".">
<UniIcon>
<img width={'24px'} src={darkMode ? LogoDark : Logo} alt="logo" />
{darkMode ? (
<LogoDark width="24px" height="100%" title="logo" />
) : (
<Logo width="24px" height="100%" title="logo" />
)}
</UniIcon>
</Title>
<HeaderLinks>
@@ -284,7 +293,7 @@ export default function Header() {
>
<Trans>Pool</Trans>
</StyledNavLink>
{chainId && chainId === SupportedChainId.MAINNET && (
{(!chainId || chainId === SupportedChainId.MAINNET) && (
<StyledNavLink id={`vote-nav-link`} to={'/vote'}>
<Trans>Vote</Trans>
</StyledNavLink>
@@ -296,7 +305,9 @@ export default function Header() {
</HeaderLinks>
<HeaderControls>
<NetworkCard />
<HeaderElement>
<NetworkSelector />
</HeaderElement>
<HeaderElement>
{availableClaim && !showClaimPopup && (
<UNIWrapper onClick={toggleClaimModal}>
@@ -322,6 +333,8 @@ export default function Header() {
) : null}
<Web3Status />
</AccountElement>
</HeaderElement>
<HeaderElement>
<Menu />
</HeaderElement>
</HeaderControls>

View File

@@ -1,9 +1,7 @@
import { useEffect, useRef } from 'react'
import Davatar from '@davatar/react'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
import Jazzicon from '@metamask/jazzicon'
const StyledIdenticonContainer = styled.div`
height: 1rem;
@@ -13,17 +11,12 @@ const StyledIdenticonContainer = styled.div`
`
export default function Identicon() {
const ref = useRef<HTMLDivElement>()
const { account } = useActiveWeb3React()
useEffect(() => {
if (account && ref.current) {
ref.current.innerHTML = ''
ref.current.appendChild(Jazzicon(16, parseInt(account.slice(2, 10), 16)))
}
}, [account])
const { account, library } = useActiveWeb3React()
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
return <StyledIdenticonContainer ref={ref as any} />
return (
<StyledIdenticonContainer>
{account && library?.provider && <Davatar address={account} size={16} provider={library.provider} />}
</StyledIdenticonContainer>
)
}

View File

@@ -1,13 +1,14 @@
import { useState, useCallback, useEffect, ReactNode } from 'react'
import { Trans } from '@lingui/macro'
import { FeeAmount } from '@uniswap/v3-sdk'
import { ButtonGray } from 'components/Button'
import { OutlineCard } from 'components/Card'
import { Input as NumericalInput } from '../NumericalInput'
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 { AutoColumn } from 'components/Column'
import { ButtonGray } from 'components/Button'
import { FeeAmount } from '@uniswap/v3-sdk'
import { Trans } from '@lingui/macro'
import { Plus, Minus } from 'react-feather'
import { Input as NumericalInput } from '../NumericalInput'
const pulse = (color: string) => keyframes`
0% {

View File

@@ -1,8 +1,9 @@
import React, { useMemo } from 'react'
import { area, curveStepAfter, ScaleLinear } from 'd3'
import styled from 'styled-components/macro'
import { ChartEntry } from './types'
import inRange from 'lodash/inRange'
import React, { useMemo } from 'react'
import styled from 'styled-components/macro'
import { ChartEntry } from './types'
const Path = styled.path<{ fill: string | undefined }>`
opacity: 0.5;

View File

@@ -1,5 +1,5 @@
import React, { useMemo } from 'react'
import { Axis as d3Axis, axisBottom, NumberValue, ScaleLinear, select } from 'd3'
import React, { useMemo } from 'react'
import styled from 'styled-components/macro'
const StyledGroup = styled.g`

View File

@@ -1,8 +1,8 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { BrushBehavior, brushX, D3BrushEvent, ScaleLinear, select } from 'd3'
import styled from 'styled-components/macro'
import { brushHandleAccentPath, brushHandlePath, OffScreenHandle } from 'components/LiquidityChartRangeInput/svg'
import { BrushBehavior, brushX, D3BrushEvent, ScaleLinear, select } from 'd3'
import usePrevious from 'hooks/usePrevious'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components/macro'
const Handle = styled.path<{ color: string }>`
cursor: ew-resize;
@@ -43,8 +43,16 @@ const FLIP_HANDLE_THRESHOLD_PX = 20
// margin to prevent tick snapping from putting the brush off screen
const BRUSH_EXTENT_MARGIN_PX = 2
const compare = (a1: [number, number], a2: [number, number], xScale: ScaleLinear<number, number>): boolean =>
xScale(a1[0]) !== xScale(a2[0]) || xScale(a1[1]) !== xScale(a2[1])
/**
* Returns true if every element in `a` maps to the
* same pixel coordinate as elements in `b`
*/
const compare = (a: [number, number], b: [number, number], xScale: ScaleLinear<number, number>): boolean => {
// normalize pixels to 1 decimals
const aNorm = a.map((x) => xScale(x).toFixed(1))
const bNorm = b.map((x) => xScale(x).toFixed(1))
return aNorm.every((v, i) => v === bNorm[i])
}
export const Brush = ({
id,
@@ -91,7 +99,7 @@ export const Brush = ({
const scaled = (selection as [number, number]).map(xScale.invert) as [number, number]
// avoid infinite render loop by checking for change
if (type === 'end' && compare(brushExtent, scaled, xScale)) {
if (type === 'end' && !compare(brushExtent, scaled, xScale)) {
setBrushExtent(scaled, mode)
}

View File

@@ -1,6 +1,7 @@
import { max, scaleLinear, ZoomTransform } from 'd3'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Bound } from 'state/mint/v3/actions'
import { Area } from './Area'
import { AxisBottom } from './AxisBottom'
import { Brush } from './Brush'

View File

@@ -1,5 +1,5 @@
import React, { useMemo } from 'react'
import { ScaleLinear } from 'd3'
import React, { useMemo } from 'react'
import styled from 'styled-components/macro'
const StyledLine = styled.line`

View File

@@ -1,8 +1,9 @@
import React, { useEffect, useMemo, useRef } from 'react'
import { ButtonGray } from 'components/Button'
import styled from 'styled-components/macro'
import { ScaleLinear, select, ZoomBehavior, zoom, ZoomTransform, zoomIdentity } from 'd3'
import { ScaleLinear, select, zoom, ZoomBehavior, zoomIdentity, ZoomTransform } from 'd3'
import React, { useEffect, useMemo, useRef } from 'react'
import { RefreshCcw, ZoomIn, ZoomOut } from 'react-feather'
import styled from 'styled-components/macro'
import { ZoomLevels } from './types'
const Wrapper = styled.div<{ count: number }>`

View File

@@ -1,9 +1,10 @@
import { useCallback, useMemo } from 'react'
import { Currency } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
import { ChartEntry } from './types'
import JSBI from 'jsbi'
import { useCallback, useMemo } from 'react'
import { ChartEntry } from './types'
export interface TickProcessed {
liquidityActive: JSBI

View File

@@ -1,21 +1,22 @@
import React, { ReactNode, useCallback, useMemo } from 'react'
import { Trans } from '@lingui/macro'
import { Currency, Price, Token } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { AutoColumn, ColumnCenter } from 'components/Column'
import Loader from 'components/Loader'
import { format } from 'd3'
import { useColor } from 'hooks/useColor'
import useTheme from 'hooks/useTheme'
import { saturate } from 'polished'
import { BarChart2, Inbox, CloudOff } from 'react-feather'
import React, { ReactNode, useCallback, useMemo } from 'react'
import { BarChart2, CloudOff, Inbox } from 'react-feather'
import ReactGA from 'react-ga'
import { batch } from 'react-redux'
import { Bound } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
import { Chart } from './Chart'
import { useDensityChartData } from './hooks'
import { format } from 'd3'
import { Bound } from 'state/mint/v3/actions'
import { FeeAmount } from '@uniswap/v3-sdk'
import ReactGA from 'react-ga'
import { ZoomLevels } from './types'
const ZOOM_LEVELS: Record<FeeAmount, ZoomLevels> = {

View File

@@ -1,7 +1,7 @@
import React from 'react'
import styled from 'styled-components/macro'
import useHttpLocations from '../../hooks/useHttpLocations'
import useHttpLocations from '../../hooks/useHttpLocations'
import Logo from '../Logo'
const StyledListLogo = styled(Logo)<{ size: string }>`

View File

@@ -0,0 +1,39 @@
import styled, { css, keyframes } from 'styled-components/macro'
export const loadingAnimation = keyframes`
0% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
`
export const LoadingRows = styled.div`
display: grid;
& > div {
animation: ${loadingAnimation} 1.5s infinite;
animation-fill-mode: both;
background: linear-gradient(
to left,
${({ theme }) => theme.bg1} 25%,
${({ theme }) => theme.bg2} 50%,
${({ theme }) => theme.bg1} 75%
);
background-size: 400%;
border-radius: 12px;
height: 2.4em;
will-change: background-position;
}
`
export const loadingOpacityMixin = css<{ $loading: boolean }>`
filter: ${({ $loading }) => ($loading ? 'grayscale(1)' : 'none')};
opacity: ${({ $loading }) => ($loading ? '0.4' : '1')};
transition: opacity 0.2s ease-in-out;
`
export const LoadingOpacityContainer = styled.div<{ $loading: boolean }>`
${loadingOpacityMixin}
`

View File

@@ -1,6 +1,7 @@
import { useState } from 'react'
import { Slash } from 'react-feather'
import { ImageProps } from 'rebass'
import useTheme from '../../hooks/useTheme'
const BAD_SRCS: { [tokenAddress: string]: true } = {}

View File

@@ -1,22 +1,22 @@
import { t } from '@lingui/macro'
import { Trans } from '@lingui/macro'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
import { useActiveLocale } from 'hooks/useActiveLocale'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
import React, { useEffect, useRef, useState } from 'react'
import { BookOpen, Code, Info, MessageCircle, PieChart, Moon, Sun, Globe, ChevronLeft, Check } from 'react-feather'
import { BookOpen, Check, ChevronLeft, Code, Globe, Info, MessageCircle, Moon, PieChart, Sun } from 'react-feather'
import { Link } from 'react-router-dom'
import { useDarkModeManager } from 'state/user/hooks'
import styled, { css } from 'styled-components/macro'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { useActiveWeb3React } from '../../hooks/web3'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleModal } from '../../state/application/hooks'
import { Trans } from '@lingui/macro'
import { ExternalLink } from '../../theme'
import { ButtonPrimary } from '../Button'
import { useDarkModeManager } from 'state/user/hooks'
import { L2_CHAIN_IDS, CHAIN_INFO, SupportedChainId } from 'constants/chains'
import { LOCALE_LABEL, SupportedLocale, SUPPORTED_LOCALES } from 'constants/locales'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
import { useActiveLocale } from 'hooks/useActiveLocale'
export enum FlyoutAlignment {
LEFT = 'LEFT',
@@ -62,7 +62,6 @@ const UNIbutton = styled(ButtonPrimary)`
`
const StyledMenu = styled.div`
margin-left: 0.5rem;
display: flex;
justify-content: center;
align-items: center;

View File

@@ -1,10 +1,10 @@
import React from 'react'
import styled, { css } from 'styled-components/macro'
import { animated, useTransition, useSpring } from 'react-spring'
import { DialogOverlay, DialogContent } from '@reach/dialog'
import { isMobile } from 'react-device-detect'
import { DialogContent, DialogOverlay } from '@reach/dialog'
import { transparentize } from 'polished'
import React from 'react'
import { isMobile } from 'react-device-detect'
import { animated, useSpring, useTransition } from 'react-spring'
import { useGesture } from 'react-use-gesture'
import styled, { css } from 'styled-components/macro'
const AnimatedDialogOverlay = animated(DialogOverlay)
// eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@@ -1,16 +1,15 @@
import { useContext } from 'react'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn, ColumnCenter } from '../Column'
import styled, { ThemeContext } from 'styled-components/macro'
import { RowBetween } from '../Row'
import { TYPE, CloseIcon, CustomLightSpinner } from '../../theme'
import { ArrowUpCircle } from 'react-feather'
import { Trans } from '@lingui/macro'
import { useContext } from 'react'
import { ArrowUpCircle } from 'react-feather'
import styled, { ThemeContext } from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { CloseIcon, CustomLightSpinner, TYPE } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn, ColumnCenter } from '../Column'
import { RowBetween } from '../Row'
const ConfirmOrLoadingWrapper = styled.div`
width: 100%;

View File

@@ -1,20 +1,19 @@
import styled from 'styled-components/macro'
import { darken } from 'polished'
import { Trans } from '@lingui/macro'
import { NavLink, Link as HistoryLink, useLocation } from 'react-router-dom'
import { Percent } from '@uniswap/sdk-core'
import useTheme from 'hooks/useTheme'
import { darken } from 'polished'
import { ReactNode } from 'react'
import { ArrowLeft } from 'react-feather'
import Row, { RowBetween } from '../Row'
import SettingsTab from '../Settings'
import { Link as HistoryLink, NavLink, useLocation } from 'react-router-dom'
import { Box } from 'rebass'
import { useAppDispatch } from 'state/hooks'
import { resetMintState } from 'state/mint/actions'
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import useTheme from 'hooks/useTheme'
import { ReactNode } from 'react'
import { Box } from 'rebass'
import Row, { RowBetween } from '../Row'
import SettingsTab from '../Settings'
const Tabs = styled.div`
${({ theme }) => theme.flexRowNoWrap}

View File

@@ -1,134 +0,0 @@
import { Trans } from '@lingui/macro'
import {
ArbitrumWrapperBackgroundDarkMode,
ArbitrumWrapperBackgroundLightMode,
OptimismWrapperBackgroundDarkMode,
OptimismWrapperBackgroundLightMode,
} from 'components/NetworkAlert/NetworkAlert'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { ArrowDownCircle } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { ReadMoreLink } from './styles'
const L2Icon = styled.img`
display: none;
height: 40px;
margin: auto 20px auto 4px;
width: 40px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
const DesktopTextBreak = styled.div`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
const Wrapper = styled.div<{ chainId: SupportedL2ChainId; darkMode: boolean; logoUrl: string }>`
${({ chainId, darkMode }) =>
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
? darkMode
? OptimismWrapperBackgroundDarkMode
: OptimismWrapperBackgroundLightMode
: darkMode
? ArbitrumWrapperBackgroundDarkMode
: ArbitrumWrapperBackgroundLightMode};
border-radius: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 12px;
position: relative;
width: 100%;
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
background-size: 300px;
content: '';
height: 300px;
opacity: 0.1;
position: absolute;
transform: rotate(25deg) translate(-90px, -40px);
width: 300px;
z-index: -1;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
flex-direction: row;
padding: 16px 20px;
}
`
const Body = styled.div`
font-size: 12px;
line-height: 143%;
margin: 12px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
flex: 1 1 auto;
margin: auto 0;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 20px;
height: 20px;
margin-left: 12px;
`
const LinkOutToBridge = styled(ExternalLink)`
align-items: center;
background-color: black;
border-radius: 16px;
color: white;
display: flex;
font-size: 14px;
justify-content: space-between;
margin: 0;
max-height: 47px;
padding: 16px 12px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
margin: auto 0 auto auto;
padding: 14px 16px;
min-width: 226px;
}
`
export function AddLiquidityNetworkAlert() {
const { chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged) {
return null
}
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
const readMoreLink = isOptimism
? 'https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism'
: 'https://help.uniswap.org/en/articles/5538618-how-to-deposit-tokens-to-arbitrum'
return (
<Wrapper darkMode={darkMode} chainId={chainId} logoUrl={info.logoUrl}>
<L2Icon src={info.logoUrl} />
<Body>
<Trans>This is an alpha release of Uniswap on the {info.label} network.</Trans>
<DesktopTextBreak /> <Trans>You must bridge L1 assets to the network to use them.</Trans>{' '}
<ReadMoreLink href={readMoreLink}>
<Trans>Read more</Trans>
</ReadMoreLink>
</Body>
<LinkOutToBridge href={depositUrl}>
<Trans>Deposit to {info.label}</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</Wrapper>
)
}

View File

@@ -1,134 +0,0 @@
import { Trans } from '@lingui/macro'
import {
ArbitrumWrapperBackgroundDarkMode,
ArbitrumWrapperBackgroundLightMode,
OptimismWrapperBackgroundDarkMode,
OptimismWrapperBackgroundLightMode,
} from 'components/NetworkAlert/NetworkAlert'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { ArrowDownCircle } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { ReadMoreLink } from './styles'
const L2Icon = styled.img`
display: none;
height: 40px;
margin: auto 20px auto 4px;
width: 40px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
display: block;
}
`
const DesktopTextBreak = styled.div`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
const Wrapper = styled.div<{ chainId: SupportedL2ChainId; darkMode: boolean; logoUrl: string }>`
${({ chainId, darkMode }) =>
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
? darkMode
? OptimismWrapperBackgroundDarkMode
: OptimismWrapperBackgroundLightMode
: darkMode
? ArbitrumWrapperBackgroundDarkMode
: ArbitrumWrapperBackgroundLightMode};
border-radius: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 12px;
position: relative;
width: 100%;
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
background-size: 300px;
content: '';
height: 300px;
opacity: 0.1;
position: absolute;
transform: rotate(25deg) translate(-90px, -40px);
width: 300px;
z-index: -1;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
flex-direction: row;
padding: 16px 20px;
}
`
const Body = styled.div`
font-size: 12px;
line-height: 143%;
margin: 12px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
flex: 1 1 auto;
margin: auto 0;
}
`
const LinkOutCircle = styled(ArrowDownCircle)`
transform: rotate(230deg);
width: 20px;
height: 20px;
margin-left: 12px;
`
const LinkOutToBridge = styled(ExternalLink)`
align-items: center;
background-color: black;
border-radius: 16px;
color: white;
display: flex;
font-size: 14px;
justify-content: space-between;
margin: 0;
max-height: 47px;
padding: 16px 8px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
margin: auto 0 auto auto;
padding: 14px 17px;
min-width: 226px;
}
`
export function MinimalNetworkAlert() {
const { chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged) {
return null
}
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
const readMoreLink = isOptimism
? 'https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism'
: 'https://help.uniswap.org/en/articles/5538618-how-to-deposit-tokens-to-arbitrum'
return (
<Wrapper darkMode={darkMode} chainId={chainId} logoUrl={info.logoUrl}>
<L2Icon src={info.logoUrl} />
<Body>
<Trans>This is an alpha release of Uniswap on the {info.label} network.</Trans>
<DesktopTextBreak /> <Trans>You must bridge L1 assets to the network to use them.</Trans>{' '}
<ReadMoreLink href={readMoreLink}>
<Trans>Read more</Trans>
</ReadMoreLink>
</Body>
<LinkOutToBridge href={depositUrl}>
<Trans>Deposit to {info.label}</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</Wrapper>
)
}

View File

@@ -1,27 +1,75 @@
import { Trans } from '@lingui/macro'
import { L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from 'constants/chains'
import {
ARBITRUM_HELP_CENTER_LINK,
L2_CHAIN_IDS,
OPTIMISM_HELP_CENTER_LINK,
SupportedChainId,
SupportedL2ChainId,
} from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useState } from 'react'
import { ArrowDownCircle, X } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager } from 'state/user/hooks'
import { useArbitrumAlphaAlert, useDarkModeManager, useOptimismAlphaAlert } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import styled, { css } from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { CHAIN_INFO } from '../../constants/chains'
import { ReadMoreLink } from './styles'
export const DesktopTextBreak = styled.div`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
const L2Icon = styled.img`
width: 40px;
height: 40px;
width: 36px;
height: 36px;
justify-self: center;
`
const BetaTag = styled.span<{ color: string }>`
align-items: center;
background-color: ${({ color }) => color};
border-radius: 6px;
color: ${({ theme }) => theme.white};
display: flex;
font-size: 14px;
height: 28px;
justify-content: center;
left: -16px;
position: absolute;
transform: rotate(-15deg);
top: -16px;
width: 60px;
z-index: 1;
`
const Body = styled.p`
font-size: 12px;
grid-column: 1 / 3;
line-height: 143%;
margin: 0;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-column: 2 / 3;
}
`
export const Controls = styled.div<{ thin?: boolean }>`
align-items: center;
display: flex;
justify-content: flex-start;
${({ thin }) =>
thin &&
css`
margin: auto 32px auto 0;
`}
`
const CloseIcon = styled(X)`
cursor: pointer;
position: absolute;
top: 16px;
right: 16px;
`
const ContentWrapper = styled.div`
const BodyText = styled.div`
align-items: center;
display: grid;
grid-gap: 4px;
@@ -33,6 +81,37 @@ const ContentWrapper = styled.div`
grid-gap: 8px;
}
`
const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
align-items: center;
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 8px;
color: ${({ theme }) => theme.text1};
display: flex;
font-size: 16px;
height: 44px;
justify-content: space-between;
margin: 0 0 20px 0;
padding: 12px 16px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: rgba(255, 255, 255, 0.05);
}
transition: background-color 150ms ease-in-out;
${({ thin }) =>
thin &&
css`
font-size: 14px;
margin: auto;
width: 112px;
`}
`
const RootWrapper = styled.div`
position: relative;
`
export const ArbitrumWrapperBackgroundDarkMode = css`
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.3) 0%, rgba(33, 114, 229, 0.3) 100%), hsla(0, 0%, 100%, 0.1);
@@ -49,7 +128,7 @@ export const OptimismWrapperBackgroundLightMode = css`
background: radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),
radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.5);
`
const RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string }>`
const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string; thin?: boolean }>`
${({ chainId, darkMode }) =>
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
? darkMode
@@ -66,7 +145,13 @@ const RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; l
overflow: hidden;
position: relative;
width: 100%;
${({ thin }) =>
thin &&
css`
flex-direction: row;
max-width: max-content;
min-height: min-content;
`}
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
@@ -80,36 +165,29 @@ const RootWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; l
z-index: -1;
}
`
const Header = styled.h2`
const Header = styled.h2<{ thin?: boolean }>`
font-weight: 600;
font-size: 20px;
margin: 0;
padding-right: 30px;
`
const Body = styled.p`
font-size: 12px;
grid-column: 1 / 3;
line-height: 143%;
margin: 0;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-column: 2 / 3;
}
display: ${({ thin }) => (thin ? 'none' : 'block')};
`
const LinkOutCircle = styled(ArrowDownCircle)`
margin-left: 12px;
transform: rotate(230deg);
width: 20px;
height: 20px;
`
const LinkOutToBridge = styled(ExternalLink)`
const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
align-items: center;
background-color: black;
border-radius: 16px;
border-radius: 8px;
color: white;
display: flex;
font-size: 16px;
height: 44px;
justify-content: space-between;
margin: 0 20px 20px 20px;
margin: 0 12px 20px 18px;
padding: 12px 16px;
text-decoration: none;
width: auto;
@@ -118,52 +196,85 @@ const LinkOutToBridge = styled(ExternalLink)`
:active {
background-color: black;
}
${({ thin }) =>
thin &&
css`
font-size: 14px;
margin: auto 10px;
width: 168px;
`}
`
export function NetworkAlert() {
interface NetworkAlertProps {
thin?: boolean
}
export function NetworkAlert(props: NetworkAlertProps) {
const { account, chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
const [optimismAlphaAcknowledged, setOptimismAlphaAcknowledged] = useOptimismAlphaAlert()
const [locallyDismissed, setLocallyDimissed] = useState(false)
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
const dismiss = useCallback(() => {
if (userEthBalance?.greaterThan(0)) {
setArbitrumAlphaAcknowledged(true)
switch (chainId) {
case SupportedChainId.OPTIMISM:
setOptimismAlphaAcknowledged(true)
break
case SupportedChainId.ARBITRUM_ONE:
setArbitrumAlphaAcknowledged(true)
break
}
} else {
setLocallyDimissed(true)
}
}, [setArbitrumAlphaAcknowledged, userEthBalance])
if (!chainId || !L2_CHAIN_IDS.includes(chainId) || arbitrumAlphaAcknowledged || locallyDismissed) {
}, [chainId, setArbitrumAlphaAcknowledged, setOptimismAlphaAcknowledged, userEthBalance])
const onOptimismAndOptimismAcknowledged = SupportedChainId.OPTIMISM === chainId && optimismAlphaAcknowledged
const onArbitrumAndArbitrumAcknowledged = SupportedChainId.ARBITRUM_ONE === chainId && arbitrumAlphaAcknowledged
if (
!chainId ||
!L2_CHAIN_IDS.includes(chainId) ||
onArbitrumAndArbitrumAcknowledged ||
onOptimismAndOptimismAcknowledged ||
locallyDismissed
) {
return null
}
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
const readMoreLink = isOptimism
? 'https://help.uniswap.org/en/articles/5392809-how-to-deposit-tokens-to-optimism'
: 'https://help.uniswap.org/en/articles/5538618-how-to-deposit-tokens-to-arbitrum'
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
const showCloseIcon = Boolean(userEthBalance?.greaterThan(0) && !props.thin)
return (
<RootWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl}>
<CloseIcon onClick={dismiss} />
<ContentWrapper>
<L2Icon src={info.logoUrl} />
<Header>
<Trans>Uniswap on {info.label}</Trans>
</Header>
<Body>
<Trans>
This is an alpha release of Uniswap on the {info.label} network. You must bridge L1 assets to the network to
swap them.
</Trans>{' '}
<ReadMoreLink href={readMoreLink}>
<Trans>Read more</Trans>
</ReadMoreLink>
</Body>
<RootWrapper>
<BetaTag color={isOptimism ? '#ff0420' : '#0490ed'}>Beta</BetaTag>
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl} thin={props.thin}>
{showCloseIcon && <CloseIcon onClick={dismiss} />}
<BodyText>
<L2Icon src={info.logoUrl} />
<Header thin={props.thin}>
<Trans>Uniswap on {info.label}</Trans>
</Header>
<Body>
<Trans>
To starting trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
release and learn about the risks before using {info.label}.
</Trans>
</Body>
</BodyText>
<Controls thin={props.thin}>
<LinkOutToBridge href={depositUrl} thin={props.thin}>
<Trans>Deposit Assets</Trans>
<LinkOutCircle />
</LinkOutToBridge>
<LearnMoreLink href={helpCenterLink} thin={props.thin}>
<Trans>Learn More</Trans>
</LearnMoreLink>
</Controls>
</ContentWrapper>
<LinkOutToBridge href={depositUrl}>
<Trans>Deposit to {info.label}</Trans>
<LinkOutCircle />
</LinkOutToBridge>
</RootWrapper>
)
}

View File

@@ -1,7 +0,0 @@
import styled from 'styled-components/macro'
import { ExternalLink } from 'theme'
export const ReadMoreLink = styled(ExternalLink)`
color: ${({ theme }) => theme.text1};
text-decoration: underline;
`

View File

@@ -1,5 +1,6 @@
import React from 'react'
import styled from 'styled-components/macro'
import { escapeRegExp } from '../../utils'
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`

View File

@@ -1,63 +0,0 @@
import { Trans } from '@lingui/macro'
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { AlertOctagon } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink } from 'theme'
const Root = styled.div`
background-color: ${({ theme }) => theme.yellow3};
border-radius: 18px;
color: black;
margin-top: 16px;
padding: 16px;
width: 100%;
max-width: 880px;
`
const WarningIcon = styled(AlertOctagon)`
margin: 0 8px 0 0;
`
const TitleRow = styled.div`
align-items: center;
display: flex;
flex-direction: row;
justify-content: flex-start;
margin: 0;
font-size: 20px;
font-weight: 600;
line-height: 25px;
`
const Body = styled.div`
font-size: 12px;
line-height: 15px;
margin: 8px 0 0 0;
`
const ReadMoreLink = styled(ExternalLink)`
color: black;
text-decoration: underline;
`
export default function OptimismDowntimeWarning() {
const { chainId } = useActiveWeb3React()
if (!chainId || ![SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)) {
return null
}
return (
<Root>
<TitleRow>
<WarningIcon />
<Trans>Optimism Planned Downtime</Trans>
</TitleRow>
<Body>
<Trans>
Optimism expects planned downtime in the near future. Unplanned downtime may also occur. While the network is
down, fees will not be generated and you will be unable to remove liquidity.{' '}
<ReadMoreLink href="https://help.uniswap.org/en/articles/5406082-what-happens-if-the-optimistic-ethereum-network-experiences-downtime">
Read more.
</ReadMoreLink>
</Trans>
</Body>
</Root>
)
}

View File

@@ -1,21 +1,17 @@
import { Placement } from '@popperjs/core'
import { transparentize } from 'polished'
import React, { useCallback, useState } from 'react'
import { Options, Placement } from '@popperjs/core'
import Portal from '@reach/portal'
import React, { useCallback, useMemo, useState } from 'react'
import { usePopper } from 'react-popper'
import styled from 'styled-components/macro'
import useInterval from '../../hooks/useInterval'
import Portal from '@reach/portal'
const PopoverContainer = styled.div<{ show: boolean }>`
z-index: 9999;
visibility: ${(props) => (props.show ? 'visible' : 'hidden')};
opacity: ${(props) => (props.show ? 1 : 0)};
transition: visibility 150ms linear, opacity 150ms linear;
background: ${({ theme }) => theme.bg2};
border: 1px solid ${({ theme }) => theme.bg3};
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.9, theme.shadow1)};
color: ${({ theme }) => theme.text2};
border-radius: 8px;
`
const ReferenceElement = styled.div`
@@ -34,9 +30,9 @@ const Arrow = styled.div`
z-index: 9998;
content: '';
border: 1px solid ${({ theme }) => theme.bg3};
border: 1px solid ${({ theme }) => theme.bg2};
transform: rotate(45deg);
background: ${({ theme }) => theme.bg2};
background: ${({ theme }) => theme.bg0};
}
&.arrow-top {
@@ -84,14 +80,22 @@ export default function Popover({ content, show, children, placement = 'auto' }:
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null)
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null)
const [arrowElement, setArrowElement] = useState<HTMLDivElement | null>(null)
const { styles, update, attributes } = usePopper(referenceElement, popperElement, {
placement,
strategy: 'fixed',
modifiers: [
{ name: 'offset', options: { offset: [8, 8] } },
{ name: 'arrow', options: { element: arrowElement } },
],
})
const options = useMemo(
(): Options => ({
placement,
strategy: 'fixed',
modifiers: [
{ name: 'offset', options: { offset: [8, 8] } },
{ name: 'arrow', options: { element: arrowElement } },
{ name: 'preventOverflow', options: { padding: 8 } },
],
}),
[arrowElement, placement]
)
const { styles, update, attributes } = usePopper(referenceElement, popperElement, options)
const updateCallback = useCallback(() => {
update && update()
}, [update])

View File

@@ -1,9 +1,10 @@
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useCallback, useEffect } from 'react'
import ReactGA from 'react-ga'
import { Heart, X } from 'react-feather'
import ReactGA from 'react-ga'
import styled, { keyframes } from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { ButtonPrimary } from '../../components/Button'
import { useActiveWeb3React } from '../../hooks/web3'
@@ -14,7 +15,6 @@ import {
useToggleSelfClaimModal,
useToggleShowClaimPopup,
} from '../../state/application/hooks'
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { TYPE } from '../../theme'
import { AutoColumn } from '../Column'

View File

@@ -1,8 +1,9 @@
import { useCallback, useContext, useEffect } from 'react'
import { X } from 'react-feather'
import { animated } from 'react-spring'
import { useSpring } from 'react-spring/web'
import styled, { ThemeContext } from 'styled-components/macro'
import { animated } from 'react-spring'
import { PopupContent } from '../../state/application/actions'
import { useRemovePopup } from '../../state/application/hooks'
import TransactionPopup from './TransactionPopup'
@@ -73,9 +74,9 @@ export default function PopupItem({
let popupContent
if ('txn' in content) {
const {
txn: { hash, success, summary },
txn: { hash },
} = content
popupContent = <TransactionPopup hash={hash} success={success} summary={summary} />
popupContent = <TransactionPopup hash={hash} />
}
const faderStyle = useSpring({

View File

@@ -1,10 +1,13 @@
import { useContext } from 'react'
import { AlertCircle, CheckCircle } from 'react-feather'
import styled, { ThemeContext } from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTransaction } from '../../state/transactions/hooks'
import { TYPE } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
@@ -12,26 +15,24 @@ const RowNoFlex = styled(AutoRow)`
flex-wrap: nowrap;
`
export default function TransactionPopup({
hash,
success,
summary,
}: {
hash: string
success?: boolean
summary?: string
}) {
export default function TransactionPopup({ hash }: { hash: string }) {
const { chainId } = useActiveWeb3React()
const tx = useTransaction(hash)
const theme = useContext(ThemeContext)
if (!tx) return null
const success = Boolean(tx.receipt && tx.receipt.status === 1)
return (
<RowNoFlex>
<div style={{ paddingRight: 16 }}>
{success ? <CheckCircle color={theme.green1} size={24} /> : <AlertCircle color={theme.red1} size={24} />}
</div>
<AutoColumn gap="8px">
<TYPE.body fontWeight={500}>{summary ?? 'Hash: ' + hash.slice(0, 8) + '...' + hash.slice(58, 65)}</TYPE.body>
<TYPE.body fontWeight={500}>
<TransactionSummary info={tx.info} />
</TYPE.body>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
View on Explorer

View File

@@ -1,13 +1,14 @@
import styled from 'styled-components/macro'
import { useActivePopups } from '../../state/application/hooks'
import { AutoColumn } from '../Column'
import PopupItem from './PopupItem'
import ClaimPopup from './ClaimPopup'
import { useURLWarningVisible } from '../../state/user/hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme'
import { useActivePopups } from '../../state/application/hooks'
import { useURLWarningVisible } from '../../state/user/hooks'
import { AutoColumn } from '../Column'
import ClaimPopup from './ClaimPopup'
import PopupItem from './PopupItem'
const MobilePopupWrapper = styled.div<{ height: string | number }>`
position: relative;
max-width: 100%;

View File

@@ -1,23 +1,21 @@
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import Badge, { BadgeVariant } from 'components/Badge'
import { transparentize } from 'polished'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { Trans } from '@lingui/macro'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonEmpty } from '../Button'
import { transparentize } from 'polished'
import { CardNoise } from '../earn/styled'
import { useColor } from '../../hooks/useColor'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonEmpty } from '../Button'
import { LightCard } from '../Card'
import { AutoColumn } from '../Column'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowFixed, AutoRow } from '../Row'
import { CardNoise } from '../earn/styled'
import { AutoRow, RowFixed } from '../Row'
import { Dots } from '../swap/styleds'
import { FixedHeightRow } from '.'
import Badge, { BadgeVariant } from 'components/Badge'
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`
border: none;

View File

@@ -1,31 +1,29 @@
import JSBI from 'jsbi'
import { useState } from 'react'
import { Percent, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import JSBI from 'jsbi'
import { transparentize } from 'polished'
import { useState } from 'react'
import { ChevronDown, ChevronUp } from 'react-feather'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { Trans } from '@lingui/macro'
import { BIG_INT_ZERO } from '../../constants/misc'
import { useColor } from '../../hooks/useColor'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonPrimary, ButtonSecondary, ButtonEmpty } from '../Button'
import { transparentize } from 'polished'
import { CardNoise } from '../earn/styled'
import { useColor } from '../../hooks/useColor'
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
import { LightCard } from '../Card'
import { AutoColumn } from '../Column'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween, RowFixed, AutoRow } from '../Row'
import { CardNoise } from '../earn/styled'
import { AutoRow, RowBetween, RowFixed } from '../Row'
import { Dots } from '../swap/styleds'
import { BIG_INT_ZERO } from '../../constants/misc'
import { FixedHeightRow } from '.'
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`

View File

@@ -1,32 +1,30 @@
import JSBI from 'jsbi'
import { Percent, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import JSBI from 'jsbi'
import { transparentize } from 'polished'
import { useState } from 'react'
import { ChevronDown, ChevronUp } from 'react-feather'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { Trans } from '@lingui/macro'
import { BIG_INT_ZERO } from '../../constants/misc'
import { useColor } from '../../hooks/useColor'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonPrimary, ButtonSecondary, ButtonEmpty } from '../Button'
import { transparentize } from 'polished'
import { CardNoise } from '../earn/styled'
import { useColor } from '../../hooks/useColor'
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
import { GreyCard, LightCard } from '../Card'
import { AutoColumn } from '../Column'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween, RowFixed, AutoRow } from '../Row'
import { CardNoise } from '../earn/styled'
import { AutoRow, RowBetween, RowFixed } from '../Row'
import { Dots } from '../swap/styleds'
import { BIG_INT_ZERO } from '../../constants/misc'
export const FixedHeightRow = styled(RowBetween)`
height: 24px;

View File

@@ -1,6 +1,6 @@
import { Trans } from '@lingui/macro'
import PositionListItem from 'components/PositionListItem'
import React from 'react'
import { Trans } from '@lingui/macro'
import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme'
import { PositionDetails } from 'types/position'

View File

@@ -1,24 +1,25 @@
import { useMemo } from 'react'
import { Trans } from '@lingui/macro'
import { Percent, Price, Token } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import RangeBadge from 'components/Badge/RangeBadge'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { usePool } from 'hooks/usePools'
import HoverInlineText from 'components/HoverInlineText'
import Loader from 'components/Loader'
import { RowBetween } from 'components/Row'
import { useToken } from 'hooks/Tokens'
import useIsTickAtLimit from 'hooks/useIsTickAtLimit'
import { usePool } from 'hooks/usePools'
import { useMemo } from 'react'
import { Link } from 'react-router-dom'
import { Bound } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { HideSmall, MEDIA_WIDTHS, SmallOnly } from 'theme'
import { PositionDetails } from 'types/position'
import { Price, Token, Percent } from '@uniswap/sdk-core'
import { formatTickPrice } from 'utils/formatTickPrice'
import Loader from 'components/Loader'
import { unwrappedToken } from 'utils/unwrappedToken'
import RangeBadge from 'components/Badge/RangeBadge'
import { RowBetween } from 'components/Row'
import HoverInlineText from 'components/HoverInlineText'
import { DAI, USDC, USDT, WBTC, WETH9_EXTENDED } from '../../constants/tokens'
import { Trans } from '@lingui/macro'
import useIsTickAtLimit from 'hooks/useIsTickAtLimit'
import { Bound } from 'state/mint/v3/actions'
const LinkRow = styled(Link)`
align-items: center;

View File

@@ -1,21 +1,21 @@
import { useState, useCallback, useContext, ReactNode } from 'react'
import { Position } from '@uniswap/v3-sdk'
import { LightCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
import { TYPE } from 'theme'
import { RowBetween, RowFixed } from 'components/Row'
import CurrencyLogo from 'components/CurrencyLogo'
import { unwrappedToken } from 'utils/unwrappedToken'
import { Break } from 'components/earn/styled'
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import RateToggle from 'components/RateToggle'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { Position } from '@uniswap/v3-sdk'
import RangeBadge from 'components/Badge/RangeBadge'
import { ThemeContext } from 'styled-components/macro'
import { LightCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { Break } from 'components/earn/styled'
import RateToggle from 'components/RateToggle'
import { RowBetween, RowFixed } from 'components/Row'
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 { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/unwrappedToken'
export const PositionPreview = ({
position,

View File

@@ -1,8 +1,9 @@
import { useContext } from 'react'
import styled from 'styled-components/macro'
import { AutoColumn } from '../Column'
import { ThemeContext } from 'styled-components/macro'
import { TYPE } from '../../theme'
import { AutoColumn } from '../Column'
const Wrapper = styled(AutoColumn)`
margin-right: 8px;

View File

@@ -1,5 +1,6 @@
import { ReactNode, useCallback, useState } from 'react'
import styled from 'styled-components/macro'
import Tooltip from '../Tooltip'
const QuestionWrapper = styled.div`

View File

@@ -1,10 +1,10 @@
import React from 'react'
import { Trans } from '@lingui/macro'
import { ButtonOutlined } from 'components/Button'
import { AutoRow } from 'components/Row'
import { TYPE } from 'theme'
import styled from 'styled-components/macro'
import { Trans } from '@lingui/macro'
import React from 'react'
import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
const Button = styled(ButtonOutlined).attrs(() => ({
padding: '8px',

View File

@@ -1,8 +1,8 @@
import { Trans } from '@lingui/macro'
import { Currency, Price, Token } from '@uniswap/sdk-core'
import { AutoColumn } from 'components/Column'
import StepCounter from 'components/InputStepCounter/InputStepCounter'
import { RowBetween } from 'components/Row'
import { AutoColumn } from 'components/Column'
import { Bound } from 'state/mint/v3/actions'
// currencyA is the base token

View File

@@ -0,0 +1,56 @@
import { Currency, Percent } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { DAI, USDC, WBTC } from 'constants/tokens'
import { render } from 'test-utils'
import RoutingDiagram, { RoutingDiagramEntry } from './RoutingDiagram'
const percent = (strings: TemplateStringsArray) => new Percent(parseInt(strings[0]), 100)
const singleRoute: RoutingDiagramEntry = { percent: percent`100`, path: [[USDC, DAI, FeeAmount.LOW]] }
const multiRoute: RoutingDiagramEntry[] = [
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOW]] },
{
percent: percent`25`,
path: [
[USDC, WBTC, FeeAmount.MEDIUM],
[WBTC, DAI, FeeAmount.HIGH],
],
},
]
jest.mock(
'components/CurrencyLogo',
() =>
({ currency }: { currency: Currency }) =>
`CurrencyLogo currency=${currency.symbol}`
)
jest.mock(
'components/DoubleLogo',
() =>
({ currency0, currency1 }: { currency0: Currency; currency1: Currency }) =>
`DoubleCurrencyLogo currency0=${currency0.symbol} currency1=${currency1.symbol}`
)
jest.mock('../Popover', () => () => 'Popover')
jest.mock('hooks/useTokenInfoFromActiveList', () => ({
useTokenInfoFromActiveList: (currency: Currency) => currency,
}))
it('renders when no routes are provided', () => {
const { asFragment } = render(<RoutingDiagram currencyIn={DAI} currencyOut={USDC} routes={[]} />)
expect(asFragment()).toMatchSnapshot()
})
it('renders single route', () => {
const { asFragment } = render(<RoutingDiagram currencyIn={USDC} currencyOut={DAI} routes={[singleRoute]} />)
expect(asFragment()).toMatchSnapshot()
})
it('renders multi route', () => {
const { asFragment } = render(<RoutingDiagram currencyIn={USDC} currencyOut={DAI} routes={multiRoute} />)
expect(asFragment()).toMatchSnapshot()
})

View File

@@ -0,0 +1,113 @@
import { Currency, Percent } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import CurrencyLogo from 'components/CurrencyLogo'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import Row, { AutoRow } from 'components/Row'
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
import { Box } from 'rebass'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
export interface RoutingDiagramEntry {
percent: Percent
path: [Currency, Currency, FeeAmount][]
}
const Wrapper = styled(Box)`
align-items: center;
background-color: ${({ theme }) => theme.bg0};
width: 400px;
`
const RouteContainerRow = styled(Row)`
display: grid;
grid-gap: 8px;
grid-template-columns: 24px 1fr 24px;
`
const RouteRow = styled(Row)`
align-items: center;
display: flex;
justify-content: center;
padding: 0.1rem 0.5rem;
position: relative;
`
const PoolBadge = styled(Badge)`
display: flex;
padding: 0.25rem 0.5rem;
`
const DottedLine = styled.div`
border-color: ${({ theme }) => theme.bg4};
border-top-style: dotted;
border-width: 4px;
height: 0px;
position: absolute;
width: calc(100%);
z-index: 1;
`
const OpaqueBadge = styled(Badge)`
background-color: ${({ theme }) => theme.bg2};
z-index: 2;
`
export default function RoutingDiagram({
currencyIn,
currencyOut,
routes,
}: {
currencyIn: Currency
currencyOut: Currency
routes: RoutingDiagramEntry[]
}) {
const tokenIn = useTokenInfoFromActiveList(currencyIn)
const tokenOut = useTokenInfoFromActiveList(currencyOut)
return (
<Wrapper>
{routes.map(({ percent, path }, index) => (
<RouteContainerRow key={index}>
<CurrencyLogo currency={tokenIn} />
<Route percent={percent} path={path} />
<CurrencyLogo currency={tokenOut} />
</RouteContainerRow>
))}
</Wrapper>
)
}
function Route({ percent, path }: { percent: RoutingDiagramEntry['percent']; path: RoutingDiagramEntry['path'] }) {
return (
<RouteRow>
<DottedLine />
<OpaqueBadge>
<TYPE.small fontSize={12} style={{ wordBreak: 'normal' }}>
{percent.toSignificant(2)}%
</TYPE.small>
</OpaqueBadge>
<AutoRow gap="1px" width="100%" style={{ justifyContent: 'space-evenly', zIndex: 2 }}>
{path.map(([currency0, currency1, feeAmount], index) => (
<Pool key={index} currency0={currency0} currency1={currency1} feeAmount={feeAmount} />
))}
</AutoRow>
</RouteRow>
)
}
function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; currency1: Currency; feeAmount: FeeAmount }) {
const tokenInfo0 = useTokenInfoFromActiveList(currency0)
const tokenInfo1 = useTokenInfoFromActiveList(currency1)
return (
<PoolBadge>
<Box margin="0 5px 0 10px">
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
</Box>
<TYPE.small fontSize={12}>{feeAmount / 10000}%</TYPE.small>
</PoolBadge>
)
}

View File

@@ -0,0 +1,170 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders multi route 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
>
CurrencyLogo currency=USDC
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
>
<div
class="RoutingDiagram__DottedLine-sc-o1ook0-4 gwivhA"
/>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-5 gayll cvyxdH"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
>
75%
</div>
</div>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
style="justify-content: space-evenly; z-index: 2;"
width="100%"
>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
>
<div
class="css-1t7xebc"
>
DoubleCurrencyLogo currency0=DAI currency1=USDC
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
>
0.05%
</div>
</div>
</div>
</div>
CurrencyLogo currency=DAI
</div>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
>
CurrencyLogo currency=USDC
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
>
<div
class="RoutingDiagram__DottedLine-sc-o1ook0-4 gwivhA"
/>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-5 gayll cvyxdH"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
>
25%
</div>
</div>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
style="justify-content: space-evenly; z-index: 2;"
width="100%"
>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
>
<div
class="css-1t7xebc"
>
DoubleCurrencyLogo currency0=WBTC currency1=USDC
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
>
0.3%
</div>
</div>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
>
<div
class="css-1t7xebc"
>
DoubleCurrencyLogo currency0=DAI currency1=WBTC
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
>
1%
</div>
</div>
</div>
</div>
CurrencyLogo currency=DAI
</div>
</div>
</DocumentFragment>
`;
exports[`renders single route 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
>
CurrencyLogo currency=USDC
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteRow-sc-o1ook0-2 lmTMKd itvFNV fzMiot"
>
<div
class="RoutingDiagram__DottedLine-sc-o1ook0-4 gwivhA"
/>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-5 gayll cvyxdH"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
>
100%
</div>
</div>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 Row__AutoRow-sc-nrd8cx-3 iqvZFe itvFNV kkMfuq"
style="justify-content: space-evenly; z-index: 2;"
width="100%"
>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
>
<div
class="css-1t7xebc"
>
DoubleCurrencyLogo currency0=DAI currency1=USDC
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
>
0.05%
</div>
</div>
</div>
</div>
CurrencyLogo currency=DAI
</div>
</div>
</DocumentFragment>
`;
exports[`renders when no routes are provided 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
/>
</DocumentFragment>
`;

View File

@@ -1,5 +1,5 @@
import styled from 'styled-components/macro'
import { Box } from 'rebass/styled-components'
import styled from 'styled-components/macro'
const Row = styled(Box)<{
width?: string

View File

@@ -1,14 +1,14 @@
import { Trans } from '@lingui/macro'
import { Text } from 'rebass'
import { Currency } from '@uniswap/sdk-core'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { COMMON_BASES } from '../../constants/routing'
import { currencyId } from '../../utils/currencyId'
import { AutoColumn } from '../Column'
import CurrencyLogo from '../CurrencyLogo'
import QuestionHelper from '../QuestionHelper'
import { AutoRow } from '../Row'
import CurrencyLogo from '../CurrencyLogo'
const MobileWrapper = styled(AutoColumn)`
${({ theme }) => theme.mediaWidth.upToSmall`

View File

@@ -1,27 +1,28 @@
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { LightGreyCard } from 'components/Card'
import QuestionHelper from 'components/QuestionHelper'
import useTheme from 'hooks/useTheme'
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import TokenListLogo from '../../assets/svg/tokenlist.svg'
import { useIsUserAddedToken } from '../../hooks/Tokens'
import { useActiveWeb3React } from '../../hooks/web3'
import { useCombinedActiveList } from '../../state/lists/hooks'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import { useCurrencyBalance } from '../../state/wallet/hooks'
import { TYPE } from '../../theme'
import { useIsUserAddedToken } from '../../hooks/Tokens'
import Column from '../Column'
import { RowFixed, RowBetween } from '../Row'
import CurrencyLogo from '../CurrencyLogo'
import { MouseoverTooltip } from '../Tooltip'
import { MenuItem } from './styleds'
import Loader from '../Loader'
import { isTokenOnList } from '../../utils'
import Column from '../Column'
import CurrencyLogo from '../CurrencyLogo'
import Loader from '../Loader'
import { RowBetween, RowFixed } from '../Row'
import { MouseoverTooltip } from '../Tooltip'
import ImportRow from './ImportRow'
import { LightGreyCard } from 'components/Card'
import TokenListLogo from '../../assets/svg/tokenlist.svg'
import QuestionHelper from 'components/QuestionHelper'
import useTheme from 'hooks/useTheme'
import { MenuItem } from './styleds'
function currencyKey(currency: Currency): string {
return currency.isToken ? currency.address : 'ETHER'

View File

@@ -1,29 +1,30 @@
import { Currency, Token } from '@uniswap/sdk-core'
import { KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import ReactGA from 'react-ga'
import { t, Trans } from '@lingui/macro'
import { Currency, Token } from '@uniswap/sdk-core'
import useDebounce from 'hooks/useDebounce'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useTheme from 'hooks/useTheme'
import useToggle from 'hooks/useToggle'
import { KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Edit } from 'react-feather'
import ReactGA from 'react-ga'
import AutoSizer from 'react-virtualized-auto-sizer'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { ExtendedEther } from '../../constants/tokens'
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
import { useActiveWeb3React } from '../../hooks/web3'
import { useAllTokens, useToken, useIsUserAddedToken, useSearchInactiveTokenLists } from '../../hooks/Tokens'
import { CloseIcon, TYPE, ButtonText, IconWrapper } from '../../theme'
import { ButtonText, CloseIcon, IconWrapper, TYPE } from '../../theme'
import { isAddress } from '../../utils'
import Column from '../Column'
import Row, { RowBetween, RowFixed } from '../Row'
import CommonBases from './CommonBases'
import CurrencyList from './CurrencyList'
import { filterTokens, useSortedTokensByQuery } from './filtering'
import ImportRow from './ImportRow'
import { useTokenComparator } from './sorting'
import { PaddedColumn, SearchInput, Separator } from './styleds'
import AutoSizer from 'react-virtualized-auto-sizer'
import styled from 'styled-components/macro'
import useToggle from 'hooks/useToggle'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useTheme from 'hooks/useTheme'
import ImportRow from './ImportRow'
import { Edit } from 'react-feather'
import useDebounce from 'hooks/useDebounce'
const ContentWrapper = styled(Column)`
width: 100%;

View File

@@ -1,14 +1,15 @@
import { Currency, Token } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists'
import usePrevious from 'hooks/usePrevious'
import { useCallback, useEffect, useState } from 'react'
import useLast from '../../hooks/useLast'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import Modal from '../Modal'
import { CurrencySearch } from './CurrencySearch'
import { ImportToken } from './ImportToken'
import usePrevious from 'hooks/usePrevious'
import Manage from './Manage'
import { TokenList } from '@uniswap/token-lists'
import { ImportList } from './ImportList'
import { ImportToken } from './ImportToken'
import Manage from './Manage'
interface CurrencySearchModalProps {
isOpen: boolean

View File

@@ -1,26 +1,26 @@
import { useState, useCallback } from 'react'
import styled from 'styled-components/macro'
import ReactGA from 'react-ga'
import { TYPE, CloseIcon } from 'theme'
import { Trans } from '@lingui/macro'
import { TokenList } from '@uniswap/token-lists'
import { ButtonPrimary } from 'components/Button'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed, AutoRow } from 'components/Row'
import { ArrowLeft, AlertTriangle } from 'react-feather'
import ListLogo from 'components/ListLogo'
import { AutoRow, RowBetween, RowFixed } from 'components/Row'
import { SectionBreak } from 'components/swap/styleds'
import { useFetchListCallback } from 'hooks/useFetchListCallback'
import useTheme from 'hooks/useTheme'
import { transparentize } from 'polished'
import { ButtonPrimary } from 'components/Button'
import { SectionBreak } from 'components/swap/styleds'
import { ExternalLink } from '../../theme/components'
import ListLogo from 'components/ListLogo'
import { PaddedColumn, Checkbox, TextDot } from './styleds'
import { TokenList } from '@uniswap/token-lists'
import { useCallback, useState } from 'react'
import { AlertTriangle, ArrowLeft } from 'react-feather'
import ReactGA from 'react-ga'
import { useAppDispatch } from 'state/hooks'
import { useFetchListCallback } from 'hooks/useFetchListCallback'
import { removeList, enableList } from 'state/lists/actions'
import { CurrencyModalView } from './CurrencySearchModal'
import { enableList, removeList } from 'state/lists/actions'
import { useAllLists } from 'state/lists/hooks'
import { Trans } from '@lingui/macro'
import styled from 'styled-components/macro'
import { CloseIcon, TYPE } from 'theme'
import { ExternalLink } from '../../theme/components'
import { CurrencyModalView } from './CurrencySearchModal'
import { Checkbox, PaddedColumn, TextDot } from './styleds'
const Wrapper = styled.div`
position: relative;

View File

@@ -1,17 +1,18 @@
import { CSSProperties } from 'react'
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import { AutoRow, RowFixed } from 'components/Row'
import { ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import { TYPE } from 'theme'
import ListLogo from 'components/ListLogo'
import { AutoRow, RowFixed } from 'components/Row'
import { useIsTokenActive, useIsUserAddedToken } from 'hooks/Tokens'
import useTheme from 'hooks/useTheme'
import { ButtonPrimary } from 'components/Button'
import styled from 'styled-components/macro'
import { useIsUserAddedToken, useIsTokenActive } from 'hooks/Tokens'
import { CSSProperties } from 'react'
import { CheckCircle } from 'react-feather'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import { Trans } from '@lingui/macro'
const TokenSection = styled.div<{ dim?: boolean }>`
padding: 4px 20px;

View File

@@ -1,23 +1,24 @@
import { Plural, Trans } from '@lingui/macro'
import { Currency, Token } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists/dist/types'
import { Token, Currency } from '@uniswap/sdk-core'
import styled from 'styled-components/macro'
import { TYPE, CloseIcon } from 'theme'
import { ButtonPrimary } from 'components/Button'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed } from 'components/Row'
import CurrencyLogo from 'components/CurrencyLogo'
import { ArrowLeft, AlertCircle } from 'react-feather'
import { transparentize } from 'polished'
import useTheme from 'hooks/useTheme'
import { ButtonPrimary } from 'components/Button'
import { SectionBreak } from 'components/swap/styleds'
import { useAddUserToken } from 'state/user/hooks'
import { useActiveWeb3React } from 'hooks/web3'
import { ExternalLink } from '../../theme/components'
import ListLogo from 'components/ListLogo'
import { RowBetween, RowFixed } from 'components/Row'
import { SectionBreak } from 'components/swap/styleds'
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 { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { PaddedColumn } from './styleds'
import { Plural, Trans } from '@lingui/macro'
const Wrapper = styled.div`
position: relative;

View File

@@ -1,16 +1,17 @@
import { Trans } from '@lingui/macro'
import { useState } from 'react'
import { PaddedColumn, Separator } from './styleds'
import { Token } from '@uniswap/sdk-core'
import { TokenList } from '@uniswap/token-lists'
import { RowBetween } from 'components/Row'
import { useState } from 'react'
import { ArrowLeft } from 'react-feather'
import { Text } from 'rebass'
import { CloseIcon } from 'theme'
import styled from 'styled-components/macro'
import { Token } from '@uniswap/sdk-core'
import { CloseIcon } from 'theme'
import { CurrencyModalView } from './CurrencySearchModal'
import { ManageLists } from './ManageLists'
import ManageTokens from './ManageTokens'
import { TokenList } from '@uniswap/token-lists'
import { CurrencyModalView } from './CurrencySearchModal'
import { PaddedColumn, Separator } from './styleds'
const Wrapper = styled.div`
width: 100%;

View File

@@ -10,6 +10,7 @@ import ReactGA from 'react-ga'
import { usePopper } from 'react-popper'
import { useAppDispatch, useAppSelector } from 'state/hooks'
import styled from 'styled-components/macro'
import { useFetchListCallback } from '../../hooks/useFetchListCallback'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import useTheme from '../../hooks/useTheme'

View File

@@ -1,22 +1,22 @@
import { useRef, RefObject, useCallback, useState, useMemo } from 'react'
import Column from 'components/Column'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { PaddedColumn, Separator, SearchInput } from './styleds'
import Row, { RowBetween, RowFixed } from 'components/Row'
import { TYPE, ExternalLinkIcon, TrashIcon, ButtonText, ExternalLink } from 'theme'
import { useToken } from 'hooks/Tokens'
import styled from 'styled-components/macro'
import { useUserAddedTokens, useRemoveUserAddedToken } from 'state/user/hooks'
import { Token } from '@uniswap/sdk-core'
import CurrencyLogo from 'components/CurrencyLogo'
import { isAddress } from 'utils'
import { useActiveWeb3React } from 'hooks/web3'
import Card from 'components/Card'
import ImportRow from './ImportRow'
import useTheme from '../../hooks/useTheme'
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import Card from 'components/Card'
import Column from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import Row, { RowBetween, RowFixed } from 'components/Row'
import { useToken } from 'hooks/Tokens'
import { useActiveWeb3React } from 'hooks/web3'
import { 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 { isAddress } from 'utils'
import useTheme from '../../hooks/useTheme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { CurrencyModalView } from './CurrencySearchModal'
import ImportRow from './ImportRow'
import { PaddedColumn, SearchInput, Separator } from './styleds'
const Wrapper = styled.div`
width: 100%;

View File

@@ -1,7 +1,8 @@
import { Token } from '@uniswap/sdk-core'
import { TokenInfo } from '@uniswap/token-lists'
import { useMemo } from 'react'
import { isAddress } from '../../utils'
import { Token } from '@uniswap/sdk-core'
const alwaysTrue = () => true

View File

@@ -1,5 +1,6 @@
import { Token, CurrencyAmount, Currency } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useAllTokenBalances } from '../../state/wallet/hooks'
// compare two token amounts with highest one coming first

View File

@@ -1,4 +1,5 @@
import styled from 'styled-components/macro'
import { AutoColumn } from '../Column'
import { RowBetween } from '../Row'

View File

@@ -1,13 +1,17 @@
import { t, Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core'
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { useContext, useRef, useState } from 'react'
import { Settings, X } from 'react-feather'
import ReactGA from 'react-ga'
import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components/macro'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { ApplicationModal } from '../../state/application/actions'
import { useModalOpen, useToggleSettingsMenu } from '../../state/application/hooks'
import { useExpertModeManager, useUserSingleHopOnly } from '../../state/user/hooks'
import { useClientSideRouter, useExpertModeManager } from '../../state/user/hooks'
import { TYPE } from '../../theme'
import { ButtonError } from '../Button'
import { AutoColumn } from '../Column'
@@ -16,7 +20,6 @@ import QuestionHelper from '../QuestionHelper'
import { RowBetween, RowFixed } from '../Row'
import Toggle from '../Toggle'
import TransactionSettings from '../TransactionSettings'
import { Percent } from '@uniswap/sdk-core'
const StyledMenuIcon = styled(Settings)`
height: 20px;
@@ -115,6 +118,8 @@ const ModalContentWrapper = styled.div`
`
export default function SettingsTab({ placeholderSlippage }: { placeholderSlippage: Percent }) {
const { chainId } = useActiveWeb3React()
const node = useRef<HTMLDivElement>()
const open = useModalOpen(ApplicationModal.SETTINGS)
const toggle = useToggleSettingsMenu()
@@ -123,7 +128,7 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
const [expertMode, toggleExpertMode] = useExpertModeManager()
const [singleHopOnly, setSingleHopOnly] = useUserSingleHopOnly()
const [clientSideRouter, setClientSideRouter] = useClientSideRouter()
// show confirmation view before turning on
const [showConfirmation, setShowConfirmation] = useState(false)
@@ -193,10 +198,35 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
<Text fontWeight={600} fontSize={14}>
<Trans>Interface Settings</Trans>
</Text>
{chainId === SupportedChainId.MAINNET && (
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Auto Router</Trans>
</TYPE.black>
<QuestionHelper
text={<Trans>Use the Uniswap Labs API to get better pricing through a more efficient route.</Trans>}
/>
</RowFixed>
<Toggle
id="toggle-optimized-router-button"
isActive={!clientSideRouter}
toggle={() => {
ReactGA.event({
category: 'Routing',
action: clientSideRouter ? 'enable routing API' : 'disable routing API',
})
setClientSideRouter(!clientSideRouter)
}}
/>
</RowBetween>
)}
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Toggle Expert Mode</Trans>
<Trans>Expert Mode</Trans>
</TYPE.black>
<QuestionHelper
text={
@@ -220,25 +250,6 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
}
/>
</RowBetween>
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Disable Multihops</Trans>
</TYPE.black>
<QuestionHelper text={<Trans>Restricts swaps to direct pairs only.</Trans>} />
</RowFixed>
<Toggle
id="toggle-disable-multihop-button"
isActive={singleHopOnly}
toggle={() => {
ReactGA.event({
category: 'Routing',
action: singleHopOnly ? 'disable single hop' : 'enable single hop',
})
setSingleHopOnly(!singleHopOnly)
}}
/>
</RowBetween>
</AutoColumn>
</MenuFlyout>
)}

View File

@@ -1,10 +1,11 @@
import { Trans } from '@lingui/macro'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
import { useMemo } from 'react'
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 { useLocationLinkProps } from 'hooks/useLocationLinkProps'
const Container = styled(TYPE.small)`
opacity: 0.6;

View File

@@ -1,5 +1,9 @@
import { TextInput, ResizingTextArea } from './'
import { render, screen, fireEvent } from 'test-utils'
// include style rules in snapshots
import 'jest-styled-components'
import { fireEvent, render, screen } from 'test-utils'
import { ResizingTextArea, TextInput } from './'
describe('TextInput', () => {
it('renders correctly', () => {

View File

@@ -1,5 +1,6 @@
import { Trans } from '@lingui/macro'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean }>`

View File

@@ -1,7 +1,8 @@
import { Token } from '@uniswap/sdk-core'
import Modal from '../Modal'
import { ImportToken } from 'components/SearchModal/ImportToken'
import Modal from '../Modal'
export default function TokenWarningModal({
isOpen,
tokens,

View File

@@ -1,12 +1,19 @@
import { transparentize } from 'polished'
import { ReactNode, useCallback, useState } from 'react'
import styled from 'styled-components/macro'
import Popover, { PopoverProps } from '../Popover'
const TooltipContainer = styled.div`
export const TooltipContainer = styled.div`
width: 256px;
padding: 0.6rem 1rem;
font-weight: 400;
word-break: break-word;
background: ${({ theme }) => theme.bg0};
border-radius: 12px;
border: 1px solid ${({ theme }) => theme.bg2};
box-shadow: 0 4px 8px 0 ${({ theme }) => transparentize(0.9, theme.shadow1)};
`
interface TooltipProps extends Omit<PopoverProps, 'content'> {
@@ -15,14 +22,17 @@ interface TooltipProps extends Omit<PopoverProps, 'content'> {
interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
content: ReactNode
onOpen?: () => void
// whether to wrap the content in a `TooltipContainer`
wrap?: boolean
}
export default function Tooltip({ text, ...rest }: TooltipProps) {
return <Popover content={<TooltipContainer>{text}</TooltipContainer>} {...rest} />
}
function TooltipContent({ content, ...rest }: TooltipContentProps) {
return <Popover content={<TooltipContainer>{content}</TooltipContainer>} {...rest} />
function TooltipContent({ content, wrap = false, ...rest }: TooltipContentProps) {
return <Popover content={wrap ? <TooltipContainer>{content}</TooltipContainer> : content} {...rest} />
}
export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show'>) {
@@ -38,9 +48,17 @@ export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show
)
}
export function MouseoverTooltipContent({ content, children, ...rest }: Omit<TooltipContentProps, 'show'>) {
export function MouseoverTooltipContent({
content,
children,
onOpen: openCallback = undefined,
...rest
}: Omit<TooltipContentProps, 'show'>) {
const [show, setShow] = useState(false)
const open = useCallback(() => setShow(true), [setShow])
const open = useCallback(() => {
setShow(true)
openCallback?.()
}, [openCallback])
const close = useCallback(() => setShow(false), [setShow])
return (
<TooltipContent {...rest} show={show} content={content}>

View File

@@ -1,23 +1,25 @@
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import Badge from 'components/Badge'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
import useAddTokenToMetamask from 'hooks/useAddTokenToMetamask'
import { ReactNode, useContext } from 'react'
import styled, { ThemeContext } from 'styled-components/macro'
import { getExplorerLink, ExplorerDataType } from '../../utils/getExplorerLink'
import Modal from '../Modal'
import { ExternalLink } from '../../theme'
import { Text } from 'rebass'
import { CloseIcon, CustomLightSpinner } from '../../theme/components'
import { RowBetween, RowFixed } from '../Row'
import { AlertCircle, AlertTriangle, ArrowUpCircle, CheckCircle } from 'react-feather'
import { ButtonPrimary, ButtonLight } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
import { Text } from 'rebass'
import { useIsTransactionConfirmed, useTransaction } from 'state/transactions/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import MetaMaskLogo from '../../assets/images/metamask.png'
import { useActiveWeb3React } from '../../hooks/web3'
import useAddTokenToMetamask from 'hooks/useAddTokenToMetamask'
import { Trans } from '@lingui/macro'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
import { useIsTransactionConfirmed, useTransaction } from 'state/transactions/hooks'
import Badge from 'components/Badge'
import { ExternalLink } from '../../theme'
import { CloseIcon, CustomLightSpinner } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
import { ButtonLight, ButtonPrimary } from '../Button'
import { AutoColumn, ColumnCenter } from '../Column'
import Modal from '../Modal'
import { RowBetween, RowFixed } from '../Row'
import AnimatedConfirmation from './AnimatedConfirmation'
const Wrapper = styled.div`
@@ -273,7 +275,7 @@ function L2Content({
)}
</Text>
<Text fontWeight={400} fontSize={16} textAlign="center">
{transaction?.summary ?? pendingText ?? ''}
{transaction ? <TransactionSummary info={transaction.info} /> : pendingText}
</Text>
{chainId && hash ? (
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>

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