Compare commits

...

182 Commits

Author SHA1 Message Date
Crowdin Bot
7aecf5d398 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-28 20:07:31 +00:00
Crowdin Bot
5bf2b81743 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-28 18:07:13 +00:00
Ian Lapham
ed247065a7 feat: format usd prices, add loading states (#3196)
* format usd prices, add loading states

* remove tildes, collapse details by default

* update swap deadline to use seconds

* update syntax for loading states
2022-01-28 12:59:23 -05:00
Crowdin Bot
0d0ad633fb chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-28 17:10:31 +00:00
Jordan Frankfurt
4a8f1d9b96 feat(widgets): move uniswap protocol branding from header to bottom of output (#3194)
* move branding from header to bottom of output

* remove old prop

* BrandingFooter component

* pr feedback
2022-01-28 10:45:35 -06:00
Zach Pomerantz
043fb95d22 chore: no default color extraction (#3192) 2022-01-27 13:24:50 -08:00
Zach Pomerantz
06536bc925 chore: comment out routing tooltip (#3191) 2022-01-27 13:24:39 -08:00
Ian Lapham
a598a15799 feat: Make pending txn status functional (#3193)
* update swap hooks to add swap txn confirmations

* fix: remove uneeded comments

* update with latest

* update utils to separate swap callback hooks

* create generic swap callabck to be used by both app and widget

* update app swap callback to use logic from lib

* update big number import

* add swap txn to state on submit

* remove redundant  fields in txn interfaces

* consolidate trade type logic
2022-01-27 13:38:35 -05:00
Crowdin Bot
b0265c081e chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-27 01:28:46 +00:00
Zach Pomerantz
47aff6ff74 feat: max slippage ui (#3190)
* style: input padding

* feat: expand Row grow

* style: polish max slippage
2022-01-26 16:44:21 -08:00
Zach Pomerantz
56717005e6 feat: pending tx state (#3189)
* refactor: state cleanup

* feat: add pending tx hash to swap state

* fix: update name to display tx hash
2022-01-26 16:39:10 -08:00
Ian Lapham
b50d10cbb2 feat: update swap hooks and add swap txn submission (#3187)
* update swap hooks to add swap txn confirmations

* fix: remove uneeded comments

* update with latest

* update utils to separate swap callback hooks

* create generic swap callabck to be used by both app and widget

* update app swap callback to use logic from lib

* update big number import
2022-01-26 19:21:10 -05:00
Jordan Frankfurt
ce96873a72 feat(widgets): use default input/output (#3161)
* feat: use default input/output on chain switch

* feat(widgets): ErrorGenerator -> PropValidator

* default prop validation

* useDefaults hook

* pr feedback

* fix cosmos

* drop token map changes

* add default inputs to cosmos fixture

* set up different validation layers for widget and swap

* split widget/swap prop types

* cleanup

* pr feedback

* clear defaults when they're no longer valid on the current chain

* remove state checks on validators

* stop using address in cosmos fixture

* pr feedback

* useMemo on useSwapDefaults args

* tell the user what they gave to error'd props

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
2022-01-26 12:14:18 -06:00
Tina
779625a04e fix: chain parameter should be able to switch chains on initial load (#3180)
* fix switch network on load

* dont run useeffect when chainId isnt defined yet

* remove newline
2022-01-26 10:03:48 -08:00
Crowdin Bot
d1e0812684 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-26 03:53:51 +00:00
Zach Pomerantz
98e62b4f93 Revert "chore(i18n): synchronize translations from crowdin [skip ci]"
This reverts commit 9fb0d424c2.
2022-01-25 19:46:36 -08:00
Crowdin Bot
9fb0d424c2 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-26 01:31:09 +00:00
Zach Pomerantz
8d145b908e feat: pending approval ui (#3186)
* feat: track approval txs

* refactor: update transactions

* feat: pending approval ui

* chore: fix pending approval doc

* fix: clarify optimized trade

* fix: use relative path for data uri assets
2022-01-25 16:24:36 -08:00
Zach Pomerantz
c7633d910b refactor: track txs (#3185)
* feat: track approval txs

* refactor: update transactions

* chore: add ms to deps

* test: rm stale test

* fix: comment usage of trade for optimized trade
2022-01-25 18:55:27 -05:00
Crowdin Bot
1f89a46a3f chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-25 20:07:16 +00:00
Crowdin Bot
8d54b01878 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-25 19:07:17 +00:00
Zach Pomerantz
ffe334ccbf feat: update summary view with real values (#3179)
* refactor: isolate approval callback hooks

* fix: use approval callback from trade

* chore: pass optimized trade to summary

* start review screen UI updates

* chore: pass optimized trade to summary

* fix: pass Trade to summary

* remove uneeded value type

* remove uneeded styling

* code cleanup

* code styling, update props

* fix fixture bug, code style updates

* bug fix in details array

* update logic in details

Co-authored-by: ianlapham <ianlapham@gmail.com>
2022-01-25 13:48:52 -05:00
Zach Pomerantz
ffe2bd315e fix: track swap approvals (#3183)
* fix: track swap approvals

* fix: type ambiguous return value
2022-01-24 17:52:45 -08:00
Zach Pomerantz
cee4b8c77a fix: disable swap button w/o account (#3177)
* fix: disable swap button w/o account

* nit: indent less
2022-01-24 15:28:48 -08:00
Tina
3153db9f73 feat: add chainId (network) as url parameter (#3057)
* read from query param and change networks if necessary

* dont open network selector menu on url param change

* prompt network change when url changes

* keep url, network in sync

* use chain name instead of id in url param

* only prompt network switch if url chain doesnt match
2022-01-24 15:23:34 -08:00
Ian Lapham
bbdb5f3f56 feat: update slippage tolerance to use auto or custom (#3166)
* update slippage tolerance to use auto or custom

* remove attempted styling for other PR

* back out UI changes, small naming updates

* remove UI work

* small code style changes, fix typo

* update comment to doc comment
2022-01-24 17:56:12 -05:00
Crowdin Bot
7f9c56b68c chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-24 20:08:12 +00:00
Crowdin Bot
2b69974fdc chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-24 19:06:44 +00:00
Zach Pomerantz
5236065769 refactor: isolate approval callback hooks (#3172)
* refactor: isolate approval callback hooks

* fix: use approval callback from trade
2022-01-24 10:56:24 -08:00
Justin Domingue
52128a2dcd chore: reset local tick data state on input change (#3176) 2022-01-24 11:10:33 -05:00
Justin Domingue
c9642c6cd0 feat: use TickLens on chains where subgraph is not functional (#3149) 2022-01-24 09:12:07 -05:00
Crowdin Bot
b878d764e5 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-23 18:09:33 +00:00
Will Hennessy
6a4f067ac0 Display message if not mainnet (#3151) 2022-01-23 12:31:40 -05:00
Crowdin Bot
e9407bb6bd chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-22 15:07:19 +00:00
Crowdin Bot
8d822fd0e0 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-22 10:08:02 +00:00
Zach Pomerantz
6404ee6e0b fix: default tokens on chainId change only (#3169) 2022-01-21 13:14:50 -08:00
Crowdin Bot
8ac3ed1128 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-21 10:07:23 +00:00
Zach Pomerantz
b501974a76 feat: polish select (#3160)
* feat: filter selected currency from select

* test: use infura urls

* fix: load native with chain

* fix: use currencyId for key

* feat: switch currencies when selecting other

* fix: resolve merge conflict name
2022-01-20 16:15:23 -08:00
Zach Pomerantz
567fb0181c fix: chain mismatched currencies (#3163) 2022-01-20 16:12:42 -08:00
Crowdin Bot
8a37c427e6 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-21 00:11:38 +00:00
Ian Lapham
034b3e3e58 feat: Update swap state structure and attach to UI (#3155)
* refactor: mv settings state to own file

* chore: add default exports

* refactor: update swap state to match biz logic

* feat: copy biz logic to widgets

* Hook up UI to updated swap state

* fix: decimal inputs

* fix max slippage

* fix error in settings

* fix: typing errors

* revert: useBestTrade changes

* fix: use client side trade for widgets

* fix: exhaustive deps

* chore: add router-sdk

* fix: gate old web3 on widget env

* fix building errors

* update trade imports

* update hook naming for swap amount and currencies

* small changes

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
2022-01-20 18:51:45 -05:00
Ian Lapham
053000e5fc fix: update address listt (#3159) 2022-01-20 14:50:27 -05:00
Crowdin Bot
b77e7deb49 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-20 03:06:53 +00:00
Crowdin Bot
c3321ae793 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-19 22:06:45 +00:00
Jordan Frankfurt
5dec0cf72b show wrong chain message instead of throwing on incorrect chain connection (#3153) 2022-01-19 15:52:41 -06:00
Zach Pomerantz
1efda07e7a refactor: mv try parse currency amount to lib utils (#3152) 2022-01-19 14:34:01 -05:00
Crowdin Bot
fd819260f9 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-19 16:11:52 +00:00
Jordan Frankfurt
8e3b2cb4b8 feat(widgets): add error reporting component, INTEGRATION ERROR type, and Missing provider error (#3110)
* add error reporting component, INTEGRATION ERROR type, and Missing provider error

* rename reporter to generator

* pr feedback

* refactor provider check

* add chainId, convenienceFee, and width errors

* pr feedback and convenienceFeeRecipient address enforcement

* fix imports for utils
2022-01-19 09:38:21 -06:00
Zach Pomerantz
d54783a324 fix: memoize more swap (#2950)
* fix: memoize derived swap info

* fix: memoize current block timestamp

* fix: memoize price impact

* fix: memoize debounced value updates

* fix: nits
2022-01-18 18:40:23 -05:00
Zach Pomerantz
850a20f6ad feat: include native currency in widget select (#3124)
* fix: token image for chains / natives

* feat: include native currency in select

- Updates widgets swap state to use Currency (and deals with downstream updates)
- Refactors logoURI code to a new lib/hooks/useCurrencyLogoURIs
- Adds native currency to useQueryTokenList

NB: This does not build because tests must be updated to use Currency (they currently use mock tokens)

* test: update fixtures to use real currency

* fix: data uri color extraction

* fix: token img state

* fix: use new array
2022-01-18 12:11:22 -08:00
Zach Pomerantz
99f681818f refactor: mv token hooks to lib (#3122)
* refactor: mv useNativeCurrency to lib/hooks

* refactor: mv useCurrency logic to lib/hooks
2022-01-14 11:30:04 -08:00
Crowdin Bot
1127e74357 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-14 19:07:20 +00:00
Ian Lapham
27843f6189 update end timestamp for survey (#3121) 2022-01-14 11:46:13 -07:00
Ian Lapham
1b10c88c51 feat: add survey popup for survey monkey (#3116)
* add survey popup for survey monkey

* update useEffect and add 24 hour window

* upate % logic

* update logic to show after duration

* update timestamp conditional

* small changes
2022-01-14 11:33:31 -07:00
Crowdin Bot
5d97cbf6ad chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-14 08:11:26 +00:00
Crowdin Bot
064a73ca1b chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-14 07:07:17 +00:00
Zach Pomerantz
e5a1cb4276 chore: replace microbundle with rollup (#3115)
* refactor: mv gas estimate chains out of component

* chore: replace microbundle with rollup

* chore: use ts rollup config

* chore: rename lib to widgets

* chore: add rollup doc comment

* feat: rollup typings

* fix: retain tsconfig decl dir
2022-01-13 17:11:27 -08:00
Zach Pomerantz
e68e1afd9d feat: sort the widget token select (#3114)
* refactor: mv token list utils to lib

* refactor: mv balance hooks to lib

* feat: interactive token select
2022-01-13 14:37:47 -08:00
Zach Pomerantz
8784a761d6 feat: add multicall to widget (#3112)
* feat: mv block number to atom

* fix: add block updater

* fix: fast forward dep

* refactor: mv multicall to lib

* feat: add multicall to widget

* chore: update widget deps

* nit: pluralize updaters

* chore: minimize deps
2022-01-13 08:54:08 -08:00
Zach Pomerantz
7aa0f500d6 feat: mv block number to atom (#3108)
* feat: mv block number to atom

* fix: add block updater

* fix: fast forward dep
2022-01-12 19:36:08 -08:00
Jordan Frankfurt
06a8151ede Revert "add error reporting component, INTEGRATION ERROR type, and Missing provider error (#3107)" (#3109)
This reverts commit ac2642fedc.
2022-01-12 14:24:23 -06:00
Jordan Frankfurt
ac2642fedc add error reporting component, INTEGRATION ERROR type, and Missing provider error (#3107) 2022-01-12 13:29:59 -06:00
Zach Pomerantz
ac962fb00d refactor: separate useActiveWeb3React (#3106) 2022-01-12 11:18:11 -08:00
Zach Pomerantz
f3bcf64144 refactor: split chain info from chains (#3105) 2022-01-12 10:46:41 -08:00
Zach Pomerantz
711b2ca85c chore: import @ethersprojects directly (#3104)
* Revert "chore: import from ethers"

This reverts commit 6d9c0855d2.

* Revert "fix: use provider JsonRpcProvider"

This reverts commit dcbbab5e4d.

* chore: depend on @ethersprojects directly
2022-01-12 10:06:22 -08:00
willpote
aa97ec01d3 chore: bump sor to 2.5.10 (#3091) 2022-01-11 17:26:42 -05:00
Crowdin Bot
83b70f3aa6 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-11 21:06:53 +00:00
Noah Zinsmeister
e37dd77680 Revert "bump to beta (#3090)"
This reverts commit aa37b23126.
2022-01-11 16:00:52 -05:00
Noah Zinsmeister
aa37b23126 bump to beta (#3090) 2022-01-11 15:30:45 -05:00
Jordan Frankfurt
5a90f13a03 chore(deps): bump walletconnect (#3097) 2022-01-11 14:16:35 -06:00
Will Hennessy
8c213f9001 Update wrong network message (#3089)
fixes https://github.com/Uniswap/interface/issues/2740
2022-01-11 14:16:19 -06:00
Jordan Frankfurt
5722902f96 add polygon to supported walletlink chainIds (#3096) 2022-01-11 14:15:09 -06:00
Zach Pomerantz
27412e49d5 chore: import from ethers (#3094)
* chore: rm lodash

* chore: improve styled-components lint

* chore: import from ethers

* fix: use provider JsonRpcProvider
2022-01-11 11:32:20 -08:00
Zach Pomerantz
90dfdc6bef feat: populate the widget token selector (#3080)
* feat: swap defaults

* refactor: mv token list utils to lib

* feat: expand fetchTokenList to include inlined

* feat: simple widget token list

* fix: token img props

* feat: use token list in selector

* fix: update useColor for optional logoURI

* fix: avoid leaking deps

* chore: add state to lib build

* chore: mv devDeps to deps for lib

* fix: microbundle css import

* fix: match ethers versions

* fix: use color callback

* chore: clean up token info type

* chore: widget type simplification

* refactor: share token map code

* test: include list in token select fixture

* fix: no tokens without chain id
2022-01-11 09:28:02 -08:00
Jordan Frankfurt
4f896361be fix(widgets): correctly position the arrows (#3083)
* correctly position the arrows

* update reverse button css and remove popover logic

* px->em
2022-01-11 09:50:39 -06:00
yj
c9bc166c1a fix: Add {id} replacement for ERC-1155 (#3068)
* Add `{id}` replacement for ERC-1155

For issue #3010

* Update useENSAvatar.ts

Add leading zero pad to 64 hex chars

* Update useENSAvatar.ts

Following review comments
2022-01-10 23:20:04 -05:00
Noah Zinsmeister
cecbf770c6 w3r version bumps (#3086) 2022-01-10 14:43:17 -05:00
Jordan Frankfurt
a7041ea700 undo accidental package version reversion (#3084) 2022-01-10 12:17:56 -06:00
Ian Lapham
5413303d24 update addresses (#3082) 2022-01-08 17:36:18 -05:00
dependabot[bot]
103e18496f chore(deps-dev): bump @uniswap/default-token-list from 2.2.0 to 3.0.0 (#3076)
Bumps [@uniswap/default-token-list](https://github.com/Uniswap/default-token-list) from 2.2.0 to 3.0.0.
- [Release notes](https://github.com/Uniswap/default-token-list/releases)
- [Commits](https://github.com/Uniswap/default-token-list/compare/v2.2.0...v3.0.0)

---
updated-dependencies:
- dependency-name: "@uniswap/default-token-list"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-07 11:13:41 -05:00
Crowdin Bot
0e678465cb chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-06 11:07:11 +00:00
Crowdin Bot
6b68baaa4d chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-06 10:06:28 +00:00
Crowdin Bot
3c5e3744f1 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-06 05:09:06 +00:00
Crowdin Bot
d93b6f795e chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-06 04:07:29 +00:00
Jordan Frankfurt
f145a56f4a fix: web3-react-fixes (#3066) (#3075)
* add empty connector

add url connector

* naming

Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
2022-01-05 20:48:33 -06:00
Ian Lapham
7622290557 update state org and get latest (#3073) 2022-01-05 16:17:13 -05:00
Crowdin Bot
226544402a chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-05 20:06:38 +00:00
Ian Lapham
49fee909bc update unsupported list (#3071) 2022-01-05 14:07:01 -05:00
Crowdin Bot
f458ec8e12 chore(i18n): synchronize translations from crowdin [skip ci] 2022-01-05 19:05:50 +00:00
Jordan Frankfurt
f9fc506db4 chore: merge widgets work into main (#3065)
* feat: design system (#2622)

* refactor: mv setInterval to lib (#2621)

* chore: widget tooling (#2620)

* chore: remove global styles from cosmos viewer

* chore: add generated svgs to bundle

* chore: alias lib within lib

* feat: widgets swap settings and arch (#2629)

* style: update theme

* feat: grid-based row/column

* feat: widget/modal arch

* feat: tooltip arch

* feat: atoms arch

* feat: swap settings

* chore: update deps

* fix: input width

* refactor: modularize Tooltip

* feat: add grow to Row

* style: true prop

* refactor: clean NumericInput

* fix: customizable data structure

* chore: sort styled-components

* fix: import ReactNode

* fix: svgr index generation

* chore: run tests on widgets (#2635)

* chore: widgets nits (#2636)

* fix: restrict type color to theme

* feat: add types

* fix: input width

* fix: header divider

* fix: eslint

* fix: color name

* fix: use inputs for a11y (#2646)

* fix: clearable customizable

* feat: accent hovered select option

* feat: custom slippage color

* fix: use buttons for a11y

* fix: widgets styles (#2654)

* style: add body1

* refactor: modularize theme/components

* refactor: modularize all text Input

* fix: toggle opacity

* test: fixture arch

* feat: rm gas price select

* fix: toggle styles/strings

* feat: mock toggle

* fix: dialog overflow clipping

* fix: mix-blend-mode for safari

* fix: clip-path for safari svg

* fix: mock toggle content

* fix: input margin

* fix: input and cursor

* fix: validate . input

* fix: unused useMemo

* feat: widgets empty state (#2657)

* refactor: TextButton

* feat: inline icons

* feat: swap empty state

* feat: define TokenSelect

* fix: always inline icons

* feat: recent transactions (#2661)

* feat: wallet button

* fix: tx deps

* feat: widgets token select (#2685)

* fix: line height of 1

* fix: button margin

* fix: update styles

* feat: token select

* refactor: mocks and types

* feat: close dialog on esc

* feat: focus input on token select

* refactor: layer swap elements

* feat: use token color

* fix: widget theme

* fix: use vibrant

* chore: lodash types

* fix: fixture props

* feat: smoother color extraction

* fix: vibrant dep

* perf: extract input token color too

* feat: eased token background

* feat: token color prefetching

* chore: mv polished to deps

* chore: package management

* fix: token background transition

* fix: better color transitions

* feat: widgets UI (#2742)

* feat: add swap states

* fix: widget-global box-sizing

* feat: desaturate and opacity on token approval

* feat: red balance on balance insufficient

* fix: states

* feat: action button

* refactor: action button

* feat: loading spinner border

* fix: typescript errors

* fix: token color transition

* fix: unused typings

* feat: swap summary sans tooltip

* refactor: swap state

* feat: swap summary

* refactor: simpler swap names

* fix: cutoffs around footer

* refactor: recent txs

* refactor: buttons

* feat: tx status

* fix: consistent formatting

* feat: tx error

* test: tx error

* test: widget decorator

* style: theming

* fix: clean up dialogs

* fix: clean up swap

* fix: clean up overlays

* fix: action button text on hover

* fix: pickAtom

* fix: pickAtom typings

* fix: smoother error transition

* feat: enter for toggle

* fix: select tabbing

* refactor: simplify dialogs

* feat: widgets polish (#2757)

* fix: loading spinner fallback for safari

* fix: use border for focus

* refactor: token options

* fix: use react toggle event

* fix: token select

* fix: inert content when modal

* fix: windowed token select

* chore: mv windowing utils to deps

* fix: windowing with no rerender

* feat: widget i18n (#2765)

* feat: configure widget i18n

* i18n: wrap translatable strings in macros

* fix: rm lib/locales

* refactor: t to trans

* feat: cosmos locale selector

* chore: widgets nits (#2786)

* fix: tooltip color

* fix: tx ttl tooltip

* fix: tooltip positioning

* fix: token list padding top

* style: responsive tx

* nit: fix summary copy

* chore: change byline

* feat(widgets): add new @web3-react cosmos decorator (#2799)

 add new @web3-react cosmos decorator and provider api to widget

* feat: token color mock (#2878)

* chore: merge main into widgets (#2893)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: center focused outline card (#2625)

* fix: add usdc to arbitrum/optimism common bases (#2641)

* remove WETH from optimism bases (#2640)

* use l2 logos in base pairs (#2634)

* fix: split calls into more chunks if they fail due to out of gas errors (#2630)

* fix: split calls into more chunks if they fail due to out of gas errors

* set to 100m gas

* back to 25m so we batch fewer calls

* do not pass through gas limit, some simplification of the code

* unused import

* fix: restrict @davatar usage to avoid 3p fetches (#2649)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): ensure chainIds match before fetching pool data (#2652)

* ensure chainIds match before fetching pool data

* debounce both input currencies, and only look for pairs on currencies that share a chainId

* pr feedback

* fix: use optional operator for chainId (#2666)

* chore: update token list (#2670)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: update token list (#2671)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: extend privacy and terms (#2623)

* initial iteration

* add logging

* added hook

* polish

* remove unused import

* add hash

* addressed pr feedback

* remove autorouter icon

* use firebase store

* style

* adjust recat ga

* log remove liquidity

* update copy

* addressed pr feedback

* addressed pr feedback

* prevent privacy content from dismissing modal

* make top-level key origin

* use hostname

* restore trm

* chore(i18n): synchronize translations from crowdin [skip ci]

* log full signed tx (#2681)

* refactor monitoring (#2682)

* chore: set final privacy learn more link' (#2684)

* add learn more button

* add final link

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: back arrow bug in wallet modal and fill tx for wallet (#2687)

* add tx to wallet connect

* remove id from env

* restore env

* block import of unsupported tokens (#2673)

generalize custom import token block ui

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps-dev): bump @uniswap/token-lists (#2699)

* chore(i18n): synchronize translations from crowdin [skip ci]

* try out 'dimension1' (#2704)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: walletconnect modal re-open after user rejection (#2693)

Co-authored-by: M0kY <moky@example.com>

* chore: update unsupported token list (#2689)

* chore: update unsupported token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: memoize the list stuff so the tokens are consistently clickable (#2724)

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: update cmc list link (#2710)

* update cmc lists

* update CMC url

* add token to unsupported list (#2732)

* don't overwrite localstorage lists when fetch throws (#2723)

* try cd1 for custom dimension (#2734)

* fix: Update walletlink-connector to 6.2.8 (#2655)

* Update walletlink-connector to 6.2.5 which has a walletlink update to support addEthereumChain+switchEthereumChain requests

* Update walletlink-connector to 6.2.7

* Update walletlink-connector to 6.2.8

* fix: Parse latest proposal description correctly

* add proposal start time (#2738)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: #2741 Increase liquidity form off center (#2746)

* fix: bump to latest token list including ENS token

* fix: remove deprecated optimism status url (#2771)

* feat: Menu update. Add help center & feature requests. Remove analytics & github. (#2709)

* Add help center, remove analytics from menu

* Add canny feature requests link, remove github link

* add coffee icon

* no unused imports eslint rule (#2773)

* chore(i18n): synchronize translations from crowdin [skip ci]

* add protocols param to quote endpoint (#2774)

* add protocols param to quote endpoint

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: lint error (#2775)

* fix(optimism): Optimism regenesis support (#2703)

* feat(optimism): optimistic kovan local regenesis changes

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

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

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

* specific version of v3-sdk

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: add support for 0.01% tier (#2769)

* chore: add support for 0.01% tier

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

* merge main and only consider lowest tier for mainnet

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): update block warning updater to check most recent block timestamp (#2777)

* update block warning updater to check most recent block timestamp

* stop doing dumb state manipulation

* fix: copy in network alert

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): remove redux from chain connectivity (#2781)

* remove redux from chain connectivity

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

* use useInterval

* change not created font size to 10 (#2785)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: format date using Date.toLocaleString (#2459)

* fix: format date using Date.toLocaleString

Fixes #2458

* fix: date typings

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: broken link to docs (#2816)

* chore: fix typo in useAllCurrencyCombinations.ts (#2778)

occurence -> occurrence

* chore: update typechain scripts for Windows (#2707)

There are two errors when deploying on Windows system:
1. Using single quotes in path argument doesn't seem to be accepted in typechain command
2. `?(v3-core|v3-periphery)` operator doesn't work

Here are fixes/workarounds.

* perf: lazy load vote related routes (#2468)

* perf: lazy load vote related routes

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

* fix

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: Enable 3085 requests for coinbase wallet (#2753)

enable 3085 requests for coinbase wallet

* feat: set the auto slippage tolerance by the dollar value of gas (#2815)

* feat: set the auto slippage tolerance by the dollar value of gas

* comments

* min/max at 0.5% to 25%

* oops on constant

* address review feedback

* Fixing #2818 (#2820)

* Fix code style issues with ESLint

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: fix #2818

* chore(i18n): synchronize translations from crowdin [skip ci]

* log an event on max click (#2827)

* Add trailing slash to L2 info links (#2696)

Some links were broken. For example on /pools/ page click the 'Top Pools' CTA. It would mistakenly direct you to info.uniswap.org/optimismpools instead of optimism/pools

* fix(L2): block L2 tokens explicitly linked to L1 tokens that are blocked (#2721)

* block L2 tokens explicitly linked to L1 tokens that are blocked

* Fix code style issues with ESLint

* check for support on all connectors, and disable when the connector (or lack thereof) no longer supports 3085 (#2824)

* feat: display an ENS avatar (#2806)

* feat: ens avatar resolution

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

* fix: pass memoized args to multicall

* Update locales.ts (#2825)

update Finnish from person (Suomalainen) to language (suomi)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore: fix the build blocking linter error

* chore: run linters with auto_fix = false for forks (#2852)

* fix: do not show urls if issue is not occurring on app.uniswap.org (#2855)

* fix: do not show urls if issue is not occurring on app.uniswap.org

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

* address comment

* fix: remove orphaned node (#2863)

* fix: remove orphaned node

* fix: react cleanup

* refactor: use ref for jazzicon (#2874)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps): bump ws from 5.2.2 to 5.2.3 (#2759)

Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump url-parse from 1.5.1 to 1.5.3 (#2504)

Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add more tests for tryParseTick (#2110)

* fix(lint): clean up the eslint config (#2886)

* fix(lint): clean up the eslint config

* Fix code style issues with ESLint

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

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: Add routes for stakewise tokens (#2832)

* Add additional routes for stakewise tokens

* Reference StakeWise addresses with sdk tokens

* Sort token imports

* chore: yarn-deduplicate

* chore: lint widgets

* fix: use lib useInterval

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Micael Rodrigues <micaelr95@outlook.pt>
Co-authored-by: Justin Domingue <judo@uniswap.org>
Co-authored-by: Moody Salem <moodysalem@users.noreply.github.com>
Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: M0kY <46133205+M0kY@users.noreply.github.com>
Co-authored-by: M0kY <moky@example.com>
Co-authored-by: Will Hennessy <hennessywill@gmail.com>
Co-authored-by: Brendan Weinstein <65564422+brendanww@users.noreply.github.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
Co-authored-by: Ben Krochta <35636764+bkrochta@users.noreply.github.com>
Co-authored-by: Moody Salem <moody.salem@gmail.com>
Co-authored-by: Raj <sukhrajghuman@live.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: Matthew Salamon <35425388+Matthews3301@users.noreply.github.com>
Co-authored-by: Sam Chen <chenxsan@gmail.com>
Co-authored-by: Ali Eray Kısabacak <eraykisabacak@hotmail.com>
Co-authored-by: Kimmo S <kkpsiren@gmail.com>
Co-authored-by: Dmitri Tsumak <tsumak.dmitri@gmail.com>

* chore: merge main into widgets (#2923)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: center focused outline card (#2625)

* fix: add usdc to arbitrum/optimism common bases (#2641)

* remove WETH from optimism bases (#2640)

* use l2 logos in base pairs (#2634)

* fix: split calls into more chunks if they fail due to out of gas errors (#2630)

* fix: split calls into more chunks if they fail due to out of gas errors

* set to 100m gas

* back to 25m so we batch fewer calls

* do not pass through gas limit, some simplification of the code

* unused import

* fix: restrict @davatar usage to avoid 3p fetches (#2649)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): ensure chainIds match before fetching pool data (#2652)

* ensure chainIds match before fetching pool data

* debounce both input currencies, and only look for pairs on currencies that share a chainId

* pr feedback

* fix: use optional operator for chainId (#2666)

* chore: update token list (#2670)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: update token list (#2671)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: extend privacy and terms (#2623)

* initial iteration

* add logging

* added hook

* polish

* remove unused import

* add hash

* addressed pr feedback

* remove autorouter icon

* use firebase store

* style

* adjust recat ga

* log remove liquidity

* update copy

* addressed pr feedback

* addressed pr feedback

* prevent privacy content from dismissing modal

* make top-level key origin

* use hostname

* restore trm

* chore(i18n): synchronize translations from crowdin [skip ci]

* log full signed tx (#2681)

* refactor monitoring (#2682)

* chore: set final privacy learn more link' (#2684)

* add learn more button

* add final link

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: back arrow bug in wallet modal and fill tx for wallet (#2687)

* add tx to wallet connect

* remove id from env

* restore env

* block import of unsupported tokens (#2673)

generalize custom import token block ui

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps-dev): bump @uniswap/token-lists (#2699)

* chore(i18n): synchronize translations from crowdin [skip ci]

* try out 'dimension1' (#2704)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: walletconnect modal re-open after user rejection (#2693)

Co-authored-by: M0kY <moky@example.com>

* chore: update unsupported token list (#2689)

* chore: update unsupported token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: memoize the list stuff so the tokens are consistently clickable (#2724)

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: update cmc list link (#2710)

* update cmc lists

* update CMC url

* add token to unsupported list (#2732)

* don't overwrite localstorage lists when fetch throws (#2723)

* try cd1 for custom dimension (#2734)

* fix: Update walletlink-connector to 6.2.8 (#2655)

* Update walletlink-connector to 6.2.5 which has a walletlink update to support addEthereumChain+switchEthereumChain requests

* Update walletlink-connector to 6.2.7

* Update walletlink-connector to 6.2.8

* fix: Parse latest proposal description correctly

* add proposal start time (#2738)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: #2741 Increase liquidity form off center (#2746)

* fix: bump to latest token list including ENS token

* fix: remove deprecated optimism status url (#2771)

* feat: Menu update. Add help center & feature requests. Remove analytics & github. (#2709)

* Add help center, remove analytics from menu

* Add canny feature requests link, remove github link

* add coffee icon

* no unused imports eslint rule (#2773)

* chore(i18n): synchronize translations from crowdin [skip ci]

* add protocols param to quote endpoint (#2774)

* add protocols param to quote endpoint

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: lint error (#2775)

* fix(optimism): Optimism regenesis support (#2703)

* feat(optimism): optimistic kovan local regenesis changes

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

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

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

* specific version of v3-sdk

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: add support for 0.01% tier (#2769)

* chore: add support for 0.01% tier

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

* merge main and only consider lowest tier for mainnet

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): update block warning updater to check most recent block timestamp (#2777)

* update block warning updater to check most recent block timestamp

* stop doing dumb state manipulation

* fix: copy in network alert

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): remove redux from chain connectivity (#2781)

* remove redux from chain connectivity

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

* use useInterval

* change not created font size to 10 (#2785)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: format date using Date.toLocaleString (#2459)

* fix: format date using Date.toLocaleString

Fixes #2458

* fix: date typings

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: broken link to docs (#2816)

* chore: fix typo in useAllCurrencyCombinations.ts (#2778)

occurence -> occurrence

* chore: update typechain scripts for Windows (#2707)

There are two errors when deploying on Windows system:
1. Using single quotes in path argument doesn't seem to be accepted in typechain command
2. `?(v3-core|v3-periphery)` operator doesn't work

Here are fixes/workarounds.

* perf: lazy load vote related routes (#2468)

* perf: lazy load vote related routes

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

* fix

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: Enable 3085 requests for coinbase wallet (#2753)

enable 3085 requests for coinbase wallet

* feat: set the auto slippage tolerance by the dollar value of gas (#2815)

* feat: set the auto slippage tolerance by the dollar value of gas

* comments

* min/max at 0.5% to 25%

* oops on constant

* address review feedback

* Fixing #2818 (#2820)

* Fix code style issues with ESLint

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: fix #2818

* chore(i18n): synchronize translations from crowdin [skip ci]

* log an event on max click (#2827)

* Add trailing slash to L2 info links (#2696)

Some links were broken. For example on /pools/ page click the 'Top Pools' CTA. It would mistakenly direct you to info.uniswap.org/optimismpools instead of optimism/pools

* fix(L2): block L2 tokens explicitly linked to L1 tokens that are blocked (#2721)

* block L2 tokens explicitly linked to L1 tokens that are blocked

* Fix code style issues with ESLint

* check for support on all connectors, and disable when the connector (or lack thereof) no longer supports 3085 (#2824)

* feat: display an ENS avatar (#2806)

* feat: ens avatar resolution

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

* fix: pass memoized args to multicall

* Update locales.ts (#2825)

update Finnish from person (Suomalainen) to language (suomi)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore: fix the build blocking linter error

* chore: run linters with auto_fix = false for forks (#2852)

* fix: do not show urls if issue is not occurring on app.uniswap.org (#2855)

* fix: do not show urls if issue is not occurring on app.uniswap.org

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

* address comment

* fix: remove orphaned node (#2863)

* fix: remove orphaned node

* fix: react cleanup

* refactor: use ref for jazzicon (#2874)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps): bump ws from 5.2.2 to 5.2.3 (#2759)

Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump url-parse from 1.5.1 to 1.5.3 (#2504)

Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add more tests for tryParseTick (#2110)

* fix(lint): clean up the eslint config (#2886)

* fix(lint): clean up the eslint config

* Fix code style issues with ESLint

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

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: Add routes for stakewise tokens (#2832)

* Add additional routes for stakewise tokens

* Reference StakeWise addresses with sdk tokens

* Sort token imports

* fix: fix layout of proposal list items on the vote page on mobile (#2898)

* fix: fixing layout from using grid to flexbox

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

* fix: using width auto instead of disabling flex wrap

Co-authored-by: Julian Anderson <juliancanderson@gmail.com>

* fix: typo in arweave URI recognition (#2901)

* deleted files

* Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)

This reverts commit bf7a40be7a, reversing
changes made to 097b8361d4.

* fix: inadvertent merges/reverts (#2915)

* Revert "Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)"

This reverts commit 7d343dcfbd.

* Revert "deleted files"

This reverts commit 097b8361d4.

* refactor: Replace multicall implementation with library (#2768)

- Replace the local implementation of multicall with the new redux-multicall lib
- Create wrappers for redux-multicall hooks to inject block number and chainId

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Micael Rodrigues <micaelr95@outlook.pt>
Co-authored-by: Justin Domingue <judo@uniswap.org>
Co-authored-by: Moody Salem <moodysalem@users.noreply.github.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: M0kY <46133205+M0kY@users.noreply.github.com>
Co-authored-by: M0kY <moky@example.com>
Co-authored-by: Will Hennessy <hennessywill@gmail.com>
Co-authored-by: Brendan Weinstein <65564422+brendanww@users.noreply.github.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
Co-authored-by: Ben Krochta <35636764+bkrochta@users.noreply.github.com>
Co-authored-by: Moody Salem <moody.salem@gmail.com>
Co-authored-by: Raj <sukhrajghuman@live.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: Matthew Salamon <35425388+Matthews3301@users.noreply.github.com>
Co-authored-by: Sam Chen <chenxsan@gmail.com>
Co-authored-by: Ali Eray Kısabacak <eraykisabacak@hotmail.com>
Co-authored-by: Kimmo S <kkpsiren@gmail.com>
Co-authored-by: Dmitri Tsumak <tsumak.dmitri@gmail.com>
Co-authored-by: Julian Anderson <juliancanderson@gmail.com>
Co-authored-by: Carlos Diaz-Padron <carlosdiazpadron@gmail.com>
Co-authored-by: J M Rossy <jm.rossy@gmail.com>

* feat: Multicall lib integration for widgets (#2946)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: center focused outline card (#2625)

* fix: add usdc to arbitrum/optimism common bases (#2641)

* remove WETH from optimism bases (#2640)

* use l2 logos in base pairs (#2634)

* fix: split calls into more chunks if they fail due to out of gas errors (#2630)

* fix: split calls into more chunks if they fail due to out of gas errors

* set to 100m gas

* back to 25m so we batch fewer calls

* do not pass through gas limit, some simplification of the code

* unused import

* fix: restrict @davatar usage to avoid 3p fetches (#2649)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): ensure chainIds match before fetching pool data (#2652)

* ensure chainIds match before fetching pool data

* debounce both input currencies, and only look for pairs on currencies that share a chainId

* pr feedback

* fix: use optional operator for chainId (#2666)

* chore: update token list (#2670)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: update token list (#2671)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: extend privacy and terms (#2623)

* initial iteration

* add logging

* added hook

* polish

* remove unused import

* add hash

* addressed pr feedback

* remove autorouter icon

* use firebase store

* style

* adjust recat ga

* log remove liquidity

* update copy

* addressed pr feedback

* addressed pr feedback

* prevent privacy content from dismissing modal

* make top-level key origin

* use hostname

* restore trm

* chore(i18n): synchronize translations from crowdin [skip ci]

* log full signed tx (#2681)

* refactor monitoring (#2682)

* chore: set final privacy learn more link' (#2684)

* add learn more button

* add final link

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: back arrow bug in wallet modal and fill tx for wallet (#2687)

* add tx to wallet connect

* remove id from env

* restore env

* block import of unsupported tokens (#2673)

generalize custom import token block ui

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps-dev): bump @uniswap/token-lists (#2699)

* chore(i18n): synchronize translations from crowdin [skip ci]

* try out 'dimension1' (#2704)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: walletconnect modal re-open after user rejection (#2693)

Co-authored-by: M0kY <moky@example.com>

* chore: update unsupported token list (#2689)

* chore: update unsupported token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: memoize the list stuff so the tokens are consistently clickable (#2724)

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: update cmc list link (#2710)

* update cmc lists

* update CMC url

* add token to unsupported list (#2732)

* don't overwrite localstorage lists when fetch throws (#2723)

* try cd1 for custom dimension (#2734)

* fix: Update walletlink-connector to 6.2.8 (#2655)

* Update walletlink-connector to 6.2.5 which has a walletlink update to support addEthereumChain+switchEthereumChain requests

* Update walletlink-connector to 6.2.7

* Update walletlink-connector to 6.2.8

* fix: Parse latest proposal description correctly

* add proposal start time (#2738)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: #2741 Increase liquidity form off center (#2746)

* fix: bump to latest token list including ENS token

* fix: remove deprecated optimism status url (#2771)

* feat: Menu update. Add help center & feature requests. Remove analytics & github. (#2709)

* Add help center, remove analytics from menu

* Add canny feature requests link, remove github link

* add coffee icon

* no unused imports eslint rule (#2773)

* chore(i18n): synchronize translations from crowdin [skip ci]

* add protocols param to quote endpoint (#2774)

* add protocols param to quote endpoint

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: lint error (#2775)

* fix(optimism): Optimism regenesis support (#2703)

* feat(optimism): optimistic kovan local regenesis changes

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

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

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

* specific version of v3-sdk

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: add support for 0.01% tier (#2769)

* chore: add support for 0.01% tier

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

* merge main and only consider lowest tier for mainnet

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): update block warning updater to check most recent block timestamp (#2777)

* update block warning updater to check most recent block timestamp

* stop doing dumb state manipulation

* fix: copy in network alert

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): remove redux from chain connectivity (#2781)

* remove redux from chain connectivity

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

* use useInterval

* change not created font size to 10 (#2785)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: format date using Date.toLocaleString (#2459)

* fix: format date using Date.toLocaleString

Fixes #2458

* fix: date typings

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: broken link to docs (#2816)

* chore: fix typo in useAllCurrencyCombinations.ts (#2778)

occurence -> occurrence

* chore: update typechain scripts for Windows (#2707)

There are two errors when deploying on Windows system:
1. Using single quotes in path argument doesn't seem to be accepted in typechain command
2. `?(v3-core|v3-periphery)` operator doesn't work

Here are fixes/workarounds.

* perf: lazy load vote related routes (#2468)

* perf: lazy load vote related routes

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

* fix

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: Enable 3085 requests for coinbase wallet (#2753)

enable 3085 requests for coinbase wallet

* feat: set the auto slippage tolerance by the dollar value of gas (#2815)

* feat: set the auto slippage tolerance by the dollar value of gas

* comments

* min/max at 0.5% to 25%

* oops on constant

* address review feedback

* Fixing #2818 (#2820)

* Fix code style issues with ESLint

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: fix #2818

* chore(i18n): synchronize translations from crowdin [skip ci]

* log an event on max click (#2827)

* Add trailing slash to L2 info links (#2696)

Some links were broken. For example on /pools/ page click the 'Top Pools' CTA. It would mistakenly direct you to info.uniswap.org/optimismpools instead of optimism/pools

* fix(L2): block L2 tokens explicitly linked to L1 tokens that are blocked (#2721)

* block L2 tokens explicitly linked to L1 tokens that are blocked

* Fix code style issues with ESLint

* check for support on all connectors, and disable when the connector (or lack thereof) no longer supports 3085 (#2824)

* feat: display an ENS avatar (#2806)

* feat: ens avatar resolution

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

* fix: pass memoized args to multicall

* Update locales.ts (#2825)

update Finnish from person (Suomalainen) to language (suomi)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore: fix the build blocking linter error

* chore: run linters with auto_fix = false for forks (#2852)

* fix: do not show urls if issue is not occurring on app.uniswap.org (#2855)

* fix: do not show urls if issue is not occurring on app.uniswap.org

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

* address comment

* fix: remove orphaned node (#2863)

* fix: remove orphaned node

* fix: react cleanup

* refactor: use ref for jazzicon (#2874)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps): bump ws from 5.2.2 to 5.2.3 (#2759)

Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump url-parse from 1.5.1 to 1.5.3 (#2504)

Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add more tests for tryParseTick (#2110)

* fix(lint): clean up the eslint config (#2886)

* fix(lint): clean up the eslint config

* Fix code style issues with ESLint

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

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: Add routes for stakewise tokens (#2832)

* Add additional routes for stakewise tokens

* Reference StakeWise addresses with sdk tokens

* Sort token imports

* fix: fix layout of proposal list items on the vote page on mobile (#2898)

* fix: fixing layout from using grid to flexbox

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

* fix: using width auto instead of disabling flex wrap

Co-authored-by: Julian Anderson <juliancanderson@gmail.com>

* fix: typo in arweave URI recognition (#2901)

* deleted files

* Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)

This reverts commit bf7a40be7a, reversing
changes made to 097b8361d4.

* fix: inadvertent merges/reverts (#2915)

* Revert "Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)"

This reverts commit 7d343dcfbd.

* Revert "deleted files"

This reverts commit 097b8361d4.

* refactor: Replace multicall implementation with library (#2768)

- Replace the local implementation of multicall with the new redux-multicall lib
- Create wrappers for redux-multicall hooks to inject block number and chainId

* package.json tweaks

* add multicall lib and some basic provider things

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Micael Rodrigues <micaelr95@outlook.pt>
Co-authored-by: Justin Domingue <judo@uniswap.org>
Co-authored-by: Moody Salem <moodysalem@users.noreply.github.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: M0kY <46133205+M0kY@users.noreply.github.com>
Co-authored-by: M0kY <moky@example.com>
Co-authored-by: Will Hennessy <hennessywill@gmail.com>
Co-authored-by: Brendan Weinstein <65564422+brendanww@users.noreply.github.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
Co-authored-by: Ben Krochta <35636764+bkrochta@users.noreply.github.com>
Co-authored-by: Moody Salem <moody.salem@gmail.com>
Co-authored-by: Raj <sukhrajghuman@live.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: Matthew Salamon <35425388+Matthews3301@users.noreply.github.com>
Co-authored-by: Sam Chen <chenxsan@gmail.com>
Co-authored-by: Ali Eray Kısabacak <eraykisabacak@hotmail.com>
Co-authored-by: Kimmo S <kkpsiren@gmail.com>
Co-authored-by: Dmitri Tsumak <tsumak.dmitri@gmail.com>
Co-authored-by: Julian Anderson <juliancanderson@gmail.com>
Co-authored-by: Carlos Diaz-Padron <carlosdiazpadron@gmail.com>
Co-authored-by: J M Rossy <jm.rossy@gmail.com>

* feat: widgets style update (#2939)

* feat: widgets empty state (#2951)

* chore: mv onHover to computed theme; reduce to 0.16

* chore: transparentize primary on hover

* chore: transparentize dynamic primary on hover

* style: restrict icon usage

Restricts icons to lib/icons. This ensures that icons are loaded as singletons outside of the React lifecycle. Doing otherwise hinders performance.

* fix: logo mix-blend-mode

* wip: empty states

* fix: accent/active colors

* wip: empty states

* fix: input hover states

* nit: specific user select

* nit: button transition

* nit: no button transition

* chore: better cosmos toggles

* chore: load inter

* make cosmos work with new required widget props (#2956)

* separate connector atoms (#2959)

* fix: widgets nits sans summary/status (#2960)

* fix: dynamic scrollbar

* feat: system theme hook

* nit: settings

* nit: large settings icons

* fix: accessible color computation

* fix: ignore status scroll for now

* fix: ignore txs scroll for now

* feat: widgets summary (#2980)

* fix: output first in toolbar

* fix: widget height

* feat: token color extraction toggle

* fix: header sizing

* fix: height nits

* chore: re-arch sub pages

* nit: height

* feat: border radius as range

* fix: exclude cosmos setter from hook deps

* feat: default width to 360

* feat: type classes

* fix: header height

* fix: default cosmos width to 360

* refactor: icon button

* wip: summary

* fix: scrollbar

* feat: summary

* fix: summary expando

* fix: widgets transitions (#2983)

* fix: action button height

* fix: summary scrollbar fading

* fix: summary fixture

* fix: action button transitions

* feat: widgets status (#2987)

* fix: action button height

* fix: summary scrollbar fading

* fix: summary fixture

* fix: action button transitions

* refactor: commit spinner as svg asset

* feat: status dialog

* fix: spinner rounding

* feat: widgets fonts and transitions (#2998)

* feat: fonts using @fontsource

* feat: dialog transitions

* fix: swap transitions

* Refactor use active web3 react (#3002)

* separate connector atoms

* refactor cosmos and set up widgets env var

* fix: cosmos modularization (#3014)

* fix: cosmos modularization

* fix: web3 in atom provider

* feat: make connectors resettable

* drop empty test (#3022)

* Revert "feat: make connectors resettable"

This reverts commit db5af68b9b.

* undo dumb open reorder

* bump widget web3-react versions

* bump to fix tests

Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>

* chore(widgets): Merge main into widgets (#3013)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: center focused outline card (#2625)

* fix: add usdc to arbitrum/optimism common bases (#2641)

* remove WETH from optimism bases (#2640)

* use l2 logos in base pairs (#2634)

* fix: split calls into more chunks if they fail due to out of gas errors (#2630)

* fix: split calls into more chunks if they fail due to out of gas errors

* set to 100m gas

* back to 25m so we batch fewer calls

* do not pass through gas limit, some simplification of the code

* unused import

* fix: restrict @davatar usage to avoid 3p fetches (#2649)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): ensure chainIds match before fetching pool data (#2652)

* ensure chainIds match before fetching pool data

* debounce both input currencies, and only look for pairs on currencies that share a chainId

* pr feedback

* fix: use optional operator for chainId (#2666)

* chore: update token list (#2670)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: update token list (#2671)

* update token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: extend privacy and terms (#2623)

* initial iteration

* add logging

* added hook

* polish

* remove unused import

* add hash

* addressed pr feedback

* remove autorouter icon

* use firebase store

* style

* adjust recat ga

* log remove liquidity

* update copy

* addressed pr feedback

* addressed pr feedback

* prevent privacy content from dismissing modal

* make top-level key origin

* use hostname

* restore trm

* chore(i18n): synchronize translations from crowdin [skip ci]

* log full signed tx (#2681)

* refactor monitoring (#2682)

* chore: set final privacy learn more link' (#2684)

* add learn more button

* add final link

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: back arrow bug in wallet modal and fill tx for wallet (#2687)

* add tx to wallet connect

* remove id from env

* restore env

* block import of unsupported tokens (#2673)

generalize custom import token block ui

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps-dev): bump @uniswap/token-lists (#2699)

* chore(i18n): synchronize translations from crowdin [skip ci]

* try out 'dimension1' (#2704)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: walletconnect modal re-open after user rejection (#2693)

Co-authored-by: M0kY <moky@example.com>

* chore: update unsupported token list (#2689)

* chore: update unsupported token list

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: memoize the list stuff so the tokens are consistently clickable (#2724)

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: update cmc list link (#2710)

* update cmc lists

* update CMC url

* add token to unsupported list (#2732)

* don't overwrite localstorage lists when fetch throws (#2723)

* try cd1 for custom dimension (#2734)

* fix: Update walletlink-connector to 6.2.8 (#2655)

* Update walletlink-connector to 6.2.5 which has a walletlink update to support addEthereumChain+switchEthereumChain requests

* Update walletlink-connector to 6.2.7

* Update walletlink-connector to 6.2.8

* fix: Parse latest proposal description correctly

* add proposal start time (#2738)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: #2741 Increase liquidity form off center (#2746)

* fix: bump to latest token list including ENS token

* fix: remove deprecated optimism status url (#2771)

* feat: Menu update. Add help center & feature requests. Remove analytics & github. (#2709)

* Add help center, remove analytics from menu

* Add canny feature requests link, remove github link

* add coffee icon

* no unused imports eslint rule (#2773)

* chore(i18n): synchronize translations from crowdin [skip ci]

* add protocols param to quote endpoint (#2774)

* add protocols param to quote endpoint

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: lint error (#2775)

* fix(optimism): Optimism regenesis support (#2703)

* feat(optimism): optimistic kovan local regenesis changes

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

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

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

* specific version of v3-sdk

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(i18n): synchronize translations from crowdin [skip ci]

* feat: add support for 0.01% tier (#2769)

* chore: add support for 0.01% tier

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

* merge main and only consider lowest tier for mainnet

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): update block warning updater to check most recent block timestamp (#2777)

* update block warning updater to check most recent block timestamp

* stop doing dumb state manipulation

* fix: copy in network alert

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix(L2): remove redux from chain connectivity (#2781)

* remove redux from chain connectivity

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

* use useInterval

* change not created font size to 10 (#2785)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: format date using Date.toLocaleString (#2459)

* fix: format date using Date.toLocaleString

Fixes #2458

* fix: date typings

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: broken link to docs (#2816)

* chore: fix typo in useAllCurrencyCombinations.ts (#2778)

occurence -> occurrence

* chore: update typechain scripts for Windows (#2707)

There are two errors when deploying on Windows system:
1. Using single quotes in path argument doesn't seem to be accepted in typechain command
2. `?(v3-core|v3-periphery)` operator doesn't work

Here are fixes/workarounds.

* perf: lazy load vote related routes (#2468)

* perf: lazy load vote related routes

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

* fix

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: Enable 3085 requests for coinbase wallet (#2753)

enable 3085 requests for coinbase wallet

* feat: set the auto slippage tolerance by the dollar value of gas (#2815)

* feat: set the auto slippage tolerance by the dollar value of gas

* comments

* min/max at 0.5% to 25%

* oops on constant

* address review feedback

* Fixing #2818 (#2820)

* Fix code style issues with ESLint

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: fix #2818

* chore(i18n): synchronize translations from crowdin [skip ci]

* log an event on max click (#2827)

* Add trailing slash to L2 info links (#2696)

Some links were broken. For example on /pools/ page click the 'Top Pools' CTA. It would mistakenly direct you to info.uniswap.org/optimismpools instead of optimism/pools

* fix(L2): block L2 tokens explicitly linked to L1 tokens that are blocked (#2721)

* block L2 tokens explicitly linked to L1 tokens that are blocked

* Fix code style issues with ESLint

* check for support on all connectors, and disable when the connector (or lack thereof) no longer supports 3085 (#2824)

* feat: display an ENS avatar (#2806)

* feat: ens avatar resolution

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

* fix: pass memoized args to multicall

* Update locales.ts (#2825)

update Finnish from person (Suomalainen) to language (suomi)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore: fix the build blocking linter error

* chore: run linters with auto_fix = false for forks (#2852)

* fix: do not show urls if issue is not occurring on app.uniswap.org (#2855)

* fix: do not show urls if issue is not occurring on app.uniswap.org

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

* address comment

* fix: remove orphaned node (#2863)

* fix: remove orphaned node

* fix: react cleanup

* refactor: use ref for jazzicon (#2874)

* chore(i18n): synchronize translations from crowdin [skip ci]

* chore(deps): bump ws from 5.2.2 to 5.2.3 (#2759)

Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump url-parse from 1.5.1 to 1.5.3 (#2504)

Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add more tests for tryParseTick (#2110)

* fix(lint): clean up the eslint config (#2886)

* fix(lint): clean up the eslint config

* Fix code style issues with ESLint

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

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: Add routes for stakewise tokens (#2832)

* Add additional routes for stakewise tokens

* Reference StakeWise addresses with sdk tokens

* Sort token imports

* fix: fix layout of proposal list items on the vote page on mobile (#2898)

* fix: fixing layout from using grid to flexbox

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

* fix: using width auto instead of disabling flex wrap

Co-authored-by: Julian Anderson <juliancanderson@gmail.com>

* fix: typo in arweave URI recognition (#2901)

* deleted files

* Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)

This reverts commit bf7a40be7a, reversing
changes made to 097b8361d4.

* fix: inadvertent merges/reverts (#2915)

* Revert "Revert "Merge branch 'main' of https://github.com/Uniswap/interface" (#2912)"

This reverts commit 7d343dcfbd.

* Revert "deleted files"

This reverts commit 097b8361d4.

* refactor: Replace multicall implementation with library (#2768)

- Replace the local implementation of multicall with the new redux-multicall lib
- Create wrappers for redux-multicall hooks to inject block number and chainId

* fix: introduce safeNamehash (#2925)

* namehash -> safeNamehash where necessary

* cleanup

* address comment

* feat: Add learn more link in TRM description (#2919)

* Add learn more link in TRM description

* Update src/components/PrivacyPolicy/index.tsx

Co-authored-by: Justin Domingue <judo@uniswap.org>

* give a bit more gas to balanceOf (#2943)

* fix: memoize hooks from /swap (#2949)

* fix: memoize hooks from /swap

* chore: rm console

* add fix for polygon proposal title (#2974)

* fix: display Uniswap token list in UI (#2821)

* fix: display Uniswap token list in UI

* chore: remove default-token-list build dependency

* fix: use ENS name for Uniswap token list

* fix: change Uniswap token list url

* fix: extend transaction deadline to 3 days (#2982)

* feat: integrate SwapRouter02 on L1/L2 + gas ui

* client-side smart order router support
* support auto router on L2s
* add swap router version in approval/swap callback GA events to save $ on approval txs
* add persistent UI view of gas estimate on L1s

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Callil Capuozzo <callil.capuozzo@gmail.com>

* Update CONTRIBUTING.md (#2992)

* feat: Update contribution spec (#2993)

* Update CONTRIBUTING.md (#2994)

* Update CONTRIBUTING.md (#2995)

* feat: Update contribution spec (#2996)

* chore(i18n): synchronize translations from crowdin [skip ci]

* fix: double scroll in manage token list (#3020)

* fix double scroll

* remove bottom padding

* restrict walletlink to mainnet only (#3024)

* increase warning timer (#3004)

* add index.html styles to widget

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Micael Rodrigues <micaelr95@outlook.pt>
Co-authored-by: Justin Domingue <judo@uniswap.org>
Co-authored-by: Moody Salem <moodysalem@users.noreply.github.com>
Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: M0kY <46133205+M0kY@users.noreply.github.com>
Co-authored-by: M0kY <moky@example.com>
Co-authored-by: Will Hennessy <hennessywill@gmail.com>
Co-authored-by: Brendan Weinstein <65564422+brendanww@users.noreply.github.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
Co-authored-by: Ben Krochta <35636764+bkrochta@users.noreply.github.com>
Co-authored-by: Moody Salem <moody.salem@gmail.com>
Co-authored-by: Raj <sukhrajghuman@live.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: Matthew Salamon <35425388+Matthews3301@users.noreply.github.com>
Co-authored-by: Sam Chen <chenxsan@gmail.com>
Co-authored-by: Ali Eray Kısabacak <eraykisabacak@hotmail.com>
Co-authored-by: Kimmo S <kkpsiren@gmail.com>
Co-authored-by: Dmitri Tsumak <tsumak.dmitri@gmail.com>
Co-authored-by: Julian Anderson <juliancanderson@gmail.com>
Co-authored-by: Carlos Diaz-Padron <carlosdiazpadron@gmail.com>
Co-authored-by: J M Rossy <jm.rossy@gmail.com>
Co-authored-by: Barry G <bgitarts@gmail.com>
Co-authored-by: Callil Capuozzo <callil.capuozzo@gmail.com>
Co-authored-by: Tina Zheng <59578595+tinaszheng@users.noreply.github.com>

* feat: widgets transitions (#3007)

* fix: logo target

* feat: settings transition

* feat: reverse transition

* fix: transitions will-change and durations

* fix: logo color

* fix: only will-change transform

* fix: header targets

* fix: clip modal transitions

* fix: token select header

* fix: safari transparent gradients

* fix: safari scrollbar

* fix: scroll overlay

* fix: safari bounce jank

* fix: firefox overscroll

* refactor: scrollbar hook

* feat: native event hook

* fix: details nowrap

* fix: settings cog transition

* feat: expando icon

* fix: expando transition

* refactor: cosmos web3 integration (#3052)

* chore: use zustand 4.0.0-beta for dynamic stores

* chore: use strict mode

* refactor: clean connector state

* chore: mv web3 state to cosmos selectors

* chore: dedup yarn.lock

* chore: define EthereumProvider in lib

* fix: destructure would not compile

* fix: make it bundle

* chore: prune deps

* refactor: use error handler instead of GA

* chore: add make-plural

* chore: add redux

* chore: yarn dedup

* chore: do not (re)load default locale

* fix: center error headings

* feat: error dialog for boundary

* fix: tighten up transitions

* test: include bundle depcheck

* fix: rm console

* fix: do not load empty sourceLocale

* fix: no lingui defaults

* refactor: mv svg to assets/svg

* chore: block font display

* fix: remove manual zustand resolution

* fix: svg generation script

Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>

* chore: widget placeholders (#3061)

* chore: update comments

- typo
- performance comment was performant on retest

* nit: status placeholders

- prevent flashes of rerendering from lazy-loaded elements

* chore: initialize cosmos with json rpc

* refactor: token img component

- modularize the TokenImg
- add a placeholder for UX and broken images

* fix: recent tx token img usage

* pr feedback

* undo REACT_APP_IS_WIDGET network ternary

Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Micael Rodrigues <micaelr95@outlook.pt>
Co-authored-by: Justin Domingue <judo@uniswap.org>
Co-authored-by: Moody Salem <moodysalem@users.noreply.github.com>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: M0kY <46133205+M0kY@users.noreply.github.com>
Co-authored-by: M0kY <moky@example.com>
Co-authored-by: Will Hennessy <hennessywill@gmail.com>
Co-authored-by: Brendan Weinstein <65564422+brendanww@users.noreply.github.com>
Co-authored-by: Noah Zinsmeister <noahwz@gmail.com>
Co-authored-by: Ben Krochta <35636764+bkrochta@users.noreply.github.com>
Co-authored-by: Moody Salem <moody.salem@gmail.com>
Co-authored-by: Raj <sukhrajghuman@live.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: Matthew Salamon <35425388+Matthews3301@users.noreply.github.com>
Co-authored-by: Sam Chen <chenxsan@gmail.com>
Co-authored-by: Ali Eray Kısabacak <eraykisabacak@hotmail.com>
Co-authored-by: Kimmo S <kkpsiren@gmail.com>
Co-authored-by: Dmitri Tsumak <tsumak.dmitri@gmail.com>
Co-authored-by: Julian Anderson <juliancanderson@gmail.com>
Co-authored-by: Carlos Diaz-Padron <carlosdiazpadron@gmail.com>
Co-authored-by: J M Rossy <jm.rossy@gmail.com>
Co-authored-by: Barry G <bgitarts@gmail.com>
Co-authored-by: Callil Capuozzo <callil.capuozzo@gmail.com>
Co-authored-by: Tina Zheng <59578595+tinaszheng@users.noreply.github.com>
2022-01-05 12:38:53 -06:00
yj
5b7a80d10d fix: Add ENSName and address check to Web3Status (#3040)
* Add ENSName and address check to Web3Status

Issue #2838

* Update useENSName.ts

Do the forward ENSAddress check in useENSName

* Update index.tsx

Revert ENSAddress check, which has been moved into ENSName hook

* Update useENSName.ts

Correcting the equality check (was testing that things work, and made a wrong commit)

* add comment, change var names

Co-authored-by: Tina Zheng <tina.s.zheng+github@gmail.com>
2021-12-29 20:04:09 -08:00
Crowdin Bot
db8dab4559 chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-28 17:11:16 +00:00
Crowdin Bot
7cc1b899ea chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-24 21:06:39 +00:00
Crowdin Bot
339a35cb1b chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-24 07:06:39 +00:00
Moody Salem
e2bd8020f3 fix(polygon): enable the smart order router for polygon (#3037)
* fix(polygon): enable the smart order router for polygon

* show gas estimates for polygon
2021-12-23 20:36:56 -05:00
Crowdin Bot
571a932d6e chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-23 21:06:33 +00:00
Callil Capuozzo
3923438011 fix(style): improve the bridge assets style (#3036)
* Re-style bridge cards

* Tweaks

- Header button height and color treatment refinement
- Small sizing issues

* Address comments

* remove network alert state

* code style nits

* remove unused parameter, rename

* copy edit

Co-authored-by: Moody Salem <moody.salem@gmail.com>
2021-12-23 15:13:50 -05:00
Crowdin Bot
4ed9c7ba94 chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-23 18:06:38 +00:00
Crowdin Bot
1ead35e782 chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-23 17:11:21 +00:00
Crowdin Bot
0af516b884 chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-23 16:07:14 +00:00
Moody Salem
13c42a384b fix(network switch): do not show failed to switch networks for successful network switches 2021-12-23 10:18:58 -05:00
Tina Zheng
458e04f94c feat: add santa hat to unicorn logo for the holidays 🎅🏼 (#3027)
* add santa hat to logo

* make generic component

* add 24th to christmas

* oops
2021-12-22 14:34:40 -08:00
Moody Salem
587edf46ea fix(polygon): infoLink should end in forward slash 2021-12-22 15:15:32 -05:00
Moody Salem
768f7659d2 fix(polygon): add missing router addresses 2021-12-22 15:08:11 -05:00
Crowdin Bot
96db27722b chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-22 19:47:25 +00:00
Moody Salem
f047f0d196 feat(polygon): polygon mainnet and testnet support (#3015)
* feat(polygon): polygon mainnet and testnet support

WIP! DO NOT USE

* fix unit test

* fix explorer links

* compute usdc prices

* - fix the header currency label
- fix unit tests

* polygon gradient colors

* chore: adding weth to common bases (#3025)

* adding weth to common bases

* adding usdc and dai

* adding usdt and wbtc

* fix a bunch of polish issues
- 3085 detection
- some wrapping stuff
- the network selector dropdown

* fix wrap/unwrap notification text on polygon

* background color per the figma

* subgraph url

* fix the re-render blinking on the network selector

* failed network switch

* clean up duplicate code in the network switching functions

* fix text color in the privacy notice on light mode

* add some routing constants for polygon

* do not show the separator in the trade route if auto router is not supported

* - network switching without a wallet connected
- remove v2 stuff from pool page when n/a
- remove WMATIC from common bases on polygon

* background colors of network alert

* oops fix background on network alert

* clean up optimism labels

* fix alignment of text on downtime warning

* finish the network alert styles

Co-authored-by: Sara Reynolds <30504811+snreynolds@users.noreply.github.com>
2021-12-22 14:25:10 -05:00
Jordan Frankfurt
7ac1ed3f52 increase warning timer (#3004) 2021-12-22 11:18:53 -05:00
Tina Zheng
205412fe1e restrict walletlink to mainnet only (#3024) 2021-12-21 14:37:42 -08:00
Tina Zheng
43e1fe9764 fix: double scroll in manage token list (#3020)
* fix double scroll

* remove bottom padding
2021-12-21 14:37:30 -08:00
Crowdin Bot
e9a9dd9779 chore(i18n): synchronize translations from crowdin [skip ci] 2021-12-20 15:59:30 +00:00
Ian Lapham
fa3325b7e4 feat: Update contribution spec (#2996) 2021-12-16 16:08:45 -05:00
Ian Lapham
19aa7173ab Update CONTRIBUTING.md (#2995) 2021-12-16 16:04:32 -05:00
Ian Lapham
a3238c701a Update CONTRIBUTING.md (#2994) 2021-12-16 15:46:26 -05:00
Ian Lapham
82a763f905 feat: Update contribution spec (#2993) 2021-12-16 15:39:28 -05:00
Ian Lapham
61e0ce096b Update CONTRIBUTING.md (#2992) 2021-12-16 15:36:48 -05:00
Justin Domingue
9e1a775c13 feat: integrate SwapRouter02 on L1/L2 + gas ui
* client-side smart order router support
* support auto router on L2s
* add swap router version in approval/swap callback GA events to save $ on approval txs
* add persistent UI view of gas estimate on L1s

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Ian Lapham <ian@uniswap.org>
Co-authored-by: Callil Capuozzo <callil.capuozzo@gmail.com>
2021-12-16 14:44:03 -05:00
Barry G
642a4177d8 fix: extend transaction deadline to 3 days (#2982) 2021-12-15 16:52:41 -08:00
Ben Krochta
37e085763c fix: display Uniswap token list in UI (#2821)
* fix: display Uniswap token list in UI

* chore: remove default-token-list build dependency

* fix: use ENS name for Uniswap token list

* fix: change Uniswap token list url
2021-12-13 19:38:37 -05:00
Noah Zinsmeister
e2baa051c5 add fix for polygon proposal title (#2974) 2021-12-13 16:28:37 -05:00
Zach Pomerantz
a5b152da06 fix: memoize hooks from /swap (#2949)
* fix: memoize hooks from /swap

* chore: rm console
2021-12-09 13:06:55 -08:00
Noah Zinsmeister
38cf4f46d7 give a bit more gas to balanceOf (#2943) 2021-12-07 18:07:11 -05:00
Will Hennessy
744c313ecf feat: Add learn more link in TRM description (#2919)
* Add learn more link in TRM description

* Update src/components/PrivacyPolicy/index.tsx

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

* cleanup

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

This reverts commit 7d343dcfbd.

* Revert "deleted files"

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

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

* fix: using width auto instead of disabling flex wrap

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

* Reference StakeWise addresses with sdk tokens

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

* Fix code style issues with ESLint

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

* clean up the rebass text renames

* fix if statement, use the config

* use the same name prefix for both steps

* `TextPreset` -> `ThemedText`

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

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

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

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

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

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

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

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

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

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

* chore: uninstall @davatar/react

* fix: add avatar alt

* feat: support data uris

* feat: support arweave uris

* feat: support erc721 avatars

* feat: support erc1155 avatars

* fix: jazzicon integration

* fix: clean usage of status icon

* fix: fix jazzicon svg offset

* refactor: share status icon component

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

* comments

* min/max at 0.5% to 25%

* oops on constant

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

* wrap Switch in Suspense

* remove exact to match nested routes

* fix nested routes

* split Landing

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

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

Fixes #2458

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

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

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

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

* only show 1bps on mainnet

* rename VERY_LOW to LOWEST

* upgrade to v3-sdk 3.7.0

* add snapshot testing for lowest tier

* fix integration test

* fix integration test

* use ALL_SUPPORTED_CHAIN_IDS over string all

* consider 0.01% tier in pool (#2770)

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

* use the regenesis version of the sdk

* remove the override no longer necessary

* diff rpc url

* back to kovan url

* lint error

* Optimism mainnet regenesis test (#2695)

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

* point at the old mainnet multicall address

* bump the sdk version

* copy the list

* multicall address regenesis change

* revert the gas limit special casing for optimism

* bump the sdk version

* remove a couple other temporary edits

* unused test case

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

* Fix code style issues with ESLint

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

* Add canny feature requests link, remove github link

* add coffee icon
2021-11-11 10:31:08 -05:00
Will Hennessy
dc55a21285 fix: remove deprecated optimism status url (#2771) 2021-11-10 16:41:00 -05:00
Moody Salem
48cc6811c9 fix: bump to latest token list including ENS token 2021-11-08 23:46:50 -05:00
446 changed files with 27316 additions and 14828 deletions

2
.env
View File

@@ -1 +1 @@
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"

View File

@@ -8,21 +8,42 @@
"jsx": true
}
},
"ignorePatterns": ["node_modules/**/*"],
"settings": {
"react": {
"version": "detect"
}
},
"ignorePatterns": [
"src/types/v3",
"src/abis/types",
"src/locales/**/*.js",
"src/locales/**/en-US.po",
"src/state/data/generated.ts",
"node_modules",
"coverage",
"build",
"dist",
".DS_Store",
".env.local",
".env.development.local",
".env.test.local",
".env.production.local",
".idea/",
".vscode/",
"package-lock.json",
"yarn.lock"
],
"extends": [
"react-app",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"plugins": ["simple-import-sort"],
"plugins": ["simple-import-sort", "unused-imports"],
"rules": {
"unused-imports/no-unused-imports": "error",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"@typescript-eslint/explicit-function-return-type": "off",
@@ -37,10 +58,6 @@
"error",
{
"paths": [
{
"name": "lodash",
"message": "Please import from 'lodash/module' directly to support tree-shaking."
},
{
"name": "ethers",
"message": "Please import from '@ethersproject/module' directly to support tree-shaking."

View File

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

40
.github/workflows/bundle.yaml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Widgets
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up node
uses: actions/setup-node@v2
with:
node-version: 14
registry-url: https://registry.npmjs.org
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn widgets:build

View File

@@ -11,7 +11,6 @@ on:
jobs:
run-linters:
name: Run linters
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
runs-on: ubuntu-latest
steps:
@@ -39,10 +38,15 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run linters
- name: Run eslint w/ autofix
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
uses: wearerequired/lint-action@36c7e6689e80d785d27a22f71d970f3a3b4fcb70
with:
github_token: ${{ secrets.github_token }}
eslint: true
eslint_extensions: js,jsx,ts,tsx,json
eslint_args: "-c .eslintrc.json"
auto_fix: true
- name: Run eslint
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.owner.login != github.repository_owner }}
run: yarn eslint .

6
.gitignore vendored
View File

@@ -3,8 +3,12 @@
# generated contract types
/src/types/v3
/src/abis/types
/src/lib/locales/**/*.js
/src/lib/locales/**/en-US.po
/src/lib/locales/**/pseudo.po
/src/locales/**/*.js
/src/locales/**/en-US.po
/src/locales/**/pseudo.po
/src/state/data/generated.ts
# dependencies
@@ -16,7 +20,7 @@
# production
/build
# bundle
# widgets
/dist
# misc

View File

@@ -27,7 +27,7 @@ makes large architectural changes, consider following all the standards.
- If something breaks, add automated tests so it doesn't break again
- Add integration tests for new pages or flows
- Verify that all CI checks pass before merging
- Have at least one product manager or designer approve of significant UX changes
- Have at least one product manager or designer approve of any significant UX changes
## Guidelines
@@ -42,7 +42,7 @@ The following points should help guide your development:
- An Ethereum node should be the only critical dependency
- All other external dependencies should only enhance the UX ([graceful degradation](https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation))
- Accessibility: anyone can use the interface
- The interface should be responsive, small and run well on low performance devices (majority of swaps on mobile!)
- The interface should be responsive, small and also run well on low performance devices (majority of swaps on mobile!)
## Release process
@@ -73,4 +73,4 @@ We sync to the repository on a schedule, rather than download translations at bu
You can contribute by joining Crowdin to proofread existing translations [here](https://crowdin.com/project/uniswap-interface/invite?d=93i5n413q403t4g473p443o4c3t2g3s21343u2c3n403l4b3v2735353i4g4k4l4g453j4g4o4j4e4k4b323l4a3h463s4g453q443m4e3t2b303s2a35353l403o443v293e303k4g4n4r4g483i4g4r4j4e4o473i5n4a3t463t4o4)
Or, ask to join us as a translator in the Discord!
Or, ask to join us as a translator in the Discord!!

View File

@@ -10,7 +10,7 @@ An open source interface for Uniswap -- a protocol for decentralized exchange of
- Website: [uniswap.org](https://uniswap.org/)
- Interface: [app.uniswap.org](https://app.uniswap.org)
- Docs: [uniswap.org/docs/](https://uniswap.org/docs/)
- Docs: [uniswap.org/docs/](https://docs.uniswap.org/)
- Twitter: [@Uniswap](https://twitter.com/Uniswap)
- Reddit: [/r/Uniswap](https://www.reddit.com/r/Uniswap/)
- Email: [contact@uniswap.org](mailto:contact@uniswap.org)

View File

@@ -1,7 +1,9 @@
{
"staticPath": "public",
"watchDirs": ["src"],
"watchDirs": [
"src"
],
"webpack": {
"configPath": "react-scripts/config/webpack.config"
"configPath": "react-scripts/config/webpack.config",
"overridePath": "cosmos.override.js"
}
}
}

25
cosmos.override.js Normal file
View File

@@ -0,0 +1,25 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require('webpack')
// Renders the cosmos fixtures in isolation, instead of using public/index.html.
module.exports = (webpackConfig) => ({
...webpackConfig,
plugins: webpackConfig.plugins.map((plugin) => {
if (plugin instanceof HtmlWebpackPlugin) {
return new HtmlWebpackPlugin({
templateContent: '<body></body>',
})
}
if (plugin instanceof DefinePlugin) {
return new DefinePlugin({
...plugin.definitions,
'process.env': {
...plugin.definitions['process.env'],
REACT_APP_IS_WIDGET: true,
},
})
}
return plugin
}),
})

View File

@@ -5,6 +5,11 @@
}
},
"asToken0": [
{
"feeTier": "100",
"totalValueLockedToken0": "0",
"totalValueLockedToken1": "3"
},
{
"feeTier": "500",
"totalValueLockedToken0": "0",
@@ -13,7 +18,7 @@
{
"feeTier": "3000",
"totalValueLockedToken0": "0",
"totalValueLockedToken1": "7"
"totalValueLockedToken1": "4"
},
{
"feeTier": "10000",

View File

@@ -58,7 +58,7 @@ describe('Add Liquidity', () => {
cy.wait('@feeTierDistributionQuery')
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '70%')
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%')
})
})
})

View File

@@ -74,6 +74,7 @@ class CustomizedBridge extends Eip1193Bridge {
}
// sets up the injected provider to be a mock ethereum provider with the given mnemonic/index
// eslint-disable-next-line no-undef
Cypress.Commands.overwrite('visit', (original, url, options) => {
return original(url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url, {
...options,

View File

@@ -1,4 +1,4 @@
export default {
const linguiConfig = {
catalogs: [
{
path: '<rootDir>/src/locales/{locale}',
@@ -46,9 +46,13 @@ export default {
'vi-VN',
'zh-CN',
'zh-TW',
'pseudo',
],
orderBy: 'messageId',
rootDir: '.',
runtimeConfigModule: ['@lingui/core', 'i18n'],
sourceLocale: 'en-US',
pseudoLocale: 'pseudo',
}
export default linguiConfig

View File

@@ -11,7 +11,6 @@
],
"private": true,
"devDependencies": {
"@davatar/react": "1.8.1",
"@ethersproject/experimental": "^5.4.0",
"@gnosis.pm/safe-apps-web3-react": "^0.6.0",
"@graphql-codegen/cli": "1.21.5",
@@ -19,13 +18,16 @@
"@graphql-codegen/typescript-operations": "^1.18.2",
"@graphql-codegen/typescript-rtk-query": "^1.1.1",
"@lingui/cli": "^3.9.0",
"@lingui/macro": "^3.9.0",
"@lingui/react": "^3.9.0",
"@popperjs/core": "^2.4.4",
"@metamask/jazzicon": "^2.0.0",
"@reach/dialog": "^0.10.3",
"@reach/portal": "^0.10.3",
"@react-hook/window-scroll": "^1.3.0",
"@reduxjs/toolkit": "^1.6.1",
"@rollup/plugin-eslint": "^8.0.1",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-replace": "^3.0.1",
"@rollup/plugin-url": "^6.1.0",
"@svgr/rollup": "^6.2.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^7.0.2",
@@ -37,7 +39,6 @@
"@types/lingui__core": "^2.7.1",
"@types/lingui__macro": "^2.7.4",
"@types/lingui__react": "^2.8.3",
"@types/luxon": "^1.24.4",
"@types/ms.macro": "^2.0.0",
"@types/multicodec": "^1.0.0",
"@types/node": "^13.13.5",
@@ -55,79 +56,64 @@
"@types/wcag-contrast": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
"@uniswap/default-token-list": "^2.0.0",
"@uniswap/default-token-list": "^3.0.0",
"@uniswap/governance": "^1.0.2",
"@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "1.0.1",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/token-lists": "^1.0.0-beta.27",
"@uniswap/smart-order-router": "^2.5.10",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v2-sdk": "^3.0.0-alpha.2",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "^1.1.1",
"@uniswap/v3-sdk": "^3.4.1",
"@web3-react/core": "^6.0.9",
"@web3-react/fortmatic-connector": "^6.0.9",
"@web3-react/injected-connector": "^6.0.7",
"@web3-react/portis-connector": "^6.0.9",
"@web3-react/walletconnect-connector": "^7.0.2-alpha.0",
"@web3-react/walletlink-connector": "^6.2.8",
"ajv": "^6.12.3",
"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.3",
"cypress": "^7.7.0",
"d3": "^7.0.0",
"eslint": "^7.11.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-better-styled-components": "^1.1.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.0.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"ethers": "^5.4.6",
"eslint-plugin-unused-imports": "^2.0.0",
"firebase": "^9.1.3",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
"inter-ui": "^3.13.1",
"jest-styled-components": "^7.0.5",
"luxon": "^1.25.0",
"microbundle": "^0.13.3",
"ms.macro": "^2.0.0",
"multicodec": "^3.0.1",
"multihashes": "^4.0.2",
"node-vibrant": "^3.2.1-alpha.1",
"polished": "^3.3.2",
"polyfill-object.fromentries": "^1.0.1",
"prettier": "^2.2.1",
"qs": "^6.9.4",
"react": "^17.0.1",
"react-confetti": "^6.0.0",
"react-cosmos": "^5.6.3",
"react-dom": "^17.0.1",
"react-feather": "^2.0.8",
"react-cosmos": "^5.6.6",
"react-ga": "^2.5.7",
"react-is": "^17.0.2",
"react-markdown": "^4.3.1",
"react-popper": "^2.2.3",
"react-redux": "^7.2.2",
"react-router-dom": "^5.0.0",
"react-scripts": "^4.0.3",
"react-spring": "^8.0.27",
"react-use-gesture": "^6.0.14",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
"rebass": "^4.0.7",
"redux-localstorage-simple": "^2.3.1",
"rollup": "^2.63.0",
"rollup-plugin-dts": "^4.1.0",
"rollup-plugin-scss": "^3.0.0",
"rollup-plugin-typescript2": "^0.31.1",
"sass": "^1.45.1",
"serve": "^11.3.2",
"start-server-and-test": "^1.11.0",
"styled-components": "^5.3.0",
"typechain": "^5.0.0",
"typescript": "^4.2.3",
"ua-parser-js": "^0.7.28",
"use-count-up": "^2.2.5",
"use-resize-observer": "^8.0.0",
"wcag-contrast": "^3.0.0",
"web-vitals": "^2.1.0",
"workbox-core": "^6.1.0",
@@ -135,29 +121,24 @@
"workbox-routing": "^6.1.0"
},
"resolutions": {
"@walletconnect/ethereum-provider": "1.6.5"
"@walletconnect/ethereum-provider": "1.7.1"
},
"scripts": {
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"",
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*.json\"",
"contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3",
"graphql:generate": "graphql-codegen --config codegen.yml",
"prei18n:extract": "touch src/locales/en-US.po",
"i18n:extract": "lingui extract --locale en-US",
"i18n:compile": "yarn i18n:extract && lingui compile",
"i18n:pseudo": "lingui extract --locale pseudo && lingui compile",
"postinstall": "yarn contracts:compile && yarn graphql:generate && yarn i18n:compile",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=./custom-test-env.js",
"test:e2e": "start-server-and-test 'serve build -l 3000' http://localhost:3000 'cypress run --record'",
"bundle": "microbundle --tsconfig tsconfig.lib.json src/lib/index.tsx --format esm,cjs",
"cosmos": "open http://localhost:5000 && cross-env FAST_REFRESH=false cosmos"
},
"eslintConfig": {
"extends": "react-app",
"ignorePatterns": [
"node_modules"
]
"widgets:start": "cosmos",
"widgets:build": "rollup --config --failAfterWarnings --configPlugin typescript2"
},
"browserslist": {
"production": [
@@ -172,5 +153,63 @@
]
},
"license": "GPL-3.0-or-later",
"dependencies": {}
"dependencies": {
"@ethersproject/abi": "^5.4.1",
"@ethersproject/abstract-provider": "^5.4.1",
"@ethersproject/address": "^5.4.0",
"@ethersproject/bignumber": "^5.4.2",
"@ethersproject/bytes": "^5.4.0",
"@ethersproject/constants": "^5.4.0",
"@ethersproject/contracts": "^5.4.1",
"@ethersproject/hash": "^5.4.0",
"@ethersproject/providers": "^5.4.5",
"@ethersproject/solidity": "^5.4.0",
"@ethersproject/strings": "^5.4.0",
"@ethersproject/units": "^5.4.0",
"@ethersproject/wallet": "^5.4.0",
"@fontsource/ibm-plex-mono": "^4.5.1",
"@fontsource/inter": "^4.5.1",
"@lingui/core": "^3.9.0",
"@lingui/macro": "^3.9.0",
"@lingui/react": "^3.9.0",
"@popperjs/core": "^2.4.4",
"@uniswap/redux-multicall": "^1.0.0",
"@uniswap/router-sdk": "^1.0.3",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/token-lists": "^1.0.0-beta.27",
"@uniswap/v2-sdk": "^3.0.1",
"@uniswap/v3-sdk": "^3.7.1",
"@web3-react/core": "^6.0.9",
"ajv": "^6.12.3",
"cids": "^1.0.0",
"immer": "^9.0.6",
"jotai": "^1.3.7",
"jsbi": "^3.1.4",
"make-plural": "^7.0.0",
"ms.macro": "^2.0.0",
"multicodec": "^3.0.1",
"multihashes": "^4.0.2",
"node-vibrant": "^3.2.1-alpha.1",
"polished": "^3.3.2",
"popper-max-size-modifier": "^0.2.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-feather": "^2.0.8",
"react-popper": "^2.2.3",
"react-redux": "^7.2.2",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
"rebass": "^4.0.7",
"redux": "^4.1.2",
"styled-components": "^5.3.0",
"tiny-invariant": "^1.2.0",
"wcag-contrast": "^3.0.0",
"wicg-inert": "^3.1.1",
"widgets-web3-react/core": "npm:@web3-react/core@8.0.16-alpha.0",
"widgets-web3-react/eip1193": "npm:@web3-react/eip1193@8.0.16-alpha.0",
"widgets-web3-react/empty": "npm:@web3-react/empty@8.0.17-alpha.0",
"widgets-web3-react/metamask": "npm:@web3-react/metamask@8.0.16-alpha.0",
"widgets-web3-react/types": "npm:@web3-react/types@8.0.16-alpha.0",
"widgets-web3-react/url": "npm:@web3-react/url@8.0.17-alpha.0"
}
}

View File

@@ -67,6 +67,7 @@
html {
font-size: 16px;
font-variant: none;
font-smooth: always;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);

63
rollup.config.ts Normal file
View File

@@ -0,0 +1,63 @@
/**
* Bundles the widgets library, which is released independently of the interface application.
* This library lives in src/lib, but shares code with the interface application.
*/
import eslint from '@rollup/plugin-eslint'
import json from '@rollup/plugin-json'
import replace from '@rollup/plugin-replace'
import url from '@rollup/plugin-url'
import svgr from '@svgr/rollup'
import dts from 'rollup-plugin-dts'
import sass from 'rollup-plugin-scss'
import typescript from 'rollup-plugin-typescript2'
import { dependencies } from './package.json'
const deps = Object.keys(dependencies)
const replacements = {
'process.env.REACT_APP_IS_WIDGET': true,
}
const library = {
input: 'src/lib/index.tsx',
output: [
{
file: 'dist/widgets.js',
format: 'cjs',
inlineDynamicImports: true,
sourcemap: true,
},
{
file: 'dist/widgets.esm.js',
format: 'esm',
inlineDynamicImports: true,
sourcemap: true,
},
],
// necessary because some nested imports (eg jotai/*) would otherwise not resolve.
external: (source: string) => Boolean(deps.find((dep) => source === dep || source.startsWith(dep + '/'))),
plugins: [
eslint({ include: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'] }),
json(), // imports json
replace({ ...replacements, preventAssignment: true }),
url(), // imports files (including svgs) as data URIs
svgr({ exportType: 'named', svgo: false }), // imports svgs as React components
sass(), // imports sass styles
typescript({ tsconfig: './tsconfig.lib.json', useTsconfigDeclarationDir: true }),
],
}
const typings = {
input: 'dist/dts/lib/index.d.ts',
output: {
file: 'dist/widgets.d.ts',
format: 'es',
},
external: (source: string) => source.endsWith('.scss'),
plugins: [dts({ compilerOptions: { baseUrl: 'dist/dts' } })],
}
const config = [library, typings]
export default config

49
src/abis/erc1155.json Normal file
View File

@@ -0,0 +1,49 @@
[
{
"constant": true,
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "uri",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]

40
src/abis/erc721.json Normal file
View File

@@ -0,0 +1,40 @@
[
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.0047 9.26921H10.2714C11.0078 9.26921 11.6047 9.86617 11.6047 10.6025V12.1359C11.6047 12.7987 12.142 13.3359 12.8047 13.3359C13.4675 13.3359 14.0047 12.7995 14.0047 12.1367V5.22059C14.0047 4.86697 13.7758 4.56227 13.5258 4.31223L10.6714 1.33594M4.00472 2.00254H8.00472C8.7411 2.00254 9.33805 2.59949 9.33805 3.33587V14.0015H2.67139V3.33587C2.67139 2.59949 3.26834 2.00254 4.00472 2.00254ZM14.0047 5.33587C14.0047 6.07225 13.4078 6.66921 12.6714 6.66921C11.935 6.66921 11.3381 6.07225 11.3381 5.33587C11.3381 4.59949 11.935 4.00254 12.6714 4.00254C13.4078 4.00254 14.0047 4.59949 14.0047 5.33587Z" stroke="white"/>
<line x1="4" y1="9.99414" x2="8" y2="9.99414" stroke="white"/>
<line x1="4" y1="11.9941" x2="8" y2="11.9941" stroke="white"/>
<path d="M4 8.16113H8" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 895 B

View File

@@ -0,0 +1,12 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_988_5781)">
<path d="M11.3333 12.5C7.33329 12.5 6.66663 8.5 3.99996 8.5M3.99996 8.5C6.66663 8.5 7.33329 4.5 11.3333 4.5M3.99996 8.5H1.66663" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="13.3334" cy="4.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="13.3334" cy="12.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_988_5781">
<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 572 KiB

View File

@@ -0,0 +1,4 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="512" cy="512" r="512" fill="#8247E5"/>
<path d="M681.469 402.456C669.189 395.312 653.224 395.312 639.716 402.456L543.928 457.228L478.842 492.949L383.055 547.721C370.774 554.865 354.81 554.865 341.301 547.721L265.162 504.856C252.882 497.712 244.286 484.614 244.286 470.325V385.786C244.286 371.498 251.654 358.4 265.162 351.256L340.073 309.581C352.353 302.437 368.318 302.437 381.827 309.581L456.737 351.256C469.018 358.4 477.614 371.498 477.614 385.786V440.558L542.7 403.646V348.874C542.7 334.586 535.332 321.488 521.824 314.344L383.055 235.758C370.774 228.614 354.81 228.614 341.301 235.758L200.076 314.344C186.567 321.488 179.199 334.586 179.199 348.874V507.237C179.199 521.525 186.567 534.623 200.076 541.767L341.301 620.353C353.582 627.498 369.546 627.498 383.055 620.353L478.842 566.772L543.928 529.86L639.716 476.279C651.996 469.135 667.961 469.135 681.469 476.279L756.38 517.953C768.66 525.098 777.257 538.195 777.257 552.484V637.023C777.257 651.312 769.888 664.409 756.38 671.553L681.469 714.419C669.189 721.563 653.224 721.563 639.716 714.419L564.805 672.744C552.525 665.6 543.928 652.502 543.928 638.214V583.442L478.842 620.353V675.125C478.842 689.414 486.21 702.512 499.719 709.656L640.944 788.242C653.224 795.386 669.189 795.386 682.697 788.242L823.922 709.656C836.203 702.512 844.799 689.414 844.799 675.125V516.763C844.799 502.474 837.431 489.377 823.922 482.232L681.469 402.456Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 38.4 33.5" style="enable-background:new 0 0 38.4 33.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#8247E5;}
</style>
<g>
<path class="st0" d="M29,10.2c-0.7-0.4-1.6-0.4-2.4,0L21,13.5l-3.8,2.1l-5.5,3.3c-0.7,0.4-1.6,0.4-2.4,0L5,16.3
c-0.7-0.4-1.2-1.2-1.2-2.1v-5c0-0.8,0.4-1.6,1.2-2.1l4.3-2.5c0.7-0.4,1.6-0.4,2.4,0L16,7.2c0.7,0.4,1.2,1.2,1.2,2.1v3.3l3.8-2.2V7
c0-0.8-0.4-1.6-1.2-2.1l-8-4.7c-0.7-0.4-1.6-0.4-2.4,0L1.2,5C0.4,5.4,0,6.2,0,7v9.4c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
c0.7,0.4,1.6,0.4,2.4,0l5.5-3.2l3.8-2.2l5.5-3.2c0.7-0.4,1.6-0.4,2.4,0l4.3,2.5c0.7,0.4,1.2,1.2,1.2,2.1v5c0,0.8-0.4,1.6-1.2,2.1
L29,28.8c-0.7,0.4-1.6,0.4-2.4,0l-4.3-2.5c-0.7-0.4-1.2-1.2-1.2-2.1V21l-3.8,2.2v3.3c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
c0.7,0.4,1.6,0.4,2.4,0l8.1-4.7c0.7-0.4,1.2-1.2,1.2-2.1V17c0-0.8-0.4-1.6-1.2-2.1L29,10.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,7 +1,7 @@
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { CheckCircle, Triangle } from 'react-feather'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
import { useAllTransactions } from '../../state/transactions/hooks'
import { ExternalLink } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'

View File

@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
import { Fraction, TradeType } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import { nativeOnChain } from '../../constants/tokens'
import { useCurrency, useToken } from '../../hooks/Tokens'
import useENSName from '../../hooks/useENSName'
import { VoteOption } from '../../state/governance/types'
@@ -80,7 +81,7 @@ function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransa
)
}
function SubmitProposalTransactionSummary({}: { info: SubmitProposalTransactionInfo }) {
function SubmitProposalTransactionSummary(_: { info: SubmitProposalTransactionInfo }) {
return <Trans>Submit new proposal</Trans>
}
@@ -130,30 +131,45 @@ function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInf
return <Trans>Delegate voting power to {ENSName ?? delegatee}</Trans>
}
function WrapSummary({ info: { currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
const native = chainId ? nativeOnChain(chainId) : undefined
if (unwrapped) {
return (
<Trans>
Unwrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'WETH'} decimals={18} sigFigs={6} /> to
ETH
Unwrap{' '}
<FormattedCurrencyAmount
rawAmount={currencyAmountRaw}
symbol={native?.wrapped?.symbol ?? 'WETH'}
decimals={18}
sigFigs={6}
/>{' '}
to {native?.symbol ?? 'ETH'}
</Trans>
)
} else {
return (
<Trans>
Wrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'ETH'} decimals={18} sigFigs={6} /> to WETH
Wrap{' '}
<FormattedCurrencyAmount
rawAmount={currencyAmountRaw}
symbol={native?.symbol ?? 'ETH'}
decimals={18}
sigFigs={6}
/>{' '}
to {native?.wrapped?.symbol ?? 'WETH'}
</Trans>
)
}
}
function DepositLiquidityStakingSummary({}: { info: DepositLiquidityStakingTransactionInfo }) {
function DepositLiquidityStakingSummary(_: { info: DepositLiquidityStakingTransactionInfo }) {
// not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts
// todo: deprecate and delete the code paths that allow this, show user more information
return <Trans>Deposit liquidity</Trans>
}
function WithdrawLiquidityStakingSummary({}: { info: WithdrawLiquidityStakingTransactionInfo }) {
function WithdrawLiquidityStakingSummary(_: { info: WithdrawLiquidityStakingTransactionInfo }) {
return <Trans>Withdraw deposited liquidity</Trans>
}

View File

@@ -1,23 +1,21 @@
import { Trans } from '@lingui/macro'
import { AbstractConnector } from '@web3-react/abstract-connector'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useCallback, useContext } from 'react'
import { ExternalLink as LinkIcon } from 'react-feather'
import { useAppDispatch } from 'state/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import { Connector } from 'widgets-web3-react/types'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
import PortisIcon from '../../assets/images/portisIcon.png'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
import { injected, portis, walletlink } from '../../connectors'
import { SUPPORTED_WALLETS } from '../../constants/wallet'
import { useActiveWeb3React } from '../../hooks/web3'
import { clearAllTransactions } from '../../state/transactions/actions'
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
import { shortenAddress } from '../../utils'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { ButtonSecondary } from '../Button'
import Identicon from '../Identicon'
import StatusIcon from '../Identicon/StatusIcon'
import { AutoRow } from '../Row'
import Copy from './Copy'
import Transaction from './Transaction'
@@ -179,6 +177,23 @@ const IconWrapper = styled.div<{ size?: number }>`
`};
`
function WrappedStatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
return (
<IconWrapper size={16}>
<StatusIcon connector={connector} />
{connector === portis && (
<MainWalletAction
onClick={() => {
portis.portis.showPortis()
}}
>
<Trans>Show Portis</Trans>
</MainWalletAction>
)}
</IconWrapper>
)
}
const TransactionListWrapper = styled.div`
${({ theme }) => theme.flexColumnNoWrap};
`
@@ -244,50 +259,6 @@ export default function AccountDetails({
)
}
function getStatusIcon() {
if (connector === injected) {
return (
<IconWrapper size={16}>
<Identicon />
</IconWrapper>
)
} else if (connector === walletconnect) {
return (
<IconWrapper size={16}>
<img src={WalletConnectIcon} alt={'WalletConnect logo'} />
</IconWrapper>
)
} else if (connector === walletlink) {
return (
<IconWrapper size={16}>
<img src={CoinbaseWalletIcon} alt={'Coinbase Wallet logo'} />
</IconWrapper>
)
} else if (connector === fortmatic) {
return (
<IconWrapper size={16}>
<img src={FortmaticIcon} alt={'Fortmatic logo'} />
</IconWrapper>
)
} else if (connector === portis) {
return (
<>
<IconWrapper size={16}>
<img src={PortisIcon} alt={'Portis logo'} />
<MainWalletAction
onClick={() => {
portis.portis.showPortis()
}}
>
<Trans>Show Portis</Trans>
</MainWalletAction>
</IconWrapper>
</>
)
}
return null
}
const clearAllTransactionsCallback = useCallback(() => {
if (chainId) dispatch(clearAllTransactions({ chainId }))
}, [dispatch, chainId])
@@ -332,14 +303,14 @@ export default function AccountDetails({
{ENSName ? (
<>
<div>
{getStatusIcon()}
{connector && <WrappedStatusIcon connector={connector} />}
<p> {ENSName}</p>
</div>
</>
) : (
<>
<div>
{getStatusIcon()}
{connector && <WrappedStatusIcon connector={connector} />}
<p> {account && shortenAddress(account)}</p>
</div>
</>
@@ -408,9 +379,9 @@ export default function AccountDetails({
{!!pendingTransactions.length || !!confirmedTransactions.length ? (
<LowerSection>
<AutoRow mb={'1rem'} style={{ justifyContent: 'space-between' }}>
<TYPE.body>
<ThemedText.Body>
<Trans>Recent Transactions</Trans>
</TYPE.body>
</ThemedText.Body>
<LinkStyledButton onClick={clearAllTransactionsCallback}>
<Trans>(clear all)</Trans>
</LinkStyledButton>
@@ -420,9 +391,9 @@ export default function AccountDetails({
</LowerSection>
) : (
<LowerSection>
<TYPE.body color={theme.text1}>
<ThemedText.Body color={theme.text1}>
<Trans>Your transactions will appear here...</Trans>
</TYPE.body>
</ThemedText.Body>
</LowerSection>
)}
</>

View File

@@ -1,11 +1,12 @@
import { Trans } from '@lingui/macro'
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { t } from '@lingui/macro'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { ReactNode, useCallback, useContext } from 'react'
import styled, { ThemeContext } from 'styled-components/macro'
import useENS from '../../hooks/useENS'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn } from '../Column'
import { RowBetween } from '../Row'
@@ -107,9 +108,9 @@ export default function AddressInputPanel({
<InputContainer>
<AutoColumn gap="md">
<RowBetween>
<TYPE.black color={theme.text2} fontWeight={500} fontSize={14}>
<ThemedText.Black color={theme.text2} fontWeight={500} fontSize={14}>
{label ?? <Trans>Recipient</Trans>}
</TYPE.black>
</ThemedText.Black>
{address && chainId && (
<ExternalLink
href={getExplorerLink(chainId, name ?? address, ExplorerDataType.ADDRESS)}

View File

@@ -0,0 +1,34 @@
import { animated, useSpring } from 'react-spring'
import useResizeObserver from 'use-resize-observer'
/**
* @param open conditional to show content or hide
* @returns Wrapper to smoothly hide and expand content
*/
export default function AnimatedDropdown({ open, children }: React.PropsWithChildren<{ open: boolean }>) {
const { ref, height } = useResizeObserver()
const props = useSpring({
height: open ? height ?? 0 : 0,
config: {
mass: 1.2,
tension: 300,
friction: 20,
clamp: true,
velocity: 0.01,
},
})
return (
<animated.div
style={{
...props,
overflow: 'hidden',
width: '100%',
willChange: 'height',
}}
>
<div ref={ref}>{children}</div>
</animated.div>
)
}

View File

@@ -1,8 +1,7 @@
import { Trans } from '@lingui/macro'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { ReactNode, useMemo } from 'react'
import { useActiveWeb3React } from '../../hooks/web3'
// SDN OFAC addresses
const BLOCKED_ADDRESSES: string[] = [
'0x7Db418b5D567A4e0E8c59Ad71BE1FcE48f3E6107',
@@ -20,6 +19,19 @@ const BLOCKED_ADDRESSES: string[] = [
'0x8576aCC5C05D6Ce88f4e49bf65BdF0C62F91353C',
'0xC8a65Fadf0e0dDAf421F28FEAb69Bf6E2E589963',
'0x308eD4B7b49797e1A98D3818bFF6fe5385410370',
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B',
'0x6f1ca141a28907f78ebaa64fb83a9088b02a83',
'0x6acdfba02d390b97ac2b2d42a63e85293bcc1',
'0x48549a34ae37b12f6a30566245176994e17c6',
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121',
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e',
'0x3cbded43efdaf0fc77b9c55f6fc9988fcc9b757d',
'0x67d40EE1A85bf4a4Bb7Ffae16De985e8427B6b45',
'0x6f1ca141a28907f78ebaa64fb83a9088b02a8352',
'0x6acdfba02d390b97ac2b2d42a63e85293bcc160e',
'0x48549a34ae37b12f6a30566245176994e17c6b4a',
'0x5512d943ed1f7c8a43f3435c85f7ab68b30121b0',
'0xc455f7fd3e0e12afd51fba5c106909934d8a0e4a',
]
export default function Blocklist({ children }: { children: ReactNode }) {

View File

@@ -23,7 +23,7 @@ export const BaseButton = styled(RebassButton)<
border-radius: ${({ $borderRadius }) => $borderRadius ?? '20px'};
outline: none;
border: 1px solid transparent;
color: white;
color: ${({ theme }) => theme.text1};
text-decoration: none;
display: flex;
justify-content: center;
@@ -33,6 +33,7 @@ export const BaseButton = styled(RebassButton)<
position: relative;
z-index: 1;
&:disabled {
opacity: 50%;
cursor: auto;
pointer-events: none;
}
@@ -236,7 +237,7 @@ const ButtonConfirmedStyle = styled(BaseButton)`
/* border: 1px solid ${({ theme }) => theme.green1}; */
&:disabled {
/* opacity: 50%; */
opacity: 50%;
background-color: ${({ theme }) => theme.bg2};
color: ${({ theme }) => theme.text2};
cursor: auto;
@@ -315,8 +316,8 @@ const ActiveOutlined = styled(ButtonOutlined)`
`
const Circle = styled.div`
height: 20px;
width: 20px;
height: 17px;
width: 17px;
border-radius: 50%;
background-color: ${({ theme }) => theme.primary1};
display: flex;
@@ -325,11 +326,11 @@ const Circle = styled.div`
`
const CheckboxWrapper = styled.div`
width: 30px;
width: 20px;
padding: 0 10px;
position: absolute;
top: 10px;
right: 10px;
top: 11px;
right: 15px;
`
const ResponsiveCheck = styled(Check)`

View File

@@ -1,11 +1,14 @@
import { Trans } from '@lingui/macro'
// eslint-disable-next-line no-restricted-imports
import { t } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import HoverInlineText from 'components/HoverInlineText'
import { useMemo } from 'react'
import useTheme from '../../hooks/useTheme'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { warningSeverity } from '../../utils/prices'
import { MouseoverTooltip } from '../Tooltip'
export function FiatValue({
fiatValue,
@@ -25,10 +28,14 @@ export function FiatValue({
}, [priceImpact, theme.green1, theme.red1, theme.text3, theme.yellow1])
return (
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}>
<ThemedText.Body fontSize={14} color={fiatValue ? theme.text3 : theme.text4}>
{fiatValue ? (
<Trans>
~$ <HoverInlineText text={fiatValue?.toSignificant(6, { groupSeparator: ',' })} />
$
<HoverInlineText
text={fiatValue?.toSignificant(6, { groupSeparator: ',' })}
textColor={fiatValue ? theme.text3 : theme.text4}
/>
</Trans>
) : (
''
@@ -36,9 +43,11 @@ export function FiatValue({
{priceImpact ? (
<span style={{ color: priceImpactColor }}>
{' '}
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
<MouseoverTooltip text={t`The estimated difference between the USD values of input and output amounts.`}>
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
</MouseoverTooltip>
</span>
) : null}
</TYPE.body>
</ThemedText.Body>
)
}

View File

@@ -3,6 +3,7 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import { AutoColumn } from 'components/Column'
import { LoadingOpacityContainer, loadingOpacityMixin } from 'components/Loader/styled'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { darken } from 'polished'
import { ReactNode, useCallback, useState } from 'react'
import { Lock } from 'react-feather'
@@ -11,9 +12,8 @@ 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 { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { ButtonGray } from '../Button'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
@@ -29,6 +29,8 @@ const InputPanel = styled.div<{ hideInput?: boolean }>`
background-color: ${({ theme, hideInput }) => (hideInput ? 'transparent' : theme.bg2)};
z-index: 1;
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
transition: height 1s ease;
will-change: height;
`
const FixedContainer = styled.div`
@@ -36,8 +38,7 @@ const FixedContainer = styled.div`
height: 100%;
position: absolute;
border-radius: 20px;
background-color: ${({ theme }) => theme.bg1};
opacity: 0.95;
background-color: ${({ theme }) => theme.bg2};
display: flex;
align-items: center;
justify-content: center;
@@ -46,7 +47,7 @@ const FixedContainer = styled.div`
const Container = styled.div<{ hideInput: boolean }>`
border-radius: ${({ hideInput }) => (hideInput ? '16px' : '20px')};
border: 1px solid ${({ theme, hideInput }) => (hideInput ? ' transparent' : theme.bg2)};
border: 1px solid ${({ theme }) => theme.bg0};
background-color: ${({ theme }) => theme.bg1};
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
:focus,
@@ -56,35 +57,35 @@ const Container = styled.div<{ 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;
background-color: ${({ selected, theme }) => (selected ? theme.bg0 : theme.primary1)};
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
border-radius: 16px;
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : theme.primary1)};
box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')};
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
outline: none;
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
cursor: pointer;
border-radius: 16px;
outline: none;
user-select: none;
border: none;
font-size: 24px;
font-weight: 500;
height: ${({ hideInput }) => (hideInput ? '2.8rem' : '2.4rem')};
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
padding: 0 8px;
justify-content: space-between;
margin-right: ${({ hideInput }) => (hideInput ? '0' : '12px')};
margin-left: ${({ hideInput }) => (hideInput ? '0' : '12px')};
:focus,
:hover {
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : darken(0.05, theme.primary1))};
background-color: ${({ selected, theme }) => (selected ? theme.bg3 : darken(0.05, theme.primary1))};
}
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
`
const InputRow = styled.div<{ selected: boolean }>`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
justify-content: space-between;
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 0.75rem 1rem')};
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 1rem 1rem')};
`
const LabelRow = styled.div`
@@ -128,28 +129,30 @@ const StyledTokenName = styled.span<{ active?: boolean }>`
const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
background-color: transparent;
background-color: ${({ theme }) => theme.primary5};
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
color: ${({ theme }) => theme.primary1};
cursor: pointer;
padding: 0;
color: ${({ theme }) => theme.primaryText1};
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
font-size: 11px;
font-weight: 500;
margin-left: 0.25rem;
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
padding: 4px 6px;
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
:hover {
opacity: ${({ disabled }) => (!disabled ? 0.8 : 0.4)};
}
:focus {
outline: none;
}
${({ theme }) => theme.mediaWidth.upToExtraSmall`
margin-right: 0.5rem;
`};
`
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean }>`
${loadingOpacityMixin}
${loadingOpacityMixin};
text-align: left;
`
interface CurrencyInputPanelProps {
@@ -212,14 +215,23 @@ export default function CurrencyInputPanel({
<FixedContainer>
<AutoColumn gap="sm" justify="center">
<Lock />
<TYPE.label fontSize="12px" textAlign="center" padding="0 12px">
<ThemedText.Label fontSize="12px" textAlign="center" padding="0 12px">
<Trans>The market price is outside your specified price range. Single-asset deposit only.</Trans>
</TYPE.label>
</ThemedText.Label>
</AutoColumn>
</FixedContainer>
)}
<Container hideInput={hideInput}>
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
{!hideInput && (
<StyledNumericalInput
className="token-amount-input"
value={value}
onUserInput={onUserInput}
$loading={loading}
/>
)}
<CurrencySelect
visible={currency !== undefined}
selected={!!currency}
@@ -257,24 +269,19 @@ export default function CurrencyInputPanel({
{onCurrencySelect && <StyledDropDown selected={!!currency} />}
</Aligner>
</CurrencySelect>
{!hideInput && (
<StyledNumericalInput
className="token-amount-input"
value={value}
onUserInput={onUserInput}
$loading={loading}
/>
)}
</InputRow>
{!hideInput && !hideBalance && (
{!hideInput && !hideBalance && currency && (
<FiatRow>
<RowBetween>
<LoadingOpacityContainer $loading={loading}>
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
</LoadingOpacityContainer>
{account ? (
<RowFixed style={{ height: '17px' }}>
<TYPE.body
<ThemedText.Body
onClick={onMax}
color={theme.text2}
fontWeight={400}
color={theme.text3}
fontWeight={500}
fontSize={14}
style={{ display: 'inline', cursor: 'pointer' }}
>
@@ -282,24 +289,19 @@ export default function CurrencyInputPanel({
renderBalance ? (
renderBalance(selectedCurrencyBalance)
) : (
<Trans>
Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)} {currency.symbol}
</Trans>
<Trans>Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)}</Trans>
)
) : null}
</TYPE.body>
</ThemedText.Body>
{showMaxButton && selectedCurrencyBalance ? (
<StyledBalanceMax onClick={onMax}>
<Trans>(Max)</Trans>
<Trans>MAX</Trans>
</StyledBalanceMax>
) : null}
</RowFixed>
) : (
<span />
)}
<LoadingOpacityContainer $loading={loading}>
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
</LoadingOpacityContainer>
</RowBetween>
</FiatRow>
)}

View File

@@ -1,52 +1,19 @@
import { Currency } from '@uniswap/sdk-core'
import { SupportedChainId } from 'constants/chains'
import React, { useMemo } from 'react'
import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs'
import React from 'react'
import styled from 'styled-components/macro'
import EthereumLogo from '../../assets/images/ethereum-logo.png'
import useHttpLocations from '../../hooks/useHttpLocations'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import Logo from '../Logo'
type Network = 'ethereum' | 'arbitrum' | 'optimism'
function chainIdToNetworkName(networkId: SupportedChainId): Network {
switch (networkId) {
case SupportedChainId.MAINNET:
return 'ethereum'
case SupportedChainId.ARBITRUM_ONE:
return 'arbitrum'
case SupportedChainId.OPTIMISM:
return 'optimism'
default:
return 'ethereum'
}
}
export const getTokenLogoURL = (
address: string,
chainId: SupportedChainId = SupportedChainId.MAINNET
): string | void => {
const networkName = chainIdToNetworkName(chainId)
const networksWithUrls = [SupportedChainId.ARBITRUM_ONE, SupportedChainId.MAINNET, SupportedChainId.OPTIMISM]
if (networksWithUrls.includes(chainId)) {
return `https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/${networkName}/assets/${address}/logo.png`
}
}
const StyledEthereumLogo = styled.img<{ size: string }>`
const StyledLogo = styled(Logo)<{ size: string; native: boolean }>`
width: ${({ size }) => size};
height: ${({ size }) => size};
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
border-radius: 24px;
`
const StyledLogo = styled(Logo)<{ size: string }>`
width: ${({ size }) => size};
height: ${({ size }) => size};
border-radius: ${({ size }) => size};
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
background-color: ${({ theme }) => theme.white};
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
border-radius: 50%;
-mox-box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
-webkit-box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
box-shadow: 0 0 1px ${({ native }) => (native ? 'white' : 'black')};
border: 0px solid rgba(255, 255, 255, 0);
`
export default function CurrencyLogo({
@@ -59,28 +26,16 @@ export default function CurrencyLogo({
size?: string
style?: React.CSSProperties
}) {
const uriLocations = useHttpLocations(currency instanceof WrappedTokenInfo ? currency.logoURI : undefined)
const logoURIs = useCurrencyLogoURIs(currency)
const srcs: string[] = useMemo(() => {
if (!currency || currency.isNative) return []
if (currency.isToken) {
const defaultUrls = []
const url = getTokenLogoURL(currency.address, currency.chainId)
if (url) {
defaultUrls.push(url)
}
if (currency instanceof WrappedTokenInfo) {
return [...uriLocations, ...defaultUrls]
}
return defaultUrls
}
return []
}, [currency, uriLocations])
if (currency?.isNative) {
return <StyledEthereumLogo src={EthereumLogo} alt="ethereum logo" size={size} style={style} {...rest} />
}
return <StyledLogo size={size} srcs={srcs} alt={`${currency?.symbol ?? 'token'} logo`} style={style} {...rest} />
return (
<StyledLogo
size={size}
native={currency?.isNative ?? false}
srcs={logoURIs}
alt={`${currency?.symbol ?? 'token'} logo`}
style={style}
{...rest}
/>
)
}

View File

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

View File

@@ -4,7 +4,7 @@ import ReactGA from 'react-ga'
import styled from 'styled-components/macro'
import store, { AppState } from '../../state'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { userAgent } from '../../utils/userAgent'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
@@ -47,6 +47,8 @@ type ErrorBoundaryState = {
error: Error | null
}
const IS_UNISWAP = window.location.hostname === 'app.uniswap.org'
export default class ErrorBoundary extends React.Component<unknown, ErrorBoundaryState> {
constructor(props: unknown) {
super(props)
@@ -67,6 +69,7 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
render() {
const { error } = this.state
if (error !== null) {
const encodedBody = encodeURIComponent(issueBody(error))
return (
@@ -74,39 +77,41 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
<BodyWrapper>
<AutoColumn gap={'md'}>
<SomethingWentWrongWrapper>
<TYPE.label fontSize={24} fontWeight={600}>
<ThemedText.Label fontSize={24} fontWeight={600}>
<Trans>Something went wrong</Trans>
</TYPE.label>
</ThemedText.Label>
</SomethingWentWrongWrapper>
<CodeBlockWrapper>
<code>
<TYPE.main fontSize={10}>{error.stack}</TYPE.main>
<ThemedText.Main fontSize={10}>{error.stack}</ThemedText.Main>
</code>
</CodeBlockWrapper>
<AutoRow>
<LinkWrapper>
<ExternalLink
id="create-github-issue-link"
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
)}`}
target="_blank"
>
<TYPE.link fontSize={16}>
<Trans>Create an issue on GitHub</Trans>
<span></span>
</TYPE.link>
</ExternalLink>
</LinkWrapper>
<LinkWrapper>
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
<TYPE.link fontSize={16}>
<Trans>Get support on Discord</Trans>
<span></span>
</TYPE.link>
</ExternalLink>
</LinkWrapper>
</AutoRow>
{IS_UNISWAP ? (
<AutoRow>
<LinkWrapper>
<ExternalLink
id="create-github-issue-link"
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
)}`}
target="_blank"
>
<ThemedText.Link fontSize={16}>
<Trans>Create an issue on GitHub</Trans>
<span></span>
</ThemedText.Link>
</ExternalLink>
</LinkWrapper>
<LinkWrapper>
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
<ThemedText.Link fontSize={16}>
<Trans>Get support on Discord</Trans>
<span></span>
</ThemedText.Link>
</ExternalLink>
</LinkWrapper>
</AutoRow>
) : null}
</AutoColumn>
</BodyWrapper>
</FallbackWrapper>
@@ -121,7 +126,7 @@ function getRelevantState(): null | keyof AppState {
if (!path.startsWith('#/')) {
return null
}
const pieces = path.substring(2).split(/[\/\\?]/)
const pieces = path.substring(2).split(/[/\\?]/)
switch (pieces[0]) {
case 'swap':
return 'swap'

View File

@@ -0,0 +1,51 @@
import { Trans } from '@lingui/macro'
import { FeeAmount } from '@uniswap/v3-sdk'
import { ButtonRadioChecked } from 'components/Button'
import { AutoColumn } from 'components/Column'
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
import { PoolState } from 'hooks/usePools'
import React from 'react'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
import { FEE_AMOUNT_DETAIL } from './shared'
const ResponsiveText = styled(ThemedText.Label)`
line-height: 16px;
font-size: 14px;
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 12px;
line-height: 12px;
`};
`
interface FeeOptionProps {
feeAmount: FeeAmount
active: boolean
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
poolState: PoolState
onClick: () => void
}
export function FeeOption({ feeAmount, active, poolState, distributions, onClick }: FeeOptionProps) {
return (
<ButtonRadioChecked active={active} onClick={onClick}>
<AutoColumn gap="sm" justify="flex-start">
<AutoColumn justify="flex-start" gap="6px">
<ResponsiveText>
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}%</Trans>
</ResponsiveText>
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
{FEE_AMOUNT_DETAIL[feeAmount].description}
</ThemedText.Main>
</AutoColumn>
{distributions && (
<FeeTierPercentageBadge distributions={distributions} feeAmount={feeAmount} poolState={poolState} />
)}
</AutoColumn>
</ButtonRadioChecked>
)
}

View File

@@ -0,0 +1,31 @@
import { Trans } from '@lingui/macro'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
import { PoolState } from 'hooks/usePools'
import React from 'react'
import { ThemedText } from 'theme'
export function FeeTierPercentageBadge({
feeAmount,
distributions,
poolState,
}: {
feeAmount: FeeAmount
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
poolState: PoolState
}) {
return (
<Badge>
<ThemedText.Label fontSize={10}>
{!distributions || poolState === PoolState.NOT_EXISTS || poolState === PoolState.INVALID ? (
<Trans>Not created</Trans>
) : distributions[feeAmount] !== undefined ? (
<Trans>{distributions[feeAmount]?.toFixed(0)}% select</Trans>
) : (
<Trans>No data</Trans>
)}
</ThemedText.Label>
</Badge>
)
}

View File

@@ -1,11 +1,11 @@
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
import { ButtonGray } from 'components/Button'
import Card from 'components/Card'
import { AutoColumn } from 'components/Column'
import { RowBetween } from 'components/Row'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
import { PoolState, usePools } from 'hooks/usePools'
import usePrevious from 'hooks/usePrevious'
@@ -14,7 +14,11 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import ReactGA from 'react-ga'
import { Box } from 'rebass'
import styled, { keyframes } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { FeeOption } from './FeeOption'
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
import { FEE_AMOUNT_DETAIL } from './shared'
const pulse = (color: string) => keyframes`
0% {
@@ -29,60 +33,18 @@ const pulse = (color: string) => keyframes`
box-shadow: 0 0 0 0 ${color};
}
`
const ResponsiveText = styled(TYPE.label)`
line-height: 16px;
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 12px;
line-height: 12px;
`};
`
const FocusedOutlineCard = styled(Card)<{ pulsing: boolean }>`
border: 1px solid ${({ theme }) => theme.bg2};
animation: ${({ pulsing, theme }) => pulsing && pulse(theme.primary1)} 0.6s linear;
align-self: center;
`
const FeeAmountLabel = {
[FeeAmount.LOW]: {
label: '0.05',
description: <Trans>Best for stable pairs.</Trans>,
},
[FeeAmount.MEDIUM]: {
label: '0.3',
description: <Trans>Best for most pairs.</Trans>,
},
[FeeAmount.HIGH]: {
label: '1',
description: <Trans>Best for exotic pairs.</Trans>,
},
}
function FeeTierPercentageBadge({
feeAmount,
distributions,
poolState,
}: {
feeAmount: FeeAmount
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
poolState: PoolState
}) {
return (
<Badge>
<TYPE.label fontSize={12}>
{!distributions || poolState === PoolState.NOT_EXISTS || poolState === PoolState.INVALID ? (
<Trans>Not created</Trans>
) : distributions[feeAmount] !== undefined ? (
<Trans>{distributions[feeAmount]?.toFixed(0)}% select</Trans>
) : (
<Trans>No data</Trans>
)}
</TYPE.label>
</Badge>
)
}
const Select = styled.div`
align-items: flex-start;
display: grid;
grid-auto-flow: column;
grid-gap: 8px;
`
export default function FeeSelector({
disabled = false,
@@ -97,16 +59,19 @@ export default function FeeSelector({
currencyA?: Currency | undefined
currencyB?: Currency | undefined
}) {
const { chainId } = useActiveWeb3React()
const { isLoading, isError, largestUsageFeeTier, distributions } = useFeeTierDistribution(currencyA, currencyB)
// get pool data on-chain for latest states
const pools = usePools([
[currencyA, currencyB, FeeAmount.LOWEST],
[currencyA, currencyB, FeeAmount.LOW],
[currencyA, currencyB, FeeAmount.MEDIUM],
[currencyA, currencyB, FeeAmount.HIGH],
])
const poolsByFeeTier = useMemo(
const poolsByFeeTier: Record<FeeAmount, PoolState> = useMemo(
() =>
pools.reduce(
(acc, [curPoolState, curPool]) => {
@@ -118,6 +83,7 @@ export default function FeeSelector({
},
{
// default all states to NOT_EXISTS
[FeeAmount.LOWEST]: PoolState.NOT_EXISTS,
[FeeAmount.LOW]: PoolState.NOT_EXISTS,
[FeeAmount.MEDIUM]: PoolState.NOT_EXISTS,
[FeeAmount.HIGH]: PoolState.NOT_EXISTS,
@@ -134,7 +100,7 @@ export default function FeeSelector({
const recommended = useRef(false)
const handleFeePoolSelectWithEvent = useCallback(
(fee) => {
(fee: FeeAmount) => {
ReactGA.event({
category: 'FeePoolSelect',
action: 'Manual',
@@ -183,18 +149,18 @@ export default function FeeSelector({
<AutoColumn id="add-liquidity-selected-fee">
{!feeAmount ? (
<>
<TYPE.label>
<ThemedText.Label>
<Trans>Fee tier</Trans>
</TYPE.label>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
</ThemedText.Label>
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
<Trans>The % you will earn in fees.</Trans>
</TYPE.main>
</ThemedText.Main>
</>
) : (
<>
<TYPE.label className="selected-fee-label">
<Trans>{FeeAmountLabel[feeAmount].label}% fee tier</Trans>
</TYPE.label>
<ThemedText.Label className="selected-fee-label">
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}% fee tier</Trans>
</ThemedText.Label>
<Box style={{ width: 'fit-content', marginTop: '8px' }} className="selected-fee-percentage">
{distributions && (
<FeeTierPercentageBadge
@@ -214,81 +180,25 @@ export default function FeeSelector({
</RowBetween>
</FocusedOutlineCard>
{showOptions && (
<RowBetween>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.LOW}
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.LOW)}
>
<AutoColumn gap="sm" justify="flex-start">
<AutoColumn justify="flex-start" gap="6px">
<ResponsiveText>
<Trans>0.05% fee</Trans>
</ResponsiveText>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
<Trans>Best for stable pairs.</Trans>
</TYPE.main>
</AutoColumn>
{distributions && (
<FeeTierPercentageBadge
{chainId && showOptions && (
<Select>
{[FeeAmount.LOWEST, FeeAmount.LOW, FeeAmount.MEDIUM, FeeAmount.HIGH].map((_feeAmount, i) => {
const { supportedChains } = FEE_AMOUNT_DETAIL[_feeAmount]
if (supportedChains.includes(chainId)) {
return (
<FeeOption
feeAmount={_feeAmount}
active={feeAmount === _feeAmount}
onClick={() => handleFeePoolSelectWithEvent(_feeAmount)}
distributions={distributions}
feeAmount={FeeAmount.LOW}
poolState={poolsByFeeTier[FeeAmount.LOW]}
poolState={poolsByFeeTier[_feeAmount]}
key={i}
/>
)}
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.MEDIUM}
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.MEDIUM)}
>
<AutoColumn gap="sm" justify="flex-start">
<AutoColumn justify="flex-start" gap="4px">
<ResponsiveText>
<Trans>0.3% fee</Trans>
</ResponsiveText>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
<Trans>Best for most pairs.</Trans>
</TYPE.main>
</AutoColumn>
{distributions && (
<FeeTierPercentageBadge
distributions={distributions}
feeAmount={FeeAmount.MEDIUM}
poolState={poolsByFeeTier[FeeAmount.MEDIUM]}
/>
)}
</AutoColumn>
</ButtonRadioChecked>
<ButtonRadioChecked
width="32%"
active={feeAmount === FeeAmount.HIGH}
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.HIGH)}
>
<AutoColumn gap="sm" justify="flex-start">
<AutoColumn justify="flex-start" gap="4px">
<ResponsiveText>
<Trans>1% fee</Trans>
</ResponsiveText>
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
<Trans>Best for exotic pairs.</Trans>
</TYPE.main>
</AutoColumn>
{distributions && (
<FeeTierPercentageBadge
distributions={distributions}
feeAmount={FeeAmount.HIGH}
poolState={poolsByFeeTier[FeeAmount.HIGH]}
/>
)}
</AutoColumn>
</ButtonRadioChecked>
</RowBetween>
)
}
return null
})}
</Select>
)}
</DynamicSection>
</AutoColumn>

View File

@@ -0,0 +1,30 @@
import { Trans } from '@lingui/macro'
import { FeeAmount } from '@uniswap/v3-sdk'
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { ReactNode } from 'react'
export const FEE_AMOUNT_DETAIL: Record<
FeeAmount,
{ label: string; description: ReactNode; supportedChains: SupportedChainId[] }
> = {
[FeeAmount.LOWEST]: {
label: '0.01',
description: <Trans>Best for very stable pairs.</Trans>,
supportedChains: [SupportedChainId.MAINNET],
},
[FeeAmount.LOW]: {
label: '0.05',
description: <Trans>Best for stable pairs.</Trans>,
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
},
[FeeAmount.MEDIUM]: {
label: '0.3',
description: <Trans>Best for most pairs.</Trans>,
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
},
[FeeAmount.HIGH]: {
label: '1',
description: <Trans>Best for exotic pairs.</Trans>,
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
},
}

View File

@@ -1,6 +1,7 @@
import { Trans } from '@lingui/macro'
import { CHAIN_INFO, L2ChainInfo, SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { CHAIN_INFO, L2ChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { AlertOctagon } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'

View File

@@ -0,0 +1,26 @@
import { ReactElement } from 'react'
import styled from 'styled-components/macro'
import SantaHat from '../../assets/images/santa-hat.png'
const SantaHatImage = styled.img`
position: absolute;
top: -4px;
right: -4px;
height: 18px;
`
const Christmas = <SantaHatImage src={SantaHat} alt="Santa hat" />
const DATE_TO_ORNAMENT: { [date: string]: ReactElement } = {
'12-24': Christmas,
'12-25': Christmas,
}
const HolidayOrnament = () => {
// months in javascript are 0 indexed...
const today = `${new Date().getMonth() + 1}-${new Date().getDate()}`
return DATE_TO_ORNAMENT[today] || null
}
export default HolidayOrnament

View File

@@ -1,22 +1,22 @@
import { Trans } from '@lingui/macro'
import {
ARBITRUM_HELP_CENTER_LINK,
CHAIN_INFO,
L2_CHAIN_IDS,
OPTIMISM_HELP_CENTER_LINK,
SupportedChainId,
SupportedL2ChainId,
} from 'constants/chains'
import { CHAIN_INFO } from 'constants/chainInfo'
import { CHAIN_IDS_TO_NAMES, SupportedChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useRef } from 'react'
import useParsedQueryString from 'hooks/useParsedQueryString'
import usePrevious from 'hooks/usePrevious'
import { ParsedQs } from 'qs'
import { useCallback, useEffect, useRef } from 'react'
import { ArrowDownCircle, ChevronDown } from 'react-feather'
import { useHistory } from 'react-router-dom'
import { useModalOpen, useToggleModal } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer'
import { useAppSelector } from 'state/hooks'
import { addPopup, ApplicationModal } from 'state/application/reducer'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { switchToNetwork } from 'utils/switchToNetwork'
import { replaceURLParam } from 'utils/routes'
import { useAppDispatch } from '../../state/hooks'
import { switchToNetwork } from '../../utils/switchToNetwork'
const ActiveRowLinkList = styled.div`
display: flex;
@@ -34,17 +34,16 @@ const ActiveRowLinkList = styled.div`
text-decoration: none;
}
& > a:first-child {
border-top: 1px solid ${({ theme }) => theme.text2};
margin: 0;
margin-top: 6px;
margin-top: 0px;
padding-top: 10px;
}
`
const ActiveRowWrapper = styled.div`
background-color: ${({ theme }) => theme.bg2};
background-color: ${({ theme }) => theme.bg1};
border-radius: 8px;
cursor: pointer;
padding: 8px 0 8px 0;
padding: 8px;
width: 100%;
`
const FlyoutHeader = styled.div`
@@ -53,7 +52,7 @@ const FlyoutHeader = styled.div`
`
const FlyoutMenu = styled.div`
align-items: flex-start;
background-color: ${({ theme }) => theme.bg1};
background-color: ${({ theme }) => theme.bg0};
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 20px;
@@ -75,7 +74,7 @@ const FlyoutMenu = styled.div`
`
const FlyoutRow = styled.div<{ active: boolean }>`
align-items: center;
background-color: ${({ active, theme }) => (active ? theme.bg2 : 'transparent')};
background-color: ${({ active, theme }) => (active ? theme.bg1 : 'transparent')};
border-radius: 8px;
cursor: pointer;
display: flex;
@@ -113,9 +112,9 @@ const SelectorLabel = styled(NetworkLabel)`
`
const SelectorControls = styled.div<{ interactive: boolean }>`
align-items: center;
background-color: ${({ theme }) => theme.bg1};
border: 2px solid ${({ theme }) => theme.bg1};
border-radius: 12px;
background-color: ${({ theme }) => theme.bg0};
border: 2px solid ${({ theme }) => theme.bg0};
border-radius: 16px;
color: ${({ theme }) => theme.text1};
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
display: flex;
@@ -135,9 +134,9 @@ const SelectorWrapper = styled.div`
}
`
const StyledChevronDown = styled(ChevronDown)`
width: 12px;
width: 16px;
`
const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
const BridgeLabel = ({ chainId }: { chainId: SupportedChainId }) => {
switch (chainId) {
case SupportedChainId.ARBITRUM_ONE:
case SupportedChainId.ARBITRUM_RINKEBY:
@@ -145,11 +144,14 @@ const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
case SupportedChainId.OPTIMISM:
case SupportedChainId.OPTIMISTIC_KOVAN:
return <Trans>Optimism Gateway</Trans>
case SupportedChainId.POLYGON:
case SupportedChainId.POLYGON_MUMBAI:
return <Trans>Polygon Bridge</Trans>
default:
return <Trans>Bridge</Trans>
}
}
const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
const ExplorerLabel = ({ chainId }: { chainId: SupportedChainId }) => {
switch (chainId) {
case SupportedChainId.ARBITRUM_ONE:
case SupportedChainId.ARBITRUM_RINKEBY:
@@ -157,91 +159,167 @@ const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
case SupportedChainId.OPTIMISM:
case SupportedChainId.OPTIMISTIC_KOVAN:
return <Trans>Optimistic Etherscan</Trans>
case SupportedChainId.POLYGON:
case SupportedChainId.POLYGON_MUMBAI:
return <Trans>Polygonscan</Trans>
default:
return <Trans>Explorer</Trans>
return <Trans>Etherscan</Trans>
}
}
function Row({
targetChain,
onSelectChain,
}: {
targetChain: SupportedChainId
onSelectChain: (targetChain: number) => void
}) {
const { library, chainId } = useActiveWeb3React()
if (!library || !chainId) {
return null
}
const active = chainId === targetChain
const { helpCenterUrl, explorer, bridge, label, logoUrl } = CHAIN_INFO[targetChain]
const rowContent = (
<FlyoutRow onClick={() => onSelectChain(targetChain)} active={active}>
<Logo src={logoUrl} />
<NetworkLabel>{label}</NetworkLabel>
{chainId === targetChain && <FlyoutRowActiveIndicator />}
</FlyoutRow>
)
if (active) {
return (
<ActiveRowWrapper>
{rowContent}
<ActiveRowLinkList>
{bridge ? (
<ExternalLink href={bridge}>
<BridgeLabel chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
) : null}
{explorer ? (
<ExternalLink href={explorer}>
<ExplorerLabel chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
) : null}
{helpCenterUrl ? (
<ExternalLink href={helpCenterUrl}>
<Trans>Help Center</Trans> <LinkOutCircle />
</ExternalLink>
) : null}
</ActiveRowLinkList>
</ActiveRowWrapper>
)
}
return rowContent
}
const getParsedChainId = (parsedQs?: ParsedQs) => {
const chain = parsedQs?.chain
if (!chain || typeof chain !== 'string') return { urlChain: undefined, urlChainId: undefined }
return { urlChain: chain.toLowerCase(), urlChainId: getChainIdFromName(chain) }
}
const getChainIdFromName = (name: string) => {
const entry = Object.entries(CHAIN_IDS_TO_NAMES).find(([_, n]) => n === name)
const chainId = entry?.[0]
return chainId ? parseInt(chainId) : undefined
}
const getChainNameFromId = (id: string | number) => {
// casting here may not be right but fine to return undefined if it's not a supported chain ID
return CHAIN_IDS_TO_NAMES[id as SupportedChainId] || ''
}
export default function NetworkSelector() {
const { chainId, library } = useActiveWeb3React()
const parsedQs = useParsedQueryString()
const { urlChain, urlChainId } = getParsedChainId(parsedQs)
const prevChainId = usePrevious(chainId)
const node = useRef<HTMLDivElement>()
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
useOnClickOutside(node, open ? toggle : undefined)
const implements3085 = useAppSelector((state) => state.application.implements3085)
const history = useHistory()
const info = chainId ? CHAIN_INFO[chainId] : undefined
const isOnL2 = chainId ? L2_CHAIN_IDS.includes(chainId) : false
const showSelector = Boolean(implements3085 || isOnL2)
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]
const dispatch = useAppDispatch()
const conditionalToggle = useCallback(() => {
if (showSelector) {
toggle()
const handleChainSwitch = useCallback(
(targetChain: number, skipToggle?: boolean) => {
if (!library) return
switchToNetwork({ library, chainId: targetChain })
.then(() => {
if (!skipToggle) {
toggle()
}
history.replace({
search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(targetChain)),
})
})
.catch((error) => {
console.error('Failed to switch networks', error)
// we want app network <-> chainId param to be in sync, so if user changes the network by changing the URL
// but the request fails, revert the URL back to current chainId
if (chainId) {
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
}
if (!skipToggle) {
toggle()
}
dispatch(addPopup({ content: { failedSwitchNetwork: targetChain }, key: `failed-network-switch` }))
})
},
[dispatch, library, toggle, history, chainId]
)
useEffect(() => {
if (!chainId || !prevChainId) return
// when network change originates from wallet or dropdown selector, just update URL
if (chainId !== prevChainId) {
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
// otherwise assume network change originates from URL
} else if (urlChainId && urlChainId !== chainId) {
handleChainSwitch(urlChainId, true)
}
}, [showSelector, toggle])
}, [chainId, urlChainId, prevChainId, handleChainSwitch, history])
// set chain parameter on initial load if not there
useEffect(() => {
if (chainId && !urlChainId) {
history.replace({ search: replaceURLParam(history.location.search, 'chain', getChainNameFromId(chainId)) })
}
}, [chainId, history, urlChainId, urlChain])
if (!chainId || !info || !library) {
return null
}
function Row({ targetChain }: { targetChain: number }) {
if (!library || !chainId || (!implements3085 && targetChain !== chainId)) {
return null
}
const handleRowClick = () => {
switchToNetwork({ library, chainId: targetChain })
toggle()
}
const active = chainId === targetChain
const hasExtendedInfo = L2_CHAIN_IDS.includes(targetChain)
const isOptimism = targetChain === SupportedChainId.OPTIMISM
const rowText = `${CHAIN_INFO[targetChain].label}${isOptimism ? ' (Optimism)' : ''}`
const RowContent = () => (
<FlyoutRow onClick={handleRowClick} active={active}>
<Logo src={CHAIN_INFO[targetChain].logoUrl} />
<NetworkLabel>{rowText}</NetworkLabel>
{chainId === targetChain && <FlyoutRowActiveIndicator />}
</FlyoutRow>
)
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
if (active && hasExtendedInfo) {
return (
<ActiveRowWrapper>
<RowContent />
<ActiveRowLinkList>
<ExternalLink href={CHAIN_INFO[targetChain as SupportedL2ChainId].bridge}>
<BridgeText chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
<ExternalLink href={CHAIN_INFO[targetChain].explorer}>
<ExplorerText chainId={chainId} /> <LinkOutCircle />
</ExternalLink>
<ExternalLink href={helpCenterLink}>
<Trans>Help Center</Trans> <LinkOutCircle />
</ExternalLink>
</ActiveRowLinkList>
</ActiveRowWrapper>
)
}
return <RowContent />
}
return (
<SelectorWrapper ref={node as any}>
<SelectorControls onClick={conditionalToggle} interactive={showSelector}>
<SelectorLogo interactive={showSelector} src={info.logoUrl || mainnetInfo.logoUrl} />
<SelectorControls onClick={toggle} interactive>
<SelectorLogo interactive src={info.logoUrl} />
<SelectorLabel>{info.label}</SelectorLabel>
{showSelector && <StyledChevronDown />}
<StyledChevronDown />
</SelectorControls>
{open && (
<FlyoutMenu>
<FlyoutMenu onMouseLeave={toggle}>
<FlyoutHeader>
<Trans>Select a network</Trans>
</FlyoutHeader>
<Row targetChain={SupportedChainId.MAINNET} />
<Row targetChain={SupportedChainId.OPTIMISM} />
<Row targetChain={SupportedChainId.ARBITRUM_ONE} />
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.MAINNET} />
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.POLYGON} />
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.OPTIMISM} />
<Row onSelectChain={handleChainSwitch} targetChain={SupportedChainId.ARBITRUM_ONE} />
</FlyoutMenu>
)}
</SelectorWrapper>

View File

@@ -1,11 +1,20 @@
import { Trans } from '@lingui/macro'
import { RowFixed } from 'components/Row'
import { CHAIN_INFO } from 'constants/chainInfo'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useGasPrice from 'hooks/useGasPrice'
import useMachineTimeMs from 'hooks/useMachineTime'
import useTheme from 'hooks/useTheme'
import JSBI from 'jsbi'
import useBlockNumber from 'lib/hooks/useBlockNumber'
import ms from 'ms.macro'
import { useEffect, useState } from 'react'
import { useAppSelector } from 'state/hooks'
import styled, { keyframes } from 'styled-components/macro'
import { ExternalLink, ThemedText } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import { useActiveWeb3React } from '../../hooks/web3'
import { useBlockNumber } from '../../state/application/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { MouseoverTooltip } from '../Tooltip'
import { ChainConnectivityWarning } from './ChainConnectivityWarning'
const StyledPolling = styled.div<{ warning: boolean }>`
@@ -22,12 +31,20 @@ const StyledPolling = styled.div<{ warning: boolean }>`
display: none;
`}
`
const StyledPollingNumber = styled(TYPE.small)<{ breathe: boolean; hovering: boolean }>`
const StyledPollingNumber = styled(ThemedText.Small)<{ breathe: boolean; hovering: boolean }>`
transition: opacity 0.25s ease;
opacity: ${({ breathe, hovering }) => (hovering ? 0.7 : breathe ? 1 : 0.5)};
:hover {
opacity: 1;
}
a {
color: unset;
}
a:hover {
text-decoration: none;
color: unset;
}
`
const StyledPollingDot = styled.div<{ warning: boolean }>`
width: 8px;
@@ -40,6 +57,17 @@ const StyledPollingDot = styled.div<{ warning: boolean }>`
transition: 250ms ease background-color;
`
const StyledGasDot = styled.div`
background-color: ${({ theme }) => theme.text3};
border-radius: 50%;
height: 4px;
min-height: 4px;
min-width: 4px;
position: relative;
transition: 250ms ease background-color;
width: 4px;
`
const rotate360 = keyframes`
from {
transform: rotate(0deg);
@@ -68,12 +96,25 @@ const Spinner = styled.div<{ warning: boolean }>`
top: -3px;
`
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
const NETWORK_HEALTH_CHECK_MS = ms`10s`
export default function Polling() {
const { chainId } = useActiveWeb3React()
const blockNumber = useBlockNumber()
const [isMounting, setIsMounting] = useState(false)
const [isHover, setIsHover] = useState(false)
const chainConnectivityWarning = useAppSelector((state) => state.application.chainConnectivityWarning)
const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
const blockTime = useCurrentBlockTimestamp()
const theme = useTheme()
const ethGasPrice = useGasPrice()
const priceGwei = ethGasPrice ? JSBI.divide(ethGasPrice, JSBI.BigInt(1000000000)) : undefined
const waitMsBeforeWarning =
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
useEffect(
() => {
@@ -93,25 +134,48 @@ export default function Polling() {
//if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
)
//TODO - chainlink gas oracle is really slow. Can we get a better data source?
return (
<>
<ExternalLink
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
>
<StyledPolling
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
warning={chainConnectivityWarning}
>
<RowFixed>
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} warning={warning}>
<ExternalLink href={'https://etherscan.io/gastracker'}>
{priceGwei ? (
<RowFixed style={{ marginRight: '8px' }}>
<ThemedText.Main fontSize="11px" mr="8px" color={theme.text3}>
<MouseoverTooltip
text={
<Trans>
The current fast gas amount for sending a transaction on L1. Gas fees are paid in
Ethereum&apos;s native currency Ether (ETH) and denominated in GWEI.
</Trans>
}
>
{priceGwei.toString()} <Trans>gwei</Trans>
</MouseoverTooltip>
</ThemedText.Main>
<StyledGasDot />
</RowFixed>
) : null}
</ExternalLink>
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
{blockNumber}&ensp;
<ExternalLink
href={
chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''
}
>
<MouseoverTooltip
text={<Trans>The most recent block number on this network. Prices update on every block.</Trans>}
>
{blockNumber}&ensp;
</MouseoverTooltip>
</ExternalLink>
</StyledPollingNumber>
<StyledPollingDot warning={chainConnectivityWarning}>
{isMounting && <Spinner warning={chainConnectivityWarning} />}
</StyledPollingDot>{' '}
<StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
</StyledPolling>
</ExternalLink>
{chainConnectivityWarning && <ChainConnectivityWarning />}
{warning && <ChainConnectivityWarning />}
</RowFixed>
</>
)
}

View File

@@ -1,144 +0,0 @@
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
import { useMemo } from 'react'
import { X } from 'react-feather'
import styled from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { UNI } from '../../constants/tokens'
import { useMerkleDistributorContract } from '../../hooks/useContract'
import useCurrentBlockTimestamp from '../../hooks/useCurrentBlockTimestamp'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import useUSDCPrice from '../../hooks/useUSDCPrice'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTotalUniEarned } from '../../state/stake/hooks'
import { useAggregateUniBalance, useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, StyledInternalLink, TYPE, UniTokenAnimated } from '../../theme'
import { computeUniCirculation } from '../../utils/computeUniCirculation'
import { AutoColumn } from '../Column'
import { Break, CardBGImage, CardNoise, CardSection, DataCard } from '../earn/styled'
import { RowBetween } from '../Row'
const ContentWrapper = styled(AutoColumn)`
width: 100%;
`
const ModalUpper = styled(DataCard)`
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
background: radial-gradient(76.02% 75.41% at 1.84% 0%, #ff007a 0%, #021d43 100%);
padding: 0.5rem;
`
const StyledClose = styled(X)`
position: absolute;
right: 16px;
top: 16px;
:hover {
cursor: pointer;
}
`
/**
* Content for balance stats modal
*/
export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowUniBalanceModal: any }) {
const { account, chainId } = useActiveWeb3React()
const uni = chainId ? UNI[chainId] : undefined
const total = useAggregateUniBalance()
const uniBalance: CurrencyAmount<Token> | undefined = useTokenBalance(account ?? undefined, uni)
const uniToClaim: CurrencyAmount<Token> | undefined = useTotalUniEarned()
const totalSupply: CurrencyAmount<Token> | undefined = useTotalSupply(uni)
const uniPrice = useUSDCPrice(uni)
const blockTimestamp = useCurrentBlockTimestamp()
const unclaimedUni = useTokenBalance(useMerkleDistributorContract()?.address, uni)
const circulation: CurrencyAmount<Token> | undefined = useMemo(
() =>
blockTimestamp && uni && chainId === 1 ? computeUniCirculation(uni, blockTimestamp, unclaimedUni) : totalSupply,
[blockTimestamp, chainId, totalSupply, unclaimedUni, uni]
)
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
return (
<ContentWrapper gap="lg">
<ModalUpper>
<CardBGImage />
<CardNoise />
<CardSection gap="md">
<RowBetween>
<TYPE.white color="white">
<Trans>Your UNI Breakdown</Trans>
</TYPE.white>
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
</RowBetween>
</CardSection>
<Break />
{account && (
<>
<CardSection gap="sm">
<AutoColumn gap="md" justify="center">
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
<TYPE.white fontSize={48} fontWeight={600} color="white">
{total?.toFixed(2, { groupSeparator: ',' })}
</TYPE.white>
</AutoColumn>
<AutoColumn gap="md">
<RowBetween>
<TYPE.white color="white">
<Trans>Balance:</Trans>
</TYPE.white>
<TYPE.white color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</TYPE.white>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<Trans>Unclaimed:</Trans>
</TYPE.white>
<TYPE.white color="white">
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
{uniToClaim && uniToClaim.greaterThan('0') && (
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
<Trans>(claim)</Trans>
</StyledInternalLink>
)}
</TYPE.white>
</RowBetween>
</AutoColumn>
</CardSection>
<Break />
</>
)}
<CardSection gap="sm">
<AutoColumn gap="md">
<RowBetween>
<TYPE.white color="white">
<Trans>UNI price:</Trans>
</TYPE.white>
<TYPE.white color="white">${uniPrice?.toFixed(2) ?? '-'}</TYPE.white>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<Trans>UNI in circulation:</Trans>
</TYPE.white>
<TYPE.white color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
</RowBetween>
<RowBetween>
<TYPE.white color="white">
<Trans>Total Supply</Trans>
</TYPE.white>
<TYPE.white color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
</RowBetween>
{uni && uni.chainId === 1 ? (
<ExternalLink href={`${infoLink}/token/${uni.address}`}>
<Trans>View UNI Analytics</Trans>
</ExternalLink>
) : null}
</AutoColumn>
</CardSection>
</ModalUpper>
</ContentWrapper>
)
}

View File

@@ -1,30 +1,29 @@
import { Trans } from '@lingui/macro'
import useScrollPosition from '@react-hook/window-scroll'
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
import { CHAIN_INFO } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useTheme from 'hooks/useTheme'
import { darken } from 'polished'
import { useState } from 'react'
import { NavLink } from 'react-router-dom'
import { Text } from 'rebass'
import { useShowClaimPopup, useToggleSelfClaimModal } from 'state/application/hooks'
import { useUserHasAvailableClaim } from 'state/claim/hooks'
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
import { useDarkModeManager } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import { useNativeCurrencyBalances } from 'state/wallet/hooks'
import styled from 'styled-components/macro'
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import ClaimModal from '../claim/ClaimModal'
import { CardNoise } from '../earn/styled'
import Menu from '../Menu'
import Modal from '../Modal'
import Row from '../Row'
import { Dots } from '../swap/styleds'
import Web3Status from '../Web3Status'
import HolidayOrnament from './HolidayOrnament'
import NetworkSelector from './NetworkSelector'
import UniBalanceContent from './UniBalanceContent'
const HeaderFrame = styled.div<{ showBackground: boolean }>`
display: grid;
@@ -91,7 +90,7 @@ const HeaderLinks = styled(Row)`
justify-self: center;
background-color: ${({ theme }) => theme.bg0};
width: fit-content;
padding: 4px;
padding: 2px;
border-radius: 16px;
display: grid;
grid-auto-flow: column;
@@ -123,10 +122,11 @@ const AccountElement = styled.div<{ active: boolean }>`
display: flex;
flex-direction: row;
align-items: center;
background-color: ${({ theme, active }) => (!active ? theme.bg1 : theme.bg1)};
border-radius: 12px;
background-color: ${({ theme, active }) => (!active ? theme.bg0 : theme.bg0)};
border-radius: 16px;
white-space: nowrap;
width: 100%;
height: 40px;
:focus {
border: 1px solid blue;
@@ -181,6 +181,8 @@ const UniIcon = styled.div`
:hover {
transform: rotate(-5deg);
}
position: relative;
`
const activeClassName = 'ACTIVE'
@@ -202,11 +204,11 @@ const StyledNavLink = styled(NavLink).attrs({
overflow: hidden;
white-space: nowrap;
&.${activeClassName} {
border-radius: 12px;
border-radius: 14px;
font-weight: 600;
justify-content: center;
color: ${({ theme }) => theme.text1};
background-color: ${({ theme }) => theme.bg2};
background-color: ${({ theme }) => theme.bg1};
}
:hover,
@@ -231,7 +233,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
font-weight: 500;
&.${activeClassName} {
border-radius: 12px;
border-radius: 14px;
font-weight: 600;
color: ${({ theme }) => theme.text1};
}
@@ -246,7 +248,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
export default function Header() {
const { account, chainId } = useActiveWeb3React()
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
const userEthBalance = useNativeCurrencyBalances(account ? [account] : [])?.[account ?? '']
const [darkMode] = useDarkModeManager()
const { white, black } = useTheme()
@@ -256,21 +258,24 @@ export default function Header() {
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
const [showUniBalanceModal, setShowUniBalanceModal] = useState(false)
const showClaimPopup = useShowClaimPopup()
const scrollY = useScrollPosition()
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
const {
infoLink,
addNetworkInfo: {
nativeCurrency: { symbol: nativeCurrencySymbol },
},
} = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
return (
<HeaderFrame showBackground={scrollY > 45}>
<ClaimModal />
<Modal isOpen={showUniBalanceModal} onDismiss={() => setShowUniBalanceModal(false)}>
<UniBalanceContent setShowUniBalanceModal={setShowUniBalanceModal} />
</Modal>
<Title href=".">
<UniIcon>
<Logo fill={darkMode ? white : black} width="24px" height="100%" title="logo" />
<HolidayOrnament />
</UniIcon>
</Title>
<HeaderLinks>
@@ -309,7 +314,7 @@ export default function Header() {
{availableClaim && !showClaimPopup && (
<UNIWrapper onClick={toggleClaimModal}>
<UNIAmount active={!!account && !availableClaim} style={{ pointerEvents: 'auto' }}>
<TYPE.white padding="0 2px">
<ThemedText.White padding="0 2px">
{claimTxn && !claimTxn?.receipt ? (
<Dots>
<Trans>Claiming UNI</Trans>
@@ -317,7 +322,7 @@ export default function Header() {
) : (
<Trans>Claim UNI</Trans>
)}
</TYPE.white>
</ThemedText.White>
</UNIAmount>
<CardNoise />
</UNIWrapper>
@@ -325,7 +330,9 @@ export default function Header() {
<AccountElement active={!!account}>
{account && userEthBalance ? (
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
<Trans>{userEthBalance?.toSignificant(3)} ETH</Trans>
<Trans>
{userEthBalance?.toSignificant(3)} {nativeCurrencySymbol}
</Trans>
</BalanceText>
) : null}
<Web3Status />

View File

@@ -2,9 +2,15 @@ import Tooltip from 'components/Tooltip'
import { useState } from 'react'
import styled from 'styled-components/macro'
const TextWrapper = styled.span<{ margin: boolean; link?: boolean; fontSize?: string; adjustSize?: boolean }>`
const TextWrapper = styled.span<{
margin: boolean
link?: boolean
fontSize?: string
adjustSize?: boolean
textColor?: string
}>`
margin-left: ${({ margin }) => margin && '4px'};
color: ${({ theme, link }) => (link ? theme.blue1 : theme.text1)};
color: ${({ theme, link, textColor }) => (link ? theme.blue1 : textColor ?? theme.text1)};
font-size: ${({ fontSize }) => fontSize ?? 'inherit'};
@media screen and (max-width: 600px) {
@@ -18,6 +24,7 @@ const HoverInlineText = ({
margin = false,
adjustSize = false,
fontSize,
textColor,
link,
...rest
}: {
@@ -26,6 +33,7 @@ const HoverInlineText = ({
margin?: boolean
adjustSize?: boolean
fontSize?: string
textColor?: string
link?: boolean
}) => {
const [showHover, setShowHover] = useState(false)
@@ -42,6 +50,7 @@ const HoverInlineText = ({
onMouseLeave={() => setShowHover(false)}
margin={margin}
adjustSize={adjustSize}
textColor={textColor}
link={link}
fontSize={fontSize}
{...rest}
@@ -53,7 +62,14 @@ const HoverInlineText = ({
}
return (
<TextWrapper margin={margin} adjustSize={adjustSize} link={link} fontSize={fontSize} {...rest}>
<TextWrapper
margin={margin}
adjustSize={adjustSize}
link={link}
fontSize={fontSize}
textColor={textColor}
{...rest}
>
{text}
</TextWrapper>
)

View File

@@ -0,0 +1,26 @@
import { AbstractConnector } from '@web3-react/abstract-connector'
import { Connector } from 'widgets-web3-react/types'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
import PortisIcon from '../../assets/images/portisIcon.png'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
import Identicon from '../Identicon'
export default function StatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
switch (connector) {
case injected:
return <Identicon />
case walletconnect:
return <img src={WalletConnectIcon} alt={'WalletConnect'} />
case walletlink:
return <img src={CoinbaseWalletIcon} alt={'Coinbase Wallet'} />
case fortmatic:
return <img src={FortmaticIcon} alt={'Fortmatic'} />
case portis:
return <img src={PortisIcon} alt={'Portis'} />
default:
return null
}
}

View File

@@ -1,32 +1,52 @@
import Davatar, { Image } from '@davatar/react'
import { useMemo } from 'react'
import jazzicon from '@metamask/jazzicon'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useENSAvatar from 'hooks/useENSAvatar'
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components/macro'
import { useActiveWeb3React } from '../../hooks/web3'
const StyledIdenticonContainer = styled.div`
const StyledIdenticon = styled.div`
height: 1rem;
width: 1rem;
border-radius: 1.125rem;
background-color: ${({ theme }) => theme.bg4};
font-size: initial;
`
const StyledAvatar = styled.img`
height: inherit;
width: inherit;
border-radius: inherit;
`
export default function Identicon() {
const { account, library } = useActiveWeb3React()
const { account } = useActiveWeb3React()
const { avatar } = useENSAvatar(account ?? undefined)
const [fetchable, setFetchable] = useState(true)
// restrict usage of Davatar until it stops sending 3p requests
// see https://github.com/metaphor-xyz/davatar-helpers/issues/18
const supportsENS = useMemo(() => {
return ([1, 3, 4, 5] as Array<number | undefined>).includes(library?.network?.chainId)
}, [library])
const icon = useMemo(() => account && jazzicon(16, parseInt(account.slice(2, 10), 16)), [account])
const iconRef = useRef<HTMLDivElement>(null)
useLayoutEffect(() => {
const current = iconRef.current
if (icon) {
current?.appendChild(icon)
return () => {
try {
current?.removeChild(icon)
} catch (e) {
console.error('Avatar icon not found')
}
}
}
return
}, [icon, iconRef])
return (
<StyledIdenticonContainer>
{account && supportsENS ? (
<Davatar address={account} size={16} provider={library} />
<StyledIdenticon>
{avatar && fetchable ? (
<StyledAvatar alt="avatar" src={avatar} onError={() => setFetchable(false)}></StyledAvatar>
) : (
<Image address={account} size={16} />
<span ref={iconRef} />
)}
</StyledIdenticonContainer>
</StyledIdenticon>
)
}

View File

@@ -6,7 +6,7 @@ import { AutoColumn } from 'components/Column'
import { ReactNode, useCallback, useEffect, useState } from 'react'
import { Minus, Plus } from 'react-feather'
import styled, { keyframes } from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import { Input as NumericalInput } from '../NumericalInput'
@@ -57,13 +57,13 @@ const StyledInput = styled(NumericalInput)<{ usePercent?: boolean }>`
`};
`
const InputTitle = styled(TYPE.small)`
const InputTitle = styled(ThemedText.Small)`
color: ${({ theme }) => theme.text2};
font-size: 12px;
font-weight: 500;
`
const ButtonLabel = styled(TYPE.white)<{ disabled: boolean }>`
const ButtonLabel = styled(ThemedText.White)<{ disabled: boolean }>`
color: ${({ theme, disabled }) => (disabled ? theme.text2 : theme.text1)} !important;
`

View File

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

View File

@@ -1,16 +1,10 @@
import { Currency } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
import JSBI from 'jsbi'
import { TickProcessed, usePoolActiveLiquidity } from 'hooks/usePoolTickData'
import { useCallback, useMemo } from 'react'
import { ChartEntry } from './types'
export interface TickProcessed {
liquidityActive: JSBI
price0: string
}
export function useDensityChartData({
currencyA,
currencyB,

View File

@@ -14,12 +14,18 @@ import { batch } from 'react-redux'
import { Bound } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { Chart } from './Chart'
import { useDensityChartData } from './hooks'
import { ZoomLevels } from './types'
const ZOOM_LEVELS: Record<FeeAmount, ZoomLevels> = {
[FeeAmount.LOWEST]: {
initialMin: 0.999,
initialMax: 1.001,
min: 0.00001,
max: 1.5,
},
[FeeAmount.LOW]: {
initialMin: 0.999,
initialMax: 1.001,
@@ -52,9 +58,9 @@ function InfoBox({ message, icon }: { message?: ReactNode; icon: ReactNode }) {
<ColumnCenter style={{ height: '100%', justifyContent: 'center' }}>
{icon}
{message && (
<TYPE.mediumHeader padding={10} marginTop="20px" textAlign="center">
<ThemedText.MediumHeader padding={10} marginTop="20px" textAlign="center">
{message}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
)}
</ColumnCenter>
)

View File

@@ -1,22 +1,23 @@
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
import { L2_CHAIN_IDS } from 'constants/chains'
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
import { useActiveLocale } from 'hooks/useActiveLocale'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
import React, { useEffect, useRef, useState } from 'react'
import {
BookOpen,
Check,
ChevronLeft,
Code,
Coffee,
FileText,
Globe,
HelpCircle,
Info,
MessageCircle,
Moon,
PieChart,
Sun,
} from 'react-feather'
import { Link } from 'react-router-dom'
@@ -25,7 +26,6 @@ import styled, { css } from 'styled-components/macro'
import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { useActiveWeb3React } from '../../hooks/web3'
import { useModalOpen, useToggleModal } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { ExternalLink } from '../../theme'
@@ -49,12 +49,11 @@ const StyledMenuButton = styled.button`
background-color: transparent;
margin: 0;
padding: 0;
height: 38px;
height: 40px;
background-color: ${({ theme }) => theme.bg0};
border: 1px solid ${({ theme }) => theme.bg0};
padding: 0.15rem 0.5rem;
border-radius: 12px;
border-radius: 16px;
:hover,
:focus {
@@ -179,8 +178,6 @@ const ToggleMenuItem = styled.button`
}
`
const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface'
function LanguageMenuItem({ locale, active, key }: { locale: SupportedLocale; active: boolean; key: string }) {
const { to, onClick } = useLocationLinkProps(locale)
@@ -219,7 +216,6 @@ export default function Menu() {
const togglePrivacyPolicy = useToggleModal(ApplicationModal.PRIVACY_POLICY)
const openClaimModal = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
const showUNIClaimOption = Boolean(!!account && !!chainId && !L2_CHAIN_IDS.includes(chainId))
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
const [darkMode, toggleDarkMode] = useDarkModeManager()
@@ -252,17 +248,17 @@ export default function Menu() {
</div>
<Info opacity={0.6} size={16} />
</MenuItem>
<MenuItem href="https://docs.uniswap.org/">
<MenuItem href="https://help.uniswap.org/">
<div>
<Trans>Docs</Trans>
<Trans>Help Center</Trans>
</div>
<BookOpen opacity={0.6} size={16} />
<HelpCircle opacity={0.6} size={16} />
</MenuItem>
<MenuItem href={CODE_LINK}>
<MenuItem href="https://uniswap.canny.io/feature-requests">
<div>
<Trans>Code</Trans>
<Trans>Request Features</Trans>
</div>
<Code opacity={0.6} size={16} />
<Coffee opacity={0.6} size={16} />
</MenuItem>
<MenuItem href="https://discord.gg/FCfyBSbCU5">
<div>
@@ -270,12 +266,6 @@ export default function Menu() {
</div>
<MessageCircle opacity={0.6} size={16} />
</MenuItem>
<MenuItem href={infoLink}>
<div>
<Trans>Analytics</Trans>
</div>
<PieChart opacity={0.6} size={16} />
</MenuItem>
<ToggleMenuItem onClick={() => setMenu('lang')}>
<div>
<Trans>Language</Trans>
@@ -286,6 +276,12 @@ export default function Menu() {
<div>{darkMode ? <Trans>Light Theme</Trans> : <Trans>Dark Theme</Trans>}</div>
{darkMode ? <Moon opacity={0.6} size={16} /> : <Sun opacity={0.6} size={16} />}
</ToggleMenuItem>
<MenuItem href="https://docs.uniswap.org/">
<div>
<Trans>Docs</Trans>
</div>
<BookOpen opacity={0.6} size={16} />
</MenuItem>
<ToggleMenuItem onClick={() => togglePrivacyPolicy()}>
<div>
<Trans>Legal & Privacy</Trans>

View File

@@ -1,11 +1,11 @@
import { Trans } from '@lingui/macro'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useContext } from 'react'
import { ArrowUpCircle } from 'react-feather'
import styled, { ThemeContext } from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import { useActiveWeb3React } from '../../hooks/web3'
import { CloseIcon, CustomLightSpinner, TYPE } from '../../theme'
import { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
import { ExternalLink } from '../../theme/components'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { AutoColumn, ColumnCenter } from '../Column'
@@ -32,9 +32,9 @@ export function LoadingView({ children, onDismiss }: { children: any; onDismiss:
</ConfirmedIcon>
<AutoColumn gap="100px" justify={'center'}>
{children}
<TYPE.subHeader>
<ThemedText.SubHeader>
<Trans>Confirm this transaction in your wallet</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</AutoColumn>
</ConfirmOrLoadingWrapper>
)
@@ -68,9 +68,9 @@ export function SubmittedView({
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
style={{ marginLeft: '4px' }}
>
<TYPE.subHeader>
<ThemedText.SubHeader>
<Trans>View transaction on Explorer</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</ExternalLink>
)}
</AutoColumn>

View File

@@ -10,7 +10,7 @@ import { useAppDispatch } from 'state/hooks'
import { resetMintState } from 'state/mint/actions'
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText } from 'theme'
import Row, { RowBetween } from '../Row'
import SettingsTab from '../Settings'
@@ -136,7 +136,7 @@ export function AddRemoveTabs({
>
<StyledArrowLeft stroke={theme.text2} />
</StyledHistoryLink>
<TYPE.mediumHeader
<ThemedText.MediumHeader
fontWeight={500}
fontSize={20}
style={{ flex: '1', margin: 'auto', textAlign: children ? 'start' : 'center' }}
@@ -148,7 +148,7 @@ export function AddRemoveTabs({
) : (
<Trans>Remove Liquidity</Trans>
)}
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
<Box style={{ marginRight: '.5rem' }}>{children}</Box>
<SettingsTab placeholderSlippage={defaultSlippage} />
</RowBetween>

View File

@@ -1,157 +1,93 @@
import { Trans } from '@lingui/macro'
import {
ARBITRUM_HELP_CENTER_LINK,
L2_CHAIN_IDS,
OPTIMISM_HELP_CENTER_LINK,
SupportedChainId,
SupportedL2ChainId,
} from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import { useCallback, useState } from 'react'
import { ArrowDownCircle, X } from 'react-feather'
import { useArbitrumAlphaAlert, useDarkModeManager, useOptimismAlphaAlert } from 'state/user/hooks'
import { useETHBalances } from 'state/wallet/hooks'
import styled, { css } from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
import { CHAIN_INFO } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { ArrowUpRight } from 'react-feather'
import { useDarkModeManager } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, HideSmall } from 'theme'
import { CHAIN_INFO } from '../../constants/chains'
export const DesktopTextBreak = styled.div`
display: none;
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
display: block;
}
`
import { AutoRow } from '../Row'
const L2Icon = styled.img`
width: 36px;
height: 36px;
justify-self: center;
width: 24px;
height: 24px;
margin-right: 16px;
`
const BetaTag = styled.span<{ color: string }>`
align-items: center;
background-color: ${({ color }) => color};
border-radius: 6px;
color: ${({ theme }) => theme.white};
display: flex;
font-size: 14px;
height: 28px;
justify-content: center;
left: -16px;
position: absolute;
transform: rotate(-15deg);
top: -16px;
width: 60px;
z-index: 1;
`
const Body = styled.p`
font-size: 12px;
grid-column: 1 / 3;
line-height: 143%;
margin: 0;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-column: 2 / 3;
}
`
export const Controls = styled.div<{ thin?: boolean }>`
export const Controls = styled.div`
align-items: center;
display: flex;
justify-content: flex-start;
${({ thin }) =>
thin &&
css`
margin: auto 32px auto 0;
`}
`
const CloseIcon = styled(X)`
cursor: pointer;
position: absolute;
top: 16px;
right: 16px;
padding: 0 20px 20px 20px;
`
const BodyText = styled.div`
align-items: center;
display: grid;
grid-gap: 4px;
grid-template-columns: 40px 4fr;
grid-template-rows: auto auto;
margin: 20px 16px;
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
grid-template-columns: 42px 4fr;
grid-gap: 8px;
}
`
const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
align-items: center;
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 8px;
color: ${({ theme }) => theme.text1};
color: ${({ color }) => color};
display: flex;
font-size: 16px;
height: 44px;
justify-content: space-between;
margin: 0 0 20px 0;
padding: 12px 16px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: rgba(255, 255, 255, 0.05);
}
transition: background-color 150ms ease-in-out;
${({ thin }) =>
thin &&
css`
font-size: 14px;
margin: auto;
width: 112px;
`}
align-items: center;
justify-content: flex-start;
margin: 8px;
font-size: 14px;
`
const RootWrapper = styled.div`
position: relative;
margin-top: 16px;
`
export const ArbitrumWrapperBackgroundDarkMode = css`
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.3) 0%, rgba(33, 114, 229, 0.3) 100%), hsla(0, 0%, 100%, 0.1);
`
export const ArbitrumWrapperBackgroundLightMode = css`
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1);
`
export const OptimismWrapperBackgroundDarkMode = css`
background: radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%),
radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.5) 0%, rgba(235, 0, 255, 0.345) 96%);
`
export const OptimismWrapperBackgroundLightMode = css`
background: radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),
radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.5);
`
const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string; thin?: boolean }>`
${({ chainId, darkMode }) =>
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
? darkMode
? OptimismWrapperBackgroundDarkMode
: OptimismWrapperBackgroundLightMode
: darkMode
? ArbitrumWrapperBackgroundDarkMode
: ArbitrumWrapperBackgroundLightMode};
const SHOULD_SHOW_ALERT = {
[SupportedChainId.OPTIMISM]: true,
[SupportedChainId.OPTIMISTIC_KOVAN]: true,
[SupportedChainId.ARBITRUM_ONE]: true,
[SupportedChainId.ARBITRUM_RINKEBY]: true,
[SupportedChainId.POLYGON]: true,
[SupportedChainId.POLYGON_MUMBAI]: true,
}
type NetworkAlertChains = keyof typeof SHOULD_SHOW_ALERT
const BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID: {
[darkMode in 'dark' | 'light']: { [chainId in NetworkAlertChains]: string }
} = {
dark: {
[SupportedChainId.POLYGON]:
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
[SupportedChainId.POLYGON_MUMBAI]:
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
[SupportedChainId.OPTIMISM]:
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.01) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.01) 0%, rgba(235, 0, 255, 0.01) 96%)',
[SupportedChainId.OPTIMISTIC_KOVAN]:
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.04) 0%, rgba(235, 0, 255, 0.01 96%)',
[SupportedChainId.ARBITRUM_ONE]:
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.01) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.05) 100%), hsla(0, 0%, 100%, 0.05)',
[SupportedChainId.ARBITRUM_RINKEBY]:
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.05) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.1) 100%), hsla(0, 0%, 100%, 0.05)',
},
light: {
[SupportedChainId.POLYGON]:
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
[SupportedChainId.POLYGON_MUMBAI]:
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
[SupportedChainId.OPTIMISM]:
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
[SupportedChainId.OPTIMISTIC_KOVAN]:
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
[SupportedChainId.ARBITRUM_ONE]:
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
[SupportedChainId.ARBITRUM_RINKEBY]:
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
},
}
const ContentWrapper = styled.div<{ chainId: NetworkAlertChains; darkMode: boolean; logoUrl: string }>`
background: ${({ chainId, darkMode }) => BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID[darkMode ? 'dark' : 'light'][chainId]};
border-radius: 20px;
display: flex;
flex-direction: column;
max-width: 480px;
min-height: 174px;
flex-direction: row;
overflow: hidden;
position: relative;
width: 100%;
${({ thin }) =>
thin &&
css`
flex-direction: row;
max-width: max-content;
min-height: min-content;
`}
:before {
background-image: url(${({ logoUrl }) => logoUrl});
background-repeat: no-repeat;
@@ -165,116 +101,73 @@ const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean
z-index: -1;
}
`
const Header = styled.h2<{ thin?: boolean }>`
const Header = styled.h2`
font-weight: 600;
font-size: 20px;
font-size: 16px;
margin: 0;
padding-right: 30px;
display: ${({ thin }) => (thin ? 'none' : 'block')};
`
const LinkOutCircle = styled(ArrowDownCircle)`
margin-left: 12px;
transform: rotate(230deg);
width: 20px;
height: 20px;
`
const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
const LinkOutToBridge = styled(ExternalLink)`
align-items: center;
background-color: black;
border-radius: 8px;
color: white;
display: flex;
font-size: 16px;
height: 44px;
justify-content: space-between;
margin: 0 12px 20px 18px;
padding: 12px 16px;
text-decoration: none;
width: auto;
:hover,
:focus,
:active {
background-color: black;
}
${({ thin }) =>
thin &&
css`
font-size: 14px;
margin: auto 10px;
width: 168px;
`}
padding: 6px 8px;
margin-right: 12px;
text-decoration: none !important;
width: 100%;
`
interface NetworkAlertProps {
thin?: boolean
const StyledArrowUpRight = styled(ArrowUpRight)`
margin-left: 12px;
width: 24px;
height: 24px;
`
const TEXT_COLORS: { [chainId in NetworkAlertChains]: string } = {
[SupportedChainId.POLYGON]: 'rgba(130, 71, 229)',
[SupportedChainId.POLYGON_MUMBAI]: 'rgba(130, 71, 229)',
[SupportedChainId.OPTIMISM]: '#ff3856',
[SupportedChainId.OPTIMISTIC_KOVAN]: '#ff3856',
[SupportedChainId.ARBITRUM_ONE]: '#0490ed',
[SupportedChainId.ARBITRUM_RINKEBY]: '#0490ed',
}
export function NetworkAlert(props: NetworkAlertProps) {
const { account, chainId } = useActiveWeb3React()
function shouldShowAlert(chainId: number | undefined): chainId is NetworkAlertChains {
return Boolean(chainId && SHOULD_SHOW_ALERT[chainId as unknown as NetworkAlertChains])
}
export function NetworkAlert() {
const { chainId } = useActiveWeb3React()
const [darkMode] = useDarkModeManager()
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
const [optimismAlphaAcknowledged, setOptimismAlphaAcknowledged] = useOptimismAlphaAlert()
const [locallyDismissed, setLocallyDimissed] = useState(false)
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
const dismiss = useCallback(() => {
if (userEthBalance?.greaterThan(0)) {
switch (chainId) {
case SupportedChainId.OPTIMISM:
setOptimismAlphaAcknowledged(true)
break
case SupportedChainId.ARBITRUM_ONE:
setArbitrumAlphaAcknowledged(true)
break
}
} else {
setLocallyDimissed(true)
}
}, [chainId, setArbitrumAlphaAcknowledged, setOptimismAlphaAcknowledged, userEthBalance])
const onOptimismAndOptimismAcknowledged = SupportedChainId.OPTIMISM === chainId && optimismAlphaAcknowledged
const onArbitrumAndArbitrumAcknowledged = SupportedChainId.ARBITRUM_ONE === chainId && arbitrumAlphaAcknowledged
if (
!chainId ||
!L2_CHAIN_IDS.includes(chainId) ||
onArbitrumAndArbitrumAcknowledged ||
onOptimismAndOptimismAcknowledged ||
locallyDismissed
) {
if (!shouldShowAlert(chainId)) {
return null
}
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
const showCloseIcon = Boolean(userEthBalance?.greaterThan(0) && !props.thin)
return (
const { label, logoUrl, bridge } = CHAIN_INFO[chainId]
const textColor = TEXT_COLORS[chainId]
return bridge ? (
<RootWrapper>
<BetaTag color={isOptimism ? '#ff0420' : '#0490ed'}>Beta</BetaTag>
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl} thin={props.thin}>
{showCloseIcon && <CloseIcon onClick={dismiss} />}
<BodyText>
<L2Icon src={info.logoUrl} />
<Header thin={props.thin}>
<Trans>Uniswap on {info.label}</Trans>
</Header>
<Body>
<Trans>
To 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 chainId={chainId} darkMode={darkMode} logoUrl={logoUrl}>
<LinkOutToBridge href={bridge}>
<BodyText color={textColor}>
<L2Icon src={logoUrl} />
<AutoRow>
<Header>
<Trans>{label} token bridge</Trans>
</Header>
<HideSmall>
<Trans>Deposit tokens to the {label} network.</Trans>
</HideSmall>
</AutoRow>
</BodyText>
<StyledArrowUpRight color={textColor} />
</LinkOutToBridge>
</ContentWrapper>
</RootWrapper>
)
) : null
}

View File

@@ -12,7 +12,7 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s
border: none;
flex: 1 1 auto;
background-color: ${({ theme }) => theme.bg1};
font-size: ${({ fontSize }) => fontSize ?? '24px'};
font-size: ${({ fontSize }) => fontSize ?? '28px'};
text-align: ${({ align }) => align && align};
white-space: nowrap;
overflow: hidden;

View File

@@ -1,11 +1,10 @@
import { Options, Placement } from '@popperjs/core'
import Portal from '@reach/portal'
import useInterval from 'lib/hooks/useInterval'
import React, { useCallback, useMemo, useState } from 'react'
import { usePopper } from 'react-popper'
import styled from 'styled-components/macro'
import useInterval from '../../hooks/useInterval'
const PopoverContainer = styled.div<{ show: boolean }>`
z-index: 9999;
visibility: ${(props) => (props.show ? 'visible' : 'hidden')};

View File

@@ -1,13 +1,12 @@
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useCallback, useEffect } from 'react'
import { Heart, X } from 'react-feather'
import ReactGA from 'react-ga'
import styled, { keyframes } from 'styled-components/macro'
import tokenLogo from '../../assets/images/token-logo.png'
import { ButtonPrimary } from '../../components/Button'
import { useActiveWeb3React } from '../../hooks/web3'
import {
useModalOpen,
useShowClaimPopup,
@@ -16,7 +15,8 @@ import {
} from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { ButtonPrimary } from '../Button'
import { AutoColumn } from '../Column'
import { CardBGImage, CardNoise } from '../earn/styled'
@@ -98,10 +98,10 @@ export default function ClaimPopup() {
<StyledClose stroke="white" onClick={toggleShowClaimPopup} />
<AutoColumn style={{ padding: '2rem 0', zIndex: 10 }} justify="center">
<UniToken width="48px" src={tokenLogo} />{' '}
<TYPE.white style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
<ThemedText.White style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI
</TYPE.white>
<TYPE.white style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
</ThemedText.White>
<ThemedText.White style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
<span role="img" aria-label="party">
🎉
</span>{' '}
@@ -109,12 +109,12 @@ export default function ClaimPopup() {
<span role="img" aria-label="party">
🎉
</span>
</TYPE.white>
<TYPE.subHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
</ThemedText.White>
<ThemedText.SubHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
<Trans>
Thanks for being part of the Uniswap community <Heart size={12} />
</Trans>
</TYPE.subHeader>
</ThemedText.SubHeader>
</AutoColumn>
<AutoColumn style={{ zIndex: 10 }} justify="center">
<ButtonPrimary padding="8px" $borderRadius="8px" width={'fit-content'} onClick={handleToggleSelfClaimModal}>

View File

@@ -0,0 +1,35 @@
import { Trans } from '@lingui/macro'
import { CHAIN_INFO } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { useContext } from 'react'
import { AlertCircle } from 'react-feather'
import styled, { ThemeContext } from 'styled-components/macro'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
import { AutoRow } from '../Row'
const RowNoFlex = styled(AutoRow)`
flex-wrap: nowrap;
`
export default function FailedNetworkSwitchPopup({ chainId }: { chainId: SupportedChainId }) {
const chainInfo = CHAIN_INFO[chainId]
const theme = useContext(ThemeContext)
return (
<RowNoFlex>
<div style={{ paddingRight: 16 }}>
<AlertCircle color={theme.red1} size={24} />
</div>
<AutoColumn gap="8px">
<ThemedText.Body fontWeight={500}>
<Trans>
Failed to switch networks from the Uniswap Interface. In order to use Uniswap on {chainInfo.label}, you must
change the network in your wallet.
</Trans>
</ThemedText.Body>
</AutoColumn>
</RowNoFlex>
)
}

View File

@@ -6,6 +6,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
import { useRemovePopup } from '../../state/application/hooks'
import { PopupContent } from '../../state/application/reducer'
import FailedNetworkSwitchPopup from './FailedNetworkSwitchPopup'
import TransactionPopup from './TransactionPopup'
const StyledClose = styled(X)`
@@ -77,6 +78,8 @@ export default function PopupItem({
txn: { hash },
} = content
popupContent = <TransactionPopup hash={hash} />
} else if ('failedSwitchNetwork' in content) {
popupContent = <FailedNetworkSwitchPopup chainId={content.failedSwitchNetwork} />
}
const faderStyle = useSpring({

View File

@@ -0,0 +1,106 @@
import { Trans } from '@lingui/macro'
import { AutoColumn } from 'components/Column'
import { RowFixed } from 'components/Row'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import { useEffect } from 'react'
import { MessageCircle, X } from 'react-feather'
import ReactGA from 'react-ga'
import { useShowSurveyPopup } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
import BGImage from '../../assets/images/survey-orb.svg'
import useTheme from '../../hooks/useTheme'
const Wrapper = styled(AutoColumn)`
background: #edeef2;
position: relative;
border-radius: 12px;
padding: 18px;
max-width: 360px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
color: ${({ theme }) => theme.text1};
overflow: hidden;
${({ theme }) => theme.mediaWidth.upToSmall`
max-width: 100%;
`}
`
const BGOrb = styled.img`
position: absolute;
right: -64px;
top: -64px;
width: 180px;
z-index: ${Z_INDEX.sticky};
`
const WrappedCloseIcon = styled(X)`
position: absolute;
top: 10px;
right: 10px;
width: 20px;
height: 20px;
stroke: #7c7c80;
z-index: ${Z_INDEX.fixed};
:hover {
cursor: pointer;
opacity: 0.8;
}
`
const END_TIMESTAMP = 1642272346 // Jan 15th
export default function SurveyPopup() {
const theme = useTheme()
const [showPopup, setShowSurveyPopup] = useShowSurveyPopup()
// show popup to 1% of users
useEffect(() => {
// has not visited page during A/B testing if undefined
if (showPopup === undefined) {
if (Math.random() < 0.01) {
setShowSurveyPopup(true)
// log a case of succesful view
ReactGA.event({
category: 'Survey',
action: 'Saw Survey',
})
}
}
}, [setShowSurveyPopup, showPopup])
// limit survey to 24 hours based on timestamps
const timestamp = useCurrentBlockTimestamp()
const durationOver = timestamp ? timestamp.toNumber() > END_TIMESTAMP : false
return (
<>
{!showPopup || durationOver ? null : (
<Wrapper gap="10px">
<WrappedCloseIcon
onClick={() => {
ReactGA.event({
category: 'Survey',
action: 'Clicked Survey Link',
})
setShowSurveyPopup(false)
}}
/>
<BGOrb src={BGImage} />
<ExternalLink href="https://www.surveymonkey.com/r/YGWV9VD">
<RowFixed>
<MessageCircle stroke={theme.black} size="20px" strokeWidth="1px" />
<ThemedText.White fontWeight={600} color={theme.black} ml="6px">
<Trans>Tell us what you think </Trans>
</ThemedText.White>
</RowFixed>
</ExternalLink>
<ThemedText.Black style={{ zIndex: Z_INDEX.fixed }} fontWeight={400} fontSize="12px" color={theme.black}>
<Trans>Take a 10 minute survey to help us improve your experience in the Uniswap app.</Trans>
</ThemedText.Black>
</Wrapper>
)}
</>
)
}

View File

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

View File

@@ -1,13 +1,14 @@
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import styled from 'styled-components/macro'
import { MEDIA_WIDTHS } from 'theme'
import { useActivePopups } from '../../state/application/hooks'
import { useURLWarningVisible } from '../../state/user/hooks'
import { useShowSurveyPopup, useURLWarningVisible } from '../../state/user/hooks'
import { AutoColumn } from '../Column'
import ClaimPopup from './ClaimPopup'
import PopupItem from './PopupItem'
import SurveyPopup from './SurveyPopup'
const MobilePopupWrapper = styled.div<{ height: string | number }>`
position: relative;
@@ -59,6 +60,9 @@ export default function Popups() {
// get all popups
const activePopups = useActivePopups()
// show survey popup if user has not closed
const [showSurveyPopup] = useShowSurveyPopup()
const urlWarningActive = useURLWarningVisible()
// need extra padding if network is not L1 Ethereum
@@ -69,12 +73,14 @@ export default function Popups() {
<>
<FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}>
<ClaimPopup />
<SurveyPopup />
{activePopups.map((item) => (
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
))}
</FixedPopupColumn>
<MobilePopupWrapper height={activePopups?.length > 0 ? 'fit-content' : 0}>
<MobilePopupWrapper height={activePopups?.length > 0 || showSurveyPopup ? 'fit-content' : 0}>
<MobilePopupInner>
<SurveyPopup />
{activePopups // reverse so new items up front
.slice(0)
.reverse()

View File

@@ -1,6 +1,7 @@
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import JSBI from 'jsbi'
import { transparentize } from 'polished'
import { useState } from 'react'
@@ -12,7 +13,6 @@ import styled from 'styled-components/macro'
import { BIG_INT_ZERO } from '../../constants/misc'
import { useColor } from '../../hooks/useColor'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'

View File

@@ -1,6 +1,7 @@
import { Trans } from '@lingui/macro'
import { CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import JSBI from 'jsbi'
import { transparentize } from 'polished'
import { useState } from 'react'
@@ -12,9 +13,8 @@ import styled from 'styled-components/macro'
import { BIG_INT_ZERO } from '../../constants/misc'
import { useColor } from '../../hooks/useColor'
import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useActiveWeb3React } from '../../hooks/web3'
import { useTokenBalance } from '../../state/wallet/hooks'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/unwrappedToken'
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
@@ -142,7 +142,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
</GreyCard>
) : (
<LightCard>
<TYPE.subHeader style={{ textAlign: 'center' }}>
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
<span role="img" aria-label="wizard-icon">
</span>{' '}
@@ -150,7 +150,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
By adding liquidity you&apos;ll earn 0.3% of all trades on this pair proportional to your share of the
pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
</Trans>{' '}
</TYPE.subHeader>
</ThemedText.SubHeader>
</LightCard>
)}
</>

View File

@@ -1,4 +1,5 @@
import { Trans } from '@lingui/macro'
import { ButtonText } from 'components/Button'
import PositionListItem from 'components/PositionListItem'
import React from 'react'
import styled from 'styled-components/macro'
@@ -14,9 +15,7 @@ const DesktopHeader = styled.div`
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
align-items: center;
display: flex;
display: grid;
grid-template-columns: 1fr 1fr;
justify-content: space-between;
& > div:last-child {
text-align: right;
margin-right: 12px;
@@ -36,9 +35,15 @@ const MobileHeader = styled.div`
type PositionListProps = React.PropsWithChildren<{
positions: PositionDetails[]
setUserHideClosedPositions: any
userHideClosedPositions: boolean
}>
export default function PositionList({ positions }: PositionListProps) {
export default function PositionList({
positions,
setUserHideClosedPositions,
userHideClosedPositions,
}: PositionListProps) {
return (
<>
<DesktopHeader>
@@ -46,9 +51,9 @@ export default function PositionList({ positions }: PositionListProps) {
<Trans>Your positions</Trans>
{positions && ' (' + positions.length + ')'}
</div>
<div>
<Trans>Status</Trans>
</div>
<ButtonText style={{ opacity: 0.6 }} onClick={() => setUserHideClosedPositions(!userHideClosedPositions)}>
<Trans>Hide closed positions</Trans>
</ButtonText>
</DesktopHeader>
<MobileHeader>
<Trans>Your positions</Trans>

View File

@@ -19,7 +19,7 @@ import { PositionDetails } from 'types/position'
import { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/unwrappedToken'
import { DAI, USDC, USDT, WBTC, WETH9_EXTENDED } from '../../constants/tokens'
import { DAI, USDC, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
const LinkRow = styled(Link)`
align-items: center;
@@ -156,7 +156,7 @@ export function getPriceOrderingFromPositionForUI(position?: Position): {
}
// if token1 is an ETH-/BTC-stable asset, set it as the base token
const bases = [...Object.values(WETH9_EXTENDED), WBTC]
const bases = [...Object.values(WRAPPED_NATIVE_CURRENCY), WBTC]
if (bases.some((base) => base.equals(token1))) {
return {
priceLower: position.token0PriceUpper.invert(),

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
import { Protocol } from '@uniswap/router-sdk'
import { Currency, Percent } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import { DAI, USDC, WBTC } from 'constants/tokens'
@@ -7,16 +8,21 @@ 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 singleRoute: RoutingDiagramEntry = {
percent: percent`100`,
path: [[USDC, DAI, FeeAmount.LOW]],
protocol: Protocol.V3,
}
const multiRoute: RoutingDiagramEntry[] = [
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOW]] },
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOWEST]], protocol: Protocol.V2 },
{
percent: percent`25`,
path: [
[USDC, WBTC, FeeAmount.MEDIUM],
[WBTC, DAI, FeeAmount.HIGH],
],
protocol: Protocol.V3,
},
]

View File

@@ -1,3 +1,5 @@
import { Trans } from '@lingui/macro'
import { Protocol } from '@uniswap/router-sdk'
import { Currency, Percent } from '@uniswap/sdk-core'
import { FeeAmount } from '@uniswap/v3-sdk'
import Badge from 'components/Badge'
@@ -7,24 +9,24 @@ import Row, { AutoRow } from 'components/Row'
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
import { Box } from 'rebass'
import styled from 'styled-components/macro'
import { TYPE } from 'theme'
import { ThemedText, Z_INDEX } from 'theme'
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
import { MouseoverTooltip } from '../Tooltip'
export interface RoutingDiagramEntry {
percent: Percent
path: [Currency, Currency, FeeAmount][]
protocol: Protocol
}
const Wrapper = styled(Box)`
align-items: center;
background-color: ${({ theme }) => theme.bg0};
width: 400px;
width: 100%;
`
const RouteContainerRow = styled(Row)`
display: grid;
grid-gap: 8px;
grid-template-columns: 24px 1fr 24px;
`
@@ -38,7 +40,7 @@ const RouteRow = styled(Row)`
const PoolBadge = styled(Badge)`
display: flex;
padding: 0.25rem 0.5rem;
padding: 4px 4px;
`
const DottedLine = styled.div`
@@ -58,7 +60,27 @@ const DotColor = styled(DotLine)`
const OpaqueBadge = styled(Badge)`
background-color: ${({ theme }) => theme.bg2};
z-index: 2;
border-radius: 8px;
display: grid;
font-size: 12px;
grid-gap: 4px;
grid-auto-flow: column;
justify-content: start;
padding: 4px 6px 4px 4px;
z-index: ${Z_INDEX.sticky};
`
const ProtocolBadge = styled(Badge)`
background-color: ${({ theme }) => theme.bg3};
border-radius: 4px;
color: ${({ theme }) => theme.text2};
font-size: 10px;
padding: 2px 4px;
z-index: ${Z_INDEX.sticky + 1};
`
const BadgeText = styled(ThemedText.Small)`
word-break: normal;
`
export default function RoutingDiagram({
@@ -75,29 +97,31 @@ export default function RoutingDiagram({
return (
<Wrapper>
{routes.map(({ percent, path }, index) => (
{routes.map((entry, index) => (
<RouteContainerRow key={index}>
<CurrencyLogo currency={tokenIn} />
<Route percent={percent} path={path} />
<CurrencyLogo currency={tokenOut} />
<CurrencyLogo currency={tokenIn} size={'20px'} />
<Route entry={entry} />
<CurrencyLogo currency={tokenOut} size={'20px'} />
</RouteContainerRow>
))}
</Wrapper>
)
}
function Route({ percent, path }: { percent: RoutingDiagramEntry['percent']; path: RoutingDiagramEntry['path'] }) {
function Route({ entry: { percent, path, protocol } }: { entry: RoutingDiagramEntry }) {
return (
<RouteRow>
<DottedLine>
<DotColor />
</DottedLine>
<OpaqueBadge>
<TYPE.small fontSize={12} style={{ wordBreak: 'normal' }}>
<ProtocolBadge>
<BadgeText fontSize={12}>{protocol.toUpperCase()}</BadgeText>
</ProtocolBadge>
<BadgeText fontSize={14} style={{ minWidth: 'auto' }}>
{percent.toSignificant(2)}%
</TYPE.small>
</BadgeText>
</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} />
@@ -111,12 +135,17 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren
const tokenInfo0 = useTokenInfoFromActiveList(currency0)
const tokenInfo1 = useTokenInfoFromActiveList(currency1)
// TODO - link pool icon to info.uniswap.org via query params
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>
<MouseoverTooltip
text={<Trans>{tokenInfo0?.symbol + '/' + tokenInfo1?.symbol + ' ' + feeAmount / 10000}% pool</Trans>}
>
<PoolBadge>
<Box margin="0 4px 0 12px">
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
</Box>
<ThemedText.Small fontSize={14}>{feeAmount / 10000}%</ThemedText.Small>
</PoolBadge>
</MouseoverTooltip>
)
}

View File

@@ -3,10 +3,10 @@
exports[`renders multi route 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
>
CurrencyLogo currency=USDC
<div
@@ -22,11 +22,20 @@ exports[`renders multi route 1`] = `
</svg>
</div>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
>
V2
</div>
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
style="min-width: auto;"
>
75%
</div>
@@ -36,26 +45,13 @@ exports[`renders multi route 1`] = `
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>
Popover
</div>
</div>
CurrencyLogo currency=DAI
</div>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
>
CurrencyLogo currency=USDC
<div
@@ -71,11 +67,20 @@ exports[`renders multi route 1`] = `
</svg>
</div>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
>
V3
</div>
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
style="min-width: auto;"
>
25%
</div>
@@ -85,34 +90,7 @@ exports[`renders multi route 1`] = `
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>
PopoverPopover
</div>
</div>
CurrencyLogo currency=DAI
@@ -124,10 +102,10 @@ exports[`renders multi route 1`] = `
exports[`renders single route 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
>
<div
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
>
CurrencyLogo currency=USDC
<div
@@ -143,11 +121,20 @@ exports[`renders single route 1`] = `
</svg>
</div>
<div
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
style="word-break: normal;"
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
>
V3
</div>
</div>
<div
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
style="min-width: auto;"
>
100%
</div>
@@ -157,20 +144,7 @@ exports[`renders single route 1`] = `
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>
Popover
</div>
</div>
CurrencyLogo currency=DAI
@@ -182,7 +156,7 @@ exports[`renders single route 1`] = `
exports[`renders when no routes are provided 1`] = `
<DocumentFragment>
<div
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
/>
</DocumentFragment>
`;

View File

@@ -3,7 +3,7 @@ import { Token } from '@uniswap/sdk-core'
import { ButtonPrimary } from 'components/Button'
import { AlertCircle, ArrowLeft } from 'react-feather'
import styled from 'styled-components/macro'
import { CloseIcon, TYPE } from 'theme'
import { CloseIcon, ThemedText } from 'theme'
import TokenImportCard from './TokenImportCard'
@@ -22,7 +22,7 @@ const Button = styled(ButtonPrimary)`
const Content = styled.div`
padding: 1em;
`
const Copy = styled(TYPE.body)`
const Copy = styled(ThemedText.Body)`
text-align: center;
margin: 0 2em 1em !important;
font-weight: 400;
@@ -51,9 +51,9 @@ const BlockedToken = ({ onBack, onDismiss, blockedTokens }: BlockedTokenProps) =
<Wrapper>
<Header>
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Token not supported</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
</Header>
<Icon />

View File

@@ -1,8 +1,6 @@
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import QuestionHelper from 'components/QuestionHelper'
import { AutoRow } from 'components/Row'
import { COMMON_BASES } from 'constants/routing'
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
@@ -46,12 +44,6 @@ export default function CommonBases({
return bases.length > 0 ? (
<MobileWrapper gap="md">
<AutoRow>
<Text fontWeight={500} fontSize={14}>
<Trans>Common bases</Trans>
</Text>
<QuestionHelper text={<Trans>These tokens are commonly paired with other tokens.</Trans>} />
</AutoRow>
<AutoRow gap="4px">
{bases.map((currency: Currency) => {
const isSelected = selectedCurrency?.equals(currency)

View File

@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { LightGreyCard } from 'components/Card'
import QuestionHelper from 'components/QuestionHelper'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useTheme from 'hooks/useTheme'
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
import { FixedSizeList } from 'react-window'
@@ -10,11 +11,10 @@ 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 { ThemedText } from '../../theme'
import { isTokenOnList } from '../../utils'
import Column from '../Column'
import CurrencyLogo from '../CurrencyLogo'
@@ -135,13 +135,13 @@ function CurrencyRow({
<Text title={currency.name} fontWeight={500}>
{currency.symbol}
</Text>
<TYPE.darkGray ml="0px" fontSize={'12px'} fontWeight={300}>
<ThemedText.DarkGray ml="0px" fontSize={'12px'} fontWeight={300}>
{!currency.isNative && !isOnSelectedList && customAdded ? (
<Trans>{currency.name} Added by user</Trans>
) : (
currency.name
)}
</TYPE.darkGray>
</ThemedText.DarkGray>
</Column>
<TokenTags currency={currency} />
{showCurrencyAmount && (
@@ -167,9 +167,9 @@ function BreakLineComponent({ style }: { style: CSSProperties }) {
<RowBetween>
<RowFixed>
<TokenListLogoWrapper src={TokenListLogo} />
<TYPE.main ml="6px" fontSize="12px" color={theme.text1}>
<ThemedText.Main ml="6px" fontSize="12px" color={theme.text1}>
<Trans>Expanded results from inactive Token Lists</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
<QuestionHelper
text={

View File

@@ -1,30 +1,31 @@
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { Currency, Token } from '@uniswap/sdk-core'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useDebounce from 'hooks/useDebounce'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useTheme from 'hooks/useTheme'
import useToggle from 'hooks/useToggle'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { getTokenFilter } from 'lib/hooks/useTokenList/filtering'
import { tokenComparator, useSortTokensByQuery } from 'lib/hooks/useTokenList/sorting'
import { KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Edit } from 'react-feather'
import ReactGA from 'react-ga'
import AutoSizer from 'react-virtualized-auto-sizer'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import { useAllTokenBalances } from 'state/wallet/hooks'
import styled from 'styled-components/macro'
import { ExtendedEther } from '../../constants/tokens'
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
import { useActiveWeb3React } from '../../hooks/web3'
import { ButtonText, CloseIcon, IconWrapper, TYPE } from '../../theme'
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
import { isAddress } from '../../utils'
import Column from '../Column'
import Row, { RowBetween, RowFixed } from '../Row'
import CommonBases from './CommonBases'
import CurrencyList from './CurrencyList'
import { filterTokens, useSortedTokensByQuery } from './filtering'
import ImportRow from './ImportRow'
import { useTokenComparator } from './sorting'
import { PaddedColumn, SearchInput, Separator } from './styleds'
const ContentWrapper = styled(Column)`
@@ -79,8 +80,6 @@ export function CurrencySearch({
const [searchQuery, setSearchQuery] = useState<string>('')
const debouncedQuery = useDebounce(searchQuery, 200)
const [invertSearchOrder] = useState<boolean>(false)
const allTokens = useAllTokens()
// if they input an address, use it
@@ -100,27 +99,28 @@ export function CurrencySearch({
}
}, [isAddressSearch])
const tokenComparator = useTokenComparator(invertSearchOrder)
const filteredTokens: Token[] = useMemo(() => {
return filterTokens(Object.values(allTokens), debouncedQuery)
return Object.values(allTokens).filter(getTokenFilter(debouncedQuery))
}, [allTokens, debouncedQuery])
const balances = useAllTokenBalances()
const sortedTokens: Token[] = useMemo(() => {
return filteredTokens.sort(tokenComparator)
}, [filteredTokens, tokenComparator])
return filteredTokens.sort(tokenComparator.bind(null, balances))
}, [balances, filteredTokens])
const filteredSortedTokens = useSortedTokensByQuery(sortedTokens, debouncedQuery)
const filteredSortedTokens = useSortTokensByQuery(debouncedQuery, sortedTokens)
const ether = useMemo(() => chainId && ExtendedEther.onChain(chainId), [chainId])
const native = useNativeCurrency()
const filteredSortedTokensWithETH: Currency[] = useMemo(() => {
if (!native) return filteredSortedTokens
const s = debouncedQuery.toLowerCase().trim()
if (s === '' || s === 'e' || s === 'et' || s === 'eth') {
return ether ? [ether, ...filteredSortedTokens] : filteredSortedTokens
if (native.symbol?.toLowerCase()?.indexOf(s) !== -1) {
return native ? [native, ...filteredSortedTokens] : filteredSortedTokens
}
return filteredSortedTokens
}, [debouncedQuery, ether, filteredSortedTokens])
}, [debouncedQuery, native, filteredSortedTokens])
const handleCurrencySelect = useCallback(
(currency: Currency) => {
@@ -148,8 +148,8 @@ export function CurrencySearch({
(e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
const s = debouncedQuery.toLowerCase().trim()
if (s === 'eth' && ether) {
handleCurrencySelect(ether)
if (s === native?.symbol?.toLowerCase()) {
handleCurrencySelect(native)
} else if (filteredSortedTokensWithETH.length > 0) {
if (
filteredSortedTokensWithETH[0].symbol?.toLowerCase() === debouncedQuery.trim().toLowerCase() ||
@@ -160,7 +160,7 @@ export function CurrencySearch({
}
}
},
[debouncedQuery, ether, filteredSortedTokensWithETH, handleCurrencySelect]
[debouncedQuery, native, filteredSortedTokensWithETH, handleCurrencySelect]
)
// menu ui
@@ -224,9 +224,9 @@ export function CurrencySearch({
</div>
) : (
<Column style={{ padding: '20px', height: '100%' }}>
<TYPE.main color={theme.text3} textAlign="center" mb="20px">
<ThemedText.Main color={theme.text3} textAlign="center" mb="20px">
<Trans>No results found.</Trans>
</TYPE.main>
</ThemedText.Main>
</Column>
)}
<Footer>
@@ -236,9 +236,9 @@ export function CurrencySearch({
<IconWrapper size="16px" marginRight="6px" stroke={theme.primaryText1}>
<Edit />
</IconWrapper>
<TYPE.main color={theme.primaryText1}>
<ThemedText.Main color={theme.primaryText1}>
<Trans>Manage Token Lists</Trans>
</TYPE.main>
</ThemedText.Main>
</RowFixed>
</ButtonText>
</Row>

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ import useTheme from 'hooks/useTheme'
import { AlertCircle, ArrowLeft } from 'react-feather'
import { useAddUserToken } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { CloseIcon, TYPE } from 'theme'
import { CloseIcon, ThemedText } from 'theme'
import BlockedToken from './BlockedToken'
import { PaddedColumn } from './styleds'
@@ -47,9 +47,9 @@ export function ImportToken(props: ImportProps) {
<PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
<RowBetween>
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Plural value={tokens.length} one="Import token" other="Import tokens" />
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
</RowBetween>
</PaddedColumn>
@@ -57,12 +57,12 @@ export function ImportToken(props: ImportProps) {
<AutoColumn gap="md" style={{ marginBottom: '32px', padding: '1rem' }}>
<AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', padding: '1rem' }}>
<AlertCircle size={48} stroke={theme.text2} strokeWidth={1} />
<TYPE.body fontWeight={400} fontSize={16}>
<ThemedText.Body fontWeight={400} fontSize={16}>
<Trans>
This token doesn&apos;t appear on the active token list(s). Make sure this is the token that you want to
trade.
</Trans>
</TYPE.body>
</ThemedText.Body>
</AutoColumn>
{tokens.map((token) => (
<TokenImportCard token={token} list={list} key={'import' + token.address} />

View File

@@ -16,7 +16,8 @@ import { PaddedColumn, Separator } from './styleds'
const Wrapper = styled.div`
width: 100%;
position: relative;
padding-bottom: 80px;
display: flex;
flex-flow: column;
`
const ToggleWrapper = styled(RowBetween)`

View File

@@ -3,8 +3,10 @@ import { t, Trans } from '@lingui/macro'
import { TokenList } from '@uniswap/token-lists'
import Card from 'components/Card'
import { UNSUPPORTED_LIST_URLS } from 'constants/lists'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useListColor } from 'hooks/useColor'
import { useActiveWeb3React } from 'hooks/web3'
import parseENSAddress from 'lib/utils/parseENSAddress'
import uriToHttp from 'lib/utils/uriToHttp'
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { CheckCircle, Settings } from 'react-feather'
import ReactGA from 'react-ga'
@@ -18,10 +20,8 @@ import useTheme from '../../hooks/useTheme'
import useToggle from '../../hooks/useToggle'
import { acceptListUpdate, disableList, enableList, removeList } from '../../state/lists/actions'
import { useActiveListUrls, useAllLists, useIsListActive } from '../../state/lists/hooks'
import { ExternalLink, IconWrapper, LinkStyledButton, TYPE } from '../../theme'
import { ExternalLink, IconWrapper, LinkStyledButton, ThemedText } from '../../theme'
import listVersionLabel from '../../utils/listVersionLabel'
import { parseENSAddress } from '../../utils/parseENSAddress'
import uriToHttp from '../../utils/uriToHttp'
import { ButtonEmpty, ButtonPrimary } from '../Button'
import Column, { AutoColumn } from '../Column'
import ListLogo from '../ListLogo'
@@ -31,7 +31,8 @@ import { CurrencyModalView } from './CurrencySearchModal'
import { PaddedColumn, SearchInput, Separator, SeparatorDark } from './styleds'
const Wrapper = styled(Column)`
height: 100%;
flex: 1;
overflow-y: hidden;
`
const UnpaddedLinkStyledButton = styled(LinkStyledButton)`
@@ -75,7 +76,7 @@ const StyledTitleText = styled.div<{ active: boolean }>`
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
`
const StyledListUrlText = styled(TYPE.main)<{ active: boolean }>`
const StyledListUrlText = styled(ThemedText.Main)<{ active: boolean }>`
font-size: 12px;
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
`
@@ -229,7 +230,7 @@ const ListContainer = styled.div`
padding: 1rem;
height: 100%;
overflow: auto;
padding-bottom: 80px;
flex: 1;
`
export function ManageLists({
@@ -361,9 +362,9 @@ export function ManageLists({
/>
</Row>
{addError ? (
<TYPE.error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
<ThemedText.Error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
{addError}
</TYPE.error>
</ThemedText.Error>
) : null}
</PaddedColumn>
{tempList && (
@@ -373,10 +374,10 @@ export function ManageLists({
<RowFixed>
{tempList.logoURI && <ListLogo logoURI={tempList.logoURI} size="40px" />}
<AutoColumn gap="4px" style={{ marginLeft: '20px' }}>
<TYPE.body fontWeight={600}>{tempList.name}</TYPE.body>
<TYPE.main fontSize={'12px'}>
<ThemedText.Body fontWeight={600}>{tempList.name}</ThemedText.Body>
<ThemedText.Main fontSize={'12px'}>
<Trans>{tempList.tokens.length} tokens</Trans>
</TYPE.main>
</ThemedText.Main>
</AutoColumn>
</RowFixed>
{isImported ? (
@@ -384,9 +385,9 @@ export function ManageLists({
<IconWrapper stroke={theme.text2} size="16px" marginRight={'10px'}>
<CheckCircle />
</IconWrapper>
<TYPE.body color={theme.text2}>
<ThemedText.Body color={theme.text2}>
<Trans>Loaded</Trans>
</TYPE.body>
</ThemedText.Body>
</RowFixed>
) : (
<ButtonPrimary

View File

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

View File

@@ -6,11 +6,11 @@ import { AutoColumn } from 'components/Column'
import CurrencyLogo from 'components/CurrencyLogo'
import ListLogo from 'components/ListLogo'
import { RowFixed } from 'components/Row'
import { useActiveWeb3React } from 'hooks/web3'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { transparentize } from 'polished'
import { AlertCircle } from 'react-feather'
import styled, { useTheme } from 'styled-components/macro'
import { ExternalLink, TYPE } from 'theme'
import { ExternalLink, ThemedText } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
@@ -19,7 +19,7 @@ const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
width: fit-content;
`
const AddressText = styled(TYPE.blue)`
const AddressText = styled(ThemedText.Blue)`
font-size: 12px;
word-break: break-all;
@@ -39,12 +39,12 @@ const TokenImportCard = ({ list, token }: TokenImportCardProps) => {
<AutoColumn gap="10px" justify="center">
<CurrencyLogo currency={token} size={'32px'} />
<AutoColumn gap="4px" justify="center">
<TYPE.body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
<ThemedText.Body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
{token.symbol}
</TYPE.body>
<TYPE.darkGray fontWeight={400} fontSize={14}>
</ThemedText.Body>
<ThemedText.DarkGray fontWeight={400} fontSize={14}>
{token.name}
</TYPE.darkGray>
</ThemedText.DarkGray>
</AutoColumn>
{chainId && (
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
@@ -54,17 +54,17 @@ const TokenImportCard = ({ list, token }: TokenImportCardProps) => {
{list !== undefined ? (
<RowFixed>
{list.logoURI && <ListLogo logoURI={list.logoURI} size="16px" />}
<TYPE.small ml="6px" fontSize={14} color={theme.text3}>
<ThemedText.Small ml="6px" fontSize={14} color={theme.text3}>
<Trans>via {list.name} token list</Trans>
</TYPE.small>
</ThemedText.Small>
</RowFixed>
) : (
<WarningWrapper $borderRadius="4px" padding="4px" highWarning={true}>
<RowFixed>
<AlertCircle stroke={theme.red1} size="10px" />
<TYPE.body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
<ThemedText.Body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
<Trans>Unknown Source</Trans>
</TYPE.body>
</ThemedText.Body>
</RowFixed>
</WarningWrapper>
)}

View File

@@ -1,76 +0,0 @@
import { Token } from '@uniswap/sdk-core'
import { TokenInfo } from '@uniswap/token-lists'
import { useMemo } from 'react'
import { isAddress } from '../../utils'
const alwaysTrue = () => true
/**
* Create a filter function to apply to a token for whether it matches a particular search query
* @param search the search query to apply to the token
*/
export function createTokenFilterFunction<T extends Token | TokenInfo>(search: string): (tokens: T) => boolean {
const searchingAddress = isAddress(search)
if (searchingAddress) {
const lower = searchingAddress.toLowerCase()
return (t: T) => ('isToken' in t ? searchingAddress === t.address : lower === t.address.toLowerCase())
}
const lowerSearchParts = search
.toLowerCase()
.split(/\s+/)
.filter((s) => s.length > 0)
if (lowerSearchParts.length === 0) return alwaysTrue
const matchesSearch = (s: string): boolean => {
const sParts = s
.toLowerCase()
.split(/\s+/)
.filter((s) => s.length > 0)
return lowerSearchParts.every((p) => p.length === 0 || sParts.some((sp) => sp.startsWith(p) || sp.endsWith(p)))
}
return ({ name, symbol }: T): boolean => Boolean((symbol && matchesSearch(symbol)) || (name && matchesSearch(name)))
}
export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: string): T[] {
return tokens.filter(createTokenFilterFunction(search))
}
export function useSortedTokensByQuery(tokens: Token[] | undefined, searchQuery: string): Token[] {
return useMemo(() => {
if (!tokens) {
return []
}
const symbolMatch = searchQuery
.toLowerCase()
.split(/\s+/)
.filter((s) => s.length > 0)
if (symbolMatch.length > 1) {
return tokens
}
const exactMatches: Token[] = []
const symbolSubtrings: Token[] = []
const rest: Token[] = []
// sort tokens by exact match -> subtring on symbol match -> rest
tokens.map((token) => {
if (token.symbol?.toLowerCase() === symbolMatch[0]) {
return exactMatches.push(token)
} else if (token.symbol?.toLowerCase().startsWith(searchQuery.toLowerCase().trim())) {
return symbolSubtrings.push(token)
} else {
return rest.push(token)
}
})
return [...exactMatches, ...symbolSubtrings, ...rest]
}, [tokens, searchQuery])
}

View File

@@ -1,51 +0,0 @@
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useAllTokenBalances } from '../../state/wallet/hooks'
// compare two token amounts with highest one coming first
function balanceComparator(balanceA?: CurrencyAmount<Currency>, balanceB?: CurrencyAmount<Currency>) {
if (balanceA && balanceB) {
return balanceA.greaterThan(balanceB) ? -1 : balanceA.equalTo(balanceB) ? 0 : 1
} else if (balanceA && balanceA.greaterThan('0')) {
return -1
} else if (balanceB && balanceB.greaterThan('0')) {
return 1
}
return 0
}
function getTokenComparator(balances: {
[tokenAddress: string]: CurrencyAmount<Currency> | undefined
}): (tokenA: Token, tokenB: Token) => number {
return function sortTokens(tokenA: Token, tokenB: Token): number {
// -1 = a is first
// 1 = b is first
// sort by balances
const balanceA = balances[tokenA.address]
const balanceB = balances[tokenB.address]
const balanceComp = balanceComparator(balanceA, balanceB)
if (balanceComp !== 0) return balanceComp
if (tokenA.symbol && tokenB.symbol) {
// sort by symbol
return tokenA.symbol.toLowerCase() < tokenB.symbol.toLowerCase() ? -1 : 1
} else {
return tokenA.symbol ? -1 : tokenB.symbol ? -1 : 0
}
}
}
export function useTokenComparator(inverted: boolean): (tokenA: Token, tokenB: Token) => number {
const balances = useAllTokenBalances()
const comparator = useMemo(() => getTokenComparator(balances ?? {}), [balances])
return useMemo(() => {
if (inverted) {
return (tokenA: Token, tokenB: Token) => comparator(tokenA, tokenB) * -1
} else {
return comparator
}
}, [inverted, comparator])
}

View File

@@ -1,19 +1,19 @@
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core'
import { SupportedChainId } from 'constants/chains'
import { useActiveWeb3React } from 'hooks/web3'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useContext, useRef, useState } from 'react'
import { Settings, X } from 'react-feather'
import ReactGA from 'react-ga'
import { Text } from 'rebass'
import { AUTO_ROUTER_SUPPORTED_CHAINS } from 'state/routing/clientSideSmartOrderRouter/constants'
import styled, { ThemeContext } from 'styled-components/macro'
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
import { useModalOpen, useToggleSettingsMenu } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { useClientSideRouter, useExpertModeManager } from '../../state/user/hooks'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { ButtonError } from '../Button'
import { AutoColumn } from '../Column'
import Modal from '../Modal'
@@ -27,7 +27,7 @@ const StyledMenuIcon = styled(Settings)`
width: 20px;
> * {
stroke: ${({ theme }) => theme.text2};
stroke: ${({ theme }) => theme.text1};
}
:hover {
@@ -199,16 +199,13 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
<Text fontWeight={600} fontSize={14}>
<Trans>Interface Settings</Trans>
</Text>
{chainId === SupportedChainId.MAINNET && (
{chainId && AUTO_ROUTER_SUPPORTED_CHAINS.includes(chainId) && (
<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>}
/>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Auto Router API</Trans>
</ThemedText.Black>
<QuestionHelper text={<Trans>Use the Uniswap Labs API to get faster quotes.</Trans>} />
</RowFixed>
<Toggle
id="toggle-optimized-router-button"
@@ -223,12 +220,11 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
/>
</RowBetween>
)}
<RowBetween>
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Expert Mode</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={
<Trans>Allow high price impact trades and skip the confirm screen. Use at your own risk.</Trans>

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ import styled from 'styled-components/macro'
import Popover, { PopoverProps } from '../Popover'
export const TooltipContainer = styled.div`
width: 256px;
max-width: 256px;
padding: 0.6rem 1rem;
font-weight: 400;
word-break: break-word;
@@ -25,6 +25,7 @@ interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
onOpen?: () => void
// whether to wrap the content in a `TooltipContainer`
wrap?: boolean
disableHover?: boolean // disable the hover and content display
}
export default function Tooltip({ text, ...rest }: TooltipProps) {
@@ -52,6 +53,7 @@ export function MouseoverTooltipContent({
content,
children,
onOpen: openCallback = undefined,
disableHover,
...rest
}: Omit<TooltipContentProps, 'show'>) {
const [show, setShow] = useState(false)
@@ -61,7 +63,7 @@ export function MouseoverTooltipContent({
}, [openCallback])
const close = useCallback(() => setShow(false), [setShow])
return (
<TooltipContent {...rest} show={show} content={content}>
<TooltipContent {...rest} show={show} content={disableHover ? null : content}>
<div
style={{ display: 'inline-block', lineHeight: 0, padding: '0.25rem' }}
onMouseEnter={open}

View File

@@ -1,7 +1,9 @@
import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core'
import Badge from 'components/Badge'
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
import { CHAIN_INFO } from 'constants/chainInfo'
import { L2_CHAIN_IDS, SupportedL2ChainId } from 'constants/chains'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import useAddTokenToMetamask from 'hooks/useAddTokenToMetamask'
import { ReactNode, useContext } from 'react'
import { AlertCircle, AlertTriangle, ArrowUpCircle, CheckCircle } from 'react-feather'
@@ -11,9 +13,8 @@ import styled, { ThemeContext } from 'styled-components/macro'
import Circle from '../../assets/images/blue-loader.svg'
import MetaMaskLogo from '../../assets/images/metamask.png'
import { useActiveWeb3React } from '../../hooks/web3'
import { ExternalLink } from '../../theme'
import { CloseIcon, CustomLightSpinner } from '../../theme/components'
import { CloseIcon, CustomLightSpinner } from '../../theme'
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
import { ButtonLight, ButtonPrimary } from '../Button'
@@ -284,11 +285,11 @@ function L2Content({
</Text>
</ExternalLink>
) : (
<div style={{ height: '17px' }}></div>
<div style={{ height: '17px' }} />
)}
<Text color={theme.text3} style={{ margin: '20px 0 0 0' }} fontSize={'14px'}>
{!secondsToConfirm ? (
<div style={{ height: '24px' }}></div>
<div style={{ height: '24px' }} />
) : (
<div>
<Trans>Transaction completed in </Trans>

View File

@@ -2,13 +2,14 @@ import { Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core'
import { L2_CHAIN_IDS } from 'constants/chains'
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
import { useActiveWeb3React } from 'hooks/web3'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import ms from 'ms.macro'
import { darken } from 'polished'
import { useContext, useState } from 'react'
import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'
import styled, { ThemeContext } from 'styled-components/macro'
import { TYPE } from '../../theme'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
import QuestionHelper from '../QuestionHelper'
import { RowBetween, RowFixed } from '../Row'
@@ -85,7 +86,7 @@ const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean }
const SlippageEmojiContainer = styled.span`
color: #f3841e;
${({ theme }) => theme.mediaWidth.upToSmall`
display: none;
display: none;
`}
`
@@ -93,6 +94,8 @@ interface TransactionSettingsProps {
placeholderSlippage: Percent // varies according to the context in which the settings dialog is placed
}
const THREE_DAYS_IN_SECONDS = ms`3 days` / 1000
export default function TransactionSettings({ placeholderSlippage }: TransactionSettingsProps) {
const { chainId } = useActiveWeb3React()
const theme = useContext(ThemeContext)
@@ -142,7 +145,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
} else {
try {
const parsed: number = Math.floor(Number.parseFloat(value) * 60)
if (!Number.isInteger(parsed) || parsed < 60 || parsed > 180 * 60) {
if (!Number.isInteger(parsed) || parsed < 60 || parsed > THREE_DAYS_IN_SECONDS) {
setDeadlineError(DeadlineError.InvalidInput)
} else {
setDeadline(parsed)
@@ -160,9 +163,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
<AutoColumn gap="md">
<AutoColumn gap="sm">
<RowFixed>
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
<Trans>Slippage tolerance</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={
<Trans>Your transaction will revert if the price changes unfavorably by more than this percentage.</Trans>
@@ -229,9 +232,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
{showCustomDeadlineRow && (
<AutoColumn gap="sm">
<RowFixed>
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
<ThemedText.Black fontSize={14} fontWeight={400} color={theme.text2}>
<Trans>Transaction deadline</Trans>
</TYPE.black>
</ThemedText.Black>
<QuestionHelper
text={<Trans>Your transaction will revert if it is pending for more than this period of time.</Trans>}
/>
@@ -255,9 +258,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
color={deadlineError ? 'red' : ''}
/>
</OptionCustom>
<TYPE.body style={{ paddingLeft: '8px' }} fontSize={14}>
<ThemedText.Body style={{ paddingLeft: '8px' }} fontSize={14}>
<Trans>minutes</Trans>
</TYPE.body>
</ThemedText.Body>
</RowFixed>
</AutoColumn>
)}

View File

@@ -19,7 +19,7 @@ import { SUPPORTED_WALLETS } from '../../constants/wallet'
import usePrevious from '../../hooks/usePrevious'
import { useModalOpen, useWalletModalToggle } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
import { ExternalLink, TYPE } from '../../theme'
import { ExternalLink, ThemedText } from '../../theme'
import { isMobile } from '../../utils/userAgent'
import AccountDetails from '../AccountDetails'
import Card, { LightCard } from '../Card'
@@ -110,8 +110,8 @@ const HoverText = styled.div`
`
const LinkCard = styled(Card)`
background-color: ${({ theme }) => theme.primary1};
color: ${({ theme }) => theme.white};
background-color: ${({ theme }) => theme.bg1};
color: ${({ theme }) => theme.text3};
:hover {
cursor: pointer;
@@ -320,7 +320,7 @@ export default function WalletModal({
<ContentWrapper>
{error instanceof UnsupportedChainIdError ? (
<h5>
<Trans>Please connect to the appropriate Ethereum network.</Trans>
<Trans>Please connect to a supported network in the dropdown menu or in your wallet.</Trans>
</h5>
) : (
<Trans>Error connecting. Try refreshing the page.</Trans>
@@ -344,9 +344,9 @@ export default function WalletModal({
<ArrowLeft />
</HoverText>
<Row justify="center">
<TYPE.mediumHeader>
<ThemedText.MediumHeader>
<Trans>Legal & Privacy</Trans>
</TYPE.mediumHeader>
</ThemedText.MediumHeader>
</Row>
</HeaderRow>
<PrivacyPolicy />
@@ -392,27 +392,16 @@ export default function WalletModal({
<AutoColumn gap="16px">
<LightCard>
<AutoRow style={{ flexWrap: 'nowrap' }}>
<TYPE.black fontSize={14}>
<ThemedText.Black fontSize={14}>
<Trans>
By connecting a wallet, you agree to Uniswap Labs{' '}
<ExternalLink href="https://uniswap.org/terms-of-service/">Terms of Service</ExternalLink> and
acknowledge that you have read and understand the Uniswap{' '}
<ExternalLink href="https://uniswap.org/disclaimer/">Protocol Disclaimer</ExternalLink>.
</Trans>
</TYPE.black>
</ThemedText.Black>
</AutoRow>
</LightCard>
<LinkCard padding=".5rem" $borderRadius=".75rem" onClick={() => setWalletView(WALLET_VIEWS.LEGAL)}>
<RowBetween>
<AutoRow gap="4px">
<Info size={20} />
<TYPE.white fontSize={14}>
<Trans>How this app uses APIs</Trans>
</TYPE.white>
</AutoRow>
<ArrowRight size={16} />
</RowBetween>
</LinkCard>
{walletView === WALLET_VIEWS.PENDING ? (
<PendingView
connector={pendingWallet}
@@ -423,6 +412,17 @@ export default function WalletModal({
) : (
<OptionGrid>{getOptions()}</OptionGrid>
)}
<LinkCard padding=".5rem" $borderRadius=".75rem" onClick={() => setWalletView(WALLET_VIEWS.LEGAL)}>
<RowBetween>
<AutoRow gap="4px">
<Info size={20} />
<ThemedText.Label fontSize={14}>
<Trans>How this app uses APIs</Trans>
</ThemedText.Label>
</AutoRow>
<ArrowRight size={16} />
</RowBetween>
</LinkCard>
</AutoColumn>
</ContentWrapper>
</UpperSection>

View File

@@ -6,12 +6,8 @@ import { darken } from 'polished'
import { useMemo } from 'react'
import { Activity } from 'react-feather'
import styled, { css } from 'styled-components/macro'
import { Connector } from 'widgets-web3-react/types'
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
import PortisIcon from '../../assets/images/portisIcon.png'
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
import { NetworkContextName } from '../../constants/misc'
import useENSName from '../../hooks/useENSName'
import { useHasSocks } from '../../hooks/useSocksBalance'
@@ -20,7 +16,7 @@ import { isTransactionRecent, useAllTransactions } from '../../state/transaction
import { TransactionDetails } from '../../state/transactions/reducer'
import { shortenAddress } from '../../utils'
import { ButtonSecondary } from '../Button'
import Identicon from '../Identicon'
import StatusIcon from '../Identicon/StatusIcon'
import Loader from '../Loader'
import { RowBetween } from '../Row'
import WalletModal from '../WalletModal'
@@ -40,9 +36,12 @@ const Web3StatusGeneric = styled(ButtonSecondary)`
width: 100%;
align-items: center;
padding: 0.5rem;
border-radius: 12px;
border-radius: 14px;
cursor: pointer;
user-select: none;
height: 36px;
margin-right: 2px;
margin-left: 1px;
:focus {
outline: none;
}
@@ -87,7 +86,7 @@ const Web3StatusConnect = styled(Web3StatusGeneric)<{ faded?: boolean }>`
`
const Web3StatusConnected = styled(Web3StatusGeneric)<{ pending?: boolean }>`
background-color: ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg0)};
background-color: ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg1)};
border: 1px solid ${({ pending, theme }) => (pending ? theme.primary1 : theme.bg1)};
color: ${({ pending, theme }) => (pending ? theme.white : theme.text1)};
font-weight: 500;
@@ -132,36 +131,12 @@ function Sock() {
)
}
// eslint-disable-next-line react/prop-types
function StatusIcon({ connector }: { connector: AbstractConnector }) {
if (connector === injected) {
return <Identicon />
} else if (connector === walletconnect) {
return (
<IconWrapper size={16}>
<img src={WalletConnectIcon} alt={'WalletConnect'} />
</IconWrapper>
)
} else if (connector === walletlink) {
return (
<IconWrapper size={16}>
<img src={CoinbaseWalletIcon} alt={'CoinbaseWallet'} />
</IconWrapper>
)
} else if (connector === fortmatic) {
return (
<IconWrapper size={16}>
<img src={FortmaticIcon} alt={'Fortmatic'} />
</IconWrapper>
)
} else if (connector === portis) {
return (
<IconWrapper size={16}>
<img src={PortisIcon} alt={'Portis'} />
</IconWrapper>
)
}
return null
function WrappedStatusIcon({ connector }: { connector: AbstractConnector | Connector }) {
return (
<IconWrapper size={16}>
<StatusIcon connector={connector} />
</IconWrapper>
)
}
function Web3StatusInner() {
@@ -198,7 +173,7 @@ function Web3StatusInner() {
<Text>{ENSName || shortenAddress(account)}</Text>
</>
)}
{!hasPendingTransactions && connector && <StatusIcon connector={connector} />}
{!hasPendingTransactions && connector && <WrappedStatusIcon connector={connector} />}
</Web3StatusConnected>
)
} else if (error) {

View File

@@ -1,4 +1,4 @@
import { useActiveWeb3React } from 'hooks/web3'
import useActiveWeb3React from 'hooks/useActiveWeb3React'
import { useEffect } from 'react'
import ReactGA from 'react-ga'
import { RouteComponentProps } from 'react-router-dom'

View File

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

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