Compare commits

...

18 Commits

Author SHA1 Message Date
dependabot[bot]
e4dd4f9283 chore(deps): bump ini from 1.3.5 to 1.3.8 (#1277)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-19 10:55:13 -05:00
Moody Salem
7798443919 improvement(walletconnect): upgrade the walletconnect connector to 6.1.9 2021-04-19 09:52:41 -05:00
Noah Zinsmeister
392d78b9da add to ADDITIONAL_BASES 2021-04-16 13:54:31 -04:00
Noah Zinsmeister
231289732c add additional bases (#1363)
* add routing token

* add logic for additional bases

* update address
2021-04-16 13:47:38 -04:00
Brandon Curtis
140ff7a674 update BASES_TO_CHECK_TRADES_AGAINST (#1333) 2021-04-12 11:32:45 -05:00
Gökhan Çoban
3fbc4e34f4 typo: use main branch for pull requests (#1355) 2021-04-03 19:17:38 -05:00
Moody Salem
b964953daf fix(walletconnect): use a dedicated walletconnect bridge 2021-03-31 12:36:56 -05:00
Moody Salem
649fd9c845 fixes https://github.com/Uniswap/uniswap-interface/issues/1351 (#1352) 2021-03-31 12:26:03 -05:00
Ian Lapham
6347e63a15 update unsupported list (#1346) 2021-03-28 16:11:18 -04:00
Moody Salem
bdcb9a8a0a fix(google analytics): anonymize IP in hits sent to google analytics
https://developers.google.com/analytics/devguides/collection/analyticsjs/ip-anonymization
2021-03-26 16:40:16 -05:00
Moody Salem
8d90bb7a39 fix(google analytics): don't set user cookies 2021-03-26 16:32:13 -05:00
Kun
d70b456855 Add Pin to Crust workflow (#1342) 2021-03-26 10:03:25 -05:00
Luke Donato
fbb797fa54 Move single hop toggle GA event (#1344)
* Move single hop toggle GA event

Move GA event from setSingleHopOnly hook to toggle function

* Fix code style issues with ESLint

* refactor ternary operator out

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
2021-03-26 10:02:07 -05:00
Jordan Frankfurt
8ace518311 stop destructuring merkle drop response object (#1338)
stop destructuring merkle drop response object

Co-authored-by: Jordan Frankfurt <layup-entropy@protonmail.com>
2021-03-18 11:57:13 -04:00
Jordan Frankfurt
67c776c995 fix(merkle drop): make claim a post request 2021-03-18 01:46:11 -04:00
Rand Seay
719754c46c fix(info link): Update view pair analytics link
fixes #1299
2021-03-16 13:55:38 -05:00
Ian Lapham
9170af888e handle dismiss (#1328) 2021-03-11 18:08:41 -05:00
Ian Lapham
b258f557d1 improvement(lists): add BA SEC tokens to unsupported list (#1327)
* show hidden search results by default

* update break styles

* optimize filter, use debounce on input

* increase debounce time

* add ba association list
2021-02-25 14:08:17 -05:00
21 changed files with 792 additions and 238 deletions

3
.env
View File

@@ -1,2 +1,3 @@
REACT_APP_CHAIN_ID="1" REACT_APP_CHAIN_ID="1"
REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847" REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847"
REACT_APP_WALLETCONNECT_BRIDGE_URL="https://uniswap.bridge.walletconnect.org"

View File

@@ -54,6 +54,14 @@ jobs:
pinata-api-key: ${{ secrets.PINATA_API_KEY }} pinata-api-key: ${{ secrets.PINATA_API_KEY }}
pinata-secret-api-key: ${{ secrets.PINATA_API_SECRET_KEY }} pinata-secret-api-key: ${{ secrets.PINATA_API_SECRET_KEY }}
- name: Pin to Crust
uses: crustio/ipfs-crust-action@v1.0.8
continue-on-error: true
timeout-minutes: 2
with:
cid: ${{ steps.upload.outputs.hash }}
seeds: ${{ secrets.CRUST_SEEDS }}
- name: Convert CIDv0 to CIDv1 - name: Convert CIDv0 to CIDv1
id: convert_cidv0 id: convert_cidv0
uses: uniswap/convert-cidv0-cidv1@v1.0.0 uses: uniswap/convert-cidv0-cidv1@v1.0.0

View File

@@ -56,7 +56,7 @@ The interface will not work on other networks.
## Contributions ## Contributions
**Please open all pull requests against the `master` branch.** **Please open all pull requests against the `main` branch.**
CI checks will run against all PRs. CI checks will run against all PRs.
## Accessing Uniswap Interface V1 ## Accessing Uniswap Interface V1

View File

@@ -94,9 +94,6 @@
"workbox-routing": "^6.1.0", "workbox-routing": "^6.1.0",
"workbox-strategies": "^6.1.0" "workbox-strategies": "^6.1.0"
}, },
"resolutions": {
"@walletconnect/web3-provider": "1.1.1-alpha.0"
},
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"start:service-worker": "yarn build && yarn serve -s build", "start:service-worker": "yarn build && yarn serve -s build",

View File

@@ -1,5 +1,6 @@
import React, { useContext, useRef, useState } from 'react' import React, { useContext, useRef, useState } from 'react'
import { Settings, X } from 'react-feather' import { Settings, X } from 'react-feather'
import ReactGA from 'react-ga'
import { Text } from 'rebass' import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
import { useOnClickOutside } from '../../hooks/useOnClickOutside' import { useOnClickOutside } from '../../hooks/useOnClickOutside'
@@ -236,7 +237,13 @@ export default function SettingsTab() {
<Toggle <Toggle
id="toggle-disable-multihop-button" id="toggle-disable-multihop-button"
isActive={singleHopOnly} isActive={singleHopOnly}
toggle={() => (singleHopOnly ? setSingleHopOnly(false) : setSingleHopOnly(true))} toggle={() => {
ReactGA.event({
category: 'Routing',
action: singleHopOnly ? 'disable single hop' : 'enable single hop'
})
setSingleHopOnly(!singleHopOnly)
}}
/> />
</RowBetween> </RowBetween>
</AutoColumn> </AutoColumn>

View File

@@ -1,21 +1,21 @@
import { Token } from '@uniswap/sdk' import { Token } from '@uniswap/sdk'
import React, { useCallback } from 'react' import React from 'react'
import Modal from '../Modal' import Modal from '../Modal'
import { ImportToken } from 'components/SearchModal/ImportToken' import { ImportToken } from 'components/SearchModal/ImportToken'
export default function TokenWarningModal({ export default function TokenWarningModal({
isOpen, isOpen,
tokens, tokens,
onConfirm onConfirm,
onDismiss
}: { }: {
isOpen: boolean isOpen: boolean
tokens: Token[] tokens: Token[]
onConfirm: () => void onConfirm: () => void
onDismiss: () => void
}) { }) {
const handleDismiss = useCallback(() => null, [])
return ( return (
<Modal isOpen={isOpen} onDismiss={handleDismiss} maxHeight={90}> <Modal isOpen={isOpen} onDismiss={onDismiss} maxHeight={100}>
<ImportToken tokens={tokens} handleCurrencySelect={onConfirm} /> <ImportToken tokens={tokens} handleCurrencySelect={onConfirm} />
</Modal> </Modal>
) )

View File

@@ -105,7 +105,7 @@ export function AdvancedSwapDetails({ trade }: AdvancedSwapDetailsProps) {
{!showRoute && ( {!showRoute && (
<AutoColumn style={{ padding: '12px 16px 0 16px' }}> <AutoColumn style={{ padding: '12px 16px 0 16px' }}>
<InfoLink <InfoLink
href={'https://uniswap.info/pair/' + trade.route.pairs[0].liquidityToken.address} href={'https://info.uniswap.org/pair/' + trade.route.pairs[0].liquidityToken.address}
target="_blank" target="_blank"
> >
View pair analytics View pair analytics

View File

@@ -64,7 +64,6 @@ export default function UnsupportedCurrencyFooter({
<AutoColumn gap="lg"> <AutoColumn gap="lg">
<RowBetween> <RowBetween>
<TYPE.mediumHeader>Unsupported Assets</TYPE.mediumHeader> <TYPE.mediumHeader>Unsupported Assets</TYPE.mediumHeader>
<CloseIcon onClick={() => setShowDetails(false)} /> <CloseIcon onClick={() => setShowDetails(false)} />
</RowBetween> </RowBetween>
{tokens.map(token => { {tokens.map(token => {

View File

@@ -6,10 +6,12 @@ import { PortisConnector } from '@web3-react/portis-connector'
import { FortmaticConnector } from './Fortmatic' import { FortmaticConnector } from './Fortmatic'
import { NetworkConnector } from './NetworkConnector' import { NetworkConnector } from './NetworkConnector'
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
const NETWORK_URL = process.env.REACT_APP_NETWORK_URL const NETWORK_URL = process.env.REACT_APP_NETWORK_URL
const FORMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY const FORMATIC_KEY = process.env.REACT_APP_FORTMATIC_KEY
const PORTIS_ID = process.env.REACT_APP_PORTIS_ID const PORTIS_ID = process.env.REACT_APP_PORTIS_ID
const WALLETCONNECT_BRIDGE_URL = process.env.REACT_APP_WALLETCONNECT_BRIDGE_URL
export const NETWORK_CHAIN_ID: number = parseInt(process.env.REACT_APP_CHAIN_ID ?? '1') export const NETWORK_CHAIN_ID: number = parseInt(process.env.REACT_APP_CHAIN_ID ?? '1')
@@ -33,7 +35,7 @@ export const injected = new InjectedConnector({
// mainnet only // mainnet only
export const walletconnect = new WalletConnectConnector({ export const walletconnect = new WalletConnectConnector({
rpc: { 1: NETWORK_URL }, rpc: { 1: NETWORK_URL },
bridge: 'https://bridge.walletconnect.org', bridge: WALLETCONNECT_BRIDGE_URL,
qrcode: true, qrcode: true,
pollingInterval: 15000 pollingInterval: 15000
}) })
@@ -54,6 +56,5 @@ export const portis = new PortisConnector({
export const walletlink = new WalletLinkConnector({ export const walletlink = new WalletLinkConnector({
url: NETWORK_URL, url: NETWORK_URL,
appName: 'Uniswap', appName: 'Uniswap',
appLogoUrl: appLogoUrl: UNISWAP_LOGO_URL
'https://mpng.pngfly.com/20181202/bex/kisspng-emoji-domain-unicorn-pin-badges-sticker-unicorn-tumblr-emoji-unicorn-iphoneemoji-5c046729264a77.5671679315437924251569.jpg'
}) })

View File

@@ -14,13 +14,16 @@ type ChainTokenList = {
readonly [chainId in ChainId]: Token[] readonly [chainId in ChainId]: Token[]
} }
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
export const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') export const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin')
export const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC', 'USD//C') export const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC', 'USD//C')
export const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6, 'USDT', 'Tether USD') export const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6, 'USDT', 'Tether USD')
export const COMP = new Token(ChainId.MAINNET, '0xc00e94Cb662C3520282E6f5717214004A7f26888', 18, 'COMP', 'Compound')
export const MKR = new Token(ChainId.MAINNET, '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 18, 'MKR', 'Maker')
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 8, 'WBTC', 'Wrapped BTC') export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 8, 'WBTC', 'Wrapped BTC')
export const FEI = new Token(ChainId.MAINNET, '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', 18, 'FEI', 'Fei USD')
export const TRIBE = new Token(ChainId.MAINNET, '0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B', 18, 'TRIBE', 'Tribe')
export const FRAX = new Token(ChainId.MAINNET, '0x853d955aCEf822Db058eb8505911ED77F175b99e', 18, 'FRAX', 'Frax')
export const FXS = new Token(ChainId.MAINNET, '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', 18, 'FXS', 'Frax Share')
export const renBTC = new Token(ChainId.MAINNET, '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', 8, 'renBTC', 'renBTC')
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time // Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
export const AVERAGE_BLOCK_TIME_IN_SECS = 13 export const AVERAGE_BLOCK_TIME_IN_SECS = 13
@@ -62,7 +65,20 @@ const WETH_ONLY: ChainTokenList = {
// used to construct intermediary pairs for trading // used to construct intermediary pairs for trading
export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
...WETH_ONLY, ...WETH_ONLY,
[ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, COMP, MKR, WBTC] [ChainId.MAINNET]: [...WETH_ONLY[ChainId.MAINNET], DAI, USDC, USDT, WBTC]
}
export const ADDITIONAL_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
'0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18': [new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap')],
'0x561a4717537ff4AF5c687328c0f7E90a319705C0': [new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap')],
[FEI.address]: [TRIBE],
[TRIBE.address]: [FEI],
[FRAX.address]: [FXS],
[FXS.address]: [FRAX],
[WBTC.address]: [renBTC],
[renBTC.address]: [WBTC]
}
} }
/** /**

View File

@@ -1,8 +1,4 @@
// used to mark unsupported tokens, these are hosted lists of unsupported tokens // used to mark unsupported tokens, these are hosted lists of unsupported tokens
/**
* @TODO add list from blockchain association
*/
export const UNSUPPORTED_LIST_URLS: string[] = []
const COMPOUND_LIST = 'https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json' const COMPOUND_LIST = 'https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json'
const UMA_LIST = 'https://umaproject.org/uma.tokenlist.json' const UMA_LIST = 'https://umaproject.org/uma.tokenlist.json'
@@ -17,6 +13,9 @@ const CMC_ALL_LIST = 'defi.cmc.eth'
const CMC_STABLECOIN = 'stablecoin.cmc.eth' const CMC_STABLECOIN = 'stablecoin.cmc.eth'
const KLEROS_LIST = 't2crtokens.eth' const KLEROS_LIST = 't2crtokens.eth'
const GEMINI_LIST = 'https://www.gemini.com/uniswap/manifest.json' const GEMINI_LIST = 'https://www.gemini.com/uniswap/manifest.json'
const BA_LIST = 'https://raw.githubusercontent.com/The-Blockchain-Association/sec-notice-list/master/ba-sec-list.json'
export const UNSUPPORTED_LIST_URLS: string[] = [BA_LIST]
// lower index == higher priority for token import // lower index == higher priority for token import
export const DEFAULT_LIST_OF_LISTS: string[] = [ export const DEFAULT_LIST_OF_LISTS: string[] = [

View File

@@ -17,6 +17,14 @@
"decimals": 6, "decimals": 6,
"chainId": 1, "chainId": 1,
"logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x4922a015c4407F87432B179bb209e125432E4a2A/logo.png" "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x4922a015c4407F87432B179bb209e125432E4a2A/logo.png"
},
{
"name": "Grump Cat",
"address": "0x93B2FfF814FCaEFFB01406e80B4Ecd89Ca6A021b",
"symbol": "GRUMPY",
"decimals": 9,
"chainId": 1,
"logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x4922a015c4407F87432B179bb209e125432E4a2A/logo.png"
} }
] ]
} }

View File

@@ -3,7 +3,12 @@ import { Currency, CurrencyAmount, Pair, Token, Trade } from '@uniswap/sdk'
import flatMap from 'lodash.flatmap' import flatMap from 'lodash.flatmap'
import { useMemo } from 'react' import { useMemo } from 'react'
import { BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES, BETTER_TRADE_LESS_HOPS_THRESHOLD } from '../constants' import {
BASES_TO_CHECK_TRADES_AGAINST,
CUSTOM_BASES,
BETTER_TRADE_LESS_HOPS_THRESHOLD,
ADDITIONAL_BASES
} from '../constants'
import { PairState, usePairs } from '../data/Reserves' import { PairState, usePairs } from '../data/Reserves'
import { wrappedCurrency } from '../utils/wrappedCurrency' import { wrappedCurrency } from '../utils/wrappedCurrency'
@@ -14,17 +19,22 @@ import { useUserSingleHopOnly } from 'state/user/hooks'
function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] { function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const bases: Token[] = chainId ? BASES_TO_CHECK_TRADES_AGAINST[chainId] : []
const [tokenA, tokenB] = chainId const [tokenA, tokenB] = chainId
? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)] ? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)]
: [undefined, undefined] : [undefined, undefined]
const bases: Token[] = useMemo(() => {
if (!chainId) return []
const common = BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? []
const additionalA = tokenA ? ADDITIONAL_BASES[chainId]?.[tokenA.address] ?? [] : []
const additionalB = tokenB ? ADDITIONAL_BASES[chainId]?.[tokenB.address] ?? [] : []
return [...common, ...additionalA, ...additionalB]
}, [chainId, tokenA, tokenB])
const basePairs: [Token, Token][] = useMemo( const basePairs: [Token, Token][] = useMemo(
() => () => flatMap(bases, (base): [Token, Token][] => bases.map(otherBase => [base, otherBase])),
flatMap(bases, (base): [Token, Token][] => bases.map(otherBase => [base, otherBase])).filter(
([t0, t1]) => t0.address !== t1.address
),
[bases] [bases]
) )
@@ -46,10 +56,9 @@ function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] {
.filter(([tokenA, tokenB]) => { .filter(([tokenA, tokenB]) => {
if (!chainId) return true if (!chainId) return true
const customBases = CUSTOM_BASES[chainId] const customBases = CUSTOM_BASES[chainId]
if (!customBases) return true
const customBasesA: Token[] | undefined = customBases[tokenA.address] const customBasesA: Token[] | undefined = customBases?.[tokenA.address]
const customBasesB: Token[] | undefined = customBases[tokenB.address] const customBasesB: Token[] | undefined = customBases?.[tokenB.address]
if (!customBasesA && !customBasesB) return true if (!customBasesA && !customBasesB) return true
@@ -150,18 +159,18 @@ export function useTradeExactOut(currencyIn?: Currency, currencyAmountOut?: Curr
} }
export function useIsTransactionUnsupported(currencyIn?: Currency, currencyOut?: Currency): boolean { export function useIsTransactionUnsupported(currencyIn?: Currency, currencyOut?: Currency): boolean {
const unsupportedToken: { [address: string]: Token } = useUnsupportedTokens() const unsupportedTokens: { [address: string]: Token } = useUnsupportedTokens()
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const tokenIn = wrappedCurrency(currencyIn, chainId) const tokenIn = wrappedCurrency(currencyIn, chainId)
const tokenOut = wrappedCurrency(currencyOut, chainId) const tokenOut = wrappedCurrency(currencyOut, chainId)
// if unsupported list loaded & either token on list, mark as unsupported // if unsupported list loaded & either token on list, mark as unsupported
if (unsupportedToken) { if (unsupportedTokens) {
if (tokenIn && Object.keys(unsupportedToken).includes(tokenIn.address)) { if (tokenIn && Object.keys(unsupportedTokens).includes(tokenIn.address)) {
return true return true
} }
if (tokenOut && Object.keys(unsupportedToken).includes(tokenOut.address)) { if (tokenOut && Object.keys(unsupportedTokens).includes(tokenOut.address)) {
return true return true
} }
} }

View File

@@ -28,8 +28,14 @@ if (!!window.ethereum) {
const GOOGLE_ANALYTICS_ID: string | undefined = process.env.REACT_APP_GOOGLE_ANALYTICS_ID const GOOGLE_ANALYTICS_ID: string | undefined = process.env.REACT_APP_GOOGLE_ANALYTICS_ID
if (typeof GOOGLE_ANALYTICS_ID === 'string') { if (typeof GOOGLE_ANALYTICS_ID === 'string') {
ReactGA.initialize(GOOGLE_ANALYTICS_ID) ReactGA.initialize(GOOGLE_ANALYTICS_ID, {
gaOptions: {
storage: 'none',
storeGac: false
}
})
ReactGA.set({ ReactGA.set({
anonymizeIp: true,
customBrowserType: !isMobile ? 'desktop' : 'web3' in window || 'ethereum' in window ? 'mobileWeb3' : 'mobileRegular' customBrowserType: !isMobile ? 'desktop' : 'web3' in window || 'ethereum' in window ? 'mobileWeb3' : 'mobileRegular'
}) })
} else { } else {

View File

@@ -48,8 +48,9 @@ import Loader from '../../components/Loader'
import { useIsTransactionUnsupported } from 'hooks/Trades' import { useIsTransactionUnsupported } from 'hooks/Trades'
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
import { isTradeBetter } from 'utils/trades' import { isTradeBetter } from 'utils/trades'
import { RouteComponentProps } from 'react-router-dom'
export default function Swap() { export default function Swap({ history }: RouteComponentProps) {
const loadedUrlParams = useDefaultsFromURLSearch() const loadedUrlParams = useDefaultsFromURLSearch()
// token warning stuff // token warning stuff
@@ -97,6 +98,7 @@ export default function Swap() {
currencies, currencies,
inputError: swapInputError inputError: swapInputError
} = useDerivedSwapInfo() } = useDerivedSwapInfo()
const { wrapType, execute: onWrap, inputError: wrapInputError } = useWrapCallback( const { wrapType, execute: onWrap, inputError: wrapInputError } = useWrapCallback(
currencies[Field.INPUT], currencies[Field.INPUT],
currencies[Field.OUTPUT], currencies[Field.OUTPUT],
@@ -142,6 +144,12 @@ export default function Swap() {
[onUserInput] [onUserInput]
) )
// reset if they close warning without tokens in params
const handleDismissTokenWarning = useCallback(() => {
setDismissTokenWarning(true)
history.push('/swap/')
}, [history])
// modal and loading // modal and loading
const [{ showConfirm, tradeToConfirm, swapErrorMessage, attemptingTxn, txHash }, setSwapState] = useState<{ const [{ showConfirm, tradeToConfirm, swapErrorMessage, attemptingTxn, txHash }, setSwapState] = useState<{
showConfirm: boolean showConfirm: boolean
@@ -297,6 +305,7 @@ export default function Swap() {
isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning} isOpen={importTokensNotInDefault.length > 0 && !dismissTokenWarning}
tokens={importTokensNotInDefault} tokens={importTokensNotInDefault}
onConfirm={handleConfirmTokenWarning} onConfirm={handleConfirmTokenWarning}
onDismiss={handleDismissTokenWarning}
/> />
<SwapPoolTabs active={'swap'} /> <SwapPoolTabs active={'swap'} />
<AppBody> <AppBody>

View File

@@ -29,18 +29,16 @@ function fetchClaim(account: string, chainId: ChainId): Promise<UserClaimData |
return (CLAIM_PROMISES[key] = return (CLAIM_PROMISES[key] =
CLAIM_PROMISES[key] ?? CLAIM_PROMISES[key] ??
fetch(`https://gentle-frost-9e74.uniswap.workers.dev/${chainId}/${formatted}`) fetch('https://merkle-drop-1.uniswap.workers.dev/', {
.then(res => { body: JSON.stringify({ chainId, address: formatted }),
if (res.status === 200) { headers: {
return res.json() 'Content-Type': 'application/json',
} else { 'Referrer-Policy': 'no-referrer'
console.debug(`No claim for account ${formatted} on chain ID ${chainId}`) },
return null method: 'POST'
} })
}) .then(res => (res.ok ? res.json() : console.log(`No claim for account ${formatted} on chain ID ${chainId}`)))
.catch(error => { .catch(error => console.error('Failed to get claim data', error)))
console.error('Failed to get claim data', error)
}))
} }
// parse distributorContract blob and detect if user has claim data // parse distributorContract blob and detect if user has claim data

View File

@@ -1,4 +1,4 @@
import { DEFAULT_ACTIVE_LIST_URLS } from './../../constants/lists' import { DEFAULT_ACTIVE_LIST_URLS, UNSUPPORTED_LIST_URLS } from './../../constants/lists'
import { createReducer } from '@reduxjs/toolkit' import { createReducer } from '@reduxjs/toolkit'
import { getVersionUpgrade, VersionUpgrade } from '@uniswap/token-lists' import { getVersionUpgrade, VersionUpgrade } from '@uniswap/token-lists'
import { TokenList } from '@uniswap/token-lists/dist/types' import { TokenList } from '@uniswap/token-lists/dist/types'
@@ -36,7 +36,7 @@ type Mutable<T> = { -readonly [P in keyof T]: T[P] extends ReadonlyArray<infer U
const initialState: ListsState = { const initialState: ListsState = {
lastInitializedDefaultListOfLists: DEFAULT_LIST_OF_LISTS, lastInitializedDefaultListOfLists: DEFAULT_LIST_OF_LISTS,
byUrl: { byUrl: {
...DEFAULT_LIST_OF_LISTS.reduce<Mutable<ListsState['byUrl']>>((memo, listUrl) => { ...DEFAULT_LIST_OF_LISTS.concat(...UNSUPPORTED_LIST_URLS).reduce<Mutable<ListsState['byUrl']>>((memo, listUrl) => {
memo[listUrl] = NEW_LIST_STATE memo[listUrl] = NEW_LIST_STATE
return memo return memo
}, {}) }, {})

View File

@@ -10,6 +10,7 @@ import { AppDispatch } from '../index'
import { acceptListUpdate } from './actions' import { acceptListUpdate } from './actions'
import { useActiveListUrls } from './hooks' import { useActiveListUrls } from './hooks'
import { useAllInactiveTokens } from 'hooks/Tokens' import { useAllInactiveTokens } from 'hooks/Tokens'
import { UNSUPPORTED_LIST_URLS } from 'constants/lists'
export default function Updater(): null { export default function Updater(): null {
const { library } = useActiveWeb3React() const { library } = useActiveWeb3React()
@@ -44,6 +45,16 @@ export default function Updater(): null {
}) })
}, [dispatch, fetchList, library, lists]) }, [dispatch, fetchList, library, lists])
// if any lists from unsupported lists are loaded, check them too (in case new updates since last visit)
useEffect(() => {
Object.keys(UNSUPPORTED_LIST_URLS).forEach(listUrl => {
const list = lists[listUrl]
if (!list || (!list.current && !list.loadingRequestId && !list.error)) {
fetchList(listUrl).catch(error => console.debug('list added fetching error', error))
}
})
}, [dispatch, fetchList, library, lists])
// automatically update lists if versions are minor/patch // automatically update lists if versions are minor/patch
useEffect(() => { useEffect(() => {
Object.keys(lists).forEach(listUrl => { Object.keys(lists).forEach(listUrl => {

View File

@@ -1,6 +1,5 @@
import { ChainId, Pair, Token } from '@uniswap/sdk' import { ChainId, Pair, Token } from '@uniswap/sdk'
import flatMap from 'lodash.flatmap' import flatMap from 'lodash.flatmap'
import ReactGA from 'react-ga'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { shallowEqual, useDispatch, useSelector } from 'react-redux' import { shallowEqual, useDispatch, useSelector } from 'react-redux'
import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from '../../constants' import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from '../../constants'
@@ -92,10 +91,6 @@ export function useUserSingleHopOnly(): [boolean, (newSingleHopOnly: boolean) =>
const setSingleHopOnly = useCallback( const setSingleHopOnly = useCallback(
(newSingleHopOnly: boolean) => { (newSingleHopOnly: boolean) => {
ReactGA.event({
category: 'Routing',
action: newSingleHopOnly ? 'enable single hop' : 'disable single hop'
})
dispatch(updateUserSingleHopOnly({ userSingleHopOnly: newSingleHopOnly })) dispatch(updateUserSingleHopOnly({ userSingleHopOnly: newSingleHopOnly }))
}, },
[dispatch] [dispatch]
@@ -162,7 +157,7 @@ export function useUserAddedTokens(): Token[] {
return useMemo(() => { return useMemo(() => {
if (!chainId) return [] if (!chainId) return []
return Object.values(serializedTokensMap[chainId as ChainId] ?? {}).map(deserializeToken) return Object.values(serializedTokensMap?.[chainId as ChainId] ?? {}).map(deserializeToken)
}, [serializedTokensMap, chainId]) }, [serializedTokensMap, chainId])
} }

View File

@@ -111,11 +111,17 @@ export default createReducer(initialState, builder =>
state.userSingleHopOnly = action.payload.userSingleHopOnly state.userSingleHopOnly = action.payload.userSingleHopOnly
}) })
.addCase(addSerializedToken, (state, { payload: { serializedToken } }) => { .addCase(addSerializedToken, (state, { payload: { serializedToken } }) => {
if (!state.tokens) {
state.tokens = {}
}
state.tokens[serializedToken.chainId] = state.tokens[serializedToken.chainId] || {} state.tokens[serializedToken.chainId] = state.tokens[serializedToken.chainId] || {}
state.tokens[serializedToken.chainId][serializedToken.address] = serializedToken state.tokens[serializedToken.chainId][serializedToken.address] = serializedToken
state.timestamp = currentTimestamp() state.timestamp = currentTimestamp()
}) })
.addCase(removeSerializedToken, (state, { payload: { address, chainId } }) => { .addCase(removeSerializedToken, (state, { payload: { address, chainId } }) => {
if (!state.tokens) {
state.tokens = {}
}
state.tokens[chainId] = state.tokens[chainId] || {} state.tokens[chainId] = state.tokens[chainId] || {}
delete state.tokens[chainId][address] delete state.tokens[chainId][address]
state.timestamp = currentTimestamp() state.timestamp = currentTimestamp()

840
yarn.lock

File diff suppressed because it is too large Load Diff