Compare commits

...

155 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
Zach Pomerantz
15a339a0d7 lint: connect SafeApp on mount (#2341) 2021-09-13 15:29:27 -07:00
Zach Pomerantz
3c371af32a fix: only try SafeApp connection in an iframe (#2340)
* fix: only try SafeApp connection in an iframe

Improves non-iframe pageload by 300ms. Fixes #2338.

The Gnosis check for a SafeApp races a postMessage and a 300ms timeout [1]. The SafeApp embeds the interface in an iframe, so this avoids the check when not in iframes.

[1]: f224869dd5/packages/safe-apps-web3-react/src/connector.ts (L52)

* refactor: IS_IN_IFRAME const
2021-09-13 15:17:54 -07:00
Crowdin Bot
5797a6229b chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-13 18:05:31 +00:00
Crowdin Bot
32212332bb chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-13 17:07:56 +00:00
Justin Domingue
f7ac87fa85 fix: increase max block age for l2s (#2333)
* fix: increase max block age and refresh fee tier more often

* similar for tick data
2021-09-13 12:22:44 -04:00
Crowdin Bot
540ec24e21 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-13 16:05:01 +00:00
Crowdin Bot
cd4f19836c chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-13 14:05:06 +00:00
Crowdin Bot
a20b2ff7fa chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-10 07:05:03 +00:00
Noah Zinsmeister
a52b7bf06b feat: use SDK to format calldata passed to quoter (#2305)
* replace useSingleCallResult implementation

use useSingleContractMultipleData instead

* use sdk methods to format quoter calldata

* create cleaner useSingleContractWithCallData fn

* clean up useMultipleContractSingleData

* address comments
2021-09-09 16:40:37 -04:00
Moody Salem
0ab1e5f144 fix: cherry pick the logs hook fix from the liquidity incentives branch (#2315) 2021-09-08 14:06:41 -05:00
Justin Domingue
115c72db9e chore: start tracking approvals in ReactGA (#2311)
* chore: start tracking approvals in ReactGA

* move reactga to swap-only code
2021-09-08 10:22:44 -04:00
Ian Lapham
2bb695d84c reduce popup dismiss time on l2; (#2262) 2021-09-07 12:42:30 -04:00
kun
3ea6f6e0c8 chore(ci): upgrade crust pinner adapt to crust mainnet (#2281)
* Add Pin to Crust workflow

* Upgrade crust pinner adapt Crust Mainnet
2021-09-07 09:37:07 -05:00
Noah Zinsmeister
627a5d3a98 Squashed commit of the following:
commit 5f1d1af62bcd47286aafacc18788f4e7e22dd7c0
Author: Aseem Sood <asood123@yahoo.com>
Date:   Fri Sep 3 12:12:39 2021 -0400

    update readme

    tweak

commit 80a5b95c0e0ae8934b5591c982077eaa813db747
Author: Noah Zinsmeister <noahwz@gmail.com>
Date:   Fri Sep 3 11:52:56 2021 -0400

    consolidate and standardize unsupported tokens
2021-09-05 13:26:47 -04:00
Crowdin Bot
353c4751b8 chore(i18n): synchronize translations from crowdin [skip ci] 2021-09-03 17:08:55 +00:00
Zach Pomerantz
416a3f9433 chore: use native flatMap (#2231) 2021-09-03 12:29:37 -04:00
Noah Zinsmeister
30cffb7442 feat: governor bravo support (#2271)
* first pass

* Fix code style issues with ESLint

* address comments

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-09-03 12:29:25 -04:00
Zach Pomerantz
f59c5f6877 chore: paint currency selector on initialization (#2245)
Avoids a flash of "Select a token" as the App initializes.
2021-09-02 10:57:01 -07:00
Zach Pomerantz
4bdf3c191a fix: always paint StyledPollingNumber (#2254)
Adds a en-space to StyledPollingNumber so it is always painted. Fixes a layout shift when rendering the first block number.
StyledPollingNumber is taller than its container, so waiting to paint it causes a layout shift when rendering.
2021-09-02 10:42:07 -07:00
Zach Pomerantz
7b829135df fix: make non-interactive header elements unselectable (#2288) 2021-09-01 15:30:17 -07:00
Zach Pomerantz
5831328364 style: enforce object-shorthand (#2286) 2021-09-01 13:32:20 -07:00
Jordan Frankfurt
6b99740f91 use network-specific help center link (#2285) 2021-09-01 16:01:24 -04:00
Zach Pomerantz
f5557a434c chore: upgrade type system (#2276)
* chore: upgrade type system

Upgrade types, typescript, and formatters.

* fix: ListsState tests
2021-09-01 12:38:10 -07:00
circlehotarux
5dfe44dad4 fix: older browser suppport (#2228)
* fix: Object.fromEntries polyfill

* fix: update polyfills

* fix: update polyfills
2021-09-01 11:17:49 -07:00
Justin Domingue
cd50d576d4 update optimism subgraph url (#2282) 2021-09-01 11:58:10 -04:00
dependabot[bot]
d922447ef2 chore(deps): bump tar from 6.1.4 to 6.1.11 (#2280)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.4 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.4...v6.1.11)

---
updated-dependencies:
- dependency-name: tar
  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-01 09:31:25 -04:00
Jordan Frankfurt
81b1346937 update explorer links for arbitrum (#2279) 2021-08-31 18:19:26 -04:00
Zach Pomerantz
f51335df9d fix: disable serviceworker in integration tests (#2274) 2021-08-31 11:00:19 -07:00
Zach Pomerantz
13a289f6f1 Revert "test: support stubbing subgraph data in cypress (#2259)" (#2269)
This reverts commit 00403a4810.
2021-08-31 11:10:07 -04:00
Jordan Frankfurt
0afeb5acaf add arbitrum token list (#2268) 2021-08-31 11:05:12 -04:00
Zach Pomerantz
9e8d08e22c fix(governance): special case bravo parsing (#2247)
* fix(governance): special case bravo parsing

* fix(governance): explicitly parse U+2018, U+2026

* chore: upgrade ethers to ^5.4.6

Updates parseLog to delay parsing nested properties, so that they will only fail when accessed.

* fix(vote): recover from invalid UTF-8 in proposal descriptions

* fix(vote): special case bravo proposal newlines

* chore: rm dead reference
2021-08-31 10:47:06 -04:00
Ian Lapham
299286a0d9 update token list (#2270) 2021-08-31 10:37:58 -04:00
Justin Domingue
00403a4810 test: support stubbing subgraph data in cypress (#2259)
* upgrade to 7.0

* first iteration of stubbing subgraph in integration tests

* added fixtures

* add tests for fee tier distribution and liquidity chart

* remove unused test utils

* update yarn.lock

* fixed merge artifacts
2021-08-30 15:56:38 -04:00
Moody Salem
b8a9191653 fix: turn service workers back on (#1944)
reconfigure service workers to only cache used assets (excluding .po language files and non-.var.woff2 font files)

* fix: turn service workers back on

* chore: configure service worker caches

* chore: add newline

* Fix code style issues with ESLint

* chore: limit service-worker caching

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-08-25 12:46:56 -07:00
Moody Salem
1304acd8c7 fix: walletconnect on L2 issues with Rainbow (#2242)
* fix: remove the walletconnect bridge url

* fix: use the latest ethereum provider which fixes the optimism rainbow issue
2021-08-24 12:01:53 -05:00
Zach Pomerantz
8112e48e9a chore: rm redux-devtools-extension (#2230)
redux-devtools-extension integration is already provided through @reduxjs/toolkit.
2021-08-23 10:17:24 -05:00
Zach Pomerantz
f3c400c514 chore: remove unused cross-env (#2232) 2021-08-23 10:15:54 -05:00
Zach Pomerantz
c2c7d87ca3 chore: update multicodec usage (#2233) 2021-08-23 10:15:43 -05:00
Zach Pomerantz
db18b486b4 chore: rm unused styled-system (#2234) 2021-08-23 10:13:57 -05:00
Noah Zinsmeister
1613cc473b fix: proposal formatting 2021-08-20 16:57:45 -04:00
Noah Zinsmeister
e1f37b0ec6 fix(governance): hot fix for parseLog crash 2021-08-20 00:04:06 -04:00
Zach Pomerantz
805af2fdb4 chore(accessibility): increase contrast for connections (#2223) 2021-08-19 16:53:06 -04:00
Zach Pomerantz
b833d07b4f chore: change language icon to globe (#2222)
* chore: change language icon to globe
2021-08-19 16:44:28 -04:00
Moody Salem
ec5da7ec8f fix: update walletconnect for deep links and scalability (#2215) 2021-08-18 12:26:00 -05:00
Crowdin Bot
ff10346b06 chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-17 11:04:45 +00:00
Crowdin Bot
f15522a47c chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-17 00:09:22 +00:00
Crowdin Bot
67b66235ba chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-16 23:05:26 +00:00
Zach Pomerantz
7153908935 chore: fix SEO and accessibility nits for Lighthouse (#2212)
* refactor: index.html

* chore: preconnect to GA

* chore(SEO): add meta content

* chore(SEO): add alt to ethereum logo

* chore(accessibility): add aria-labels to menus

* chore(accessibility): mark AppBody as main

* chore(accessibility): update nav link ids

* chore(accessibility): set html.lang to match i18n locale

* chore(refactor): mv html.lang to useEffect
2021-08-16 18:30:52 -04:00
Crowdin Bot
4541e37388 chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-16 13:18:27 +00:00
Crowdin Bot
3bbcdcb8ae chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-13 22:05:18 +00:00
Zach Pomerantz
2daee152ef chore(i18n): do not compile i18n messages (#2211) 2021-08-13 14:03:14 -07:00
Zach Pomerantz
9af7e0e0c3 chore(i18n): touch en-US to prevent lingui from adding a creation date (#2210)
Fixes #2198. Touching en-US.po before extracting messages prevents lingui from adding a creation date, maintaining deterministic builds and IPFS hashes.
2021-08-13 14:02:59 -07:00
Noah Zinsmeister
757741c3df fix: use @walletconnect/ethereum-provider instead of @walletconnect/web3-provider (#2175)
* use @walletconnect/ethereum-provider

* bump to support client-side disconnect
2021-08-13 10:01:56 -05:00
Moody Salem
a3aa6647e7 chore: set default_bump to false per https://github.com/mathieudutour/github-tag-action/issues/85 2021-08-11 10:19:37 -05:00
Moody Salem
f463df97bf fix: do not construct routes with the same pool twice (#2196) 2021-08-11 10:15:53 -05:00
Ian Lapham
99a282b7b4 update blocked address list (#2182)
Co-authored-by: Ian Lapham <ianlapham@Ians-MacBook-Pro.local>
2021-08-10 10:30:54 -04:00
Moody Salem
5a3165358f fix: #isTradeBetter should check that output currencies are equal (#2177)
* fix: isTradeBetter should check that input/output are equal

* fix the fix
2021-08-10 09:25:43 -05:00
Moody Salem
26e334c78f fix: proposal descriptions should be pulled from the right governor (#2176) 2021-08-10 08:53:22 -05:00
Justin Domingue
bd8192c81e update chinese simplified and traditional display names (#2180) 2021-08-10 09:05:17 -04:00
Justin Domingue
ff6bd38992 add ReactGA event for full range (#2181) 2021-08-10 09:05:05 -04:00
Justin Domingue
a48b7ce702 fix: avoid running BestV3Trade when tokens are the same (#2172)
* avoid running BestV3Trade when tokens are the same

* flipped condition
2021-08-09 10:38:23 -04:00
Crowdin Bot
fc08d1fc6a chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-06 20:05:37 +00:00
Ian Lapham
b416603ff4 update unsupported list (#2143)
Co-authored-by: Ian Lapham <ianlapham@Ians-MacBook-Pro.local>
2021-08-05 20:52:17 -04:00
Justin Domingue
c4dc26e1b2 fix: rename weth9 to weth (#2133)
* update @uniswap/sdk-core and @uniswap/v3-sdk

* reorder
2021-08-05 14:43:02 -04:00
Justin Domingue
adfe7225a8 upgrade to walletconnect 1.5.2 (#2134) 2021-08-04 08:49:46 -04:00
dependabot[bot]
13e347ee02 chore(deps): bump tar from 6.1.0 to 6.1.4 (#2132)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.4.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.4)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-04 08:40:22 -04:00
Crowdin Bot
b527bfbeea chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-03 12:05:13 +00:00
Crowdin Bot
a25df00ef6 chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-03 08:05:04 +00:00
Crowdin Bot
2446a6e88b chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-03 07:04:40 +00:00
Crowdin Bot
3b3bf14e8a chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-02 19:04:33 +00:00
Crowdin Bot
017e79f7ae chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-02 17:09:09 +00:00
Crowdin Bot
804fe8f5ee chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-02 15:05:55 +00:00
Jordan Frankfurt
bf01b0d342 fix: optimism link and some copy changes (#2126)
* fix: optimism link

* fix: (un)planned downtime copy changes
2021-08-02 10:50:46 -04:00
Crowdin Bot
f46f73f35f chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-02 06:05:04 +00:00
Crowdin Bot
cad3575247 chore(i18n): synchronize translations from crowdin [skip ci] 2021-08-02 03:10:20 +00:00
Crowdin Bot
17aa9fcdb0 chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-31 12:05:49 +00:00
Crowdin Bot
087745d7c6 chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-31 08:05:54 +00:00
Lint Action
20e6ca6fd5 Fix code style issues with ESLint 2021-07-30 22:06:48 +00:00
Justin Domingue
d51b7e779b update full range documentation link 2021-07-30 15:05:43 -07:00
Matthew Quinn
cfd0412d78 fix: center import pool text V2 (#2122)
* fix: center import pool text V2

* fix: updated based on feedback

Co-authored-by: Matthew Quinn <matthew.quinn@libertymutual.com>
2021-07-30 14:39:46 -04:00
Matthew Quinn
50afef03cb fix: update mobile header to fix overflow (#2125)
Co-authored-by: Matthew Quinn <matthew.quinn@libertymutual.com>
2021-07-30 14:38:40 -04:00
Crowdin Bot
43b6e7abf4 chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-30 05:04:40 +00:00
Moody Salem
64b9df8710 fix: upgrade ethers to allow constructing transaction data compatible with eip-1559 (#2121)
* fix: upgrade ethers to allow constructing transaction data compatible with eip-1559

* bump the experimental provider
2021-07-29 17:46:35 -05:00
Crowdin Bot
d75271484a chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-29 21:04:53 +00:00
Justin Domingue
952cc98df3 fix: add support for full range positions in add liquidity (#2090)
* remove arbitrary range buttons and move full range button

* better align full range to deposit

* support dragging range when in full range

* hack to support full range brushing

* restore zoom levels

* adjusted for mocks

* fix styling

* simplify type

* restore rate toggle change

* fix lower bound by looking at isSorted

* better align bottoms

* add reset button for full range positions

* only flip when not at limit

* fix +/- buttons in range selector

* add help link
2021-07-29 13:47:03 -07:00
Crowdin Bot
9b7637e012 chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-29 19:04:45 +00:00
Jordan Frankfurt
a7f599127b add link (#2113) 2021-07-29 14:16:47 -04:00
Jordan Frankfurt
676890d89c fix(L2): update downtime warning copy (#2114) 2021-07-29 14:16:09 -04:00
Lint Action
beb1bf3bdc Fix code style issues with ESLint 2021-07-29 17:26:43 +00:00
Justin Domingue
631c202c49 document useQueryCacheInvalidator
explains why `chainId` is pulled directly from the store.
2021-07-29 10:25:29 -07:00
Moody Salem
491c9b4fd3 fix: upgrade walletconnect to 1.5.1 (#2120)
* upgrade walletconnect to 1.5.0

* bump again
2021-07-28 13:48:10 -05:00
Crowdin Bot
dcaed9094e chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-28 11:04:43 +00:00
Jeffrey Lin
8996ba6e38 fix: toggle liquidity position when toggling rates (#2117)
If field A and field B are already populated, chances are the user wants
them to remain the same and only wants to invert the price range
selector.

The conversion isn't exact, but should be preferable to the previous
behavior.
2021-07-27 16:57:52 -07:00
Crowdin Bot
c8570e5427 chore(i18n): synchronize translations from crowdin [skip ci] 2021-07-27 20:04:39 +00:00
Ian Lapham
2806f6513a feat: use modal for txn confirmation on l2 (#2055)
* use modal for txn confirmation on l2

* update with error state

* remove 1 translation

* dedicated L2 component

* update styling on to be less jumpy

* add success animation to modal

* revert regular submitted content

* remove useless hook in popups

* remove import

Co-authored-by: Ian Lapham <ian_lapham@alumni.brown.edu>
2021-07-27 15:55:47 -04:00
Noah Zinsmeister
422c703e71 Revert "feat(uma): uma call option routing (#1385)"
This reverts commit 89d484d882.
2021-07-26 14:19:29 -04:00
Noah Zinsmeister
506493e8ab Revert "feat(routing): support mirror protocol routing as additional bases (#1375)"
This reverts commit 3198129af2.
2021-07-26 13:51:53 -04:00
Justin Domingue
8dfd143208 test: set up component snapshot testing (#2102)
* set up snapshot testing

* improvements

* add tests for TextInput as an example

* Fix code style issues with ESLint

* add comment to custom-test-env file

* only set up needed providers

* include style rules in snapshots

* disable redux storage warning

* added setupTests to avoid boilerplate

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-07-26 10:41:08 -07:00
Moody Salem
718003b6f2 fix: prevent error if user selects ETH and WETH in add liquidity (#2112)
* fix: prevent error if user selects ETH and WETH in add liquidity

fixes https://github.com/Uniswap/uniswap-interface/issues/1763

* linting error

* revert changes to Tokens.ts
2021-07-26 11:08:15 -05:00
Moody Salem
80b3aa9e61 fix: remove html ids and unnecessary keys from the menu 2021-07-26 07:34:11 -05:00
355 changed files with 19534 additions and 8103 deletions

1
.env
View File

@@ -1,2 +1 @@
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_WALLETCONNECT_BRIDGE_URL="https://uniswap.bridge.walletconnect.org"

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",
@@ -29,6 +32,7 @@
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/react-in-jsx-scope": "off",
"object-shorthand": ["error", "always"],
"no-restricted-imports": [
"error",
{

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
@@ -42,6 +42,7 @@ jobs:
env:
CI: false
REACT_APP_NETWORK_URL: "https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_SERVICE_WORKER: false
- run: yarn integration-test
env:

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

View File

@@ -23,6 +23,7 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
release_branches: .*
default_bump: false
create_release:
name: Create Release
@@ -55,7 +56,7 @@ jobs:
pinata-secret-api-key: ${{ secrets.PINATA_API_SECRET_KEY }}
- name: Pin to Crust
uses: crustio/ipfs-crust-action@v1.0.8
uses: crustio/ipfs-crust-action@v2.0.3
continue-on-error: true
timeout-minutes: 2
with:

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

@@ -26,14 +26,19 @@ To access the Uniswap Interface, use an IPFS gateway link from the
[latest release](https://github.com/Uniswap/uniswap-interface/releases/latest),
or visit [app.uniswap.org](https://app.uniswap.org).
## Unsupported tokens
Check out `useUnsupportedTokenList()` in [src/state/lists/hooks.ts](./src/state/lists/hooks.ts) for blocking tokens in your instance of the interface.
You can block an entire list of tokens by passing in a tokenlist like [here](./src/constants/lists.ts) or you can block specific tokens by adding them to [unsupported.tokenlist.json](./src/constants/tokenLists/unsupported.tokenlist.json).
## Contributions
For steps on local deployment, development, and code contribution, please see [CONTRIBUTING](./CONTRIBUTING.md).
## Accessing Uniswap V2
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for
Uniswap protocol V2.
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for Uniswap protocol V2.
- Swap on Uniswap V2: https://app.uniswap.org/#/swap?use=v2
- View V2 liquidity: https://app.uniswap.org/#/pool/v2
@@ -41,6 +46,6 @@ Uniswap protocol V2.
- Migrate V2 liquidity to V3: https://app.uniswap.org/#/migrate/v2
## Accessing Uniswap V1
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
linked from the [v1.0.0 release](https://github.com/Uniswap/uniswap-interface/releases/tag/v1.0.0).

16
custom-test-env.js Normal file
View File

@@ -0,0 +1,16 @@
// Custom test environment to provide `TextEncoder`/`TextDecoder`
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Environment = require('jest-environment-jsdom')
module.exports = class CustomTestEnvironment extends Environment {
async setup() {
await super.setup()
if (typeof this.global.TextEncoder === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { TextEncoder, TextDecoder } = require('util')
this.global.TextEncoder = TextEncoder
this.global.TextDecoder = TextDecoder
}
}
}

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,29 +4,32 @@
"homepage": ".",
"private": true,
"devDependencies": {
"@ethersproject/experimental": "^5.2.0",
"@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",
"@graphql-codegen/typescript": "1.22.3",
"@graphql-codegen/typescript-operations": "^1.18.2",
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
"@lingui/cli": "^3.9.0",
"@lingui/loader": "^3.9.0",
"@lingui/macro": "^3.9.0",
"@lingui/react": "^3.9.0",
"@metamask/jazzicon": "^2.0.0",
"@popperjs/core": "^2.4.4",
"@reach/dialog": "^0.10.3",
"@reach/portal": "^0.10.3",
"@react-hook/window-scroll": "^1.3.0",
"@reduxjs/toolkit": "^1.6.1",
"@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",
@@ -49,23 +52,25 @@
"@uniswap/governance": "^1.0.2",
"@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "1.0.1",
"@uniswap/token-lists": "^1.0.0-beta.25",
"@uniswap/sdk-core": "^3.0.1",
"@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",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "^1.1.1",
"@uniswap/v3-sdk": "^3.2.1",
"@uniswap/v3-sdk": "^3.4.1",
"@web3-react/core": "^6.0.9",
"@web3-react/fortmatic-connector": "^6.0.9",
"@web3-react/injected-connector": "^6.0.7",
"@web3-react/portis-connector": "^6.0.9",
"@web3-react/walletconnect-connector": "^6.2.0",
"@web3-react/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",
"cross-env": "^7.0.2",
"cypress": "^7.7.0",
"d3": "^7.0.0",
"eslint": "^7.11.0",
@@ -73,17 +78,19 @@
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.0.0",
"ethers": "^5.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"ethers": "^5.4.6",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
"inter-ui": "^3.13.1",
"lodash.flatmap": "^4.5.0",
"jest-styled-components": "^7.0.5",
"luxon": "^1.25.0",
"ms.macro": "^2.0.0",
"multicodec": "^3.0.1",
"multihashes": "^4.0.2",
"node-vibrant": "^3.1.5",
"polished": "^3.3.2",
"polyfill-object.fromentries": "^1.0.1",
"prettier": "^2.2.1",
"qs": "^6.9.4",
"react": "^17.0.1",
@@ -103,25 +110,22 @@
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
"rebass": "^4.0.7",
"redux-devtools-extension": "^2.13.9",
"redux-localstorage-simple": "^2.3.1",
"serve": "^11.3.2",
"start-server-and-test": "^1.11.0",
"styled-components": "^5.3.0",
"styled-system": "^5.1.5",
"typechain": "^5.0.0",
"typescript": "^4.2.3",
"ua-parser-js": "^0.7.28",
"use-count-up": "^2.2.5",
"wcag-contrast": "^3.0.0",
"web-vitals": "^2.1.0",
"workbox-core": "^6.1.0",
"workbox-expiration": "^6.1.0",
"workbox-precaching": "^6.1.0",
"workbox-routing": "^6.1.0",
"workbox-strategies": "^6.1.0"
"workbox-routing": "^6.1.0"
},
"resolutions": {
"@walletconnect/web3-provider": "1.5.0-rc.5"
"@walletconnect/ethereum-provider": "1.6.5"
},
"scripts": {
"compile-contract-types": "yarn compile-external-abi-types && yarn compile-v3-contract-types",
@@ -134,8 +138,9 @@
"graphql:generate": "graphql-codegen --config codegen.yml",
"postinstall": "yarn compile-contract-types",
"start": "yarn compile-contract-types && react-scripts start",
"test": "react-scripts test --env=jsdom",
"prestart": "yarn graphql:generate && touch src/locales/en-US.po"
"test": "react-scripts test --env=./custom-test-env.js",
"prei18n:extract": "touch src/locales/en-US.po",
"prestart": "yarn graphql:generate && yarn prei18n:extract && yarn i18n:compile"
},
"eslintConfig": {
"extends": "react-app",

Binary file not shown.

View File

@@ -2,27 +2,31 @@
<html translate="no">
<head>
<meta charset="utf-8" />
<title>Uniswap Interface</title>
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
<!--
%PUBLIC_URL% will be replaced with the URL of the `public` folder during build.
Only files inside the `public` folder can be referenced from the HTML.
-->
<link rel="shortcut icon" type="image/png" href="%PUBLIC_URL%/favicon.png" />
<link rel="apple-touch-icon" sizes="192x192" href="%PUBLIC_URL%/images/192x192_App_Icon.png" />
<link rel="apple-touch-icon" sizes="512x512" href="%PUBLIC_URL%/images/512x512_App_Icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="theme-color" content="#ff007a" />
<meta name="fortmatic-site-verification" content="j93LgcVZk79qcgyo" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
manifest.json provides metadata used when the app is installed as a PWA.
See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="preconnect" href="https://www.google-analytics.com/">
<link rel="preload" href="%PUBLIC_URL%/fonts/Inter-roman.var.woff2" as="font" type="font/woff2" crossorigin>
<style>
* {
@@ -30,9 +34,23 @@
box-sizing: border-box;
}
/**
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
font-named-instance: 'Regular';
src: url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2 supports variations(gvar)"),
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2-variations"),
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format("woff2");
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Inter var', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@@ -83,8 +101,6 @@
}
}
</style>
<title>Uniswap Interface</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
@@ -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>

1046
src/abis/governor-bravo.json Normal file

File diff suppressed because it is too large Load Diff

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[] = [
@@ -9,6 +10,8 @@ const BLOCKED_ADDRESSES: string[] = [
'0x901bb9583b24D97e995513C6778dc6888AB6870e',
'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}
@@ -53,7 +55,8 @@ const Container = styled.div<{ hideInput: boolean }>`
}
`
const CurrencySelect = styled(ButtonGray)<{ selected: boolean; hideInput?: boolean }>`
const CurrencySelect = styled(ButtonGray)<{ visible: boolean; selected: boolean; hideInput?: boolean }>`
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
align-items: center;
font-size: 24px;
font-weight: 500;
@@ -80,6 +83,7 @@ const CurrencySelect = styled(ButtonGray)<{ selected: boolean; hideInput?: boole
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')};
`
@@ -144,6 +148,10 @@ const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
`};
`
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean }>`
${loadingOpacityMixin}
`
interface CurrencyInputPanelProps {
value: string
onUserInput: (value: string) => void
@@ -164,6 +172,7 @@ interface CurrencyInputPanelProps {
disableNonToken?: boolean
renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode
locked?: boolean
loading?: boolean
}
export default function CurrencyInputPanel({
@@ -185,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)
@@ -211,6 +221,7 @@ export default function CurrencyInputPanel({
<Container hideInput={hideInput}>
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
<CurrencySelect
visible={currency !== null}
selected={!!currency}
hideInput={hideInput}
className="open-currency-select-button"
@@ -247,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 && (
@@ -289,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'
@@ -30,7 +31,7 @@ export default function CurrencyLogo({
style,
...rest
}: {
currency?: Currency
currency?: Currency | null
size?: string
style?: React.CSSProperties
}) {
@@ -50,7 +51,7 @@ export default function CurrencyLogo({
}, [currency, uriLocations])
if (currency?.isNative) {
return <StyledEthereumLogo src={EthereumLogo} size={size} style={style} {...rest} />
return <StyledEthereumLogo src={EthereumLogo} alt="ethereum logo" size={size} style={style} {...rest} />
}
return <StyledLogo size={size} srcs={srcs} alt={`${currency?.symbol ?? 'token'} logo`} style={style} {...rest} />

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

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,15 +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;
margin-left: 0.5rem;
border-radius: 50%;
position: relative;
background-color: ${({ theme }) => theme.green1};
background-color: ${({ theme, warning }) => (warning ? theme.yellow3 : theme.green1)};
transition: 250ms ease background-color;
`
const rotate360 = keyframes`
@@ -46,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;
@@ -66,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(
() => {
@@ -91,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}
</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;
@@ -122,7 +127,6 @@ const AccountElement = styled.div<{ active: boolean }>`
border-radius: 12px;
white-space: nowrap;
width: 100%;
cursor: pointer;
:focus {
border: 1px solid blue;
@@ -192,14 +196,15 @@ const StyledNavLink = styled(NavLink).attrs({
text-decoration: none;
color: ${({ theme }) => theme.text2};
font-size: 1rem;
width: fit-content;
font-weight: 500;
padding: 8px 12px;
word-break: break-word;
overflow: hidden;
white-space: nowrap;
&.${activeClassName} {
border-radius: 12px;
font-weight: 600;
justify-content: center;
color: ${({ theme }) => theme.text1};
background-color: ${({ theme }) => theme.bg2};
}
@@ -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,19 +293,21 @@ export default function Header() {
>
<Trans>Pool</Trans>
</StyledNavLink>
{chainId && chainId === SupportedChainId.MAINNET && (
<StyledNavLink id={`stake-nav-link`} to={'/vote'}>
{(!chainId || chainId === SupportedChainId.MAINNET) && (
<StyledNavLink id={`vote-nav-link`} to={'/vote'}>
<Trans>Vote</Trans>
</StyledNavLink>
)}
<StyledExternalLink id={`stake-nav-link`} href={infoLink}>
<StyledExternalLink id={`charts-nav-link`} href={infoLink}>
<Trans>Charts</Trans>
<sup></sup>
</StyledExternalLink>
</HeaderLinks>
<HeaderControls>
<NetworkCard />
<HeaderElement>
<NetworkSelector />
</HeaderElement>
<HeaderElement>
{availableClaim && !showClaimPopup && (
<UNIWrapper onClick={toggleClaimModal}>
@@ -314,14 +325,16 @@ export default function Header() {
<CardNoise />
</UNIWrapper>
)}
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
<AccountElement active={!!account}>
{account && userEthBalance ? (
<BalanceText style={{ flexShrink: 0 }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
<Trans>{userEthBalance?.toSignificant(3)} ETH</Trans>
</BalanceText>
) : 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,7 +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]): boolean => a1[0] !== a2[0] || a1[1] !== 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,
@@ -62,7 +71,7 @@ export const Brush = ({
interactive: boolean
brushLabelValue: (d: 'w' | 'e', x: number) => string
brushExtent: [number, number]
setBrushExtent: (extent: [number, number]) => void
setBrushExtent: (extent: [number, number], mode: string | undefined) => void
innerWidth: number
innerHeight: number
westHandleColor: string
@@ -79,7 +88,9 @@ export const Brush = ({
const previousBrushExtent = usePrevious(brushExtent)
const brushed = useCallback(
({ type, selection }: D3BrushEvent<unknown>) => {
(event: D3BrushEvent<unknown>) => {
const { type, selection, mode } = event
if (!selection) {
setLocalBrushExtent(null)
return
@@ -88,8 +99,8 @@ 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)) {
setBrushExtent(scaled)
if (type === 'end' && !compare(brushExtent, scaled, xScale)) {
setBrushExtent(scaled, mode)
}
setLocalBrushExtent(scaled)
@@ -118,7 +129,7 @@ export const Brush = ({
brushBehavior.current(select(brushRef.current))
if (previousBrushExtent && compare(brushExtent, previousBrushExtent)) {
if (previousBrushExtent && compare(brushExtent, previousBrushExtent, xScale)) {
select(brushRef.current)
.transition()
.call(brushBehavior.current.move as any, brushExtent.map(xScale))

View File

@@ -1,5 +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'
@@ -13,6 +15,7 @@ export const yAccessor = (d: ChartEntry) => d.activeLiquidity
export function Chart({
id = 'liquidityChartRangeInput',
data: { series, current },
ticksAtLimit,
styles,
dimensions: { width, height },
margins,
@@ -56,7 +59,7 @@ export function Chart({
useEffect(() => {
if (!brushDomain) {
onBrushDomainChange(xScale.domain() as [number, number])
onBrushDomainChange(xScale.domain() as [number, number], undefined)
}
}, [brushDomain, onBrushDomainChange, xScale])
@@ -71,7 +74,13 @@ export function Chart({
// allow zooming inside the x-axis
height
}
showClear={false}
resetBrush={() => {
onBrushDomainChange(
[current * zoomLevels.initialMin, current * zoomLevels.initialMax] as [number, number],
'reset'
)
}}
showResetButton={Boolean(ticksAtLimit[Bound.LOWER] || ticksAtLimit[Bound.UPPER])}
zoomLevels={zoomLevels}
/>
<svg width="100%" height="100%" viewBox={`0 0 ${width} ${height}`} style={{ overflow: 'visible' }}>

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 } 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 }>`
@@ -41,7 +42,8 @@ export default function Zoom({
setZoom,
width,
height,
showClear,
resetBrush,
showResetButton,
zoomLevels,
}: {
svg: SVGElement | null
@@ -49,12 +51,13 @@ export default function Zoom({
setZoom: (transform: ZoomTransform) => void
width: number
height: number
showClear: boolean
resetBrush: () => void
showResetButton: boolean
zoomLevels: ZoomLevels
}) {
const zoomBehavior = useRef<ZoomBehavior<Element, unknown>>()
const [zoomIn, zoomOut, reset, initial] = useMemo(
const [zoomIn, zoomOut, zoomInitial, zoomReset] = useMemo(
() => [
() =>
svg &&
@@ -73,15 +76,16 @@ export default function Zoom({
zoomBehavior.current &&
select(svg as Element)
.transition()
.call(zoomBehavior.current.scaleTo, 1),
.call(zoomBehavior.current.scaleTo, 0.5),
() =>
svg &&
zoomBehavior.current &&
select(svg as Element)
.call(zoomBehavior.current.transform, zoomIdentity.translate(0, 0).scale(1))
.transition()
.call(zoomBehavior.current.scaleTo, 0.5),
],
[svg, zoomBehavior]
[svg]
)
useEffect(() => {
@@ -100,13 +104,19 @@ export default function Zoom({
useEffect(() => {
// reset zoom to initial on zoomLevel change
initial()
}, [initial, zoomLevels])
zoomInitial()
}, [zoomInitial, zoomLevels])
return (
<Wrapper count={showClear ? 3 : 2}>
{showClear && (
<Button onClick={reset} disabled={false}>
<Wrapper count={showResetButton ? 3 : 2}>
{showResetButton && (
<Button
onClick={() => {
resetBrush()
zoomReset()
}}
disabled={false}
>
<RefreshCcw size={16} />
</Button>
)}

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> = {
@@ -87,6 +88,8 @@ export default function LiquidityChartRangeInput({
const tokenAColor = useColor(currencyA?.wrapped)
const tokenBColor = useColor(currencyB?.wrapped)
const isSorted = currencyA && currencyB && currencyA?.wrapped.sortsBefore(currencyB?.wrapped)
const { isLoading, isUninitialized, isError, error, formattedData } = useDensityChartData({
currencyA,
currencyB,
@@ -94,7 +97,7 @@ export default function LiquidityChartRangeInput({
})
const onBrushDomainChangeEnded = useCallback(
(domain) => {
(domain, mode) => {
let leftRangeValue = Number(domain[0])
const rightRangeValue = Number(domain[1])
@@ -104,40 +107,48 @@ export default function LiquidityChartRangeInput({
batch(() => {
// simulate user input for auto-formatting and other validations
leftRangeValue > 0 && onLeftRangeInput(leftRangeValue.toFixed(6))
rightRangeValue > 0 && onRightRangeInput(rightRangeValue.toFixed(6))
if (
(!ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER] || mode === 'handle' || mode === 'reset') &&
leftRangeValue > 0
) {
onLeftRangeInput(leftRangeValue.toFixed(6))
}
if ((!ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER] || mode === 'reset') && rightRangeValue > 0) {
// todo: remove this check. Upper bound for large numbers
// sometimes fails to parse to tick.
if (rightRangeValue < 1e35) {
onRightRangeInput(rightRangeValue.toFixed(6))
}
}
})
},
[onLeftRangeInput, onRightRangeInput]
[isSorted, onLeftRangeInput, onRightRangeInput, ticksAtLimit]
)
interactive = interactive && Boolean(formattedData?.length)
const brushDomain: [number, number] | undefined = useMemo(() => {
const isSorted = currencyA && currencyB && currencyA?.wrapped.sortsBefore(currencyB?.wrapped)
const leftPrice = isSorted ? priceLower : priceUpper?.invert()
const rightPrice = isSorted ? priceUpper : priceLower?.invert()
return leftPrice && rightPrice
? [parseFloat(leftPrice?.toSignificant(5)), parseFloat(rightPrice?.toSignificant(5))]
? [parseFloat(leftPrice?.toSignificant(6)), parseFloat(rightPrice?.toSignificant(6))]
: undefined
}, [currencyA, currencyB, priceLower, priceUpper])
}, [isSorted, priceLower, priceUpper])
const brushLabelValue = useCallback(
(d: 'w' | 'e', x: number) => {
if (!price) return ''
if (d === 'w' && ticksAtLimit[Bound.LOWER]) return '0'
if (d === 'e' && ticksAtLimit[Bound.UPPER]) return '∞'
//const percent = (((x < price ? -1 : 1) * (Math.max(x, price) - Math.min(x, price))) / Math.min(x, price)) * 100
if (d === 'w' && ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]) return '0'
if (d === 'e' && ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER]) return '∞'
const percent = (x < price ? -1 : 1) * ((Math.max(x, price) - Math.min(x, price)) / price) * 100
return price ? `${format(Math.abs(percent) > 1 ? '.2~s' : '.2~f')(percent)}%` : ''
},
[price, ticksAtLimit]
[isSorted, price, ticksAtLimit]
)
if (isError) {
@@ -189,6 +200,7 @@ export default function LiquidityChartRangeInput({
brushDomain={brushDomain}
onBrushDomainChange={onBrushDomainChangeEnded}
zoomLevels={ZOOM_LEVELS[feeAmount ?? FeeAmount.MEDIUM]}
ticksAtLimit={ticksAtLimit}
/>
</ChartWrapper>
)}

View File

@@ -1,3 +1,5 @@
import { Bound } from 'state/mint/v3/actions'
export interface ChartEntry {
activeLiquidity: number
price0: number
@@ -30,6 +32,7 @@ export interface LiquidityChartRangeInputProps {
series: ChartEntry[]
current: number
}
ticksAtLimit: { [bound in Bound]?: boolean | undefined }
styles: {
area: {
@@ -52,7 +55,7 @@ export interface LiquidityChartRangeInputProps {
brushLabels: (d: 'w' | 'e', x: number) => string
brushDomain: [number, number] | undefined
onBrushDomainChange: (domain: [number, number]) => void
onBrushDomainChange: (domain: [number, number], mode: string | undefined) => void
zoomLevels: 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,32 +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,
ChevronRight,
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',
@@ -72,7 +62,6 @@ const UNIbutton = styled(ButtonPrimary)`
`
const StyledMenu = styled.div`
margin-left: 0.5rem;
display: flex;
justify-content: center;
align-items: center;
@@ -229,7 +218,7 @@ export default function Menu() {
return (
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
<StyledMenu ref={node as any}>
<StyledMenuButton onClick={toggle}>
<StyledMenuButton onClick={toggle} aria-label={t`Menu`}>
<StyledMenuIcon />
</StyledMenuButton>
@@ -276,7 +265,7 @@ export default function Menu() {
<div>
<Trans>Language</Trans>
</div>
<ChevronRight size={16} opacity={0.6} />
<Globe opacity={0.6} size={16} />
</ToggleMenuItem>
<ToggleMenuItem onClick={() => toggleDarkMode()}>
<div>{darkMode ? <Trans>Light Theme</Trans> : <Trans>Dark Theme</Trans>}</div>
@@ -337,11 +326,11 @@ export const NewMenu = ({ flyoutAlignment = FlyoutAlignment.RIGHT, ToggleUI, men
<NewMenuFlyout flyoutAlignment={flyoutAlignment}>
{menuItems.map(({ content, link, external }, i) =>
external ? (
<ExternalMenuItem id="link" href={link} key={link + i}>
<ExternalMenuItem href={link} key={i}>
{content}
</ExternalMenuItem>
) : (
<NewMenuItem id="link" to={link} key={link + i}>
<NewMenuItem to={link} key={i}>
{content}
</NewMenuItem>
)

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}
@@ -85,11 +84,11 @@ export function SwapPoolTabs({ active }: { active: 'swap' | 'pool' }) {
export function FindPoolTabs({ origin }: { origin: string }) {
return (
<Tabs>
<RowBetween style={{ padding: '1rem 1rem 0 1rem' }}>
<RowBetween style={{ padding: '1rem 1rem 0 1rem', position: 'relative' }}>
<HistoryLink to={origin}>
<StyledArrowLeft />
</HistoryLink>
<ActiveText>
<ActiveText style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)' }}>
<Trans>Import V2 Pool</Trans>
</ActiveText>
</RowBetween>

View File

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

View File

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

View File

@@ -1,26 +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'
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;
@@ -32,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);
@@ -48,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
@@ -65,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;
@@ -79,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;
@@ -117,48 +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 depositUrl = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
? `${info.bridge}?chainId=1`
: info.bridge
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
const showCloseIcon = Boolean(userEthBalance?.greaterThan(0) && !props.thin)
return (
<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>
</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,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'
const Root = styled.div`
background-color: ${({ theme }) => theme.yellow3};
border-radius: 18px;
color: black;
margin-top: 16px;
padding: 16px;
width: 100%;
`
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 LinkOutToNotion = styled.a`
color: black;
`
export default function OptimismDowntimeWarning() {
const { chainId } = useActiveWeb3React()
if (!chainId || ![SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)) {
return null
}
return (
<Root>
<TitleRow>
<WarningIcon />
<Trans>{'Optimism'} Scheduled Downtimes</Trans>
</TitleRow>
<Body>
<Trans>
{'Optimism'} expects some scheduled downtime in the near future.&nbsp;
<LinkOutToNotion
href={`https://www.notion.so/Optimism-Regenesis-Schedule-8d14a34902ca4f5a8910762b3ec4b8da`}
target="_blank"
rel="noopener noreferrer"
>
Read more.
</LinkOutToNotion>
</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,80 +1,31 @@
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 { FeeAmount } from '@uniswap/v3-sdk'
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: '4px',
borderRadius: '8px',
padding: '8px',
$borderRadius: '8px',
}))`
color: ${({ theme }) => theme.text1};
flex: 1;
background-color: ${({ theme }) => theme.bg2};
`
const RANGES = {
[FeeAmount.LOW]: [
{ label: '0.05', ticks: 5 },
{ label: '0.1', ticks: 10 },
{ label: '0.2', ticks: 20 },
],
[FeeAmount.MEDIUM]: [
{ label: '1', ticks: 100 },
{ label: '10', ticks: 953 },
{ label: '50', ticks: 4055 },
],
[FeeAmount.HIGH]: [
{ label: '2', ticks: 198 },
{ label: '10', ticks: 953 },
{ label: '80', ticks: 5878 },
],
}
interface PresetsButtonProps {
feeAmount: FeeAmount | undefined
setRange: (numTicks: number) => void
setFullRange: () => void
}
const PresetButton = ({
values: { label, ticks },
setRange,
}: {
values: {
label: string
ticks: number
}
setRange: (numTicks: number) => void
}) => (
<Button
onClick={() => {
setRange(ticks)
ReactGA.event({
category: 'Liquidity',
action: 'Preset clicked',
label: label,
})
}}
>
<TYPE.body fontSize={12}>
<Trans>+/- {label}%</Trans>
</TYPE.body>
</Button>
)
export default function PresetsButtons({ feeAmount, setRange, setFullRange }: PresetsButtonProps) {
feeAmount = feeAmount ?? FeeAmount.LOW
export default function PresetsButtons({ setFullRange }: { setFullRange: () => void }) {
return (
<AutoRow gap="4px" width="auto">
<PresetButton values={RANGES[feeAmount][0]} setRange={setRange} />
<PresetButton values={RANGES[feeAmount][1]} setRange={setRange} />
<PresetButton values={RANGES[feeAmount][2]} setRange={setRange} />
<Button onClick={() => setFullRange()}>
<Button
onClick={() => {
setFullRange()
ReactGA.event({
category: 'Liquidity',
action: 'Full Range Clicked',
})
}}
>
<TYPE.body fontSize={12}>
<Trans>Full Range</Trans>
</TYPE.body>

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
@@ -44,13 +44,13 @@ export default function RangeSelector({
<AutoColumn gap="md">
<RowBetween>
<StepCounter
value={ticksAtLimit[Bound.LOWER] ? '0' : leftPrice?.toSignificant(5) ?? ''}
value={ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER] ? '0' : leftPrice?.toSignificant(5) ?? ''}
onUserInput={onLeftRangeInput}
width="48%"
decrement={isSorted ? getDecrementLower : getIncrementUpper}
increment={isSorted ? getIncrementLower : getDecrementUpper}
decrementDisabled={ticksAtLimit[Bound.LOWER]}
incrementDisabled={ticksAtLimit[Bound.LOWER]}
decrementDisabled={ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]}
incrementDisabled={ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]}
feeAmount={feeAmount}
label={leftPrice ? `${currencyB?.symbol}` : '-'}
title={<Trans>Min Price</Trans>}
@@ -58,13 +58,13 @@ export default function RangeSelector({
tokenB={currencyB?.symbol}
/>
<StepCounter
value={ticksAtLimit[Bound.UPPER] ? '∞' : rightPrice?.toSignificant(5) ?? ''}
value={ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER] ? '∞' : rightPrice?.toSignificant(5) ?? ''}
onUserInput={onRightRangeInput}
width="48%"
decrement={isSorted ? getDecrementUpper : getIncrementLower}
increment={isSorted ? getIncrementUpper : getDecrementLower}
incrementDisabled={ticksAtLimit[Bound.UPPER]}
decrementDisabled={ticksAtLimit[Bound.UPPER]}
incrementDisabled={ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER]}
decrementDisabled={ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER]}
feeAmount={feeAmount}
label={rightPrice ? `${currencyB?.symbol}` : '-'}
tokenA={currencyA?.symbol}

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)
@@ -173,7 +178,7 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
</AutoColumn>
</ModalContentWrapper>
</Modal>
<StyledMenuButton onClick={toggle} id="open-settings-dialog-button">
<StyledMenuButton onClick={toggle} id="open-settings-dialog-button" aria-label={t`Transaction Settings`}>
<StyledMenuIcon />
{expertMode ? (
<EmojiWrapper>
@@ -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;

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