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>
This commit is contained in:
parent
7ac1ed3f52
commit
f047f0d196
4
src/assets/svg/matic-token-icon.svg
Normal file
4
src/assets/svg/matic-token-icon.svg
Normal 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 |
16
src/assets/svg/polygon-matic-logo.svg
Normal file
16
src/assets/svg/polygon-matic-logo.svg
Normal 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 |
@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
|
|||||||
import { Fraction, TradeType } from '@uniswap/sdk-core'
|
import { Fraction, TradeType } from '@uniswap/sdk-core'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
|
|
||||||
|
import { nativeOnChain } from '../../constants/tokens'
|
||||||
import { useCurrency, useToken } from '../../hooks/Tokens'
|
import { useCurrency, useToken } from '../../hooks/Tokens'
|
||||||
import useENSName from '../../hooks/useENSName'
|
import useENSName from '../../hooks/useENSName'
|
||||||
import { VoteOption } from '../../state/governance/types'
|
import { VoteOption } from '../../state/governance/types'
|
||||||
@ -130,18 +131,33 @@ function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInf
|
|||||||
return <Trans>Delegate voting power to {ENSName ?? delegatee}</Trans>
|
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) {
|
if (unwrapped) {
|
||||||
return (
|
return (
|
||||||
<Trans>
|
<Trans>
|
||||||
Unwrap <FormattedCurrencyAmount rawAmount={currencyAmountRaw} symbol={'WETH'} decimals={18} sigFigs={6} /> to
|
Unwrap{' '}
|
||||||
ETH
|
<FormattedCurrencyAmount
|
||||||
|
rawAmount={currencyAmountRaw}
|
||||||
|
symbol={native?.wrapped?.symbol ?? 'WETH'}
|
||||||
|
decimals={18}
|
||||||
|
sigFigs={6}
|
||||||
|
/>{' '}
|
||||||
|
to {native?.symbol ?? 'ETH'}
|
||||||
</Trans>
|
</Trans>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Trans>
|
<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>
|
</Trans>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Currency } from '@uniswap/sdk-core'
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
|
import EthereumLogo from 'assets/images/ethereum-logo.png'
|
||||||
|
import MaticLogo from 'assets/svg/matic-token-icon.svg'
|
||||||
import { SupportedChainId } from 'constants/chains'
|
import { SupportedChainId } from 'constants/chains'
|
||||||
|
import useHttpLocations from 'hooks/useHttpLocations'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
|
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
|
||||||
import styled from 'styled-components/macro'
|
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'
|
import Logo from '../Logo'
|
||||||
|
|
||||||
type Network = 'ethereum' | 'arbitrum' | 'optimism'
|
type Network = 'ethereum' | 'arbitrum' | 'optimism'
|
||||||
@ -34,7 +35,7 @@ export const getTokenLogoURL = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledEthereumLogo = styled.img<{ size: string }>`
|
const StyledNativeLogo = styled.img<{ size: string }>`
|
||||||
width: ${({ size }) => size};
|
width: ${({ size }) => size};
|
||||||
height: ${({ size }) => size};
|
height: ${({ size }) => size};
|
||||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||||
@ -87,7 +88,17 @@ export default function CurrencyLogo({
|
|||||||
}, [currency, uriLocations])
|
}, [currency, uriLocations])
|
||||||
|
|
||||||
if (currency?.isNative) {
|
if (currency?.isNative) {
|
||||||
return <StyledEthereumLogo src={EthereumLogo} alt="ethereum logo" size={size} style={style} {...rest} />
|
let nativeLogoUrl: string
|
||||||
|
switch (currency.chainId) {
|
||||||
|
case SupportedChainId.POLYGON_MUMBAI:
|
||||||
|
case SupportedChainId.POLYGON:
|
||||||
|
nativeLogoUrl = MaticLogo
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
nativeLogoUrl = EthereumLogo
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return <StyledNativeLogo src={nativeLogoUrl} 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} srcs={srcs} alt={`${currency?.symbol ?? 'token'} logo`} style={style} {...rest} />
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import { L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
import { SupportedChainId } from 'constants/chains'
|
||||||
import { useActiveWeb3React } from 'hooks/web3'
|
import { useActiveWeb3React } from 'hooks/web3'
|
||||||
import { AlertOctagon } from 'react-feather'
|
import { AlertOctagon } from 'react-feather'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ExternalLink } from 'theme'
|
import { ExternalLink } from 'theme'
|
||||||
|
|
||||||
|
import { isL2ChainId } from '../../utils/chains'
|
||||||
|
|
||||||
const Root = styled.div`
|
const Root = styled.div`
|
||||||
background-color: ${({ theme }) => (theme.darkMode ? '#888D9B' : '#CED0D9')};
|
background-color: ${({ theme }) => (theme.darkMode ? '#888D9B' : '#CED0D9')};
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
@ -18,7 +20,6 @@ const Root = styled.div`
|
|||||||
max-width: 880px;
|
max-width: 880px;
|
||||||
`
|
`
|
||||||
const WarningIcon = styled(AlertOctagon)`
|
const WarningIcon = styled(AlertOctagon)`
|
||||||
display: block;
|
|
||||||
margin: auto 16px auto 0;
|
margin: auto 16px auto 0;
|
||||||
min-height: 22px;
|
min-height: 22px;
|
||||||
min-width: 22px;
|
min-width: 22px;
|
||||||
@ -28,50 +29,54 @@ const ReadMoreLink = styled(ExternalLink)`
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function DowntimeWarning() {
|
function Wrapper({ children }: { children: React.ReactNode }) {
|
||||||
const { chainId } = useActiveWeb3React()
|
|
||||||
if (!chainId || !L2_CHAIN_IDS.includes(chainId)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const Content = () => {
|
|
||||||
switch (chainId) {
|
|
||||||
case SupportedChainId.OPTIMISM:
|
|
||||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Trans>
|
|
||||||
Optimistic Ethereum is in Beta and may experience downtime. Optimism expects planned downtime to upgrade
|
|
||||||
the network in the near future. During downtime, your position will not earn fees and you will be unable
|
|
||||||
to remove liquidity.{' '}
|
|
||||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5406082-what-happens-if-the-optimistic-ethereum-network-experiences-downtime">
|
|
||||||
Read more.
|
|
||||||
</ReadMoreLink>
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
case SupportedChainId.ARBITRUM_ONE:
|
|
||||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Trans>
|
|
||||||
Arbitrum is in Beta and may experience downtime. During downtime, your position will not earn fees and you
|
|
||||||
will be unable to remove liquidity.{' '}
|
|
||||||
<ReadMoreLink href="https://help.uniswap.org/en/articles/5576122-arbitrum-network-downtime">
|
|
||||||
Read more.
|
|
||||||
</ReadMoreLink>
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Root>
|
<Root>
|
||||||
<WarningIcon />
|
<WarningIcon />
|
||||||
<Content />
|
<div>{children}</div>
|
||||||
</Root>
|
</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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import {
|
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||||
ARBITRUM_HELP_CENTER_LINK,
|
|
||||||
CHAIN_INFO,
|
|
||||||
L2_CHAIN_IDS,
|
|
||||||
OPTIMISM_HELP_CENTER_LINK,
|
|
||||||
SupportedChainId,
|
|
||||||
SupportedL2ChainId,
|
|
||||||
} from 'constants/chains'
|
|
||||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||||
import { useActiveWeb3React } from 'hooks/web3'
|
import { useActiveWeb3React } from 'hooks/web3'
|
||||||
import { useCallback, useRef } from 'react'
|
import { useCallback, useRef } from 'react'
|
||||||
import { ArrowDownCircle, ChevronDown } from 'react-feather'
|
import { ArrowDownCircle, ChevronDown } from 'react-feather'
|
||||||
import { useModalOpen, useToggleModal } from 'state/application/hooks'
|
import { useModalOpen, useToggleModal } from 'state/application/hooks'
|
||||||
import { ApplicationModal } from 'state/application/reducer'
|
import { addPopup, ApplicationModal } from 'state/application/reducer'
|
||||||
import { useAppSelector } from 'state/hooks'
|
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||||
import { switchToNetwork } from 'utils/switchToNetwork'
|
|
||||||
|
import { useAppDispatch } from '../../state/hooks'
|
||||||
|
import { switchToNetwork } from '../../utils/switchToNetwork'
|
||||||
|
|
||||||
const ActiveRowLinkList = styled.div`
|
const ActiveRowLinkList = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -136,7 +130,7 @@ const SelectorWrapper = styled.div`
|
|||||||
const StyledChevronDown = styled(ChevronDown)`
|
const StyledChevronDown = styled(ChevronDown)`
|
||||||
width: 12px;
|
width: 12px;
|
||||||
`
|
`
|
||||||
const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
const BridgeLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||||
switch (chainId) {
|
switch (chainId) {
|
||||||
case SupportedChainId.ARBITRUM_ONE:
|
case SupportedChainId.ARBITRUM_ONE:
|
||||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||||
@ -144,11 +138,14 @@ const BridgeText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
|||||||
case SupportedChainId.OPTIMISM:
|
case SupportedChainId.OPTIMISM:
|
||||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||||
return <Trans>Optimism Gateway</Trans>
|
return <Trans>Optimism Gateway</Trans>
|
||||||
|
case SupportedChainId.POLYGON:
|
||||||
|
case SupportedChainId.POLYGON_MUMBAI:
|
||||||
|
return <Trans>Polygon Bridge</Trans>
|
||||||
default:
|
default:
|
||||||
return <Trans>Bridge</Trans>
|
return <Trans>Bridge</Trans>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
const ExplorerLabel = ({ chainId }: { chainId: SupportedChainId }) => {
|
||||||
switch (chainId) {
|
switch (chainId) {
|
||||||
case SupportedChainId.ARBITRUM_ONE:
|
case SupportedChainId.ARBITRUM_ONE:
|
||||||
case SupportedChainId.ARBITRUM_RINKEBY:
|
case SupportedChainId.ARBITRUM_RINKEBY:
|
||||||
@ -156,91 +153,108 @@ const ExplorerText = ({ chainId }: { chainId: SupportedL2ChainId }) => {
|
|||||||
case SupportedChainId.OPTIMISM:
|
case SupportedChainId.OPTIMISM:
|
||||||
case SupportedChainId.OPTIMISTIC_KOVAN:
|
case SupportedChainId.OPTIMISTIC_KOVAN:
|
||||||
return <Trans>Optimistic Etherscan</Trans>
|
return <Trans>Optimistic Etherscan</Trans>
|
||||||
|
case SupportedChainId.POLYGON:
|
||||||
|
case SupportedChainId.POLYGON_MUMBAI:
|
||||||
|
return <Trans>Polygonscan</Trans>
|
||||||
default:
|
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
|
||||||
|
}
|
||||||
|
|
||||||
export default function NetworkSelector() {
|
export default function NetworkSelector() {
|
||||||
const { chainId, library } = useActiveWeb3React()
|
const { chainId, library } = useActiveWeb3React()
|
||||||
const node = useRef<HTMLDivElement>()
|
const node = useRef<HTMLDivElement>()
|
||||||
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
|
const open = useModalOpen(ApplicationModal.NETWORK_SELECTOR)
|
||||||
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
|
const toggle = useToggleModal(ApplicationModal.NETWORK_SELECTOR)
|
||||||
useOnClickOutside(node, open ? toggle : undefined)
|
useOnClickOutside(node, open ? toggle : undefined)
|
||||||
const implements3085 = useAppSelector((state) => state.application.implements3085)
|
|
||||||
|
|
||||||
const info = chainId ? CHAIN_INFO[chainId] : undefined
|
const info = chainId ? CHAIN_INFO[chainId] : undefined
|
||||||
|
|
||||||
const isOnL2 = chainId ? L2_CHAIN_IDS.includes(chainId) : false
|
const dispatch = useAppDispatch()
|
||||||
const showSelector = Boolean(implements3085 || isOnL2)
|
|
||||||
const mainnetInfo = CHAIN_INFO[SupportedChainId.MAINNET]
|
|
||||||
|
|
||||||
const conditionalToggle = useCallback(() => {
|
const handleRowClick = useCallback(
|
||||||
if (showSelector) {
|
(targetChain: number) => {
|
||||||
toggle()
|
if (!library) return
|
||||||
}
|
switchToNetwork({ library, chainId: targetChain })
|
||||||
}, [showSelector, toggle])
|
.then(() => toggle())
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to switch networks', error)
|
||||||
|
toggle()
|
||||||
|
dispatch(addPopup({ content: { failedSwitchNetwork: targetChain }, key: `failed-network-switch` }))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[dispatch, library, toggle]
|
||||||
|
)
|
||||||
|
|
||||||
if (!chainId || !info || !library) {
|
if (!chainId || !info || !library) {
|
||||||
return null
|
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 (
|
return (
|
||||||
<SelectorWrapper ref={node as any}>
|
<SelectorWrapper ref={node as any}>
|
||||||
<SelectorControls onClick={conditionalToggle} interactive={showSelector}>
|
<SelectorControls onClick={toggle} interactive>
|
||||||
<SelectorLogo interactive={showSelector} src={info.logoUrl || mainnetInfo.logoUrl} />
|
<SelectorLogo interactive src={info.logoUrl} />
|
||||||
<SelectorLabel>{info.label}</SelectorLabel>
|
<SelectorLabel>{info.label}</SelectorLabel>
|
||||||
{showSelector && <StyledChevronDown />}
|
<StyledChevronDown />
|
||||||
</SelectorControls>
|
</SelectorControls>
|
||||||
{open && (
|
{open && (
|
||||||
<FlyoutMenu>
|
<FlyoutMenu>
|
||||||
<FlyoutHeader>
|
<FlyoutHeader>
|
||||||
<Trans>Select a network</Trans>
|
<Trans>Select a network</Trans>
|
||||||
</FlyoutHeader>
|
</FlyoutHeader>
|
||||||
<Row targetChain={SupportedChainId.MAINNET} />
|
<Row onSelectChain={handleRowClick} targetChain={SupportedChainId.MAINNET} />
|
||||||
<Row targetChain={SupportedChainId.OPTIMISM} />
|
<Row onSelectChain={handleRowClick} targetChain={SupportedChainId.POLYGON} />
|
||||||
<Row targetChain={SupportedChainId.ARBITRUM_ONE} />
|
<Row onSelectChain={handleRowClick} targetChain={SupportedChainId.OPTIMISM} />
|
||||||
|
<Row onSelectChain={handleRowClick} targetChain={SupportedChainId.ARBITRUM_ONE} />
|
||||||
</FlyoutMenu>
|
</FlyoutMenu>
|
||||||
)}
|
)}
|
||||||
</SelectorWrapper>
|
</SelectorWrapper>
|
||||||
|
@ -147,8 +147,8 @@ export default function Polling() {
|
|||||||
<MouseoverTooltip
|
<MouseoverTooltip
|
||||||
text={
|
text={
|
||||||
<Trans>
|
<Trans>
|
||||||
{`The current fast gas amount for sending a transaction on L1.
|
The current fast gas amount for sending a transaction on L1. Gas fees are paid in
|
||||||
Gas fees are paid in Ethereum's native currency Ether (ETH) and denominated in gwei. `}
|
Ethereum's native currency Ether (ETH) and denominated in GWEI.
|
||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -166,7 +166,7 @@ export default function Polling() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<MouseoverTooltip
|
<MouseoverTooltip
|
||||||
text={<Trans>{`The most recent block number on this network. Prices update on every block.`}</Trans>}
|
text={<Trans>The most recent block number on this network. Prices update on every block.</Trans>}
|
||||||
>
|
>
|
||||||
{blockNumber} 
|
{blockNumber} 
|
||||||
</MouseoverTooltip>
|
</MouseoverTooltip>
|
||||||
|
@ -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, ThemedText, 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>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>Your UNI Breakdown</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
|
|
||||||
</RowBetween>
|
|
||||||
</CardSection>
|
|
||||||
<Break />
|
|
||||||
{account && (
|
|
||||||
<>
|
|
||||||
<CardSection gap="sm">
|
|
||||||
<AutoColumn gap="md" justify="center">
|
|
||||||
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
|
|
||||||
<ThemedText.White fontSize={48} fontWeight={600} color="white">
|
|
||||||
{total?.toFixed(2, { groupSeparator: ',' })}
|
|
||||||
</ThemedText.White>
|
|
||||||
</AutoColumn>
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>Balance:</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<ThemedText.White color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</ThemedText.White>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>Unclaimed:</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
|
|
||||||
{uniToClaim && uniToClaim.greaterThan('0') && (
|
|
||||||
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
|
|
||||||
<Trans>(claim)</Trans>
|
|
||||||
</StyledInternalLink>
|
|
||||||
)}
|
|
||||||
</ThemedText.White>
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
</CardSection>
|
|
||||||
<Break />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<CardSection gap="sm">
|
|
||||||
<AutoColumn gap="md">
|
|
||||||
<RowBetween>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>UNI price:</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<ThemedText.White color="white">${uniPrice?.toFixed(2) ?? '-'}</ThemedText.White>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>UNI in circulation:</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<ThemedText.White color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<ThemedText.White color="white">
|
|
||||||
<Trans>Total Supply</Trans>
|
|
||||||
</ThemedText.White>
|
|
||||||
<ThemedText.White color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
|
||||||
</RowBetween>
|
|
||||||
{uni && uni.chainId === 1 ? (
|
|
||||||
<ExternalLink href={`${infoLink}/token/${uni.address}`}>
|
|
||||||
<Trans>View UNI Analytics</Trans>
|
|
||||||
</ExternalLink>
|
|
||||||
) : null}
|
|
||||||
</AutoColumn>
|
|
||||||
</CardSection>
|
|
||||||
</ModalUpper>
|
|
||||||
</ContentWrapper>
|
|
||||||
)
|
|
||||||
}
|
|
@ -3,14 +3,13 @@ import useScrollPosition from '@react-hook/window-scroll'
|
|||||||
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||||
import useTheme from 'hooks/useTheme'
|
import useTheme from 'hooks/useTheme'
|
||||||
import { darken } from 'polished'
|
import { darken } from 'polished'
|
||||||
import { useState } from 'react'
|
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { useShowClaimPopup, useToggleSelfClaimModal } from 'state/application/hooks'
|
import { useShowClaimPopup, useToggleSelfClaimModal } from 'state/application/hooks'
|
||||||
import { useUserHasAvailableClaim } from 'state/claim/hooks'
|
import { useUserHasAvailableClaim } from 'state/claim/hooks'
|
||||||
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
|
import { useUserHasSubmittedClaim } from 'state/transactions/hooks'
|
||||||
import { useDarkModeManager } from 'state/user/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 styled from 'styled-components/macro'
|
||||||
|
|
||||||
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
||||||
@ -19,12 +18,10 @@ import { ExternalLink, ThemedText } from '../../theme'
|
|||||||
import ClaimModal from '../claim/ClaimModal'
|
import ClaimModal from '../claim/ClaimModal'
|
||||||
import { CardNoise } from '../earn/styled'
|
import { CardNoise } from '../earn/styled'
|
||||||
import Menu from '../Menu'
|
import Menu from '../Menu'
|
||||||
import Modal from '../Modal'
|
|
||||||
import Row from '../Row'
|
import Row from '../Row'
|
||||||
import { Dots } from '../swap/styleds'
|
import { Dots } from '../swap/styleds'
|
||||||
import Web3Status from '../Web3Status'
|
import Web3Status from '../Web3Status'
|
||||||
import NetworkSelector from './NetworkSelector'
|
import NetworkSelector from './NetworkSelector'
|
||||||
import UniBalanceContent from './UniBalanceContent'
|
|
||||||
|
|
||||||
const HeaderFrame = styled.div<{ showBackground: boolean }>`
|
const HeaderFrame = styled.div<{ showBackground: boolean }>`
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -246,7 +243,7 @@ const StyledExternalLink = styled(ExternalLink).attrs({
|
|||||||
export default function Header() {
|
export default function Header() {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { account, chainId } = useActiveWeb3React()
|
||||||
|
|
||||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
const userEthBalance = useNativeCurrencyBalances(account ? [account] : [])?.[account ?? '']
|
||||||
const [darkMode] = useDarkModeManager()
|
const [darkMode] = useDarkModeManager()
|
||||||
const { white, black } = useTheme()
|
const { white, black } = useTheme()
|
||||||
|
|
||||||
@ -256,18 +253,20 @@ export default function Header() {
|
|||||||
|
|
||||||
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
|
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
|
||||||
|
|
||||||
const [showUniBalanceModal, setShowUniBalanceModal] = useState(false)
|
|
||||||
const showClaimPopup = useShowClaimPopup()
|
const showClaimPopup = useShowClaimPopup()
|
||||||
|
|
||||||
const scrollY = useScrollPosition()
|
const scrollY = useScrollPosition()
|
||||||
|
|
||||||
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
const {
|
||||||
|
infoLink,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { symbol: nativeCurrencySymbol },
|
||||||
|
},
|
||||||
|
} = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderFrame showBackground={scrollY > 45}>
|
<HeaderFrame showBackground={scrollY > 45}>
|
||||||
<ClaimModal />
|
<ClaimModal />
|
||||||
<Modal isOpen={showUniBalanceModal} onDismiss={() => setShowUniBalanceModal(false)}>
|
|
||||||
<UniBalanceContent setShowUniBalanceModal={setShowUniBalanceModal} />
|
|
||||||
</Modal>
|
|
||||||
<Title href=".">
|
<Title href=".">
|
||||||
<UniIcon>
|
<UniIcon>
|
||||||
<Logo fill={darkMode ? white : black} width="24px" height="100%" title="logo" />
|
<Logo fill={darkMode ? white : black} width="24px" height="100%" title="logo" />
|
||||||
@ -325,7 +324,9 @@ export default function Header() {
|
|||||||
<AccountElement active={!!account}>
|
<AccountElement active={!!account}>
|
||||||
{account && userEthBalance ? (
|
{account && userEthBalance ? (
|
||||||
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
<BalanceText style={{ flexShrink: 0, userSelect: 'none' }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||||
<Trans>{userEthBalance?.toSignificant(3)} ETH</Trans>
|
<Trans>
|
||||||
|
{userEthBalance?.toSignificant(3)} {nativeCurrencySymbol}
|
||||||
|
</Trans>
|
||||||
</BalanceText>
|
</BalanceText>
|
||||||
) : null}
|
) : null}
|
||||||
<Web3Status />
|
<Web3Status />
|
||||||
|
@ -1,32 +1,22 @@
|
|||||||
import { Trans } from '@lingui/macro'
|
import { Trans } from '@lingui/macro'
|
||||||
import {
|
import { SupportedChainId } from 'constants/chains'
|
||||||
ARBITRUM_HELP_CENTER_LINK,
|
|
||||||
L2_CHAIN_IDS,
|
|
||||||
OPTIMISM_HELP_CENTER_LINK,
|
|
||||||
SupportedChainId,
|
|
||||||
SupportedL2ChainId,
|
|
||||||
} from 'constants/chains'
|
|
||||||
import { useActiveWeb3React } from 'hooks/web3'
|
import { useActiveWeb3React } from 'hooks/web3'
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { ArrowDownCircle, X } from 'react-feather'
|
import { ArrowDownCircle, X } from 'react-feather'
|
||||||
import { useArbitrumAlphaAlert, useDarkModeManager, useOptimismAlphaAlert } from 'state/user/hooks'
|
import { useDarkModeManager, useNetworkAlertStatus } from 'state/user/hooks'
|
||||||
import { useETHBalances } from 'state/wallet/hooks'
|
import { useNativeCurrencyBalances } from 'state/wallet/hooks'
|
||||||
import styled, { css } from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
|
||||||
|
|
||||||
import { CHAIN_INFO } from '../../constants/chains'
|
import { CHAIN_INFO } from '../../constants/chains'
|
||||||
|
import { ThemedText } from '../../theme'
|
||||||
export const DesktopTextBreak = styled.div`
|
import { AutoRow } from '../Row'
|
||||||
display: none;
|
|
||||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToMedium}px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const L2Icon = styled.img`
|
const L2Icon = styled.img`
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
|
margin-right: 14px;
|
||||||
`
|
`
|
||||||
const BetaTag = styled.span<{ color: string }>`
|
const BetaTag = styled.span<{ color: string }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -44,24 +34,11 @@ const BetaTag = styled.span<{ color: string }>`
|
|||||||
width: 60px;
|
width: 60px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
`
|
`
|
||||||
const Body = styled.p`
|
export const Controls = styled.div`
|
||||||
font-size: 12px;
|
|
||||||
grid-column: 1 / 3;
|
|
||||||
line-height: 143%;
|
|
||||||
margin: 0;
|
|
||||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
|
||||||
grid-column: 2 / 3;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
export const Controls = styled.div<{ thin?: boolean }>`
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
${({ thin }) =>
|
padding: 0 20px 20px 20px;
|
||||||
thin &&
|
|
||||||
css`
|
|
||||||
margin: auto 32px auto 0;
|
|
||||||
`}
|
|
||||||
`
|
`
|
||||||
const CloseIcon = styled(X)`
|
const CloseIcon = styled(X)`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -71,17 +48,13 @@ const CloseIcon = styled(X)`
|
|||||||
`
|
`
|
||||||
const BodyText = styled.div`
|
const BodyText = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: grid;
|
|
||||||
grid-gap: 4px;
|
|
||||||
grid-template-columns: 40px 4fr;
|
|
||||||
grid-template-rows: auto auto;
|
|
||||||
margin: 20px 16px;
|
margin: 20px 16px;
|
||||||
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
@media screen and (min-width: ${MEDIA_WIDTHS.upToSmall}px) {
|
||||||
grid-template-columns: 42px 4fr;
|
grid-template-columns: 42px 4fr;
|
||||||
grid-gap: 8px;
|
grid-gap: 8px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
|
const LearnMoreLink = styled(ExternalLink)`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||||
@ -91,7 +64,6 @@ const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 0 0 20px 0;
|
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
@ -101,57 +73,51 @@ const LearnMoreLink = styled(ExternalLink)<{ thin?: boolean }>`
|
|||||||
background-color: rgba(255, 255, 255, 0.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
transition: background-color 150ms ease-in-out;
|
transition: background-color 150ms ease-in-out;
|
||||||
${({ thin }) =>
|
|
||||||
thin &&
|
|
||||||
css`
|
|
||||||
font-size: 14px;
|
|
||||||
margin: auto;
|
|
||||||
width: 112px;
|
|
||||||
`}
|
|
||||||
`
|
`
|
||||||
const RootWrapper = styled.div`
|
const RootWrapper = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
`
|
`
|
||||||
export const ArbitrumWrapperBackgroundDarkMode = css`
|
const BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID: {
|
||||||
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
|
[darkMode in 'dark' | 'light']: { [chainId in SupportedChainId]?: string }
|
||||||
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);
|
} = {
|
||||||
`
|
dark: {
|
||||||
export const ArbitrumWrapperBackgroundLightMode = css`
|
[SupportedChainId.POLYGON]:
|
||||||
background: radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),
|
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.3) 0%, rgba(82, 32, 166, 0.3) 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.POLYGON_MUMBAI]:
|
||||||
`
|
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.3) 0%, rgba(82, 32, 166, 0.3) 100%)',
|
||||||
export const OptimismWrapperBackgroundDarkMode = css`
|
[SupportedChainId.OPTIMISM]:
|
||||||
background: radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%),
|
'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%)',
|
||||||
radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.5) 0%, rgba(235, 0, 255, 0.345) 96%);
|
[SupportedChainId.OPTIMISTIC_KOVAN]:
|
||||||
`
|
'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`
|
[SupportedChainId.ARBITRUM_ONE]:
|
||||||
background: radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),
|
'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)',
|
||||||
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);
|
[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(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)',
|
||||||
const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean; logoUrl: string; thin?: boolean }>`
|
},
|
||||||
${({ chainId, darkMode }) =>
|
light: {
|
||||||
[SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
[SupportedChainId.POLYGON]:
|
||||||
? darkMode
|
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.3) 0%, rgba(167, 202, 255, 0.3) 100%)',
|
||||||
? OptimismWrapperBackgroundDarkMode
|
[SupportedChainId.POLYGON_MUMBAI]:
|
||||||
: OptimismWrapperBackgroundLightMode
|
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.3) 0%, rgba(167, 202, 255, 0.3) 100%)',
|
||||||
: darkMode
|
[SupportedChainId.OPTIMISM]:
|
||||||
? ArbitrumWrapperBackgroundDarkMode
|
'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)',
|
||||||
: ArbitrumWrapperBackgroundLightMode};
|
[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.5)',
|
||||||
|
[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: SupportedChainId; darkMode: boolean; logoUrl: string }>`
|
||||||
|
background: ${({ chainId, darkMode }) => BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID[darkMode ? 'dark' : 'light'][chainId]};
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 480px;
|
|
||||||
min-height: 174px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
${({ thin }) =>
|
|
||||||
thin &&
|
|
||||||
css`
|
|
||||||
flex-direction: row;
|
|
||||||
max-width: max-content;
|
|
||||||
min-height: min-content;
|
|
||||||
`}
|
|
||||||
:before {
|
:before {
|
||||||
background-image: url(${({ logoUrl }) => logoUrl});
|
background-image: url(${({ logoUrl }) => logoUrl});
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@ -165,12 +131,11 @@ const ContentWrapper = styled.div<{ chainId: SupportedChainId; darkMode: boolean
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const Header = styled.h2<{ thin?: boolean }>`
|
const Header = styled.h2`
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-right: 30px;
|
padding-right: 30px;
|
||||||
display: ${({ thin }) => (thin ? 'none' : 'block')};
|
|
||||||
`
|
`
|
||||||
const LinkOutCircle = styled(ArrowDownCircle)`
|
const LinkOutCircle = styled(ArrowDownCircle)`
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
@ -178,7 +143,7 @@ const LinkOutCircle = styled(ArrowDownCircle)`
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
`
|
`
|
||||||
const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
|
const LinkOutToBridge = styled(ExternalLink)`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -187,8 +152,8 @@ const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 0 12px 20px 18px;
|
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
margin-right: 20px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
:hover,
|
:hover,
|
||||||
@ -196,85 +161,154 @@ const LinkOutToBridge = styled(ExternalLink)<{ thin?: boolean }>`
|
|||||||
:active {
|
:active {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
${({ thin }) =>
|
|
||||||
thin &&
|
|
||||||
css`
|
|
||||||
font-size: 14px;
|
|
||||||
margin: auto 10px;
|
|
||||||
width: 168px;
|
|
||||||
`}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
interface NetworkAlertProps {
|
const DisclaimerText = styled(ThemedText.Body)`
|
||||||
thin?: boolean
|
padding: 0 0.5em;
|
||||||
|
font-size: 14px !important;
|
||||||
|
`
|
||||||
|
|
||||||
|
const BETA_TAG_COLORS: { [chainId in SupportedChainId]?: string } = {
|
||||||
|
[SupportedChainId.OPTIMISM]: '#ff0420',
|
||||||
|
[SupportedChainId.OPTIMISTIC_KOVAN]: '#ff0420',
|
||||||
|
[SupportedChainId.ARBITRUM_ONE]: '#0490ed',
|
||||||
|
[SupportedChainId.ARBITRUM_RINKEBY]: '#0490ed',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NetworkAlert(props: NetworkAlertProps) {
|
const SHOULD_SHOW_ALERT: { [chainId in SupportedChainId]?: true } = {
|
||||||
|
[SupportedChainId.OPTIMISM]: true,
|
||||||
|
[SupportedChainId.OPTIMISTIC_KOVAN]: true,
|
||||||
|
[SupportedChainId.ARBITRUM_ONE]: true,
|
||||||
|
[SupportedChainId.ARBITRUM_RINKEBY]: true,
|
||||||
|
[SupportedChainId.POLYGON]: true,
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldShowAlert(chainId: number | undefined): chainId is SupportedChainId {
|
||||||
|
return Boolean(chainId && SHOULD_SHOW_ALERT[chainId as SupportedChainId])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NetworkAlert() {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { account, chainId } = useActiveWeb3React()
|
||||||
const [darkMode] = useDarkModeManager()
|
const [darkMode] = useDarkModeManager()
|
||||||
const [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged] = useArbitrumAlphaAlert()
|
const [alertAcknowledged, acknowledgeAlert] = useNetworkAlertStatus(chainId)
|
||||||
const [optimismAlphaAcknowledged, setOptimismAlphaAcknowledged] = useOptimismAlphaAlert()
|
|
||||||
const [locallyDismissed, setLocallyDimissed] = useState(false)
|
const [locallyDismissed, setLocallyDimissed] = useState(false)
|
||||||
const userEthBalance = useETHBalances(account ? [account] : [])?.[account ?? '']
|
const accounts = useMemo(() => (account ? [account] : []), [account])
|
||||||
|
const userNativeCurrencyBalance = useNativeCurrencyBalances(accounts)?.[account ?? '']
|
||||||
|
|
||||||
const dismiss = useCallback(() => {
|
const dismiss = useCallback(() => {
|
||||||
if (userEthBalance?.greaterThan(0)) {
|
setLocallyDimissed(true)
|
||||||
switch (chainId) {
|
if (!alertAcknowledged) acknowledgeAlert()
|
||||||
case SupportedChainId.OPTIMISM:
|
}, [acknowledgeAlert, alertAcknowledged])
|
||||||
setOptimismAlphaAcknowledged(true)
|
|
||||||
break
|
|
||||||
case SupportedChainId.ARBITRUM_ONE:
|
|
||||||
setArbitrumAlphaAcknowledged(true)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setLocallyDimissed(true)
|
|
||||||
}
|
|
||||||
}, [chainId, setArbitrumAlphaAcknowledged, setOptimismAlphaAcknowledged, userEthBalance])
|
|
||||||
|
|
||||||
const onOptimismAndOptimismAcknowledged = SupportedChainId.OPTIMISM === chainId && optimismAlphaAcknowledged
|
if (!shouldShowAlert(chainId) || alertAcknowledged || locallyDismissed) {
|
||||||
const onArbitrumAndArbitrumAcknowledged = SupportedChainId.ARBITRUM_ONE === chainId && arbitrumAlphaAcknowledged
|
|
||||||
if (
|
|
||||||
!chainId ||
|
|
||||||
!L2_CHAIN_IDS.includes(chainId) ||
|
|
||||||
onArbitrumAndArbitrumAcknowledged ||
|
|
||||||
onOptimismAndOptimismAcknowledged ||
|
|
||||||
locallyDismissed
|
|
||||||
) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const info = CHAIN_INFO[chainId as SupportedL2ChainId]
|
|
||||||
const isOptimism = [SupportedChainId.OPTIMISM, SupportedChainId.OPTIMISTIC_KOVAN].includes(chainId)
|
const { label, logoUrl, bridge, helpCenterUrl } = CHAIN_INFO[chainId]
|
||||||
const depositUrl = isOptimism ? `${info.bridge}?chainId=1` : info.bridge
|
const showCloseIcon = Boolean(userNativeCurrencyBalance?.greaterThan(0))
|
||||||
const helpCenterLink = isOptimism ? OPTIMISM_HELP_CENTER_LINK : ARBITRUM_HELP_CENTER_LINK
|
const betaColor = BETA_TAG_COLORS[chainId]
|
||||||
const showCloseIcon = Boolean(userEthBalance?.greaterThan(0) && !props.thin)
|
|
||||||
return (
|
return (
|
||||||
<RootWrapper>
|
<RootWrapper>
|
||||||
<BetaTag color={isOptimism ? '#ff0420' : '#0490ed'}>Beta</BetaTag>
|
{betaColor ? <BetaTag color={betaColor}>Beta</BetaTag> : null}
|
||||||
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={info.logoUrl} thin={props.thin}>
|
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={logoUrl}>
|
||||||
{showCloseIcon && <CloseIcon onClick={dismiss} />}
|
{showCloseIcon && <CloseIcon onClick={dismiss} />}
|
||||||
<BodyText>
|
<BodyText>
|
||||||
<L2Icon src={info.logoUrl} />
|
<AutoRow style={{ marginBottom: '1em' }}>
|
||||||
<Header thin={props.thin}>
|
<L2Icon src={logoUrl} />
|
||||||
<Trans>Uniswap on {info.label}</Trans>
|
<Header>
|
||||||
</Header>
|
<Trans>Uniswap on {label}</Trans>
|
||||||
<Body>
|
</Header>
|
||||||
<Trans>
|
</AutoRow>
|
||||||
To start trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
|
<DisclaimerText>
|
||||||
release and learn about the risks before using {info.label}.
|
{betaColor ? (
|
||||||
</Trans>
|
<Trans>
|
||||||
</Body>
|
Please treat this as a beta release and learn about the risks before using {label}. To start trading on{' '}
|
||||||
|
{label}, first bridge your assets from L1 to L2.
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>To start trading on {label}, first bridge your assets from L1 to L2.</Trans>
|
||||||
|
)}
|
||||||
|
</DisclaimerText>
|
||||||
</BodyText>
|
</BodyText>
|
||||||
<Controls thin={props.thin}>
|
<Controls>
|
||||||
<LinkOutToBridge href={depositUrl} thin={props.thin}>
|
{bridge ? (
|
||||||
<Trans>Deposit Assets</Trans>
|
<LinkOutToBridge href={bridge}>
|
||||||
<LinkOutCircle />
|
<Trans>Deposit Assets</Trans>
|
||||||
</LinkOutToBridge>
|
<LinkOutCircle />
|
||||||
<LearnMoreLink href={helpCenterLink} thin={props.thin}>
|
</LinkOutToBridge>
|
||||||
<Trans>Learn More</Trans>
|
) : null}
|
||||||
</LearnMoreLink>
|
{helpCenterUrl ? (
|
||||||
|
<LearnMoreLink href={helpCenterUrl}>
|
||||||
|
<Trans>Learn More</Trans>
|
||||||
|
</LearnMoreLink>
|
||||||
|
) : null}
|
||||||
</Controls>
|
</Controls>
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
</RootWrapper>
|
</RootWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AlertRow = styled.div`
|
||||||
|
display: flex;
|
||||||
|
padding: 1em;
|
||||||
|
align-items: center;
|
||||||
|
`
|
||||||
|
const ButtonContainer = styled.div`
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
`
|
||||||
|
const FlexGrow = styled.div`
|
||||||
|
flex-grow: 1;
|
||||||
|
`
|
||||||
|
export function SingleRowNetworkAlert() {
|
||||||
|
const { chainId } = useActiveWeb3React()
|
||||||
|
const [darkMode] = useDarkModeManager()
|
||||||
|
|
||||||
|
if (!shouldShowAlert(chainId)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { label, logoUrl, bridge, helpCenterUrl } = CHAIN_INFO[chainId]
|
||||||
|
const betaColor = BETA_TAG_COLORS[chainId]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RootWrapper>
|
||||||
|
{betaColor ? <BetaTag color={betaColor}>Beta</BetaTag> : null}
|
||||||
|
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={logoUrl}>
|
||||||
|
<AlertRow>
|
||||||
|
<L2Icon src={logoUrl} />
|
||||||
|
|
||||||
|
<FlexGrow>
|
||||||
|
<DisclaimerText>
|
||||||
|
{betaColor ? (
|
||||||
|
<Trans>
|
||||||
|
Please treat this as a beta release and learn about the risks before using {label}. To start trading
|
||||||
|
on {label}, first bridge your assets from L1 to L2.
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>To start trading on {label}, first bridge your assets from L1 to L2.</Trans>
|
||||||
|
)}
|
||||||
|
</DisclaimerText>
|
||||||
|
</FlexGrow>
|
||||||
|
|
||||||
|
<ButtonContainer>
|
||||||
|
{bridge ? (
|
||||||
|
<LinkOutToBridge href={bridge}>
|
||||||
|
<Trans>Deposit Assets</Trans>
|
||||||
|
<LinkOutCircle />
|
||||||
|
</LinkOutToBridge>
|
||||||
|
) : null}
|
||||||
|
{helpCenterUrl ? (
|
||||||
|
<LearnMoreLink href={helpCenterUrl}>
|
||||||
|
<Trans>Learn More</Trans>
|
||||||
|
</LearnMoreLink>
|
||||||
|
) : null}
|
||||||
|
</ButtonContainer>
|
||||||
|
</AlertRow>
|
||||||
|
</ContentWrapper>
|
||||||
|
</RootWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
34
src/components/Popups/FailedNetworkSwitchPopup.tsx
Normal file
34
src/components/Popups/FailedNetworkSwitchPopup.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
|
import { useContext } from 'react'
|
||||||
|
import { AlertCircle } from 'react-feather'
|
||||||
|
import styled, { ThemeContext } from 'styled-components/macro'
|
||||||
|
|
||||||
|
import { CHAIN_INFO, SupportedChainId } from '../../constants/chains'
|
||||||
|
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>
|
||||||
|
Your wallet does not support switching 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>
|
||||||
|
)
|
||||||
|
}
|
@ -6,6 +6,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
|||||||
|
|
||||||
import { useRemovePopup } from '../../state/application/hooks'
|
import { useRemovePopup } from '../../state/application/hooks'
|
||||||
import { PopupContent } from '../../state/application/reducer'
|
import { PopupContent } from '../../state/application/reducer'
|
||||||
|
import FailedNetworkSwitchPopup from './FailedNetworkSwitchPopup'
|
||||||
import TransactionPopup from './TransactionPopup'
|
import TransactionPopup from './TransactionPopup'
|
||||||
|
|
||||||
const StyledClose = styled(X)`
|
const StyledClose = styled(X)`
|
||||||
@ -77,6 +78,8 @@ export default function PopupItem({
|
|||||||
txn: { hash },
|
txn: { hash },
|
||||||
} = content
|
} = content
|
||||||
popupContent = <TransactionPopup hash={hash} />
|
popupContent = <TransactionPopup hash={hash} />
|
||||||
|
} else if ('failedSwitchNetwork' in content) {
|
||||||
|
popupContent = <FailedNetworkSwitchPopup chainId={content.failedSwitchNetwork} />
|
||||||
}
|
}
|
||||||
|
|
||||||
const faderStyle = useSpring({
|
const faderStyle = useSpring({
|
||||||
|
@ -19,7 +19,7 @@ import { PositionDetails } from 'types/position'
|
|||||||
import { formatTickPrice } from 'utils/formatTickPrice'
|
import { formatTickPrice } from 'utils/formatTickPrice'
|
||||||
import { unwrappedToken } from 'utils/unwrappedToken'
|
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)`
|
const LinkRow = styled(Link)`
|
||||||
align-items: center;
|
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
|
// 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))) {
|
if (bases.some((base) => base.equals(token1))) {
|
||||||
return {
|
return {
|
||||||
priceLower: position.token0PriceUpper.invert(),
|
priceLower: position.token0PriceUpper.invert(),
|
||||||
|
@ -13,8 +13,13 @@ import { FixedSizeList } from 'react-window'
|
|||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
import { ExtendedEther } from '../../constants/tokens'
|
import {
|
||||||
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
useAllTokens,
|
||||||
|
useIsUserAddedToken,
|
||||||
|
useNativeCurrency,
|
||||||
|
useSearchInactiveTokenLists,
|
||||||
|
useToken,
|
||||||
|
} from '../../hooks/Tokens'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
|
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
|
||||||
import { isAddress } from '../../utils'
|
import { isAddress } from '../../utils'
|
||||||
@ -112,15 +117,17 @@ export function CurrencySearch({
|
|||||||
|
|
||||||
const filteredSortedTokens = useSortedTokensByQuery(sortedTokens, debouncedQuery)
|
const filteredSortedTokens = useSortedTokensByQuery(sortedTokens, debouncedQuery)
|
||||||
|
|
||||||
const ether = useMemo(() => chainId && ExtendedEther.onChain(chainId), [chainId])
|
const native = useNativeCurrency()
|
||||||
|
|
||||||
const filteredSortedTokensWithETH: Currency[] = useMemo(() => {
|
const filteredSortedTokensWithETH: Currency[] = useMemo(() => {
|
||||||
|
if (!native) return filteredSortedTokens
|
||||||
|
|
||||||
const s = debouncedQuery.toLowerCase().trim()
|
const s = debouncedQuery.toLowerCase().trim()
|
||||||
if (s === '' || s === 'e' || s === 'et' || s === 'eth') {
|
if (native.symbol?.toLowerCase()?.indexOf(s) !== -1) {
|
||||||
return ether ? [ether, ...filteredSortedTokens] : filteredSortedTokens
|
return native ? [native, ...filteredSortedTokens] : filteredSortedTokens
|
||||||
}
|
}
|
||||||
return filteredSortedTokens
|
return filteredSortedTokens
|
||||||
}, [debouncedQuery, ether, filteredSortedTokens])
|
}, [debouncedQuery, native, filteredSortedTokens])
|
||||||
|
|
||||||
const handleCurrencySelect = useCallback(
|
const handleCurrencySelect = useCallback(
|
||||||
(currency: Currency) => {
|
(currency: Currency) => {
|
||||||
@ -148,8 +155,8 @@ export function CurrencySearch({
|
|||||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
const s = debouncedQuery.toLowerCase().trim()
|
const s = debouncedQuery.toLowerCase().trim()
|
||||||
if (s === 'eth' && ether) {
|
if (s === native?.symbol?.toLowerCase()) {
|
||||||
handleCurrencySelect(ether)
|
handleCurrencySelect(native)
|
||||||
} else if (filteredSortedTokensWithETH.length > 0) {
|
} else if (filteredSortedTokensWithETH.length > 0) {
|
||||||
if (
|
if (
|
||||||
filteredSortedTokensWithETH[0].symbol?.toLowerCase() === debouncedQuery.trim().toLowerCase() ||
|
filteredSortedTokensWithETH[0].symbol?.toLowerCase() === debouncedQuery.trim().toLowerCase() ||
|
||||||
@ -160,7 +167,7 @@ export function CurrencySearch({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[debouncedQuery, ether, filteredSortedTokensWithETH, handleCurrencySelect]
|
[debouncedQuery, native, filteredSortedTokensWithETH, handleCurrencySelect]
|
||||||
)
|
)
|
||||||
|
|
||||||
// menu ui
|
// menu ui
|
||||||
|
@ -111,7 +111,7 @@ const HoverText = styled.div`
|
|||||||
|
|
||||||
const LinkCard = styled(Card)`
|
const LinkCard = styled(Card)`
|
||||||
background-color: ${({ theme }) => theme.bg1};
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
color: ${({ theme }) => theme.white};
|
color: ${({ theme }) => theme.text3};
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -416,9 +416,9 @@ export default function WalletModal({
|
|||||||
<RowBetween>
|
<RowBetween>
|
||||||
<AutoRow gap="4px">
|
<AutoRow gap="4px">
|
||||||
<Info size={20} />
|
<Info size={20} />
|
||||||
<ThemedText.White fontSize={14}>
|
<ThemedText.Label fontSize={14}>
|
||||||
<Trans>How this app uses APIs</Trans>
|
<Trans>How this app uses APIs</Trans>
|
||||||
</ThemedText.White>
|
</ThemedText.Label>
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
<ArrowRight size={16} />
|
<ArrowRight size={16} />
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
@ -83,23 +83,27 @@ export default memo(function SwapRoute({ trade, syncing, fixedOpen = false, ...r
|
|||||||
routes={routes}
|
routes={routes}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Separator />
|
|
||||||
{autoRouterSupported &&
|
{autoRouterSupported && (
|
||||||
(syncing ? (
|
<>
|
||||||
<LoadingRows>
|
<Separator />
|
||||||
<div style={{ width: '250px', height: '15px' }} />
|
{syncing ? (
|
||||||
</LoadingRows>
|
<LoadingRows>
|
||||||
) : (
|
<div style={{ width: '250px', height: '15px' }} />
|
||||||
<ThemedText.Main fontSize={12} width={400} margin={0}>
|
</LoadingRows>
|
||||||
{trade?.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? (
|
) : (
|
||||||
<Trans>Best price route costs ~{formattedGasPriceString} in gas. </Trans>
|
<ThemedText.Main fontSize={12} width={400} margin={0}>
|
||||||
) : null}{' '}
|
{trade?.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? (
|
||||||
<Trans>
|
<Trans>Best price route costs ~{formattedGasPriceString} in gas. </Trans>
|
||||||
This route optimizes your total output by considering split routes, multiple hops, and the gas cost of
|
) : null}{' '}
|
||||||
each step.
|
<Trans>
|
||||||
</Trans>
|
This route optimizes your total output by considering split routes, multiple hops, and the gas cost
|
||||||
</ThemedText.Main>
|
of each step.
|
||||||
))}
|
</Trans>
|
||||||
|
</ThemedText.Main>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
</AnimatedDropdown>
|
</AnimatedDropdown>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
@ -36,11 +36,14 @@ class MiniRpcProvider implements AsyncSendable {
|
|||||||
public readonly path: string
|
public readonly path: string
|
||||||
public readonly batchWaitTimeMs: number
|
public readonly batchWaitTimeMs: number
|
||||||
|
|
||||||
|
private readonly connector: NetworkConnector
|
||||||
|
|
||||||
private nextId = 1
|
private nextId = 1
|
||||||
private batchTimeoutId: ReturnType<typeof setTimeout> | null = null
|
private batchTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||||
private batch: BatchItem[] = []
|
private batch: BatchItem[] = []
|
||||||
|
|
||||||
constructor(chainId: number, url: string, batchWaitTimeMs?: number) {
|
constructor(connector: NetworkConnector, chainId: number, url: string, batchWaitTimeMs?: number) {
|
||||||
|
this.connector = connector
|
||||||
this.chainId = chainId
|
this.chainId = chainId
|
||||||
this.url = url
|
this.url = url
|
||||||
const parsed = new URL(url)
|
const parsed = new URL(url)
|
||||||
@ -52,7 +55,21 @@ class MiniRpcProvider implements AsyncSendable {
|
|||||||
|
|
||||||
public readonly clearBatch = async () => {
|
public readonly clearBatch = async () => {
|
||||||
console.debug('Clearing batch', this.batch)
|
console.debug('Clearing batch', this.batch)
|
||||||
const batch = this.batch
|
let batch = this.batch
|
||||||
|
|
||||||
|
batch = batch.filter((b) => {
|
||||||
|
if (b.request.method === 'wallet_switchEthereumChain') {
|
||||||
|
try {
|
||||||
|
this.connector.changeChainId(parseInt((b.request.params as [{ chainId: string }])[0].chainId))
|
||||||
|
b.resolve({ id: b.request.id })
|
||||||
|
} catch (error) {
|
||||||
|
b.reject(error)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
this.batch = []
|
this.batch = []
|
||||||
this.batchTimeoutId = null
|
this.batchTimeoutId = null
|
||||||
let response: Response
|
let response: Response
|
||||||
@ -148,9 +165,9 @@ export class NetworkConnector extends AbstractConnector {
|
|||||||
invariant(defaultChainId || Object.keys(urls).length === 1, 'defaultChainId is a required argument with >1 url')
|
invariant(defaultChainId || Object.keys(urls).length === 1, 'defaultChainId is a required argument with >1 url')
|
||||||
super({ supportedChainIds: Object.keys(urls).map((k): number => Number(k)) })
|
super({ supportedChainIds: Object.keys(urls).map((k): number => Number(k)) })
|
||||||
|
|
||||||
this.currentChainId = defaultChainId || Number(Object.keys(urls)[0])
|
this.currentChainId = defaultChainId ?? Number(Object.keys(urls)[0])
|
||||||
this.providers = Object.keys(urls).reduce<{ [chainId: number]: MiniRpcProvider }>((accumulator, chainId) => {
|
this.providers = Object.keys(urls).reduce<{ [chainId: number]: MiniRpcProvider }>((accumulator, chainId) => {
|
||||||
accumulator[Number(chainId)] = new MiniRpcProvider(Number(chainId), urls[Number(chainId)])
|
accumulator[Number(chainId)] = new MiniRpcProvider(this, Number(chainId), urls[Number(chainId)])
|
||||||
return accumulator
|
return accumulator
|
||||||
}, {})
|
}, {})
|
||||||
}
|
}
|
||||||
@ -178,4 +195,21 @@ export class NetworkConnector extends AbstractConnector {
|
|||||||
public deactivate() {
|
public deactivate() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meant to be called only by MiniRpcProvider
|
||||||
|
* @param chainId the new chain id
|
||||||
|
*/
|
||||||
|
public changeChainId(chainId: number) {
|
||||||
|
if (chainId in this.providers) {
|
||||||
|
this.currentChainId = chainId
|
||||||
|
this.emitUpdate({
|
||||||
|
chainId,
|
||||||
|
account: null,
|
||||||
|
provider: this.providers[chainId],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unsupported chain ID: ${chainId}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,33 +6,16 @@ import { WalletConnectConnector } from '@web3-react/walletconnect-connector'
|
|||||||
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
|
import { WalletLinkConnector } from '@web3-react/walletlink-connector'
|
||||||
|
|
||||||
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
|
import UNISWAP_LOGO_URL from '../assets/svg/logo.svg'
|
||||||
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from '../constants/chains'
|
import { ALL_SUPPORTED_CHAIN_IDS, INFURA_NETWORK_URLS, SupportedChainId } from '../constants/chains'
|
||||||
import getLibrary from '../utils/getLibrary'
|
import getLibrary from '../utils/getLibrary'
|
||||||
import { FortmaticConnector } from './Fortmatic'
|
import { FortmaticConnector } from './Fortmatic'
|
||||||
import { NetworkConnector } from './NetworkConnector'
|
import { NetworkConnector } from './NetworkConnector'
|
||||||
|
|
||||||
const INFURA_KEY = process.env.REACT_APP_INFURA_KEY
|
|
||||||
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
|
||||||
|
|
||||||
if (typeof INFURA_KEY === 'undefined') {
|
|
||||||
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
|
||||||
[SupportedChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.GOERLI]: `https://goerli.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.OPTIMISM]: `https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.OPTIMISTIC_KOVAN]: `https://optimism-kovan.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.ARBITRUM_ONE]: `https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
[SupportedChainId.ARBITRUM_RINKEBY]: `https://arbitrum-rinkeby.infura.io/v3/${INFURA_KEY}`,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const network = new NetworkConnector({
|
export const network = new NetworkConnector({
|
||||||
urls: NETWORK_URLS,
|
urls: INFURA_NETWORK_URLS,
|
||||||
defaultChainId: 1,
|
defaultChainId: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -49,7 +32,7 @@ export const gnosisSafe = new SafeAppConnector()
|
|||||||
|
|
||||||
export const walletconnect = new WalletConnectConnector({
|
export const walletconnect = new WalletConnectConnector({
|
||||||
supportedChainIds: ALL_SUPPORTED_CHAIN_IDS,
|
supportedChainIds: ALL_SUPPORTED_CHAIN_IDS,
|
||||||
rpc: NETWORK_URLS,
|
rpc: INFURA_NETWORK_URLS,
|
||||||
qrcode: true,
|
qrcode: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,7 +50,7 @@ export const portis = new PortisConnector({
|
|||||||
|
|
||||||
// mainnet only
|
// mainnet only
|
||||||
export const walletlink = new WalletLinkConnector({
|
export const walletlink = new WalletLinkConnector({
|
||||||
url: NETWORK_URLS[SupportedChainId.MAINNET],
|
url: INFURA_NETWORK_URLS[SupportedChainId.MAINNET],
|
||||||
appName: 'Uniswap',
|
appName: 'Uniswap',
|
||||||
appLogoUrl: UNISWAP_LOGO_URL,
|
appLogoUrl: UNISWAP_LOGO_URL,
|
||||||
supportedChainIds: [SupportedChainId.MAINNET],
|
supportedChainIds: [SupportedChainId.MAINNET],
|
||||||
|
@ -11,6 +11,8 @@ export const MULTICALL_ADDRESS: AddressMap = {
|
|||||||
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [
|
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [
|
||||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||||
SupportedChainId.OPTIMISM,
|
SupportedChainId.OPTIMISM,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
]),
|
]),
|
||||||
[SupportedChainId.ARBITRUM_ONE]: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB',
|
[SupportedChainId.ARBITRUM_ONE]: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB',
|
||||||
[SupportedChainId.ARBITRUM_RINKEBY]: '0xa501c031958F579dB7676fF1CE78AD305794d579',
|
[SupportedChainId.ARBITRUM_RINKEBY]: '0xa501c031958F579dB7676fF1CE78AD305794d579',
|
||||||
@ -63,12 +65,16 @@ export const V3_CORE_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V3_
|
|||||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
SupportedChainId.ARBITRUM_ONE,
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
SupportedChainId.ARBITRUM_RINKEBY,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
])
|
])
|
||||||
export const QUOTER_ADDRESSES: AddressMap = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6', [
|
export const QUOTER_ADDRESSES: AddressMap = constructSameAddressMap('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6', [
|
||||||
SupportedChainId.OPTIMISM,
|
SupportedChainId.OPTIMISM,
|
||||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
SupportedChainId.ARBITRUM_ONE,
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
SupportedChainId.ARBITRUM_RINKEBY,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
])
|
])
|
||||||
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = constructSameAddressMap(
|
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = constructSameAddressMap(
|
||||||
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88',
|
'0xC36442b4a4522E871399CD717aBDD847Ab11FE88',
|
||||||
@ -77,6 +83,8 @@ export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = constructSameA
|
|||||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
SupportedChainId.ARBITRUM_ONE,
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
SupportedChainId.ARBITRUM_RINKEBY,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
export const ENS_REGISTRAR_ADDRESSES: AddressMap = {
|
export const ENS_REGISTRAR_ADDRESSES: AddressMap = {
|
||||||
@ -92,4 +100,6 @@ export const SOCKS_CONTROLLER_ADDRESSES: AddressMap = {
|
|||||||
export const V3_MIGRATOR_ADDRESSES: AddressMap = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [
|
export const V3_MIGRATOR_ADDRESSES: AddressMap = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
SupportedChainId.ARBITRUM_ONE,
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
SupportedChainId.ARBITRUM_RINKEBY,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
])
|
])
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import ethereumLogoUrl from 'assets/images/ethereum-logo.png'
|
import ethereumLogoUrl from 'assets/images/ethereum-logo.png'
|
||||||
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
|
import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
|
||||||
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
|
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
|
||||||
|
import polygonMaticLogo from 'assets/svg/polygon-matic-logo.svg'
|
||||||
import ms from 'ms.macro'
|
import ms from 'ms.macro'
|
||||||
|
|
||||||
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
|
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all the networks supported by the Uniswap Interface
|
||||||
|
*/
|
||||||
export enum SupportedChainId {
|
export enum SupportedChainId {
|
||||||
MAINNET = 1,
|
MAINNET = 1,
|
||||||
ROPSTEN = 3,
|
ROPSTEN = 3,
|
||||||
@ -14,33 +18,45 @@ export enum SupportedChainId {
|
|||||||
|
|
||||||
ARBITRUM_ONE = 42161,
|
ARBITRUM_ONE = 42161,
|
||||||
ARBITRUM_RINKEBY = 421611,
|
ARBITRUM_RINKEBY = 421611,
|
||||||
|
|
||||||
OPTIMISM = 10,
|
OPTIMISM = 10,
|
||||||
OPTIMISTIC_KOVAN = 69,
|
OPTIMISTIC_KOVAN = 69,
|
||||||
|
|
||||||
|
POLYGON = 137,
|
||||||
|
POLYGON_MUMBAI = 80001,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = [
|
const INFURA_KEY = process.env.REACT_APP_INFURA_KEY
|
||||||
SupportedChainId.MAINNET,
|
if (typeof INFURA_KEY === 'undefined') {
|
||||||
SupportedChainId.ROPSTEN,
|
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
||||||
SupportedChainId.RINKEBY,
|
}
|
||||||
SupportedChainId.GOERLI,
|
|
||||||
SupportedChainId.KOVAN,
|
|
||||||
|
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
/**
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
* Array of all the supported chain IDs
|
||||||
SupportedChainId.OPTIMISM,
|
*/
|
||||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
export const ALL_SUPPORTED_CHAIN_IDS: SupportedChainId[] = Object.values(SupportedChainId).filter(
|
||||||
]
|
(id) => typeof id === 'number'
|
||||||
|
) as SupportedChainId[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All the chain IDs that are running the Ethereum protocol.
|
||||||
|
*/
|
||||||
export const L1_CHAIN_IDS = [
|
export const L1_CHAIN_IDS = [
|
||||||
SupportedChainId.MAINNET,
|
SupportedChainId.MAINNET,
|
||||||
SupportedChainId.ROPSTEN,
|
SupportedChainId.ROPSTEN,
|
||||||
SupportedChainId.RINKEBY,
|
SupportedChainId.RINKEBY,
|
||||||
SupportedChainId.GOERLI,
|
SupportedChainId.GOERLI,
|
||||||
SupportedChainId.KOVAN,
|
SupportedChainId.KOVAN,
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type SupportedL1ChainId = typeof L1_CHAIN_IDS[number]
|
export type SupportedL1ChainId = typeof L1_CHAIN_IDS[number]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls some L2 specific behavior, e.g. slippage tolerance, special UI behavior.
|
||||||
|
* The expectation is that all of these networks have immediate transaction confirmation.
|
||||||
|
*/
|
||||||
export const L2_CHAIN_IDS = [
|
export const L2_CHAIN_IDS = [
|
||||||
SupportedChainId.ARBITRUM_ONE,
|
SupportedChainId.ARBITRUM_ONE,
|
||||||
SupportedChainId.ARBITRUM_RINKEBY,
|
SupportedChainId.ARBITRUM_RINKEBY,
|
||||||
@ -50,106 +66,149 @@ export const L2_CHAIN_IDS = [
|
|||||||
|
|
||||||
export type SupportedL2ChainId = typeof L2_CHAIN_IDS[number]
|
export type SupportedL2ChainId = typeof L2_CHAIN_IDS[number]
|
||||||
|
|
||||||
export interface L1ChainInfo {
|
/**
|
||||||
readonly blockWaitMsBeforeWarning?: number
|
* These are the network URLs used by the interface when there is not another available source of chain data
|
||||||
readonly docs: string
|
*/
|
||||||
readonly explorer: string
|
export const INFURA_NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
||||||
readonly infoLink: string
|
[SupportedChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||||
readonly label: string
|
[SupportedChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||||
readonly logoUrl?: string
|
[SupportedChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
|
||||||
readonly rpcUrls?: string[]
|
[SupportedChainId.GOERLI]: `https://goerli.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.KOVAN]: `https://kovan.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.OPTIMISM]: `https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.OPTIMISTIC_KOVAN]: `https://optimism-kovan.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.ARBITRUM_ONE]: `https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.ARBITRUM_RINKEBY]: `https://arbitrum-rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.POLYGON]: `https://polygon-mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: `https://polygon-mumbai.infura.io/v3/${INFURA_KEY}`,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to call the add network RPC
|
||||||
|
*/
|
||||||
|
interface AddNetworkInfo {
|
||||||
|
readonly rpcUrl: string
|
||||||
readonly nativeCurrency: {
|
readonly nativeCurrency: {
|
||||||
name: string // 'Goerli ETH',
|
name: string // e.g. 'Goerli ETH',
|
||||||
symbol: string // 'gorETH',
|
symbol: string // e.g. 'gorETH',
|
||||||
decimals: number //18,
|
decimals: number // e.g. 18,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface L2ChainInfo extends L1ChainInfo {
|
|
||||||
readonly bridge: string
|
export enum NetworkType {
|
||||||
|
L1,
|
||||||
|
L2,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BaseChainInfo {
|
||||||
|
readonly networkType: NetworkType
|
||||||
|
readonly blockWaitMsBeforeWarning?: number
|
||||||
|
readonly docs: string
|
||||||
|
readonly bridge?: string
|
||||||
|
readonly explorer: string
|
||||||
|
readonly infoLink: string
|
||||||
readonly logoUrl: string
|
readonly logoUrl: string
|
||||||
|
readonly label: string
|
||||||
|
readonly helpCenterUrl?: string
|
||||||
|
readonly addNetworkInfo: AddNetworkInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface L1ChainInfo extends BaseChainInfo {
|
||||||
|
readonly networkType: NetworkType.L1
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface L2ChainInfo extends BaseChainInfo {
|
||||||
|
readonly networkType: NetworkType.L2
|
||||||
|
readonly bridge: string
|
||||||
readonly statusPage?: string
|
readonly statusPage?: string
|
||||||
readonly defaultListUrl: string
|
readonly defaultListUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChainInfo = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
|
export type ChainInfoMap = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
|
||||||
readonly [chainId in SupportedL2ChainId]: L2ChainInfo
|
readonly [chainId in SupportedL2ChainId]: L2ChainInfo
|
||||||
} &
|
} &
|
||||||
{ readonly [chainId in SupportedL1ChainId]: L1ChainInfo }
|
{ readonly [chainId in SupportedL1ChainId]: L1ChainInfo }
|
||||||
|
|
||||||
export const CHAIN_INFO: ChainInfo = {
|
export const CHAIN_INFO: ChainInfoMap = {
|
||||||
[SupportedChainId.ARBITRUM_ONE]: {
|
|
||||||
blockWaitMsBeforeWarning: ms`10m`,
|
|
||||||
bridge: 'https://bridge.arbitrum.io/',
|
|
||||||
defaultListUrl: ARBITRUM_LIST,
|
|
||||||
docs: 'https://offchainlabs.com/',
|
|
||||||
explorer: 'https://arbiscan.io/',
|
|
||||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
|
||||||
label: 'Arbitrum',
|
|
||||||
logoUrl: arbitrumLogoUrl,
|
|
||||||
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
|
|
||||||
rpcUrls: ['https://arb1.arbitrum.io/rpc'],
|
|
||||||
},
|
|
||||||
[SupportedChainId.ARBITRUM_RINKEBY]: {
|
|
||||||
blockWaitMsBeforeWarning: ms`10m`,
|
|
||||||
bridge: 'https://bridge.arbitrum.io/',
|
|
||||||
defaultListUrl: ARBITRUM_LIST,
|
|
||||||
docs: 'https://offchainlabs.com/',
|
|
||||||
explorer: 'https://rinkeby-explorer.arbitrum.io/',
|
|
||||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
|
||||||
label: 'Arbitrum Rinkeby',
|
|
||||||
logoUrl: arbitrumLogoUrl,
|
|
||||||
nativeCurrency: { name: 'Rinkeby ArbETH', symbol: 'rinkArbETH', decimals: 18 },
|
|
||||||
rpcUrls: ['https://rinkeby.arbitrum.io/rpc'],
|
|
||||||
},
|
|
||||||
[SupportedChainId.MAINNET]: {
|
[SupportedChainId.MAINNET]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
docs: 'https://docs.uniswap.org/',
|
docs: 'https://docs.uniswap.org/',
|
||||||
explorer: 'https://etherscan.io/',
|
explorer: 'https://etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/',
|
infoLink: 'https://info.uniswap.org/#/',
|
||||||
label: 'Ethereum',
|
label: 'Ethereum',
|
||||||
logoUrl: ethereumLogoUrl,
|
logoUrl: ethereumLogoUrl,
|
||||||
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||||
|
rpcUrl: INFURA_NETWORK_URLS[SupportedChainId.MAINNET],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.RINKEBY]: {
|
[SupportedChainId.RINKEBY]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
docs: 'https://docs.uniswap.org/',
|
docs: 'https://docs.uniswap.org/',
|
||||||
explorer: 'https://rinkeby.etherscan.io/',
|
explorer: 'https://rinkeby.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/',
|
infoLink: 'https://info.uniswap.org/#/',
|
||||||
label: 'Rinkeby',
|
label: 'Rinkeby',
|
||||||
nativeCurrency: { name: 'Rinkeby ETH', symbol: 'rinkETH', decimals: 18 },
|
logoUrl: ethereumLogoUrl,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Rinkeby Ether', symbol: 'rETH', decimals: 18 },
|
||||||
|
rpcUrl: INFURA_NETWORK_URLS[SupportedChainId.RINKEBY],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.ROPSTEN]: {
|
[SupportedChainId.ROPSTEN]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
docs: 'https://docs.uniswap.org/',
|
docs: 'https://docs.uniswap.org/',
|
||||||
explorer: 'https://ropsten.etherscan.io/',
|
explorer: 'https://ropsten.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/',
|
infoLink: 'https://info.uniswap.org/#/',
|
||||||
label: 'Ropsten',
|
label: 'Ropsten',
|
||||||
nativeCurrency: { name: 'Ropsten ETH', symbol: 'ropETH', decimals: 18 },
|
logoUrl: ethereumLogoUrl,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Ropsten Ether', symbol: 'ropETH', decimals: 18 },
|
||||||
|
rpcUrl: INFURA_NETWORK_URLS[SupportedChainId.ROPSTEN],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.KOVAN]: {
|
[SupportedChainId.KOVAN]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
docs: 'https://docs.uniswap.org/',
|
docs: 'https://docs.uniswap.org/',
|
||||||
explorer: 'https://kovan.etherscan.io/',
|
explorer: 'https://kovan.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/',
|
infoLink: 'https://info.uniswap.org/#/',
|
||||||
label: 'Kovan',
|
label: 'Kovan',
|
||||||
nativeCurrency: { name: 'Kovan ETH', symbol: 'kovETH', decimals: 18 },
|
logoUrl: ethereumLogoUrl,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Kovan Ether', symbol: 'kovETH', decimals: 18 },
|
||||||
|
rpcUrl: INFURA_NETWORK_URLS[SupportedChainId.KOVAN],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.GOERLI]: {
|
[SupportedChainId.GOERLI]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
docs: 'https://docs.uniswap.org/',
|
docs: 'https://docs.uniswap.org/',
|
||||||
explorer: 'https://goerli.etherscan.io/',
|
explorer: 'https://goerli.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/',
|
infoLink: 'https://info.uniswap.org/#/',
|
||||||
label: 'Görli',
|
label: 'Görli',
|
||||||
nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 },
|
logoUrl: ethereumLogoUrl,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Görli Ether', symbol: 'görETH', decimals: 18 },
|
||||||
|
rpcUrl: INFURA_NETWORK_URLS[SupportedChainId.GOERLI],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.OPTIMISM]: {
|
[SupportedChainId.OPTIMISM]: {
|
||||||
|
networkType: NetworkType.L2,
|
||||||
blockWaitMsBeforeWarning: ms`25m`,
|
blockWaitMsBeforeWarning: ms`25m`,
|
||||||
bridge: 'https://gateway.optimism.io/',
|
bridge: 'https://gateway.optimism.io/?chainId=1',
|
||||||
defaultListUrl: OPTIMISM_LIST,
|
defaultListUrl: OPTIMISM_LIST,
|
||||||
docs: 'https://optimism.io/',
|
docs: 'https://optimism.io/',
|
||||||
explorer: 'https://optimistic.etherscan.io/',
|
explorer: 'https://optimistic.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||||
label: 'OΞ',
|
label: 'Optimism',
|
||||||
logoUrl: optimismLogoUrl,
|
logoUrl: optimismLogoUrl,
|
||||||
nativeCurrency: { name: 'Optimistic ETH', symbol: 'ETH', decimals: 18 },
|
statusPage: 'https://optimism.io/status',
|
||||||
rpcUrls: ['https://mainnet.optimism.io'],
|
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ',
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||||
|
rpcUrl: 'https://mainnet.optimism.io',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[SupportedChainId.OPTIMISTIC_KOVAN]: {
|
[SupportedChainId.OPTIMISTIC_KOVAN]: {
|
||||||
|
networkType: NetworkType.L2,
|
||||||
blockWaitMsBeforeWarning: ms`25m`,
|
blockWaitMsBeforeWarning: ms`25m`,
|
||||||
bridge: 'https://gateway.optimism.io/',
|
bridge: 'https://gateway.optimism.io/',
|
||||||
defaultListUrl: OPTIMISM_LIST,
|
defaultListUrl: OPTIMISM_LIST,
|
||||||
@ -157,12 +216,72 @@ export const CHAIN_INFO: ChainInfo = {
|
|||||||
explorer: 'https://optimistic.etherscan.io/',
|
explorer: 'https://optimistic.etherscan.io/',
|
||||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||||
label: 'Optimistic Kovan',
|
label: 'Optimistic Kovan',
|
||||||
rpcUrls: ['https://kovan.optimism.io'],
|
|
||||||
logoUrl: optimismLogoUrl,
|
logoUrl: optimismLogoUrl,
|
||||||
nativeCurrency: { name: 'Optimistic kovETH', symbol: 'kovOpETH', decimals: 18 },
|
statusPage: 'https://optimism.io/status',
|
||||||
|
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ',
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Optimistic Kovan Ether', symbol: 'kovOpETH', decimals: 18 },
|
||||||
|
rpcUrl: 'https://kovan.optimism.io',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[SupportedChainId.ARBITRUM_ONE]: {
|
||||||
|
networkType: NetworkType.L2,
|
||||||
|
blockWaitMsBeforeWarning: ms`10m`,
|
||||||
|
bridge: 'https://bridge.arbitrum.io/',
|
||||||
|
docs: 'https://offchainlabs.com/',
|
||||||
|
explorer: 'https://arbiscan.io/',
|
||||||
|
infoLink: 'https://info.uniswap.org/#/arbitrum',
|
||||||
|
label: 'Arbitrum',
|
||||||
|
logoUrl: arbitrumLogoUrl,
|
||||||
|
defaultListUrl: ARBITRUM_LIST,
|
||||||
|
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum',
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
||||||
|
rpcUrl: 'https://arb1.arbitrum.io/rpc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[SupportedChainId.ARBITRUM_RINKEBY]: {
|
||||||
|
networkType: NetworkType.L2,
|
||||||
|
blockWaitMsBeforeWarning: ms`10m`,
|
||||||
|
bridge: 'https://bridge.arbitrum.io/',
|
||||||
|
docs: 'https://offchainlabs.com/',
|
||||||
|
explorer: 'https://rinkeby-explorer.arbitrum.io/',
|
||||||
|
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||||
|
label: 'Arbitrum Rinkeby',
|
||||||
|
logoUrl: arbitrumLogoUrl,
|
||||||
|
defaultListUrl: ARBITRUM_LIST,
|
||||||
|
helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum',
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Rinkeby Arbitrum Ether', symbol: 'rinkArbETH', decimals: 18 },
|
||||||
|
rpcUrl: 'https://rinkeby.arbitrum.io/rpc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[SupportedChainId.POLYGON]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
|
blockWaitMsBeforeWarning: ms`10m`,
|
||||||
|
bridge: 'https://wallet.polygon.technology/bridge',
|
||||||
|
docs: 'https://polygon.io/',
|
||||||
|
explorer: 'https://polygonscan.com/',
|
||||||
|
infoLink: 'https://info.uniswap.org/#/polygon',
|
||||||
|
label: 'Polygon',
|
||||||
|
logoUrl: polygonMaticLogo,
|
||||||
|
addNetworkInfo: {
|
||||||
|
rpcUrl: 'https://polygon-rpc.com/',
|
||||||
|
nativeCurrency: { name: 'Polygon Matic', symbol: 'MATIC', decimals: 18 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: {
|
||||||
|
networkType: NetworkType.L1,
|
||||||
|
blockWaitMsBeforeWarning: ms`10m`,
|
||||||
|
bridge: 'https://wallet.polygon.technology/bridge',
|
||||||
|
docs: 'https://polygon.io/',
|
||||||
|
explorer: 'https://mumbai.polygonscan.com/',
|
||||||
|
infoLink: 'https://info.uniswap.org/#/polygon',
|
||||||
|
label: 'Polygon Mumbai',
|
||||||
|
logoUrl: polygonMaticLogo,
|
||||||
|
addNetworkInfo: {
|
||||||
|
nativeCurrency: { name: 'Polygon Mumbai Matic', symbol: 'mMATIC', decimals: 18 },
|
||||||
|
rpcUrl: 'https://rpc-endpoints.superfluid.dev/mumbai',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ARBITRUM_HELP_CENTER_LINK = 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum'
|
|
||||||
export const OPTIMISM_HELP_CENTER_LINK =
|
|
||||||
'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ'
|
|
||||||
|
@ -7,11 +7,12 @@ import {
|
|||||||
DAI,
|
DAI,
|
||||||
DAI_ARBITRUM_ONE,
|
DAI_ARBITRUM_ONE,
|
||||||
DAI_OPTIMISM,
|
DAI_OPTIMISM,
|
||||||
|
DAI_POLYGON,
|
||||||
ETH2X_FLI,
|
ETH2X_FLI,
|
||||||
ExtendedEther,
|
|
||||||
FEI,
|
FEI,
|
||||||
FRAX,
|
FRAX,
|
||||||
FXS,
|
FXS,
|
||||||
|
nativeOnChain,
|
||||||
renBTC,
|
renBTC,
|
||||||
rETH2,
|
rETH2,
|
||||||
sETH2,
|
sETH2,
|
||||||
@ -20,13 +21,18 @@ import {
|
|||||||
USDC,
|
USDC,
|
||||||
USDC_ARBITRUM,
|
USDC_ARBITRUM,
|
||||||
USDC_OPTIMISM,
|
USDC_OPTIMISM,
|
||||||
|
USDC_POLYGON,
|
||||||
USDT,
|
USDT,
|
||||||
USDT_ARBITRUM_ONE,
|
USDT_ARBITRUM_ONE,
|
||||||
USDT_OPTIMISM,
|
USDT_OPTIMISM,
|
||||||
|
USDT_POLYGON,
|
||||||
WBTC,
|
WBTC,
|
||||||
WBTC_ARBITRUM_ONE,
|
WBTC_ARBITRUM_ONE,
|
||||||
WBTC_OPTIMISM,
|
WBTC_OPTIMISM,
|
||||||
WETH9_EXTENDED,
|
WBTC_POLYGON,
|
||||||
|
WETH_POLYGON,
|
||||||
|
WETH_POLYGON_MUMBAI,
|
||||||
|
WRAPPED_NATIVE_CURRENCY,
|
||||||
} from './tokens'
|
} from './tokens'
|
||||||
|
|
||||||
type ChainTokenList = {
|
type ChainTokenList = {
|
||||||
@ -37,21 +43,33 @@ type ChainCurrencyList = {
|
|||||||
readonly [chainId: number]: Currency[]
|
readonly [chainId: number]: Currency[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const WETH_ONLY: ChainTokenList = Object.fromEntries(
|
const WRAPPED_NATIVE_CURRENCIES_ONLY: ChainTokenList = Object.fromEntries(
|
||||||
Object.entries(WETH9_EXTENDED).map(([key, value]) => [key, [value]])
|
Object.entries(WRAPPED_NATIVE_CURRENCY).map(([key, value]) => [key, [value]])
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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,
|
...WRAPPED_NATIVE_CURRENCIES_ONLY,
|
||||||
[SupportedChainId.MAINNET]: [...WETH_ONLY[SupportedChainId.MAINNET], DAI, USDC, USDT, WBTC],
|
[SupportedChainId.MAINNET]: [...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.MAINNET], DAI, USDC, USDT, WBTC],
|
||||||
[SupportedChainId.OPTIMISM]: [...WETH_ONLY[SupportedChainId.OPTIMISM], DAI_OPTIMISM, USDT_OPTIMISM, WBTC_OPTIMISM],
|
[SupportedChainId.OPTIMISM]: [
|
||||||
|
...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.OPTIMISM],
|
||||||
|
DAI_OPTIMISM,
|
||||||
|
USDT_OPTIMISM,
|
||||||
|
WBTC_OPTIMISM,
|
||||||
|
],
|
||||||
[SupportedChainId.ARBITRUM_ONE]: [
|
[SupportedChainId.ARBITRUM_ONE]: [
|
||||||
...WETH_ONLY[SupportedChainId.ARBITRUM_ONE],
|
...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.ARBITRUM_ONE],
|
||||||
DAI_ARBITRUM_ONE,
|
DAI_ARBITRUM_ONE,
|
||||||
USDT_ARBITRUM_ONE,
|
USDT_ARBITRUM_ONE,
|
||||||
WBTC_ARBITRUM_ONE,
|
WBTC_ARBITRUM_ONE,
|
||||||
],
|
],
|
||||||
|
[SupportedChainId.POLYGON]: [
|
||||||
|
...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.POLYGON],
|
||||||
|
DAI_POLYGON,
|
||||||
|
USDC_POLYGON,
|
||||||
|
USDT_POLYGON,
|
||||||
|
WETH_POLYGON,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
||||||
[SupportedChainId.MAINNET]: {
|
[SupportedChainId.MAINNET]: {
|
||||||
@ -72,7 +90,7 @@ export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: To
|
|||||||
*/
|
*/
|
||||||
export const CUSTOM_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
export const CUSTOM_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
||||||
[SupportedChainId.MAINNET]: {
|
[SupportedChainId.MAINNET]: {
|
||||||
[AMPL.address]: [DAI, WETH9_EXTENDED[SupportedChainId.MAINNET]],
|
[AMPL.address]: [DAI, WRAPPED_NATIVE_CURRENCY[SupportedChainId.MAINNET]],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,49 +99,62 @@ export const CUSTOM_BASES: { [chainId: number]: { [tokenAddress: string]: Token[
|
|||||||
*/
|
*/
|
||||||
export const COMMON_BASES: ChainCurrencyList = {
|
export const COMMON_BASES: ChainCurrencyList = {
|
||||||
[SupportedChainId.MAINNET]: [
|
[SupportedChainId.MAINNET]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.MAINNET),
|
nativeOnChain(SupportedChainId.MAINNET),
|
||||||
DAI,
|
DAI,
|
||||||
USDC,
|
USDC,
|
||||||
USDT,
|
USDT,
|
||||||
WBTC,
|
WBTC,
|
||||||
WETH9_EXTENDED[SupportedChainId.MAINNET],
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.MAINNET],
|
||||||
],
|
],
|
||||||
[SupportedChainId.ROPSTEN]: [
|
[SupportedChainId.ROPSTEN]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.ROPSTEN),
|
nativeOnChain(SupportedChainId.ROPSTEN),
|
||||||
WETH9_EXTENDED[SupportedChainId.ROPSTEN],
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.ROPSTEN],
|
||||||
],
|
],
|
||||||
[SupportedChainId.RINKEBY]: [
|
[SupportedChainId.RINKEBY]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.RINKEBY),
|
nativeOnChain(SupportedChainId.RINKEBY),
|
||||||
WETH9_EXTENDED[SupportedChainId.RINKEBY],
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.RINKEBY],
|
||||||
],
|
],
|
||||||
[SupportedChainId.GOERLI]: [ExtendedEther.onChain(SupportedChainId.GOERLI), WETH9_EXTENDED[SupportedChainId.GOERLI]],
|
[SupportedChainId.GOERLI]: [nativeOnChain(SupportedChainId.GOERLI), WRAPPED_NATIVE_CURRENCY[SupportedChainId.GOERLI]],
|
||||||
[SupportedChainId.KOVAN]: [ExtendedEther.onChain(SupportedChainId.KOVAN), WETH9_EXTENDED[SupportedChainId.KOVAN]],
|
[SupportedChainId.KOVAN]: [nativeOnChain(SupportedChainId.KOVAN), WRAPPED_NATIVE_CURRENCY[SupportedChainId.KOVAN]],
|
||||||
[SupportedChainId.ARBITRUM_ONE]: [
|
[SupportedChainId.ARBITRUM_ONE]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.ARBITRUM_ONE),
|
nativeOnChain(SupportedChainId.ARBITRUM_ONE),
|
||||||
DAI_ARBITRUM_ONE,
|
DAI_ARBITRUM_ONE,
|
||||||
USDC_ARBITRUM,
|
USDC_ARBITRUM,
|
||||||
USDT_ARBITRUM_ONE,
|
USDT_ARBITRUM_ONE,
|
||||||
WBTC_ARBITRUM_ONE,
|
WBTC_ARBITRUM_ONE,
|
||||||
WETH9_EXTENDED[SupportedChainId.ARBITRUM_ONE],
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.ARBITRUM_ONE],
|
||||||
],
|
],
|
||||||
[SupportedChainId.ARBITRUM_RINKEBY]: [
|
[SupportedChainId.ARBITRUM_RINKEBY]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.ARBITRUM_RINKEBY),
|
nativeOnChain(SupportedChainId.ARBITRUM_RINKEBY),
|
||||||
WETH9_EXTENDED[SupportedChainId.ARBITRUM_RINKEBY],
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.ARBITRUM_RINKEBY],
|
||||||
],
|
],
|
||||||
[SupportedChainId.OPTIMISM]: [
|
[SupportedChainId.OPTIMISM]: [
|
||||||
ExtendedEther.onChain(SupportedChainId.OPTIMISM),
|
nativeOnChain(SupportedChainId.OPTIMISM),
|
||||||
DAI_OPTIMISM,
|
DAI_OPTIMISM,
|
||||||
USDC_OPTIMISM,
|
USDC_OPTIMISM,
|
||||||
USDT_OPTIMISM,
|
USDT_OPTIMISM,
|
||||||
WBTC_OPTIMISM,
|
WBTC_OPTIMISM,
|
||||||
],
|
],
|
||||||
[SupportedChainId.OPTIMISTIC_KOVAN]: [ExtendedEther.onChain(SupportedChainId.OPTIMISTIC_KOVAN)],
|
[SupportedChainId.OPTIMISTIC_KOVAN]: [nativeOnChain(SupportedChainId.OPTIMISTIC_KOVAN)],
|
||||||
|
[SupportedChainId.POLYGON]: [
|
||||||
|
nativeOnChain(SupportedChainId.POLYGON),
|
||||||
|
WETH_POLYGON,
|
||||||
|
USDC_POLYGON,
|
||||||
|
DAI_POLYGON,
|
||||||
|
USDT_POLYGON,
|
||||||
|
WBTC_POLYGON,
|
||||||
|
],
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: [
|
||||||
|
nativeOnChain(SupportedChainId.POLYGON_MUMBAI),
|
||||||
|
WRAPPED_NATIVE_CURRENCY[SupportedChainId.POLYGON_MUMBAI],
|
||||||
|
WETH_POLYGON_MUMBAI,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to construct the list of all pairs we consider by default in the frontend
|
// used to construct the list of all pairs we consider by default in the frontend
|
||||||
export const BASES_TO_TRACK_LIQUIDITY_FOR: ChainTokenList = {
|
export const BASES_TO_TRACK_LIQUIDITY_FOR: ChainTokenList = {
|
||||||
...WETH_ONLY,
|
...WRAPPED_NATIVE_CURRENCIES_ONLY,
|
||||||
[SupportedChainId.MAINNET]: [...WETH_ONLY[SupportedChainId.MAINNET], DAI, USDC, USDT, WBTC],
|
[SupportedChainId.MAINNET]: [...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.MAINNET], DAI, USDC, USDT, WBTC],
|
||||||
}
|
}
|
||||||
export const PINNED_PAIRS: { readonly [chainId: number]: [Token, Token][] } = {
|
export const PINNED_PAIRS: { readonly [chainId: number]: [Token, Token][] } = {
|
||||||
[SupportedChainId.MAINNET]: [
|
[SupportedChainId.MAINNET]: [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Ether, Token, WETH9 } from '@uniswap/sdk-core'
|
import { Currency, Ether, NativeCurrency, Token, WETH9 } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
import { UNI_ADDRESS } from './addresses'
|
import { UNI_ADDRESS } from './addresses'
|
||||||
import { SupportedChainId } from './chains'
|
import { SupportedChainId } from './chains'
|
||||||
@ -45,6 +45,34 @@ export const USDC_ARBITRUM = new Token(
|
|||||||
'USDC',
|
'USDC',
|
||||||
'USD//C'
|
'USD//C'
|
||||||
)
|
)
|
||||||
|
export const USDC_POLYGON = new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
|
||||||
|
6,
|
||||||
|
'USDC',
|
||||||
|
'USD//C'
|
||||||
|
)
|
||||||
|
export const DAI_POLYGON = new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
||||||
|
18,
|
||||||
|
'DAI',
|
||||||
|
'Dai Stablecoin'
|
||||||
|
)
|
||||||
|
export const USDT_POLYGON = new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0xc2132d05d31c914a87c6611c10748aeb04b58e8f',
|
||||||
|
6,
|
||||||
|
'USDT',
|
||||||
|
'Tether USD'
|
||||||
|
)
|
||||||
|
export const WBTC_POLYGON = new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6',
|
||||||
|
8,
|
||||||
|
'WBTC',
|
||||||
|
'Wrapped BTC'
|
||||||
|
)
|
||||||
export const USDC_OPTIMISM = new Token(
|
export const USDC_OPTIMISM = new Token(
|
||||||
SupportedChainId.OPTIMISM,
|
SupportedChainId.OPTIMISM,
|
||||||
'0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
|
'0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
|
||||||
@ -157,6 +185,21 @@ export const SWISE = new Token(
|
|||||||
'SWISE',
|
'SWISE',
|
||||||
'StakeWise'
|
'StakeWise'
|
||||||
)
|
)
|
||||||
|
export const WETH_POLYGON_MUMBAI = new Token(
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
'0xa6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa',
|
||||||
|
18,
|
||||||
|
'WETH',
|
||||||
|
'Wrapped Ether'
|
||||||
|
)
|
||||||
|
|
||||||
|
export const WETH_POLYGON = new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0x7ceb23fd6bc0add59e62ac25578270cff1b9f619',
|
||||||
|
18,
|
||||||
|
'WETH',
|
||||||
|
'Wrapped Ether'
|
||||||
|
)
|
||||||
export const UNI: { [chainId: number]: Token } = {
|
export const UNI: { [chainId: number]: Token } = {
|
||||||
[SupportedChainId.MAINNET]: new Token(SupportedChainId.MAINNET, UNI_ADDRESS[1], 18, 'UNI', 'Uniswap'),
|
[SupportedChainId.MAINNET]: new Token(SupportedChainId.MAINNET, UNI_ADDRESS[1], 18, 'UNI', 'Uniswap'),
|
||||||
[SupportedChainId.RINKEBY]: new Token(SupportedChainId.RINKEBY, UNI_ADDRESS[4], 18, 'UNI', 'Uniswap'),
|
[SupportedChainId.RINKEBY]: new Token(SupportedChainId.RINKEBY, UNI_ADDRESS[4], 18, 'UNI', 'Uniswap'),
|
||||||
@ -165,7 +208,7 @@ export const UNI: { [chainId: number]: Token } = {
|
|||||||
[SupportedChainId.KOVAN]: new Token(SupportedChainId.KOVAN, UNI_ADDRESS[42], 18, 'UNI', 'Uniswap'),
|
[SupportedChainId.KOVAN]: new Token(SupportedChainId.KOVAN, UNI_ADDRESS[42], 18, 'UNI', 'Uniswap'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WETH9_EXTENDED: { [chainId: number]: Token } = {
|
export const WRAPPED_NATIVE_CURRENCY: { [chainId: number]: Token } = {
|
||||||
...WETH9,
|
...WETH9,
|
||||||
[SupportedChainId.OPTIMISM]: new Token(
|
[SupportedChainId.OPTIMISM]: new Token(
|
||||||
SupportedChainId.OPTIMISM,
|
SupportedChainId.OPTIMISM,
|
||||||
@ -195,17 +238,61 @@ export const WETH9_EXTENDED: { [chainId: number]: Token } = {
|
|||||||
'WETH',
|
'WETH',
|
||||||
'Wrapped Ether'
|
'Wrapped Ether'
|
||||||
),
|
),
|
||||||
|
[SupportedChainId.POLYGON]: new Token(
|
||||||
|
SupportedChainId.POLYGON,
|
||||||
|
'0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
||||||
|
18,
|
||||||
|
'WMATIC',
|
||||||
|
'Wrapped MATIC'
|
||||||
|
),
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: new Token(
|
||||||
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
|
'0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889',
|
||||||
|
18,
|
||||||
|
'WMATIC',
|
||||||
|
'Wrapped MATIC'
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMatic(chainId: number): chainId is SupportedChainId.POLYGON | SupportedChainId.POLYGON_MUMBAI {
|
||||||
|
return chainId === SupportedChainId.POLYGON_MUMBAI || chainId === SupportedChainId.POLYGON
|
||||||
|
}
|
||||||
|
|
||||||
|
class MaticNativeCurrency extends NativeCurrency {
|
||||||
|
equals(other: Currency): boolean {
|
||||||
|
return other.isNative && other.chainId === this.chainId
|
||||||
|
}
|
||||||
|
|
||||||
|
get wrapped(): Token {
|
||||||
|
if (!isMatic(this.chainId)) throw new Error('Not matic')
|
||||||
|
return WRAPPED_NATIVE_CURRENCY[this.chainId]
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(chainId: number) {
|
||||||
|
if (!isMatic(chainId)) throw new Error('Not matic')
|
||||||
|
super(chainId, 18, 'MATIC', 'Polygon Matic')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExtendedEther extends Ether {
|
export class ExtendedEther extends Ether {
|
||||||
public get wrapped(): Token {
|
public get wrapped(): Token {
|
||||||
if (this.chainId in WETH9_EXTENDED) return WETH9_EXTENDED[this.chainId]
|
if (this.chainId in WRAPPED_NATIVE_CURRENCY) return WRAPPED_NATIVE_CURRENCY[this.chainId]
|
||||||
throw new Error('Unsupported chain ID')
|
throw new Error('Unsupported chain ID')
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _cachedEther: { [chainId: number]: ExtendedEther } = {}
|
private static _cachedExtendedEther: { [chainId: number]: NativeCurrency } = {}
|
||||||
|
|
||||||
public static onChain(chainId: number): ExtendedEther {
|
public static onChain(chainId: number): ExtendedEther {
|
||||||
return this._cachedEther[chainId] ?? (this._cachedEther[chainId] = new ExtendedEther(chainId))
|
return this._cachedExtendedEther[chainId] ?? (this._cachedExtendedEther[chainId] = new ExtendedEther(chainId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedNativeCurrency: { [chainId: number]: NativeCurrency } = {}
|
||||||
|
export function nativeOnChain(chainId: number): NativeCurrency {
|
||||||
|
return (
|
||||||
|
cachedNativeCurrency[chainId] ??
|
||||||
|
(cachedNativeCurrency[chainId] = isMatic(chainId)
|
||||||
|
? new MaticNativeCurrency(chainId)
|
||||||
|
: ExtendedEther.onChain(chainId))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId, SupportedL2ChainId } from '
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { createTokenFilterFunction } from '../components/SearchModal/filtering'
|
import { createTokenFilterFunction } from '../components/SearchModal/filtering'
|
||||||
import { ExtendedEther, WETH9_EXTENDED } from '../constants/tokens'
|
import { nativeOnChain } from '../constants/tokens'
|
||||||
import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks'
|
import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks'
|
||||||
import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
|
import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
|
||||||
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
|
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
|
||||||
@ -225,20 +225,28 @@ export function useToken(tokenAddress?: string | null): Token | undefined | null
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCurrency(currencyId: string | null | undefined): Currency | null | undefined {
|
export function useNativeCurrency(): Currency {
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
const isETH = currencyId?.toUpperCase() === 'ETH'
|
return useMemo(
|
||||||
const token = useToken(isETH ? undefined : currencyId)
|
|
||||||
const extendedEther = useMemo(
|
|
||||||
() =>
|
() =>
|
||||||
chainId
|
chainId
|
||||||
? ExtendedEther.onChain(chainId)
|
? nativeOnChain(chainId)
|
||||||
: // display mainnet when not connected
|
: // display mainnet when not connected
|
||||||
ExtendedEther.onChain(SupportedChainId.MAINNET),
|
nativeOnChain(SupportedChainId.MAINNET),
|
||||||
[chainId]
|
[chainId]
|
||||||
)
|
)
|
||||||
const weth = chainId ? WETH9_EXTENDED[chainId] : undefined
|
}
|
||||||
if (currencyId === null || currencyId === undefined) return currencyId
|
|
||||||
if (weth?.address?.toUpperCase() === currencyId?.toUpperCase()) return weth
|
export function useCurrency(currencyId: string | null | undefined): Currency | null | undefined {
|
||||||
return isETH ? extendedEther : token
|
const nativeCurrency = useNativeCurrency()
|
||||||
|
const isNative = Boolean(nativeCurrency && currencyId?.toUpperCase() === 'ETH')
|
||||||
|
const token = useToken(isNative ? undefined : currencyId)
|
||||||
|
|
||||||
|
if (currencyId === null || currencyId === undefined) return currencyId
|
||||||
|
|
||||||
|
// this case so we use our builtin wrapped token instead of wrapped tokens on token lists
|
||||||
|
const wrappedNative = nativeCurrency?.wrapped
|
||||||
|
if (wrappedNative?.address?.toUpperCase() === currencyId?.toUpperCase()) return wrappedNative
|
||||||
|
|
||||||
|
return isNative ? nativeCurrency : token
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ import { V3Migrator } from 'types/v3/V3Migrator'
|
|||||||
import { getContract } from 'utils'
|
import { getContract } from 'utils'
|
||||||
|
|
||||||
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Erc721, Erc1155, Weth } from '../abis/types'
|
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Erc721, Erc1155, Weth } from '../abis/types'
|
||||||
import { UNI, WETH9_EXTENDED } from '../constants/tokens'
|
import { UNI, WRAPPED_NATIVE_CURRENCY } from '../constants/tokens'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
|
|
||||||
// returns null on errors
|
// returns null on errors
|
||||||
@ -74,7 +74,11 @@ export function useTokenContract(tokenAddress?: string, withSignerIfPossible?: b
|
|||||||
|
|
||||||
export function useWETHContract(withSignerIfPossible?: boolean) {
|
export function useWETHContract(withSignerIfPossible?: boolean) {
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
return useContract<Weth>(chainId ? WETH9_EXTENDED[chainId]?.address : undefined, WETH_ABI, withSignerIfPossible)
|
return useContract<Weth>(
|
||||||
|
chainId ? WRAPPED_NATIVE_CURRENCY[chainId]?.address : undefined,
|
||||||
|
WETH_ABI,
|
||||||
|
withSignerIfPossible
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useERC721Contract(nftAddress?: string) {
|
export function useERC721Contract(nftAddress?: string) {
|
||||||
@ -113,7 +117,7 @@ export function useV2RouterContract(): Contract | null {
|
|||||||
return useContract(V2_ROUTER_ADDRESS, IUniswapV2Router02ABI, true)
|
return useContract(V2_ROUTER_ADDRESS, IUniswapV2Router02ABI, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMulticall2Contract() {
|
export function useInterfaceMulticall() {
|
||||||
return useContract<UniswapInterfaceMulticall>(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall
|
return useContract<UniswapInterfaceMulticall>(MULTICALL_ADDRESS, MulticallABI, false) as UniswapInterfaceMulticall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
import { BigNumber } from '@ethersproject/bignumber'
|
||||||
|
|
||||||
import { useSingleCallResult } from '../state/multicall/hooks'
|
import { useSingleCallResult } from '../state/multicall/hooks'
|
||||||
import { useMulticall2Contract } from './useContract'
|
import { useInterfaceMulticall } from './useContract'
|
||||||
|
|
||||||
// gets the current timestamp from the blockchain
|
// gets the current timestamp from the blockchain
|
||||||
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
|
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
|
||||||
const multicall = useMulticall2Contract()
|
const multicall = useInterfaceMulticall()
|
||||||
return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
|
return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { useMemo } from 'react'
|
|||||||
import { InterfaceTrade } from 'state/routing/types'
|
import { InterfaceTrade } from 'state/routing/types'
|
||||||
|
|
||||||
import { useUserSlippageToleranceWithDefault } from '../state/user/hooks'
|
import { useUserSlippageToleranceWithDefault } from '../state/user/hooks'
|
||||||
import { useCurrency } from './Tokens'
|
import { useNativeCurrency } from './Tokens'
|
||||||
import useGasPrice from './useGasPrice'
|
import useGasPrice from './useGasPrice'
|
||||||
import useUSDCPrice, { useUSDCValue } from './useUSDCPrice'
|
import useUSDCPrice, { useUSDCValue } from './useUSDCPrice'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
@ -35,19 +35,23 @@ export default function useSwapSlippageTolerance(
|
|||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
const onL2 = chainId && L2_CHAIN_IDS.includes(chainId)
|
const onL2 = chainId && L2_CHAIN_IDS.includes(chainId)
|
||||||
const outputDollarValue = useUSDCValue(trade?.outputAmount)
|
const outputDollarValue = useUSDCValue(trade?.outputAmount)
|
||||||
const ethGasPrice = useGasPrice()
|
const nativeGasPrice = useGasPrice()
|
||||||
|
|
||||||
const gasEstimate = guesstimateGas(trade)
|
const gasEstimate = guesstimateGas(trade)
|
||||||
const ether = useCurrency('ETH')
|
const nativeCurrency = useNativeCurrency()
|
||||||
const etherPrice = useUSDCPrice(ether ?? undefined)
|
const nativeCurrencyPrice = useUSDCPrice(nativeCurrency ?? undefined)
|
||||||
|
|
||||||
const defaultSlippageTolerance = useMemo(() => {
|
const defaultSlippageTolerance = useMemo(() => {
|
||||||
if (!trade || onL2) return ONE_TENTHS_PERCENT
|
if (!trade || onL2) return ONE_TENTHS_PERCENT
|
||||||
|
|
||||||
const ethGasCost =
|
const nativeGasCost =
|
||||||
ethGasPrice && typeof gasEstimate === 'number' ? JSBI.multiply(ethGasPrice, JSBI.BigInt(gasEstimate)) : undefined
|
nativeGasPrice && typeof gasEstimate === 'number'
|
||||||
|
? JSBI.multiply(nativeGasPrice, JSBI.BigInt(gasEstimate))
|
||||||
|
: undefined
|
||||||
const dollarGasCost =
|
const dollarGasCost =
|
||||||
ether && ethGasCost && etherPrice ? etherPrice.quote(CurrencyAmount.fromRawAmount(ether, ethGasCost)) : undefined
|
nativeCurrency && nativeGasCost && nativeCurrencyPrice
|
||||||
|
? nativeCurrencyPrice.quote(CurrencyAmount.fromRawAmount(nativeCurrency, nativeGasCost))
|
||||||
|
: undefined
|
||||||
|
|
||||||
// if valid estimate from api and using api trade, use gas estimate from api
|
// if valid estimate from api and using api trade, use gas estimate from api
|
||||||
// NOTE - dont use gas estimate for L2s yet - need to verify accuracy
|
// NOTE - dont use gas estimate for L2s yet - need to verify accuracy
|
||||||
@ -68,7 +72,7 @@ export default function useSwapSlippageTolerance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return V3_SWAP_DEFAULT_SLIPPAGE
|
return V3_SWAP_DEFAULT_SLIPPAGE
|
||||||
}, [trade, onL2, ethGasPrice, gasEstimate, ether, etherPrice, chainId, outputDollarValue])
|
}, [trade, onL2, nativeGasPrice, gasEstimate, nativeCurrency, nativeCurrencyPrice, chainId, outputDollarValue])
|
||||||
|
|
||||||
return useUserSlippageToleranceWithDefault(defaultSlippageTolerance)
|
return useUserSlippageToleranceWithDefault(defaultSlippageTolerance)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { useMemo } from 'react'
|
|||||||
import { tryParseAmount } from 'state/swap/hooks'
|
import { tryParseAmount } from 'state/swap/hooks'
|
||||||
|
|
||||||
import { SupportedChainId } from '../constants/chains'
|
import { SupportedChainId } from '../constants/chains'
|
||||||
import { DAI_OPTIMISM, USDC, USDC_ARBITRUM } from '../constants/tokens'
|
import { DAI_OPTIMISM, USDC, USDC_ARBITRUM, USDC_POLYGON } from '../constants/tokens'
|
||||||
import { useBestV2Trade } from './useBestV2Trade'
|
import { useBestV2Trade } from './useBestV2Trade'
|
||||||
import { useClientSideV3Trade } from './useClientSideV3Trade'
|
import { useClientSideV3Trade } from './useClientSideV3Trade'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
@ -14,6 +14,7 @@ export const STABLECOIN_AMOUNT_OUT: { [chainId: number]: CurrencyAmount<Token> }
|
|||||||
[SupportedChainId.MAINNET]: CurrencyAmount.fromRawAmount(USDC, 100_000e6),
|
[SupportedChainId.MAINNET]: CurrencyAmount.fromRawAmount(USDC, 100_000e6),
|
||||||
[SupportedChainId.ARBITRUM_ONE]: CurrencyAmount.fromRawAmount(USDC_ARBITRUM, 10_000e6),
|
[SupportedChainId.ARBITRUM_ONE]: CurrencyAmount.fromRawAmount(USDC_ARBITRUM, 10_000e6),
|
||||||
[SupportedChainId.OPTIMISM]: CurrencyAmount.fromRawAmount(DAI_OPTIMISM, 10_000e18),
|
[SupportedChainId.OPTIMISM]: CurrencyAmount.fromRawAmount(DAI_OPTIMISM, 10_000e18),
|
||||||
|
[SupportedChainId.POLYGON]: CurrencyAmount.fromRawAmount(USDC_POLYGON, 10_000e6),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
import { Currency } from '@uniswap/sdk-core'
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { WETH9_EXTENDED } from '../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../constants/tokens'
|
||||||
import { tryParseAmount } from '../state/swap/hooks'
|
import { tryParseAmount } from '../state/swap/hooks'
|
||||||
import { TransactionType } from '../state/transactions/actions'
|
import { TransactionType } from '../state/transactions/actions'
|
||||||
import { useTransactionAdder } from '../state/transactions/hooks'
|
import { useTransactionAdder } from '../state/transactions/hooks'
|
||||||
import { useCurrencyBalance } from '../state/wallet/hooks'
|
import { useCurrencyBalance } from '../state/wallet/hooks'
|
||||||
|
import { useNativeCurrency } from './Tokens'
|
||||||
import { useWETHContract } from './useContract'
|
import { useWETHContract } from './useContract'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
|
|
||||||
@ -16,6 +18,34 @@ export enum WrapType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NOT_APPLICABLE = { wrapType: WrapType.NOT_APPLICABLE }
|
const NOT_APPLICABLE = { wrapType: WrapType.NOT_APPLICABLE }
|
||||||
|
|
||||||
|
enum WrapInputError {
|
||||||
|
NO_ERROR, // must be equal to 0 so all other errors are truthy
|
||||||
|
ENTER_NATIVE_AMOUNT,
|
||||||
|
ENTER_WRAPPED_AMOUNT,
|
||||||
|
INSUFFICIENT_NATIVE_BALANCE,
|
||||||
|
INSUFFICIENT_WRAPPED_BALANCE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputError }) {
|
||||||
|
const native = useNativeCurrency()
|
||||||
|
const wrapped = native?.wrapped
|
||||||
|
|
||||||
|
switch (wrapInputError) {
|
||||||
|
case WrapInputError.NO_ERROR:
|
||||||
|
return null
|
||||||
|
case WrapInputError.ENTER_NATIVE_AMOUNT:
|
||||||
|
return <Trans>Enter {native?.symbol} amount</Trans>
|
||||||
|
case WrapInputError.ENTER_WRAPPED_AMOUNT:
|
||||||
|
return <Trans>Enter {wrapped?.symbol} amount</Trans>
|
||||||
|
|
||||||
|
case WrapInputError.INSUFFICIENT_NATIVE_BALANCE:
|
||||||
|
return <Trans>Insufficient {native?.symbol} balance</Trans>
|
||||||
|
case WrapInputError.INSUFFICIENT_WRAPPED_BALANCE:
|
||||||
|
return <Trans>Insufficient {wrapped?.symbol} balance</Trans>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the selected input and output currency, return a wrap callback
|
* Given the selected input and output currency, return a wrap callback
|
||||||
* @param inputCurrency the selected input currency
|
* @param inputCurrency the selected input currency
|
||||||
@ -26,7 +56,7 @@ export default function useWrapCallback(
|
|||||||
inputCurrency: Currency | undefined | null,
|
inputCurrency: Currency | undefined | null,
|
||||||
outputCurrency: Currency | undefined | null,
|
outputCurrency: Currency | undefined | null,
|
||||||
typedValue: string | undefined
|
typedValue: string | undefined
|
||||||
): { wrapType: WrapType; execute?: undefined | (() => Promise<void>); inputError?: string } {
|
): { wrapType: WrapType; execute?: undefined | (() => Promise<void>); inputError?: WrapInputError } {
|
||||||
const { chainId, account } = useActiveWeb3React()
|
const { chainId, account } = useActiveWeb3React()
|
||||||
const wethContract = useWETHContract()
|
const wethContract = useWETHContract()
|
||||||
const balance = useCurrencyBalance(account ?? undefined, inputCurrency ?? undefined)
|
const balance = useCurrencyBalance(account ?? undefined, inputCurrency ?? undefined)
|
||||||
@ -36,7 +66,7 @@ export default function useWrapCallback(
|
|||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!wethContract || !chainId || !inputCurrency || !outputCurrency) return NOT_APPLICABLE
|
if (!wethContract || !chainId || !inputCurrency || !outputCurrency) return NOT_APPLICABLE
|
||||||
const weth = WETH9_EXTENDED[chainId]
|
const weth = WRAPPED_NATIVE_CURRENCY[chainId]
|
||||||
if (!weth) return NOT_APPLICABLE
|
if (!weth) return NOT_APPLICABLE
|
||||||
|
|
||||||
const hasInputAmount = Boolean(inputAmount?.greaterThan('0'))
|
const hasInputAmount = Boolean(inputAmount?.greaterThan('0'))
|
||||||
@ -54,13 +84,18 @@ export default function useWrapCallback(
|
|||||||
type: TransactionType.WRAP,
|
type: TransactionType.WRAP,
|
||||||
unwrapped: false,
|
unwrapped: false,
|
||||||
currencyAmountRaw: inputAmount?.quotient.toString(),
|
currencyAmountRaw: inputAmount?.quotient.toString(),
|
||||||
|
chainId,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Could not deposit', error)
|
console.error('Could not deposit', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
inputError: sufficientBalance ? undefined : hasInputAmount ? 'Insufficient ETH balance' : 'Enter ETH amount',
|
inputError: sufficientBalance
|
||||||
|
? undefined
|
||||||
|
: hasInputAmount
|
||||||
|
? WrapInputError.INSUFFICIENT_NATIVE_BALANCE
|
||||||
|
: WrapInputError.ENTER_NATIVE_AMOUNT,
|
||||||
}
|
}
|
||||||
} else if (weth.equals(inputCurrency) && outputCurrency.isNative) {
|
} else if (weth.equals(inputCurrency) && outputCurrency.isNative) {
|
||||||
return {
|
return {
|
||||||
@ -74,13 +109,18 @@ export default function useWrapCallback(
|
|||||||
type: TransactionType.WRAP,
|
type: TransactionType.WRAP,
|
||||||
unwrapped: true,
|
unwrapped: true,
|
||||||
currencyAmountRaw: inputAmount?.quotient.toString(),
|
currencyAmountRaw: inputAmount?.quotient.toString(),
|
||||||
|
chainId,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Could not withdraw', error)
|
console.error('Could not withdraw', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
inputError: sufficientBalance ? undefined : hasInputAmount ? 'Insufficient WETH balance' : 'Enter WETH amount',
|
inputError: sufficientBalance
|
||||||
|
? undefined
|
||||||
|
: hasInputAmount
|
||||||
|
? WrapInputError.INSUFFICIENT_WRAPPED_BALANCE
|
||||||
|
: WrapInputError.ENTER_WRAPPED_AMOUNT,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return NOT_APPLICABLE
|
return NOT_APPLICABLE
|
@ -71,3 +71,4 @@ ReactDOM.render(
|
|||||||
if (process.env.REACT_APP_SERVICE_WORKER !== 'false') {
|
if (process.env.REACT_APP_SERVICE_WORKER !== 'false') {
|
||||||
serviceWorkerRegistration.register()
|
serviceWorkerRegistration.register()
|
||||||
}
|
}
|
||||||
|
export { INFURA_NETWORK_URLS } from './constants/chains'
|
||||||
|
@ -35,7 +35,7 @@ import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
|||||||
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
||||||
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from '../../constants/addresses'
|
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from '../../constants/addresses'
|
||||||
import { ZERO_PERCENT } from '../../constants/misc'
|
import { ZERO_PERCENT } from '../../constants/misc'
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { useCurrency } from '../../hooks/Tokens'
|
import { useCurrency } from '../../hooks/Tokens'
|
||||||
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
||||||
import { useArgentWalletContract } from '../../hooks/useArgentWalletContract'
|
import { useArgentWalletContract } from '../../hooks/useArgentWalletContract'
|
||||||
@ -315,10 +315,12 @@ export default function AddLiquidity({
|
|||||||
} else {
|
} else {
|
||||||
// prevent weth + eth
|
// prevent weth + eth
|
||||||
const isETHOrWETHNew =
|
const isETHOrWETHNew =
|
||||||
currencyIdNew === 'ETH' || (chainId !== undefined && currencyIdNew === WETH9_EXTENDED[chainId]?.address)
|
currencyIdNew === 'ETH' ||
|
||||||
|
(chainId !== undefined && currencyIdNew === WRAPPED_NATIVE_CURRENCY[chainId]?.address)
|
||||||
const isETHOrWETHOther =
|
const isETHOrWETHOther =
|
||||||
currencyIdOther !== undefined &&
|
currencyIdOther !== undefined &&
|
||||||
(currencyIdOther === 'ETH' || (chainId !== undefined && currencyIdOther === WETH9_EXTENDED[chainId]?.address))
|
(currencyIdOther === 'ETH' ||
|
||||||
|
(chainId !== undefined && currencyIdOther === WRAPPED_NATIVE_CURRENCY[chainId]?.address))
|
||||||
|
|
||||||
if (isETHOrWETHNew && isETHOrWETHOther) {
|
if (isETHOrWETHNew && isETHOrWETHOther) {
|
||||||
return [currencyIdNew, undefined]
|
return [currencyIdNew, undefined]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useActiveWeb3React } from 'hooks/web3'
|
import { useActiveWeb3React } from 'hooks/web3'
|
||||||
import { Redirect, RouteComponentProps } from 'react-router-dom'
|
import { Redirect, RouteComponentProps } from 'react-router-dom'
|
||||||
|
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import AddLiquidity from './index'
|
import AddLiquidity from './index'
|
||||||
|
|
||||||
export function RedirectDuplicateTokenIds(
|
export function RedirectDuplicateTokenIds(
|
||||||
@ -17,9 +17,9 @@ export function RedirectDuplicateTokenIds(
|
|||||||
|
|
||||||
// prevent weth + eth
|
// prevent weth + eth
|
||||||
const isETHOrWETHA =
|
const isETHOrWETHA =
|
||||||
currencyIdA === 'ETH' || (chainId !== undefined && currencyIdA === WETH9_EXTENDED[chainId]?.address)
|
currencyIdA === 'ETH' || (chainId !== undefined && currencyIdA === WRAPPED_NATIVE_CURRENCY[chainId]?.address)
|
||||||
const isETHOrWETHB =
|
const isETHOrWETHB =
|
||||||
currencyIdB === 'ETH' || (chainId !== undefined && currencyIdB === WETH9_EXTENDED[chainId]?.address)
|
currencyIdB === 'ETH' || (chainId !== undefined && currencyIdB === WRAPPED_NATIVE_CURRENCY[chainId]?.address)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currencyIdA &&
|
currencyIdA &&
|
||||||
|
@ -21,7 +21,7 @@ import { MinimalPositionCard } from '../../components/PositionCard'
|
|||||||
import Row, { RowBetween, RowFlat } from '../../components/Row'
|
import Row, { RowBetween, RowFlat } from '../../components/Row'
|
||||||
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
||||||
import { ZERO_PERCENT } from '../../constants/misc'
|
import { ZERO_PERCENT } from '../../constants/misc'
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { useCurrency } from '../../hooks/Tokens'
|
import { useCurrency } from '../../hooks/Tokens'
|
||||||
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
||||||
import { useV2RouterContract } from '../../hooks/useContract'
|
import { useV2RouterContract } from '../../hooks/useContract'
|
||||||
@ -61,8 +61,8 @@ export default function AddLiquidity({
|
|||||||
|
|
||||||
const oneCurrencyIsWETH = Boolean(
|
const oneCurrencyIsWETH = Boolean(
|
||||||
chainId &&
|
chainId &&
|
||||||
((currencyA && currencyA.equals(WETH9_EXTENDED[chainId])) ||
|
((currencyA && currencyA.equals(WRAPPED_NATIVE_CURRENCY[chainId])) ||
|
||||||
(currencyB && currencyB.equals(WETH9_EXTENDED[chainId])))
|
(currencyB && currencyB.equals(WRAPPED_NATIVE_CURRENCY[chainId])))
|
||||||
)
|
)
|
||||||
|
|
||||||
const toggleWalletModal = useWalletModalToggle() // toggle wallet when disconnected
|
const toggleWalletModal = useWalletModalToggle() // toggle wallet when disconnected
|
||||||
|
@ -36,7 +36,7 @@ import CurrencyLogo from '../../components/CurrencyLogo'
|
|||||||
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
||||||
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
|
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
|
||||||
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
|
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { useToken } from '../../hooks/Tokens'
|
import { useToken } from '../../hooks/Tokens'
|
||||||
import { usePairContract, useV2MigratorContract } from '../../hooks/useContract'
|
import { usePairContract, useV2MigratorContract } from '../../hooks/useContract'
|
||||||
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
|
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
|
||||||
@ -592,10 +592,10 @@ function V2PairMigration({
|
|||||||
<ThemedText.Black fontSize={12}>
|
<ThemedText.Black fontSize={12}>
|
||||||
<Trans>
|
<Trans>
|
||||||
At least {formatCurrencyAmount(refund0, 4)}{' '}
|
At least {formatCurrencyAmount(refund0, 4)}{' '}
|
||||||
{token0.equals(WETH9_EXTENDED[chainId]) ? 'ETH' : token0.symbol} and{' '}
|
{token0.equals(WRAPPED_NATIVE_CURRENCY[chainId]) ? 'ETH' : token0.symbol} and{' '}
|
||||||
{formatCurrencyAmount(refund1, 4)}{' '}
|
{formatCurrencyAmount(refund1, 4)}{' '}
|
||||||
{token1.equals(WETH9_EXTENDED[chainId]) ? 'ETH' : token1.symbol} will be refunded to your wallet
|
{token1.equals(WRAPPED_NATIVE_CURRENCY[chainId]) ? 'ETH' : token1.symbol} will be refunded to your
|
||||||
due to selected price range.
|
wallet due to selected price range.
|
||||||
</Trans>
|
</Trans>
|
||||||
</ThemedText.Black>
|
</ThemedText.Black>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -4,11 +4,10 @@ import { AutoColumn } from 'components/Column'
|
|||||||
import DowntimeWarning from 'components/DowntimeWarning'
|
import DowntimeWarning from 'components/DowntimeWarning'
|
||||||
import { FlyoutAlignment, NewMenu } from 'components/Menu'
|
import { FlyoutAlignment, NewMenu } from 'components/Menu'
|
||||||
import { SwapPoolTabs } from 'components/NavigationTabs'
|
import { SwapPoolTabs } from 'components/NavigationTabs'
|
||||||
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
|
import { SingleRowNetworkAlert } from 'components/NetworkAlert/NetworkAlert'
|
||||||
import PositionList from 'components/PositionList'
|
import PositionList from 'components/PositionList'
|
||||||
import { RowBetween, RowFixed } from 'components/Row'
|
import { RowBetween, RowFixed } from 'components/Row'
|
||||||
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
import { SwitchLocaleLink } from 'components/SwitchLocaleLink'
|
||||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
|
||||||
import { useV3Positions } from 'hooks/useV3Positions'
|
import { useV3Positions } from 'hooks/useV3Positions'
|
||||||
import { useActiveWeb3React } from 'hooks/web3'
|
import { useActiveWeb3React } from 'hooks/web3'
|
||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
@ -20,6 +19,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
|||||||
import { HideSmall, ThemedText } from 'theme'
|
import { HideSmall, ThemedText } from 'theme'
|
||||||
import { PositionDetails } from 'types/position'
|
import { PositionDetails } from 'types/position'
|
||||||
|
|
||||||
|
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
|
||||||
import CTACards from './CTACards'
|
import CTACards from './CTACards'
|
||||||
import { LoadingRows } from './styleds'
|
import { LoadingRows } from './styleds'
|
||||||
|
|
||||||
@ -128,6 +128,25 @@ const ResponsiveRow = styled(RowFixed)`
|
|||||||
`};
|
`};
|
||||||
`
|
`
|
||||||
|
|
||||||
|
function PositionsLoadingPlaceholder() {
|
||||||
|
return (
|
||||||
|
<LoadingRows>
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
<div />
|
||||||
|
</LoadingRows>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function Pool() {
|
export default function Pool() {
|
||||||
const { account, chainId } = useActiveWeb3React()
|
const { account, chainId } = useActiveWeb3React()
|
||||||
const toggleWalletModal = useWalletModalToggle()
|
const toggleWalletModal = useWalletModalToggle()
|
||||||
@ -147,7 +166,7 @@ export default function Pool() {
|
|||||||
|
|
||||||
const filteredPositions = [...openPositions, ...(userHideClosedPositions ? [] : closedPositions)]
|
const filteredPositions = [...openPositions, ...(userHideClosedPositions ? [] : closedPositions)]
|
||||||
const showConnectAWallet = Boolean(!account)
|
const showConnectAWallet = Boolean(!account)
|
||||||
const showV2Features = !!chainId && !L2_CHAIN_IDS.includes(chainId)
|
const showV2Features = Boolean(chainId && V2_FACTORY_ADDRESSES[chainId])
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{
|
{
|
||||||
@ -224,27 +243,14 @@ export default function Pool() {
|
|||||||
</TitleRow>
|
</TitleRow>
|
||||||
|
|
||||||
<HideSmall>
|
<HideSmall>
|
||||||
<NetworkAlert thin />
|
<SingleRowNetworkAlert />
|
||||||
<DowntimeWarning />
|
<DowntimeWarning />
|
||||||
<CTACards />
|
<CTACards />
|
||||||
</HideSmall>
|
</HideSmall>
|
||||||
|
|
||||||
<MainContentWrapper>
|
<MainContentWrapper>
|
||||||
{positionsLoading ? (
|
{positionsLoading ? (
|
||||||
<LoadingRows>
|
<PositionsLoadingPlaceholder />
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
</LoadingRows>
|
|
||||||
) : filteredPositions && filteredPositions.length > 0 ? (
|
) : filteredPositions && filteredPositions.length > 0 ? (
|
||||||
<PositionList positions={filteredPositions} />
|
<PositionList positions={filteredPositions} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -16,7 +16,7 @@ import { MinimalPositionCard } from '../../components/PositionCard'
|
|||||||
import Row from '../../components/Row'
|
import Row from '../../components/Row'
|
||||||
import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModal'
|
import CurrencySearchModal from '../../components/SearchModal/CurrencySearchModal'
|
||||||
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
|
||||||
import { ExtendedEther } from '../../constants/tokens'
|
import { nativeOnChain } from '../../constants/tokens'
|
||||||
import { PairState, useV2Pair } from '../../hooks/useV2Pairs'
|
import { PairState, useV2Pair } from '../../hooks/useV2Pairs'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { usePairAdder } from '../../state/user/hooks'
|
import { usePairAdder } from '../../state/user/hooks'
|
||||||
@ -44,7 +44,7 @@ export default function PoolFinder() {
|
|||||||
const [showSearch, setShowSearch] = useState<boolean>(false)
|
const [showSearch, setShowSearch] = useState<boolean>(false)
|
||||||
const [activeField, setActiveField] = useState<number>(Fields.TOKEN1)
|
const [activeField, setActiveField] = useState<number>(Fields.TOKEN1)
|
||||||
|
|
||||||
const [currency0, setCurrency0] = useState<Currency | null>(() => (chainId ? ExtendedEther.onChain(chainId) : null))
|
const [currency0, setCurrency0] = useState<Currency | null>(() => (chainId ? nativeOnChain(chainId) : null))
|
||||||
const [currency1, setCurrency1] = useState<Currency | null>(null)
|
const [currency1, setCurrency1] = useState<Currency | null>(null)
|
||||||
|
|
||||||
const [pairState, pair] = useV2Pair(currency0 ?? undefined, currency1 ?? undefined)
|
const [pairState, pair] = useV2Pair(currency0 ?? undefined, currency1 ?? undefined)
|
||||||
|
@ -32,7 +32,7 @@ import { useUserSlippageToleranceWithDefault } from 'state/user/hooks'
|
|||||||
import { ThemedText } from 'theme'
|
import { ThemedText } from 'theme'
|
||||||
|
|
||||||
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { TransactionType } from '../../state/transactions/actions'
|
import { TransactionType } from '../../state/transactions/actions'
|
||||||
import { calculateGasMargin } from '../../utils/calculateGasMargin'
|
import { calculateGasMargin } from '../../utils/calculateGasMargin'
|
||||||
import { currencyId } from '../../utils/currencyId'
|
import { currencyId } from '../../utils/currencyId'
|
||||||
@ -266,8 +266,8 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
|
|||||||
liquidityValue1?.currency &&
|
liquidityValue1?.currency &&
|
||||||
(liquidityValue0.currency.isNative ||
|
(liquidityValue0.currency.isNative ||
|
||||||
liquidityValue1.currency.isNative ||
|
liquidityValue1.currency.isNative ||
|
||||||
liquidityValue0.currency.wrapped.equals(WETH9_EXTENDED[liquidityValue0.currency.chainId]) ||
|
liquidityValue0.currency.wrapped.equals(WRAPPED_NATIVE_CURRENCY[liquidityValue0.currency.chainId]) ||
|
||||||
liquidityValue1.currency.wrapped.equals(WETH9_EXTENDED[liquidityValue1.currency.chainId]))
|
liquidityValue1.currency.wrapped.equals(WRAPPED_NATIVE_CURRENCY[liquidityValue1.currency.chainId]))
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<AutoColumn>
|
<AutoColumn>
|
||||||
|
@ -22,7 +22,7 @@ import Row, { RowBetween, RowFixed } from '../../components/Row'
|
|||||||
import Slider from '../../components/Slider'
|
import Slider from '../../components/Slider'
|
||||||
import { Dots } from '../../components/swap/styleds'
|
import { Dots } from '../../components/swap/styleds'
|
||||||
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
import TransactionConfirmationModal, { ConfirmationModalContent } from '../../components/TransactionConfirmationModal'
|
||||||
import { WETH9_EXTENDED } from '../../constants/tokens'
|
import { WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { useCurrency } from '../../hooks/Tokens'
|
import { useCurrency } from '../../hooks/Tokens'
|
||||||
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
|
||||||
import { usePairContract, useV2RouterContract } from '../../hooks/useContract'
|
import { usePairContract, useV2RouterContract } from '../../hooks/useContract'
|
||||||
@ -388,8 +388,8 @@ export default function RemoveLiquidity({
|
|||||||
const oneCurrencyIsETH = currencyA?.isNative || currencyB?.isNative
|
const oneCurrencyIsETH = currencyA?.isNative || currencyB?.isNative
|
||||||
const oneCurrencyIsWETH = Boolean(
|
const oneCurrencyIsWETH = Boolean(
|
||||||
chainId &&
|
chainId &&
|
||||||
WETH9_EXTENDED[chainId] &&
|
WRAPPED_NATIVE_CURRENCY[chainId] &&
|
||||||
(currencyA?.equals(WETH9_EXTENDED[chainId]) || currencyB?.equals(WETH9_EXTENDED[chainId]))
|
(currencyA?.equals(WRAPPED_NATIVE_CURRENCY[chainId]) || currencyB?.equals(WRAPPED_NATIVE_CURRENCY[chainId]))
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleSelectCurrencyA = useCallback(
|
const handleSelectCurrencyA = useCallback(
|
||||||
@ -532,17 +532,17 @@ export default function RemoveLiquidity({
|
|||||||
<RowBetween style={{ justifyContent: 'flex-end' }}>
|
<RowBetween style={{ justifyContent: 'flex-end' }}>
|
||||||
{oneCurrencyIsETH ? (
|
{oneCurrencyIsETH ? (
|
||||||
<StyledInternalLink
|
<StyledInternalLink
|
||||||
to={`/remove/v2/${currencyA?.isNative ? WETH9_EXTENDED[chainId].address : currencyIdA}/${
|
to={`/remove/v2/${
|
||||||
currencyB?.isNative ? WETH9_EXTENDED[chainId].address : currencyIdB
|
currencyA?.isNative ? WRAPPED_NATIVE_CURRENCY[chainId].address : currencyIdA
|
||||||
}`}
|
}/${currencyB?.isNative ? WRAPPED_NATIVE_CURRENCY[chainId].address : currencyIdB}`}
|
||||||
>
|
>
|
||||||
Receive WETH
|
Receive WETH
|
||||||
</StyledInternalLink>
|
</StyledInternalLink>
|
||||||
) : oneCurrencyIsWETH ? (
|
) : oneCurrencyIsWETH ? (
|
||||||
<StyledInternalLink
|
<StyledInternalLink
|
||||||
to={`/remove/v2/${currencyA?.equals(WETH9_EXTENDED[chainId]) ? 'ETH' : currencyIdA}/${
|
to={`/remove/v2/${
|
||||||
currencyB?.equals(WETH9_EXTENDED[chainId]) ? 'ETH' : currencyIdB
|
currencyA?.equals(WRAPPED_NATIVE_CURRENCY[chainId]) ? 'ETH' : currencyIdA
|
||||||
}`}
|
}/${currencyB?.equals(WRAPPED_NATIVE_CURRENCY[chainId]) ? 'ETH' : currencyIdB}`}
|
||||||
>
|
>
|
||||||
Receive ETH
|
Receive ETH
|
||||||
</StyledInternalLink>
|
</StyledInternalLink>
|
||||||
|
@ -14,7 +14,7 @@ import ReactGA from 'react-ga'
|
|||||||
import { RouteComponentProps } from 'react-router-dom'
|
import { RouteComponentProps } from 'react-router-dom'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { TradeState } from 'state/routing/types'
|
import { TradeState } from 'state/routing/types'
|
||||||
import { ThemeContext } from 'styled-components/macro'
|
import styled, { ThemeContext } from 'styled-components/macro'
|
||||||
|
|
||||||
import AddressInputPanel from '../../components/AddressInputPanel'
|
import AddressInputPanel from '../../components/AddressInputPanel'
|
||||||
import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary } from '../../components/Button'
|
import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary } from '../../components/Button'
|
||||||
@ -38,7 +38,7 @@ import useIsArgentWallet from '../../hooks/useIsArgentWallet'
|
|||||||
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
||||||
import { useSwapCallback } from '../../hooks/useSwapCallback'
|
import { useSwapCallback } from '../../hooks/useSwapCallback'
|
||||||
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
||||||
import useWrapCallback, { WrapType } from '../../hooks/useWrapCallback'
|
import useWrapCallback, { WrapErrorText, WrapType } from '../../hooks/useWrapCallback'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { useWalletModalToggle } from '../../state/application/hooks'
|
import { useWalletModalToggle } from '../../state/application/hooks'
|
||||||
import { Field } from '../../state/swap/actions'
|
import { Field } from '../../state/swap/actions'
|
||||||
@ -55,6 +55,10 @@ import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
|||||||
import { warningSeverity } from '../../utils/prices'
|
import { warningSeverity } from '../../utils/prices'
|
||||||
import AppBody from '../AppBody'
|
import AppBody from '../AppBody'
|
||||||
|
|
||||||
|
const AlertWrapper = styled.div`
|
||||||
|
max-width: 480px;
|
||||||
|
`
|
||||||
|
|
||||||
export default function Swap({ history }: RouteComponentProps) {
|
export default function Swap({ history }: RouteComponentProps) {
|
||||||
const { account } = useActiveWeb3React()
|
const { account } = useActiveWeb3React()
|
||||||
const loadedUrlParams = useDefaultsFromURLSearch()
|
const loadedUrlParams = useDefaultsFromURLSearch()
|
||||||
@ -374,7 +378,9 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
onConfirm={handleConfirmTokenWarning}
|
onConfirm={handleConfirmTokenWarning}
|
||||||
onDismiss={handleDismissTokenWarning}
|
onDismiss={handleDismissTokenWarning}
|
||||||
/>
|
/>
|
||||||
<NetworkAlert />
|
<AlertWrapper>
|
||||||
|
<NetworkAlert />
|
||||||
|
</AlertWrapper>
|
||||||
<AppBody>
|
<AppBody>
|
||||||
<SwapHeader allowedSlippage={allowedSlippage} />
|
<SwapHeader allowedSlippage={allowedSlippage} />
|
||||||
<Wrapper id="swap-page">
|
<Wrapper id="swap-page">
|
||||||
@ -473,12 +479,13 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
</ButtonLight>
|
</ButtonLight>
|
||||||
) : showWrap ? (
|
) : showWrap ? (
|
||||||
<ButtonPrimary disabled={Boolean(wrapInputError)} onClick={onWrap}>
|
<ButtonPrimary disabled={Boolean(wrapInputError)} onClick={onWrap}>
|
||||||
{wrapInputError ??
|
{wrapInputError ? (
|
||||||
(wrapType === WrapType.WRAP ? (
|
<WrapErrorText wrapInputError={wrapInputError} />
|
||||||
<Trans>Wrap</Trans>
|
) : wrapType === WrapType.WRAP ? (
|
||||||
) : wrapType === WrapType.UNWRAP ? (
|
<Trans>Wrap</Trans>
|
||||||
<Trans>Unwrap</Trans>
|
) : wrapType === WrapType.UNWRAP ? (
|
||||||
) : null)}
|
<Trans>Unwrap</Trans>
|
||||||
|
) : null}
|
||||||
</ButtonPrimary>
|
</ButtonPrimary>
|
||||||
) : routeNotFound && userHasSpecifiedInputOutput && !routeIsLoading && !routeIsSyncing ? (
|
) : routeNotFound && userHasSpecifiedInputOutput && !routeIsLoading && !routeIsSyncing ? (
|
||||||
<GreyCard style={{ textAlign: 'center' }}>
|
<GreyCard style={{ textAlign: 'center' }}>
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
export const StandardPageWrapper = styled.div`
|
|
||||||
padding-top: 160px;
|
|
||||||
width: 100%;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const IframeBodyWrapper = styled.div`
|
export const IframeBodyWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -19,7 +19,6 @@ describe('application reducer', () => {
|
|||||||
1: 3,
|
1: 3,
|
||||||
},
|
},
|
||||||
chainId: null,
|
chainId: null,
|
||||||
implements3085: false,
|
|
||||||
openModal: null,
|
openModal: null,
|
||||||
popupList: [],
|
popupList: [],
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import { createSlice, nanoid } from '@reduxjs/toolkit'
|
import { createSlice, nanoid } from '@reduxjs/toolkit'
|
||||||
import { DEFAULT_TXN_DISMISS_MS } from 'constants/misc'
|
import { DEFAULT_TXN_DISMISS_MS } from 'constants/misc'
|
||||||
|
|
||||||
export type PopupContent = {
|
import { SupportedChainId } from '../../constants/chains'
|
||||||
txn: {
|
|
||||||
hash: string
|
export type PopupContent =
|
||||||
}
|
| {
|
||||||
}
|
txn: {
|
||||||
|
hash: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
failedSwitchNetwork: SupportedChainId
|
||||||
|
}
|
||||||
|
|
||||||
export enum ApplicationModal {
|
export enum ApplicationModal {
|
||||||
WALLET,
|
WALLET,
|
||||||
@ -26,7 +32,6 @@ type PopupList = Array<{ key: string; show: boolean; content: PopupContent; remo
|
|||||||
export interface ApplicationState {
|
export interface ApplicationState {
|
||||||
readonly blockNumber: { readonly [chainId: number]: number }
|
readonly blockNumber: { readonly [chainId: number]: number }
|
||||||
readonly chainId: number | null
|
readonly chainId: number | null
|
||||||
readonly implements3085: boolean
|
|
||||||
readonly openModal: ApplicationModal | null
|
readonly openModal: ApplicationModal | null
|
||||||
readonly popupList: PopupList
|
readonly popupList: PopupList
|
||||||
}
|
}
|
||||||
@ -34,7 +39,6 @@ export interface ApplicationState {
|
|||||||
const initialState: ApplicationState = {
|
const initialState: ApplicationState = {
|
||||||
blockNumber: {},
|
blockNumber: {},
|
||||||
chainId: null,
|
chainId: null,
|
||||||
implements3085: false,
|
|
||||||
openModal: null,
|
openModal: null,
|
||||||
popupList: [],
|
popupList: [],
|
||||||
}
|
}
|
||||||
@ -75,12 +79,8 @@ const applicationSlice = createSlice({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setImplements3085(state, { payload: { implements3085 } }) {
|
|
||||||
state.implements3085 = implements3085
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const { updateChainId, updateBlockNumber, setOpenModal, addPopup, removePopup, setImplements3085 } =
|
export const { updateChainId, updateBlockNumber, setOpenModal, addPopup, removePopup } = applicationSlice.actions
|
||||||
applicationSlice.actions
|
|
||||||
export default applicationSlice.reducer
|
export default applicationSlice.reducer
|
||||||
|
@ -5,9 +5,8 @@ import { useCallback, useEffect, useState } from 'react'
|
|||||||
import { api, CHAIN_TAG } from 'state/data/enhanced'
|
import { api, CHAIN_TAG } from 'state/data/enhanced'
|
||||||
import { useAppDispatch, useAppSelector } from 'state/hooks'
|
import { useAppDispatch, useAppSelector } from 'state/hooks'
|
||||||
import { supportedChainId } from 'utils/supportedChainId'
|
import { supportedChainId } from 'utils/supportedChainId'
|
||||||
import { switchToNetwork } from 'utils/switchToNetwork'
|
|
||||||
|
|
||||||
import { setImplements3085, updateBlockNumber, updateChainId } from './reducer'
|
import { updateBlockNumber, updateChainId } from './reducer'
|
||||||
|
|
||||||
function useQueryCacheInvalidator() {
|
function useQueryCacheInvalidator() {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@ -23,7 +22,7 @@ function useQueryCacheInvalidator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Updater(): null {
|
export default function Updater(): null {
|
||||||
const { account, chainId, library } = useActiveWeb3React()
|
const { chainId, library } = useActiveWeb3React()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const windowVisible = useIsWindowVisible()
|
const windowVisible = useIsWindowVisible()
|
||||||
|
|
||||||
@ -77,19 +76,5 @@ export default function Updater(): null {
|
|||||||
)
|
)
|
||||||
}, [dispatch, debouncedState.chainId])
|
}, [dispatch, debouncedState.chainId])
|
||||||
|
|
||||||
const implements3085 = useAppSelector((state) => state.application.implements3085)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!library?.provider?.request) {
|
|
||||||
dispatch(setImplements3085({ implements3085: false }))
|
|
||||||
} else if (account && !implements3085) {
|
|
||||||
switchToNetwork({ library })
|
|
||||||
.then((x) => x ?? dispatch(setImplements3085({ implements3085: true })))
|
|
||||||
.catch(() => dispatch(setImplements3085({ implements3085: false })))
|
|
||||||
} else if (!account && implements3085) {
|
|
||||||
dispatch(setImplements3085({ implements3085: false }))
|
|
||||||
}
|
|
||||||
}, [account, dispatch, implements3085, library])
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ const CHAIN_SUBGRAPH_URL: Record<number, string> = {
|
|||||||
[SupportedChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-minimal',
|
[SupportedChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-minimal',
|
||||||
|
|
||||||
[SupportedChainId.OPTIMISM]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-optimism-dev',
|
[SupportedChainId.OPTIMISM]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-optimism-dev',
|
||||||
|
|
||||||
|
[SupportedChainId.POLYGON]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const api = createApi({
|
export const api = createApi({
|
||||||
|
@ -194,14 +194,14 @@ export function useV3DerivedMintInfo(
|
|||||||
// check for invalid price input (converts to invalid ratio)
|
// check for invalid price input (converts to invalid ratio)
|
||||||
const invalidPrice = useMemo(() => {
|
const invalidPrice = useMemo(() => {
|
||||||
const sqrtRatioX96 = price ? encodeSqrtRatioX96(price.numerator, price.denominator) : undefined
|
const sqrtRatioX96 = price ? encodeSqrtRatioX96(price.numerator, price.denominator) : undefined
|
||||||
const invalid =
|
return (
|
||||||
price &&
|
price &&
|
||||||
sqrtRatioX96 &&
|
sqrtRatioX96 &&
|
||||||
!(
|
!(
|
||||||
JSBI.greaterThanOrEqual(sqrtRatioX96, TickMath.MIN_SQRT_RATIO) &&
|
JSBI.greaterThanOrEqual(sqrtRatioX96, TickMath.MIN_SQRT_RATIO) &&
|
||||||
JSBI.lessThan(sqrtRatioX96, TickMath.MAX_SQRT_RATIO)
|
JSBI.lessThan(sqrtRatioX96, TickMath.MAX_SQRT_RATIO)
|
||||||
)
|
)
|
||||||
return invalid
|
)
|
||||||
}, [price])
|
}, [price])
|
||||||
|
|
||||||
// used for ratio calculation when pool not initialized
|
// used for ratio calculation when pool not initialized
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useMulticall2Contract } from '../../hooks/useContract'
|
import { useInterfaceMulticall } from '../../hooks/useContract'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { useBlockNumber } from '../application/hooks'
|
import { useBlockNumber } from '../application/hooks'
|
||||||
import { multicall } from './instance'
|
import { multicall } from './instance'
|
||||||
@ -7,6 +7,6 @@ import { multicall } from './instance'
|
|||||||
export default function Updater() {
|
export default function Updater() {
|
||||||
const latestBlockNumber = useBlockNumber()
|
const latestBlockNumber = useBlockNumber()
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
const multicall2Contract = useMulticall2Contract()
|
const multicall2Contract = useInterfaceMulticall()
|
||||||
return <multicall.Updater chainId={chainId} latestBlockNumber={latestBlockNumber} contract={multicall2Contract} />
|
return <multicall.Updater chainId={chainId} latestBlockNumber={latestBlockNumber} contract={multicall2Contract} />
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { AlphaRouterParams, IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router'
|
import { AlphaRouterParams, IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router'
|
||||||
import { NETWORK_URLS } from 'connectors'
|
import { INFURA_NETWORK_URLS, SupportedChainId } from 'constants/chains'
|
||||||
import { SupportedChainId } from 'constants/chains'
|
|
||||||
import { providers } from 'ethers/lib/ethers'
|
import { providers } from 'ethers/lib/ethers'
|
||||||
import ReactGA from 'react-ga'
|
import ReactGA from 'react-ga'
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ export type Dependencies = {
|
|||||||
export function buildDependencies(): Dependencies {
|
export function buildDependencies(): Dependencies {
|
||||||
const dependenciesByChain: Dependencies = {}
|
const dependenciesByChain: Dependencies = {}
|
||||||
for (const chainId of AUTO_ROUTER_SUPPORTED_CHAINS) {
|
for (const chainId of AUTO_ROUTER_SUPPORTED_CHAINS) {
|
||||||
const provider = new providers.JsonRpcProvider(NETWORK_URLS[chainId])
|
const provider = new providers.JsonRpcProvider(INFURA_NETWORK_URLS[chainId])
|
||||||
|
|
||||||
dependenciesByChain[chainId] = {
|
dependenciesByChain[chainId] = {
|
||||||
chainId,
|
chainId,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { Ether, Token, TradeType } from '@uniswap/sdk-core'
|
import { Token, TradeType } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
|
import { nativeOnChain } from '../../constants/tokens'
|
||||||
import { computeRoutes } from './utils'
|
import { computeRoutes } from './utils'
|
||||||
|
|
||||||
const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC')
|
const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC')
|
||||||
const DAI = new Token(1, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 6, 'DAI')
|
const DAI = new Token(1, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 6, 'DAI')
|
||||||
const MKR = new Token(1, '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 6, 'MKR')
|
const MKR = new Token(1, '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 6, 'MKR')
|
||||||
|
|
||||||
const ETH = Ether.onChain(1)
|
const ETH = nativeOnChain(1)
|
||||||
|
|
||||||
// helper function to make amounts more readable
|
// helper function to make amounts more readable
|
||||||
const amount = (raw: TemplateStringsArray) => (parseInt(raw[0]) * 1e6).toString()
|
const amount = (raw: TemplateStringsArray) => (parseInt(raw[0]) * 1e6).toString()
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Currency, CurrencyAmount, Ether, Token, TradeType } from '@uniswap/sdk-core'
|
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core'
|
||||||
import { Pair, Route as V2Route } from '@uniswap/v2-sdk'
|
import { Pair, Route as V2Route } from '@uniswap/v2-sdk'
|
||||||
import { FeeAmount, Pool, Route as V3Route } from '@uniswap/v3-sdk'
|
import { FeeAmount, Pool, Route as V3Route } from '@uniswap/v3-sdk'
|
||||||
|
|
||||||
|
import { nativeOnChain } from '../../constants/tokens'
|
||||||
import { GetQuoteResult, InterfaceTrade, V2PoolInRoute, V3PoolInRoute } from './types'
|
import { GetQuoteResult, InterfaceTrade, V2PoolInRoute, V3PoolInRoute } from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,9 +25,9 @@ export function computeRoutes(
|
|||||||
if (parsedTokenIn.address !== currencyIn.wrapped.address) return undefined
|
if (parsedTokenIn.address !== currencyIn.wrapped.address) return undefined
|
||||||
if (parsedTokenOut.address !== currencyOut.wrapped.address) return undefined
|
if (parsedTokenOut.address !== currencyOut.wrapped.address) return undefined
|
||||||
|
|
||||||
const parsedCurrencyIn = currencyIn.isNative ? Ether.onChain(currencyIn.chainId) : parsedTokenIn
|
const parsedCurrencyIn = currencyIn.isNative ? nativeOnChain(currencyIn.chainId) : parsedTokenIn
|
||||||
|
|
||||||
const parsedCurrencyOut = currencyOut.isNative ? Ether.onChain(currencyOut.chainId) : parsedTokenOut
|
const parsedCurrencyOut = currencyOut.isNative ? nativeOnChain(currencyOut.chainId) : parsedTokenOut
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return quoteResult.route.map((route) => {
|
return quoteResult.route.map((route) => {
|
||||||
|
@ -7,7 +7,7 @@ import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
|||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import { ReactNode, useMemo } from 'react'
|
import { ReactNode, useMemo } from 'react'
|
||||||
|
|
||||||
import { DAI, UNI, USDC, USDT, WBTC, WETH9_EXTENDED } from '../../constants/tokens'
|
import { DAI, UNI, USDC, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { NEVER_RELOAD, useMultipleContractSingleData } from '../multicall/hooks'
|
import { NEVER_RELOAD, useMultipleContractSingleData } from '../multicall/hooks'
|
||||||
import { tryParseAmount } from '../swap/hooks'
|
import { tryParseAmount } from '../swap/hooks'
|
||||||
@ -26,19 +26,19 @@ export const STAKING_REWARDS_INFO: {
|
|||||||
} = {
|
} = {
|
||||||
1: [
|
1: [
|
||||||
{
|
{
|
||||||
tokens: [WETH9_EXTENDED[1], DAI],
|
tokens: [WRAPPED_NATIVE_CURRENCY[1], DAI],
|
||||||
stakingRewardAddress: '0xa1484C3aa22a66C62b77E0AE78E15258bd0cB711',
|
stakingRewardAddress: '0xa1484C3aa22a66C62b77E0AE78E15258bd0cB711',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tokens: [WETH9_EXTENDED[1], USDC],
|
tokens: [WRAPPED_NATIVE_CURRENCY[1], USDC],
|
||||||
stakingRewardAddress: '0x7FBa4B8Dc5E7616e59622806932DBea72537A56b',
|
stakingRewardAddress: '0x7FBa4B8Dc5E7616e59622806932DBea72537A56b',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tokens: [WETH9_EXTENDED[1], USDT],
|
tokens: [WRAPPED_NATIVE_CURRENCY[1], USDT],
|
||||||
stakingRewardAddress: '0x6C3e4cb2E96B01F4b866965A91ed4437839A121a',
|
stakingRewardAddress: '0x6C3e4cb2E96B01F4b866965A91ed4437839A121a',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tokens: [WETH9_EXTENDED[1], WBTC],
|
tokens: [WRAPPED_NATIVE_CURRENCY[1], WBTC],
|
||||||
stakingRewardAddress: '0xCA35e32e7926b96A9988f61d510E038108d8068e',
|
stakingRewardAddress: '0xCA35e32e7926b96A9988f61d510E038108d8068e',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -95,6 +95,7 @@ export interface WrapTransactionInfo {
|
|||||||
type: TransactionType.WRAP
|
type: TransactionType.WRAP
|
||||||
unwrapped: boolean
|
unwrapped: boolean
|
||||||
currencyAmountRaw: string
|
currencyAmountRaw: string
|
||||||
|
chainId?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClaimTransactionInfo {
|
export interface ClaimTransactionInfo {
|
||||||
|
@ -15,13 +15,8 @@ export interface SerializedPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const updateMatchesDarkMode = createAction<{ matchesDarkMode: boolean }>('user/updateMatchesDarkMode')
|
export const updateMatchesDarkMode = createAction<{ matchesDarkMode: boolean }>('user/updateMatchesDarkMode')
|
||||||
export const updateArbitrumAlphaAcknowledged = createAction<{ arbitrumAlphaAcknowledged: boolean }>(
|
|
||||||
'user/updateArbitrumAlphaAcknowledged'
|
|
||||||
)
|
|
||||||
export const updateOptimismAlphaAcknowledged = createAction<{ optimismAlphaAcknowledged: boolean }>(
|
|
||||||
'user/updateOptimismAlphaAcknowledged'
|
|
||||||
)
|
|
||||||
export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('user/updateUserDarkMode')
|
export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('user/updateUserDarkMode')
|
||||||
|
export const acknowledgeNetworkAlert = createAction<{ chainId: number }>('user/acknowledgeNetworkAlert')
|
||||||
export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode')
|
export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode')
|
||||||
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
|
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
|
||||||
export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>(
|
export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>(
|
||||||
|
@ -14,14 +14,13 @@ import { useAllTokens } from '../../hooks/Tokens'
|
|||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { AppState } from '../index'
|
import { AppState } from '../index'
|
||||||
import {
|
import {
|
||||||
|
acknowledgeNetworkAlert,
|
||||||
addSerializedPair,
|
addSerializedPair,
|
||||||
addSerializedToken,
|
addSerializedToken,
|
||||||
removeSerializedToken,
|
removeSerializedToken,
|
||||||
SerializedPair,
|
SerializedPair,
|
||||||
SerializedToken,
|
SerializedToken,
|
||||||
updateArbitrumAlphaAcknowledged,
|
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
updateOptimismAlphaAcknowledged,
|
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
@ -339,22 +338,13 @@ export function useTrackedTokenPairs(): [Token, Token][] {
|
|||||||
}, [combinedList])
|
}, [combinedList])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useArbitrumAlphaAlert(): [boolean, (arbitrumAlphaAcknowledged: boolean) => void] {
|
export function useNetworkAlertStatus(chainId: number | undefined): [boolean, () => void] {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const arbitrumAlphaAcknowledged = useAppSelector(({ user }) => user.arbitrumAlphaAcknowledged)
|
const alertAcknowledged = useAppSelector(({ user }) => user.networkAlertsAcknowledged)
|
||||||
const setArbitrumAlphaAcknowledged = (arbitrumAlphaAcknowledged: boolean) => {
|
const acknowledgeAlert = useCallback(() => {
|
||||||
dispatch(updateArbitrumAlphaAcknowledged({ arbitrumAlphaAcknowledged }))
|
if (typeof chainId !== 'number') return
|
||||||
}
|
dispatch(acknowledgeNetworkAlert({ chainId }))
|
||||||
|
}, [chainId, dispatch])
|
||||||
|
|
||||||
return [arbitrumAlphaAcknowledged, setArbitrumAlphaAcknowledged]
|
return [typeof chainId === 'number' ? alertAcknowledged[chainId] ?? false : false, acknowledgeAlert]
|
||||||
}
|
|
||||||
|
|
||||||
export function useOptimismAlphaAlert(): [boolean, (optimismAlphaAcknowledged: boolean) => void] {
|
|
||||||
const dispatch = useAppDispatch()
|
|
||||||
const optimismAlphaAcknowledged = useAppSelector(({ user }) => user.optimismAlphaAcknowledged)
|
|
||||||
const setOptimismAlphaAcknowledged = (optimismAlphaAcknowledged: boolean) => {
|
|
||||||
dispatch(updateOptimismAlphaAcknowledged({ optimismAlphaAcknowledged }))
|
|
||||||
}
|
|
||||||
|
|
||||||
return [optimismAlphaAcknowledged, setOptimismAlphaAcknowledged]
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { createReducer } from '@reduxjs/toolkit'
|
import { createReducer } from '@reduxjs/toolkit'
|
||||||
import { SupportedLocale } from 'constants/locales'
|
import { SupportedLocale } from 'constants/locales'
|
||||||
|
|
||||||
|
import { SupportedChainId } from '../../constants/chains'
|
||||||
import { DEFAULT_DEADLINE_FROM_NOW } from '../../constants/misc'
|
import { DEFAULT_DEADLINE_FROM_NOW } from '../../constants/misc'
|
||||||
import { updateVersion } from '../global/actions'
|
import { updateVersion } from '../global/actions'
|
||||||
import {
|
import {
|
||||||
|
acknowledgeNetworkAlert,
|
||||||
addSerializedPair,
|
addSerializedPair,
|
||||||
addSerializedToken,
|
addSerializedToken,
|
||||||
removeSerializedPair,
|
removeSerializedPair,
|
||||||
removeSerializedToken,
|
removeSerializedToken,
|
||||||
SerializedPair,
|
SerializedPair,
|
||||||
SerializedToken,
|
SerializedToken,
|
||||||
updateArbitrumAlphaAcknowledged,
|
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
updateMatchesDarkMode,
|
updateMatchesDarkMode,
|
||||||
updateOptimismAlphaAcknowledged,
|
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
@ -25,13 +25,15 @@ import {
|
|||||||
const currentTimestamp = () => new Date().getTime()
|
const currentTimestamp = () => new Date().getTime()
|
||||||
|
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
arbitrumAlphaAcknowledged: boolean
|
// replaces the above two fields
|
||||||
|
networkAlertsAcknowledged: {
|
||||||
|
[chainId: number]: true
|
||||||
|
}
|
||||||
|
|
||||||
// the timestamp of the last updateVersion action
|
// the timestamp of the last updateVersion action
|
||||||
lastUpdateVersionTimestamp?: number
|
lastUpdateVersionTimestamp?: number
|
||||||
|
|
||||||
matchesDarkMode: boolean // whether the dark mode media query matches
|
matchesDarkMode: boolean // whether the dark mode media query matches
|
||||||
optimismAlphaAcknowledged: boolean
|
|
||||||
|
|
||||||
userDarkMode: boolean | null // the user's choice for dark mode or light mode
|
userDarkMode: boolean | null // the user's choice for dark mode or light mode
|
||||||
userLocale: SupportedLocale | null
|
userLocale: SupportedLocale | null
|
||||||
@ -72,9 +74,8 @@ function pairKey(token0Address: string, token1Address: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: UserState = {
|
export const initialState: UserState = {
|
||||||
arbitrumAlphaAcknowledged: false,
|
|
||||||
matchesDarkMode: false,
|
matchesDarkMode: false,
|
||||||
optimismAlphaAcknowledged: false,
|
networkAlertsAcknowledged: {},
|
||||||
userDarkMode: null,
|
userDarkMode: null,
|
||||||
userExpertMode: false,
|
userExpertMode: false,
|
||||||
userLocale: null,
|
userLocale: null,
|
||||||
@ -122,8 +123,20 @@ export default createReducer(initialState, (builder) =>
|
|||||||
state.userDeadline = DEFAULT_DEADLINE_FROM_NOW
|
state.userDeadline = DEFAULT_DEADLINE_FROM_NOW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.networkAlertsAcknowledged = state.networkAlertsAcknowledged ?? {}
|
||||||
|
if ((state as unknown as { arbitrumAlphaAcknowledged: boolean }).arbitrumAlphaAcknowledged) {
|
||||||
|
state.networkAlertsAcknowledged[SupportedChainId.ARBITRUM_ONE] = true
|
||||||
|
}
|
||||||
|
if ((state as unknown as { optimismAlphaAcknowledged: boolean }).optimismAlphaAcknowledged) {
|
||||||
|
state.networkAlertsAcknowledged[SupportedChainId.OPTIMISM] = true
|
||||||
|
}
|
||||||
|
|
||||||
state.lastUpdateVersionTimestamp = currentTimestamp()
|
state.lastUpdateVersionTimestamp = currentTimestamp()
|
||||||
})
|
})
|
||||||
|
.addCase(acknowledgeNetworkAlert, (state, action) => {
|
||||||
|
state.networkAlertsAcknowledged = state.networkAlertsAcknowledged ?? {}
|
||||||
|
state.networkAlertsAcknowledged[action.payload.chainId] = true
|
||||||
|
})
|
||||||
.addCase(updateUserDarkMode, (state, action) => {
|
.addCase(updateUserDarkMode, (state, action) => {
|
||||||
state.userDarkMode = action.payload.userDarkMode
|
state.userDarkMode = action.payload.userDarkMode
|
||||||
state.timestamp = currentTimestamp()
|
state.timestamp = currentTimestamp()
|
||||||
@ -132,12 +145,6 @@ export default createReducer(initialState, (builder) =>
|
|||||||
state.matchesDarkMode = action.payload.matchesDarkMode
|
state.matchesDarkMode = action.payload.matchesDarkMode
|
||||||
state.timestamp = currentTimestamp()
|
state.timestamp = currentTimestamp()
|
||||||
})
|
})
|
||||||
.addCase(updateArbitrumAlphaAcknowledged, (state, action) => {
|
|
||||||
state.arbitrumAlphaAcknowledged = action.payload.arbitrumAlphaAcknowledged
|
|
||||||
})
|
|
||||||
.addCase(updateOptimismAlphaAcknowledged, (state, action) => {
|
|
||||||
state.optimismAlphaAcknowledged = action.payload.optimismAlphaAcknowledged
|
|
||||||
})
|
|
||||||
.addCase(updateUserExpertMode, (state, action) => {
|
.addCase(updateUserExpertMode, (state, action) => {
|
||||||
state.userExpertMode = action.payload.userExpertMode
|
state.userExpertMode = action.payload.userExpertMode
|
||||||
state.timestamp = currentTimestamp()
|
state.timestamp = currentTimestamp()
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { Interface } from '@ethersproject/abi'
|
import { Interface } from '@ethersproject/abi'
|
||||||
import { Currency, CurrencyAmount, Ether, Token } from '@uniswap/sdk-core'
|
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||||
import ERC20ABI from 'abis/erc20.json'
|
import ERC20ABI from 'abis/erc20.json'
|
||||||
import { Erc20Interface } from 'abis/types/Erc20'
|
import { Erc20Interface } from 'abis/types/Erc20'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { UNI } from '../../constants/tokens'
|
import { nativeOnChain, UNI } from '../../constants/tokens'
|
||||||
import { useAllTokens } from '../../hooks/Tokens'
|
import { useAllTokens } from '../../hooks/Tokens'
|
||||||
import { useMulticall2Contract } from '../../hooks/useContract'
|
import { useInterfaceMulticall } from '../../hooks/useContract'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
import { isAddress } from '../../utils'
|
import { isAddress } from '../../utils'
|
||||||
import { useUserUnclaimedAmount } from '../claim/hooks'
|
import { useUserUnclaimedAmount } from '../claim/hooks'
|
||||||
@ -16,38 +16,35 @@ import { useTotalUniEarned } from '../stake/hooks'
|
|||||||
/**
|
/**
|
||||||
* Returns a map of the given addresses to their eventually consistent ETH balances.
|
* Returns a map of the given addresses to their eventually consistent ETH balances.
|
||||||
*/
|
*/
|
||||||
export function useETHBalances(uncheckedAddresses?: (string | undefined)[]): {
|
export function useNativeCurrencyBalances(uncheckedAddresses?: (string | undefined)[]): {
|
||||||
[address: string]: CurrencyAmount<Currency> | undefined
|
[address: string]: CurrencyAmount<Currency> | undefined
|
||||||
} {
|
} {
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
const multicallContract = useMulticall2Contract()
|
const multicallContract = useInterfaceMulticall()
|
||||||
|
|
||||||
const addresses: string[] = useMemo(
|
const validAddressInputs: [string][] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
uncheckedAddresses
|
uncheckedAddresses
|
||||||
? uncheckedAddresses
|
? uncheckedAddresses
|
||||||
.map(isAddress)
|
.map(isAddress)
|
||||||
.filter((a): a is string => a !== false)
|
.filter((a): a is string => a !== false)
|
||||||
.sort()
|
.sort()
|
||||||
|
.map((addr) => [addr])
|
||||||
: [],
|
: [],
|
||||||
[uncheckedAddresses]
|
[uncheckedAddresses]
|
||||||
)
|
)
|
||||||
|
|
||||||
const results = useSingleContractMultipleData(
|
const results = useSingleContractMultipleData(multicallContract, 'getEthBalance', validAddressInputs)
|
||||||
multicallContract,
|
|
||||||
'getEthBalance',
|
|
||||||
addresses.map((address) => [address])
|
|
||||||
)
|
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
addresses.reduce<{ [address: string]: CurrencyAmount<Currency> }>((memo, address, i) => {
|
validAddressInputs.reduce<{ [address: string]: CurrencyAmount<Currency> }>((memo, [address], i) => {
|
||||||
const value = results?.[i]?.result?.[0]
|
const value = results?.[i]?.result?.[0]
|
||||||
if (value && chainId)
|
if (value && chainId)
|
||||||
memo[address] = CurrencyAmount.fromRawAmount(Ether.onChain(chainId), JSBI.BigInt(value.toString()))
|
memo[address] = CurrencyAmount.fromRawAmount(nativeOnChain(chainId), JSBI.BigInt(value.toString()))
|
||||||
return memo
|
return memo
|
||||||
}, {}),
|
}, {}),
|
||||||
[addresses, chainId, results]
|
[validAddressInputs, chainId, results]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +117,7 @@ export function useCurrencyBalances(
|
|||||||
|
|
||||||
const tokenBalances = useTokenBalances(account, tokens)
|
const tokenBalances = useTokenBalances(account, tokens)
|
||||||
const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies])
|
const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies])
|
||||||
const ethBalance = useETHBalances(containsETH ? [account] : [])
|
const ethBalance = useNativeCurrencyBalances(containsETH ? [account] : [])
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -8,11 +8,13 @@ const initialStyles = {
|
|||||||
width: '200vw',
|
width: '200vw',
|
||||||
height: '200vh',
|
height: '200vh',
|
||||||
transform: 'translate(-50vw, -100vh)',
|
transform: 'translate(-50vw, -100vh)',
|
||||||
|
backgroundBlendMode: '',
|
||||||
}
|
}
|
||||||
const backgroundResetStyles = {
|
const backgroundResetStyles = {
|
||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
transform: 'unset',
|
transform: 'unset',
|
||||||
|
backgroundBlendMode: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
type TargetBackgroundStyles = typeof initialStyles | typeof backgroundResetStyles
|
type TargetBackgroundStyles = typeof initialStyles | typeof backgroundResetStyles
|
||||||
@ -48,6 +50,16 @@ export default function RadialGradientByChainUpdater(): null {
|
|||||||
const optimismDarkGradient = 'radial-gradient(150% 100% at 50% 0%, #3E2E38 2%, #2C1F2D 53%, #1F2128 100%)'
|
const optimismDarkGradient = 'radial-gradient(150% 100% at 50% 0%, #3E2E38 2%, #2C1F2D 53%, #1F2128 100%)'
|
||||||
backgroundRadialGradientElement.style.background = darkMode ? optimismDarkGradient : optimismLightGradient
|
backgroundRadialGradientElement.style.background = darkMode ? optimismDarkGradient : optimismLightGradient
|
||||||
break
|
break
|
||||||
|
case SupportedChainId.POLYGON:
|
||||||
|
case SupportedChainId.POLYGON_MUMBAI:
|
||||||
|
setBackground(backgroundResetStyles)
|
||||||
|
const polygonLightGradient =
|
||||||
|
'radial-gradient(153.32% 100% at 47.26% 0%, rgba(130, 71, 229, 0.0864) 0%, rgba(0, 41, 255, 0.06) 48.19%, rgba(0, 41, 255, 0.012) 100%), #FFFFFF'
|
||||||
|
const polygonDarkGradient =
|
||||||
|
'radial-gradient(150.6% 98.22% at 48.06% 0%, rgba(130, 71, 229, 0.6) 0%, rgba(200, 168, 255, 0) 100%), #1F2128'
|
||||||
|
backgroundRadialGradientElement.style.background = darkMode ? polygonDarkGradient : polygonLightGradient
|
||||||
|
backgroundRadialGradientElement.style.backgroundBlendMode = darkMode ? 'overlay,normal' : 'multiply,normal'
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
setBackground(initialStyles)
|
setBackground(initialStyles)
|
||||||
backgroundRadialGradientElement.style.background = ''
|
backgroundRadialGradientElement.style.background = ''
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
import { BigNumber } from '@ethersproject/bignumber'
|
|
||||||
import { hexStripZeros } from '@ethersproject/bytes'
|
|
||||||
import { Web3Provider } from '@ethersproject/providers'
|
|
||||||
import { L1ChainInfo, L2ChainInfo, SupportedChainId } from 'constants/chains'
|
|
||||||
|
|
||||||
interface AddNetworkArguments {
|
|
||||||
library: Web3Provider
|
|
||||||
chainId: SupportedChainId
|
|
||||||
info: L1ChainInfo | L2ChainInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// provider.request returns Promise<any>, but wallet_switchEthereumChain must return null or throw
|
|
||||||
// see https://github.com/rekmarks/EIPs/blob/3326-create/EIPS/eip-3326.md for more info on wallet_switchEthereumChain
|
|
||||||
export async function addNetwork({ library, chainId, info }: AddNetworkArguments): Promise<null | void> {
|
|
||||||
if (!library?.provider?.request) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const formattedChainId = hexStripZeros(BigNumber.from(chainId).toHexString())
|
|
||||||
try {
|
|
||||||
await library?.provider.request({
|
|
||||||
method: 'wallet_addEthereumChain',
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
chainId: formattedChainId,
|
|
||||||
chainName: info.label,
|
|
||||||
rpcUrls: info.rpcUrls,
|
|
||||||
nativeCurrency: info.nativeCurrency,
|
|
||||||
blockExplorerUrls: [info.explorer],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('error adding eth network: ', chainId, info, error)
|
|
||||||
}
|
|
||||||
}
|
|
9
src/utils/chains.tsx
Normal file
9
src/utils/chains.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { CHAIN_INFO, NetworkType, SupportedL1ChainId, SupportedL2ChainId } from '../constants/chains'
|
||||||
|
|
||||||
|
export function isL1ChainId(chainId: number | undefined): chainId is SupportedL1ChainId {
|
||||||
|
return typeof chainId === 'number' && CHAIN_INFO[chainId].networkType === NetworkType.L1
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isL2ChainId(chainId: number | undefined): chainId is SupportedL2ChainId {
|
||||||
|
return typeof chainId === 'number' && CHAIN_INFO[chainId].networkType === NetworkType.L2
|
||||||
|
}
|
@ -1,13 +1,19 @@
|
|||||||
import { L1_CHAIN_IDS, SupportedChainId } from '../constants/chains'
|
import { SupportedChainId } from '../constants/chains'
|
||||||
|
|
||||||
|
const DEFAULT_NETWORKS = [
|
||||||
|
SupportedChainId.MAINNET,
|
||||||
|
SupportedChainId.ROPSTEN,
|
||||||
|
SupportedChainId.RINKEBY,
|
||||||
|
SupportedChainId.GOERLI,
|
||||||
|
SupportedChainId.KOVAN,
|
||||||
|
]
|
||||||
|
|
||||||
export function constructSameAddressMap<T extends string>(
|
export function constructSameAddressMap<T extends string>(
|
||||||
address: T,
|
address: T,
|
||||||
additionalNetworks: SupportedChainId[] = []
|
additionalNetworks: SupportedChainId[] = []
|
||||||
): { [chainId: number]: T } {
|
): { [chainId: number]: T } {
|
||||||
return (L1_CHAIN_IDS as readonly SupportedChainId[])
|
return DEFAULT_NETWORKS.concat(additionalNetworks).reduce<{ [chainId: number]: T }>((memo, chainId) => {
|
||||||
.concat(additionalNetworks)
|
memo[chainId] = address
|
||||||
.reduce<{ [chainId: number]: T }>((memo, chainId) => {
|
return memo
|
||||||
memo[chainId] = address
|
}, {})
|
||||||
return memo
|
|
||||||
}, {})
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ describe('#getExplorerLink', () => {
|
|||||||
it('unrecognized chain id defaults to mainnet', () => {
|
it('unrecognized chain id defaults to mainnet', () => {
|
||||||
expect(getExplorerLink(2, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://etherscan.io/address/abc')
|
expect(getExplorerLink(2, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://etherscan.io/address/abc')
|
||||||
})
|
})
|
||||||
|
it('arbitrum', () => {
|
||||||
|
expect(getExplorerLink(42161, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://arbiscan.io/address/abc')
|
||||||
|
})
|
||||||
|
it('polygon', () => {
|
||||||
|
expect(getExplorerLink(137, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://polygonscan.com/address/abc')
|
||||||
|
})
|
||||||
it('ropsten', () => {
|
it('ropsten', () => {
|
||||||
expect(getExplorerLink(3, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://ropsten.etherscan.io/address/abc')
|
expect(getExplorerLink(3, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://ropsten.etherscan.io/address/abc')
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { SupportedChainId } from '../constants/chains'
|
import { SupportedChainId } from '../constants/chains'
|
||||||
|
|
||||||
const ETHERSCAN_PREFIXES: { [chainId: number]: string } = {
|
const ETHERSCAN_PREFIXES: { [chainId: number]: string } = {
|
||||||
[SupportedChainId.MAINNET]: '',
|
[SupportedChainId.MAINNET]: 'https://etherscan.io',
|
||||||
[SupportedChainId.ROPSTEN]: 'ropsten.',
|
[SupportedChainId.ROPSTEN]: 'https://ropsten.etherscan.io',
|
||||||
[SupportedChainId.RINKEBY]: 'rinkeby.',
|
[SupportedChainId.RINKEBY]: 'https://rinkeby.etherscan.io',
|
||||||
[SupportedChainId.GOERLI]: 'goerli.',
|
[SupportedChainId.GOERLI]: 'https://goerli.etherscan.io',
|
||||||
[SupportedChainId.KOVAN]: 'kovan.',
|
[SupportedChainId.KOVAN]: 'https://kovan.etherscan.io',
|
||||||
[SupportedChainId.OPTIMISM]: 'optimistic.',
|
[SupportedChainId.OPTIMISM]: 'https://optimistic.etherscan.io',
|
||||||
[SupportedChainId.OPTIMISTIC_KOVAN]: 'kovan-optimistic.',
|
[SupportedChainId.OPTIMISTIC_KOVAN]: 'https://kovan-optimistic.etherscan.io',
|
||||||
|
[SupportedChainId.POLYGON_MUMBAI]: 'https://mumbai.polygonscan.com',
|
||||||
|
[SupportedChainId.POLYGON]: 'https://polygonscan.com',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ExplorerDataType {
|
export enum ExplorerDataType {
|
||||||
@ -52,7 +54,7 @@ export function getExplorerLink(chainId: number, data: string, type: ExplorerDat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefix = `https://${ETHERSCAN_PREFIXES[chainId] ?? ''}etherscan.io`
|
const prefix = ETHERSCAN_PREFIXES[chainId] ?? 'https://etherscan.io'
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ExplorerDataType.TRANSACTION:
|
case ExplorerDataType.TRANSACTION:
|
||||||
|
@ -3,11 +3,9 @@ import { hexStripZeros } from '@ethersproject/bytes'
|
|||||||
import { Web3Provider } from '@ethersproject/providers'
|
import { Web3Provider } from '@ethersproject/providers'
|
||||||
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
import { CHAIN_INFO, SupportedChainId } from 'constants/chains'
|
||||||
|
|
||||||
import { addNetwork } from './addNetwork'
|
|
||||||
|
|
||||||
interface SwitchNetworkArguments {
|
interface SwitchNetworkArguments {
|
||||||
library: Web3Provider
|
library: Web3Provider
|
||||||
chainId?: SupportedChainId
|
chainId: SupportedChainId
|
||||||
}
|
}
|
||||||
|
|
||||||
// provider.request returns Promise<any>, but wallet_switchEthereumChain must return null or throw
|
// provider.request returns Promise<any>, but wallet_switchEthereumChain must return null or throw
|
||||||
@ -16,25 +14,39 @@ export async function switchToNetwork({ library, chainId }: SwitchNetworkArgumen
|
|||||||
if (!library?.provider?.request) {
|
if (!library?.provider?.request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!chainId && library?.getNetwork) {
|
|
||||||
;({ chainId } = await library.getNetwork())
|
|
||||||
}
|
|
||||||
const formattedChainId = hexStripZeros(BigNumber.from(chainId).toHexString())
|
const formattedChainId = hexStripZeros(BigNumber.from(chainId).toHexString())
|
||||||
try {
|
try {
|
||||||
await library?.provider.request({
|
await library.provider.request({
|
||||||
method: 'wallet_switchEthereumChain',
|
method: 'wallet_switchEthereumChain',
|
||||||
params: [{ chainId: formattedChainId }],
|
params: [{ chainId: formattedChainId }],
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 4902 is the error code for attempting to switch to an unrecognized chainId
|
// 4902 is the error code for attempting to switch to an unrecognized chainId
|
||||||
if (error.code === 4902 && chainId !== undefined) {
|
if (error.code === 4902) {
|
||||||
const info = CHAIN_INFO[chainId]
|
const info = CHAIN_INFO[chainId]
|
||||||
|
|
||||||
// metamask (only known implementer) automatically switches after a network is added
|
await library.provider.request({
|
||||||
// the second call is done here because that behavior is not a part of the spec and cannot be relied upon in the future
|
method: 'wallet_addEthereumChain',
|
||||||
// metamask's behavior when switching to the current network is just to return null (a no-op)
|
params: [
|
||||||
await addNetwork({ library, chainId, info })
|
{
|
||||||
await switchToNetwork({ library, chainId })
|
chainId: formattedChainId,
|
||||||
|
chainName: info.label,
|
||||||
|
rpcUrls: [info.addNetworkInfo.rpcUrl],
|
||||||
|
nativeCurrency: info.addNetworkInfo.nativeCurrency,
|
||||||
|
blockExplorerUrls: [info.explorer],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
const { chainId: chainIdAfterSwitch } = await library.getNetwork()
|
||||||
|
if (chainIdAfterSwitch !== chainId) {
|
||||||
|
// metamask (only known implementer) automatically switches after a network is added
|
||||||
|
// the second call is done here because that behavior is not a part of the spec and cannot be relied upon in the future
|
||||||
|
// metamask's behavior when switching to the current network is just to return null (a no-op)
|
||||||
|
await library.provider.request({
|
||||||
|
method: 'wallet_switchEthereumChain',
|
||||||
|
params: [{ chainId: formattedChainId }],
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Currency } from '@uniswap/sdk-core'
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
import { ExtendedEther, WETH9_EXTENDED } from '../constants/tokens'
|
import { nativeOnChain, WRAPPED_NATIVE_CURRENCY } from '../constants/tokens'
|
||||||
import { supportedChainId } from './supportedChainId'
|
import { supportedChainId } from './supportedChainId'
|
||||||
|
|
||||||
export function unwrappedToken(currency: Currency): Currency {
|
export function unwrappedToken(currency: Currency): Currency {
|
||||||
if (currency.isNative) return currency
|
if (currency.isNative) return currency
|
||||||
const formattedChainId = supportedChainId(currency.chainId)
|
const formattedChainId = supportedChainId(currency.chainId)
|
||||||
if (formattedChainId && currency.equals(WETH9_EXTENDED[formattedChainId]))
|
if (formattedChainId && currency.equals(WRAPPED_NATIVE_CURRENCY[formattedChainId]))
|
||||||
return ExtendedEther.onChain(currency.chainId)
|
return nativeOnChain(currency.chainId)
|
||||||
return currency
|
return currency
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user