Compare commits

..

12 Commits

Author SHA1 Message Date
eddie
302af21a22 fix: widget theme integration (#5880)
* fix: add missing colors to widget theme integration

* feat: upgrade widget version

* fix: conedison in jest tests
2023-01-25 17:12:23 -05:00
Rachel-Eichenberger
b61a2d4111 fix: Update footer Github and Discord links (#5841)
Update footer github and discord links

Discord and github links were reversed
2023-01-25 16:15:23 -05:00
Zach Pomerantz
9be26788a2 test: skip flaky universal search test (#5881)
test: skip flaky test
2023-01-24 12:57:08 -05:00
Zach Pomerantz
ed393de481 fix: use wallet modal for widget-prompted connection (#5879)
* fix: use wallet modal for widget-prompted connection

* fix: prevent widget modal

* fix: invoke modal toggle
2023-01-24 12:36:50 -05:00
Zach Pomerantz
cf5c393d97 fix: sanitize legacy signature format (#5878)
Upgrades @uniswap/universal-router-sdk to fix a bug where legacy wallets submitted unhandled legacy signature formats, with suffixes that failed to execute when calling estimateGas.

See ticket CX-140
2023-01-23 09:37:06 -05:00
lynn
68d81a0040 fix: txn header styling for long ens names (#5872)
done fix
2023-01-22 22:00:29 -05:00
Mike Grabowski
53caa51ac3 fix: disconnection error while switching networks with MetaMask (#5871)
* fix: disconnection error while switching networks with MetaMask

* nit: oops

* fix: tests
2023-01-21 02:20:43 +04:00
lynn
409ba72f9f fix: remove gwei indicator (#5873)
* remove polling

* remove dead code

* lint issues
2023-01-20 15:58:30 -05:00
Mike Grabowski
9d9b3dca78 feat: detect Brave Wallet (#5836)
* feat: support brave better

* fix: apply review comments

* address revieW

* chore: fix lint

* chore: add comment
2023-01-21 00:42:43 +04:00
Jack Short
a11c7e9573 feat: select input token for pay with any token (#5865)
* feat: select input token for pay with any token

* creating zustand state

* updating symbol

* cursor pointer
2023-01-20 13:02:43 -05:00
Charles Bachmeier
31bbcae1ed fix: slideout menu title overlap on firefox (#5869)
fix wallet overlap on firefox

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
2023-01-20 12:03:42 -05:00
Zach Pomerantz
a1f6c7270e fix: amend gas estimate error message (#5868)
* fix: amend gas estimate error message

* fix: language

* Update src/utils/swapErrorToUserReadableMessage.tsx

Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>

Co-authored-by: Tina <59578595+tinaszheng@users.noreply.github.com>
2023-01-19 17:48:54 -08:00
32 changed files with 209 additions and 543 deletions

View File

@@ -12,9 +12,10 @@ module.exports = {
jest: {
configure(jestConfig) {
return Object.assign({}, jestConfig, {
transformIgnorePatterns: ['@uniswap/conedison/format'],
transformIgnorePatterns: ['@uniswap/conedison/format', '@uniswap/conedison/provider'],
moduleNameMapper: {
'@uniswap/conedison/format': '@uniswap/conedison/dist/format',
'@uniswap/conedison/provider': '@uniswap/conedison/dist/provider',
},
})
},

View File

@@ -64,7 +64,7 @@ describe('Universal search bar', () => {
.should('be.eq', 3)
})
it('should show blocked badge when blocked token is searched for', () => {
it.skip('should show blocked badge when blocked token is searched for', () => {
// Search for mTSLA, which is a blocked token.
cy.get('[data-cy="search-bar-input"]').last().clear().type('mtsla')
cy.get('[data-cy="searchbar-token-row-mTSLA"]').find('[data-cy="blocked-icon"]').should('exist')

View File

@@ -135,7 +135,7 @@
"@types/react-window-infinite-loader": "^1.0.6",
"@uniswap/analytics": "1.2.0",
"@uniswap/analytics-events": "^2.1.0",
"@uniswap/conedison": "^1.1.1",
"@uniswap/conedison": "^1.2.1",
"@uniswap/governance": "^1.0.2",
"@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "1.0.1",
@@ -145,14 +145,14 @@
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/smart-order-router": "^2.10.0",
"@uniswap/token-lists": "^1.0.0-beta.30",
"@uniswap/universal-router-sdk": "1.3.0",
"@uniswap/universal-router-sdk": "1.3.4",
"@uniswap/v2-core": "1.0.0",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v2-sdk": "^3.0.1",
"@uniswap/v3-core": "1.0.0",
"@uniswap/v3-periphery": "^1.1.1",
"@uniswap/v3-sdk": "^3.9.0",
"@uniswap/widgets": "2.25.1",
"@uniswap/widgets": "^2.26.0",
"@vanilla-extract/css": "^1.7.2",
"@vanilla-extract/css-utils": "^0.1.2",
"@vanilla-extract/dynamic": "^2.0.2",
@@ -170,7 +170,7 @@
"@web3-react/eip1193": "8.0.26-beta.0",
"@web3-react/empty": "8.0.20-beta.0",
"@web3-react/gnosis-safe": "8.0.7-beta.0",
"@web3-react/metamask": "8.0.28-beta.0",
"@web3-react/metamask": "8.0.29-beta.0",
"@web3-react/network": "8.0.27-beta.0",
"@web3-react/types": "8.0.20-beta.0",
"@web3-react/url": "8.0.25-beta.0",

View File

@@ -120,7 +120,7 @@ const LogoSectionContent = () => {
<>
<StyledLogo src={isDarkMode ? darkUnicornImgSrc : lightUnicornImgSrc} alt="Uniswap Logo" />
<SocialLinks>
<SocialLink href="https://github.com/Uniswap" target="_blank" rel="noopener noreferrer">
<SocialLink href="https://discord.gg/FCfyBSbCU5" target="_blank" rel="noopener noreferrer">
<DiscordIcon size={32} />
</SocialLink>
<TraceEvent
@@ -132,7 +132,7 @@ const LogoSectionContent = () => {
<TwitterIcon size={32} />
</SocialLink>
</TraceEvent>
<SocialLink href="https://discord.gg/FCfyBSbCU5" target="_blank" rel="noopener noreferrer">
<SocialLink href="https://github.com/Uniswap" target="_blank" rel="noopener noreferrer">
<GithubIcon size={32} />
</SocialLink>
</SocialLinks>

View File

@@ -1,11 +1,6 @@
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import {
getConnection,
getConnectionName,
getHasCoinbaseExtensionInstalled,
getHasMetaMaskExtensionInstalled,
} from 'connection/utils'
import { getConnection, getConnectionName, getIsCoinbaseWallet, getIsMetaMaskWallet } from 'connection/utils'
import { useCallback } from 'react'
import { ExternalLink as LinkIcon } from 'react-feather'
import { useAppDispatch } from 'state/hooks'
@@ -215,8 +210,8 @@ export default function AccountDetails({
const theme = useTheme()
const dispatch = useAppDispatch()
const hasMetaMaskExtension = getHasMetaMaskExtensionInstalled()
const hasCoinbaseExtension = getHasCoinbaseExtensionInstalled()
const hasMetaMaskExtension = getIsMetaMaskWallet()
const hasCoinbaseExtension = getIsCoinbaseWallet()
const isInjectedMobileBrowser = (hasMetaMaskExtension || hasCoinbaseExtension) && isMobile
function formatConnectorName() {

View File

@@ -1,98 +0,0 @@
import { Trans } from '@lingui/macro'
import { ButtonPrimary } from 'components/Button'
import { AutoColumn } from 'components/Column'
import Modal from 'components/Modal'
import { RowBetween } from 'components/Row'
import { AlertTriangle } from 'react-feather'
import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { CloseIcon, ThemedText } from 'theme'
import { useModalIsOpen, useToggleMetaMaskConnectionErrorModal } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
const Wrapper = styled.div`
width: 100%;
position: relative;
display: flex;
flex-flow: column;
align-items: center;
`
const Container = styled.div`
width: 100%;
padding: 32px 32px;
display: flex;
flex-flow: column;
align-items: center;
`
const LogoContainer = styled.div`
display: flex;
gap: 16px;
`
const ShortColumn = styled(AutoColumn)`
margin-top: 10px;
`
const InfoText = styled(Text)`
padding: 0 12px 0 12px;
font-size: 14px;
line-height: 20px;
text-align: center;
`
const StyledButton = styled(ButtonPrimary)`
margin-top: 24px;
width: 100%;
font-weight: 600;
`
const WarningIcon = styled(AlertTriangle)`
width: 76px;
height: 76px;
margin-top: 4px;
margin-bottom: 28px;
stroke-width: 1px;
margin-right: 4px;
color: ${({ theme }) => theme.accentCritical};
`
const onReconnect = () => window.location.reload()
export default function MetaMaskConnectionErrorModal() {
const modalOpen = useModalIsOpen(ApplicationModal.METAMASK_CONNECTION_ERROR)
const toggleModal = useToggleMetaMaskConnectionErrorModal()
return (
<Modal isOpen={modalOpen} onDismiss={toggleModal} minHeight={false} maxHeight={90}>
<Wrapper>
<RowBetween style={{ padding: '1rem' }}>
<div />
<CloseIcon onClick={toggleModal} />
</RowBetween>
<Container>
<AutoColumn>
<LogoContainer>
<WarningIcon />
</LogoContainer>
</AutoColumn>
<ShortColumn>
<InfoText>
<ThemedText.HeadlineSmall marginBottom="8px">
<Trans>Wallet disconnected</Trans>
</ThemedText.HeadlineSmall>
<ThemedText.BodySmall>
<Trans>A MetaMask error caused your wallet to disconnect. Reload the page to reconnect.</Trans>
</ThemedText.BodySmall>
</InfoText>
</ShortColumn>
<StyledButton onClick={onReconnect}>
<Trans>Reload</Trans>
</StyledButton>
</Container>
</Wrapper>
</Modal>
)
}

View File

@@ -1,81 +0,0 @@
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { getChainInfoOrDefault, L2ChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { AlertTriangle } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink, MEDIA_WIDTHS } from 'theme'
const BodyRow = styled.div`
color: ${({ theme }) => theme.textPrimary};
font-size: 12px;
font-weight: 400;
font-size: 14px;
line-height: 20px;
`
const CautionTriangle = styled(AlertTriangle)`
color: ${({ theme }) => theme.accentWarning};
`
const Link = styled(ExternalLink)`
color: ${({ theme }) => theme.black};
text-decoration: underline;
`
const TitleRow = styled.div`
align-items: center;
display: flex;
justify-content: flex-start;
margin-bottom: 8px;
`
const TitleText = styled.div`
color: ${({ theme }) => theme.textPrimary};
font-weight: 500;
font-size: 16px;
line-height: 24px;
margin: 0px 12px;
`
const Wrapper = styled.div`
background-color: ${({ theme }) => theme.backgroundSurface};
border-radius: 12px;
border: 1px solid ${({ theme }) => theme.backgroundOutline};
bottom: 60px;
display: none;
max-width: 348px;
padding: 16px 20px;
position: fixed;
right: 16px;
@media screen and (min-width: ${MEDIA_WIDTHS.deprecated_upToMedium}px) {
display: block;
}
`
export function ChainConnectivityWarning() {
const { chainId } = useWeb3React()
const info = getChainInfoOrDefault(chainId)
const label = info?.label
return (
<Wrapper>
<TitleRow>
<CautionTriangle />
<TitleText>
<Trans>Network Warning</Trans>
</TitleText>
</TitleRow>
<BodyRow>
{chainId === SupportedChainId.MAINNET ? (
<Trans>You may have lost your network connection.</Trans>
) : (
<Trans>{label} might be down right now, or you may have lost your network connection.</Trans>
)}{' '}
{(info as L2ChainInfo).statusPage !== undefined && (
<span>
<Trans>Check network status</Trans>{' '}
<Link href={(info as L2ChainInfo).statusPage || ''}>
<Trans>here.</Trans>
</Link>
</span>
)}
</BodyRow>
</Wrapper>
)
}

View File

@@ -1,199 +0,0 @@
import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core'
import { RowFixed } from 'components/Row'
import { getChainInfo } from 'constants/chainInfo'
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
import useGasPrice from 'hooks/useGasPrice'
import { useIsLandingPage } from 'hooks/useIsLandingPage'
import { useIsNftPage } from 'hooks/useIsNftPage'
import useMachineTimeMs from 'hooks/useMachineTime'
import JSBI from 'jsbi'
import useBlockNumber from 'lib/hooks/useBlockNumber'
import ms from 'ms.macro'
import { useEffect, useMemo, useState } from 'react'
import styled, { keyframes } from 'styled-components/macro'
import { ExternalLink, ThemedText } from 'theme'
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
import { MouseoverTooltip } from '../Tooltip'
import { ChainConnectivityWarning } from './ChainConnectivityWarning'
const StyledPolling = styled.div`
align-items: center;
bottom: 0;
color: ${({ theme }) => theme.textTertiary};
display: none;
padding: 1rem;
position: fixed;
right: 0;
transition: 250ms ease color;
a {
color: unset;
}
a:hover {
color: unset;
text-decoration: none;
}
@media screen and (min-width: ${({ theme }) => theme.breakpoint.md}px) {
display: flex;
}
`
const StyledPollingBlockNumber = styled(ThemedText.DeprecatedSmall)<{
breathe: boolean
hovering: boolean
warning: boolean
}>`
color: ${({ theme, warning }) => (warning ? theme.deprecated_yellow3 : theme.accentSuccess)};
transition: opacity 0.25s ease;
opacity: ${({ breathe, hovering }) => (hovering ? 0.7 : breathe ? 1 : 0.5)};
:hover {
opacity: 1;
}
a {
color: unset;
}
a:hover {
text-decoration: none;
color: unset;
}
`
const StyledPollingDot = styled.div<{ warning: boolean }>`
width: 8px;
height: 8px;
min-height: 8px;
min-width: 8px;
border-radius: 50%;
position: relative;
background-color: ${({ theme, warning }) => (warning ? theme.deprecated_yellow3 : theme.accentSuccess)};
transition: 250ms ease background-color;
`
const StyledGasDot = styled.div`
background-color: ${({ theme }) => theme.textTertiary};
border-radius: 50%;
height: 4px;
min-height: 4px;
min-width: 4px;
position: relative;
transition: 250ms ease background-color;
width: 4px;
`
const rotate360 = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`
const Spinner = styled.div<{ warning: boolean }>`
animation: ${rotate360} 1s cubic-bezier(0.83, 0, 0.17, 1) infinite;
transform: translateZ(0);
border-top: 1px solid transparent;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
border-left: 2px solid ${({ theme, warning }) => (warning ? theme.deprecated_yellow3 : theme.accentSuccess)};
background: transparent;
width: 14px;
height: 14px;
border-radius: 50%;
position: relative;
transition: 250ms ease border-color;
left: -3px;
top: -3px;
`
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
const NETWORK_HEALTH_CHECK_MS = ms`10s`
export default function Polling() {
const { chainId } = useWeb3React()
const blockNumber = useBlockNumber()
const [isMounting, setIsMounting] = useState(false)
const [isHover, setIsHover] = useState(false)
const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
const blockTime = useCurrentBlockTimestamp()
const isNftPage = useIsNftPage()
const isLandingPage = useIsLandingPage()
const ethGasPrice = useGasPrice()
const priceGwei = ethGasPrice ? JSBI.divide(ethGasPrice, JSBI.BigInt(1000000000)) : undefined
const waitMsBeforeWarning =
(chainId ? getChainInfo(chainId)?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
useEffect(
() => {
if (!blockNumber) {
return
}
setIsMounting(true)
const mountingTimer = setTimeout(() => setIsMounting(false), 1000)
// this will clear Timeout when component unmount like in willComponentUnmount
return () => {
clearTimeout(mountingTimer)
}
},
[blockNumber] //useEffect will run only one time
//if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
)
//TODO - chainlink gas oracle is really slow. Can we get a better data source?
const blockExternalLinkHref = useMemo(() => {
if (!chainId || !blockNumber) return ''
return getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK)
}, [blockNumber, chainId])
if (isNftPage || isLandingPage) {
return null
}
return (
<RowFixed>
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
<ExternalLink href="https://etherscan.io/gastracker">
{!!priceGwei && (
<RowFixed style={{ marginRight: '8px' }}>
<ThemedText.DeprecatedMain fontSize="11px" mr="8px">
<MouseoverTooltip
text={
<Trans>
The current fast gas amount for sending a transaction on L1. Gas fees are paid in Ethereum&apos;s
native currency Ether (ETH) and denominated in GWEI.
</Trans>
}
>
{priceGwei.toString()} <Trans>gwei</Trans>
</MouseoverTooltip>
</ThemedText.DeprecatedMain>
<StyledGasDot />
</RowFixed>
)}
</ExternalLink>
<StyledPollingBlockNumber breathe={isMounting} hovering={isHover} warning={warning}>
<ExternalLink href={blockExternalLinkHref}>
<MouseoverTooltip
text={<Trans>The most recent block number on this network. Prices update on every block.</Trans>}
>
{blockNumber}&ensp;
</MouseoverTooltip>
</ExternalLink>
</StyledPollingBlockNumber>
<StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
</StyledPolling>
{warning && <ChainConnectivityWarning />}
</RowFixed>
)
}

View File

@@ -12,7 +12,6 @@ import { ApplicationModal } from 'state/application/reducer'
const Bag = lazy(() => import('nft/components/bag/Bag'))
const TransactionCompleteModal = lazy(() => import('nft/components/collection/TransactionCompleteModal'))
const AirdropModal = lazy(() => import('components/AirdropModal'))
const MetaMaskConnectionErrorModal = lazy(() => import('components/MetaMaskConnectionErrorModal'))
export default function TopLevelModals() {
const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM)
@@ -30,7 +29,6 @@ export default function TopLevelModals() {
<Bag />
<TransactionCompleteModal />
<AirdropModal />
<MetaMaskConnectionErrorModal />
{fiatOnrampFlagEnabled && <FiatOnrampModal />}
</>
)

View File

@@ -126,15 +126,6 @@ const FiatOnrampAvailabilityExternalLink = styled(ExternalLink)`
margin-left: 6px;
width: 14px;
`
const FlexContainer = styled.div`
display: flex;
`
const StatusWrapper = styled.div`
display: inline-block;
margin-top: 4px;
width: 70%;
`
const TruncatedTextStyle = css`
text-overflow: ellipsis;
@@ -142,8 +133,14 @@ const TruncatedTextStyle = css`
white-space: nowrap;
`
const AccountNamesWrapper = styled.div`
const FlexContainer = styled.div`
${TruncatedTextStyle}
padding-right: 4px;
display: inline-flex;
`
const AccountNamesWrapper = styled.div`
min-width: 0;
margin-right: 8px;
`
@@ -280,19 +277,17 @@ const AuthenticatedHeader = () => {
return (
<>
<HeaderWrapper>
<StatusWrapper>
<FlexContainer>
<StatusIcon connectionType={connectionType} size={24} />
{ENSName ? (
<AccountNamesWrapper>
<ENSNameContainer>{ENSName}</ENSNameContainer>
<AccountContainer>{account && shortenAddress(account, 2, 4)}</AccountContainer>
</AccountNamesWrapper>
) : (
<ThemedText.SubHeader marginTop="2.5px">{account && shortenAddress(account, 2, 4)}</ThemedText.SubHeader>
)}
</FlexContainer>
</StatusWrapper>
<FlexContainer>
<StatusIcon connectionType={connectionType} size={24} />
{ENSName ? (
<AccountNamesWrapper>
<ENSNameContainer>{ENSName}</ENSNameContainer>
<AccountContainer>{account && shortenAddress(account, 2, 4)}</AccountContainer>
</AccountNamesWrapper>
) : (
<ThemedText.SubHeader marginTop="2.5px">{account && shortenAddress(account, 2, 4)}</ThemedText.SubHeader>
)}
</FlexContainer>
<IconContainer>
<IconButton onClick={copy} Icon={Copy}>
{isCopied ? <Trans>Copied!</Trans> : <Trans>Copy</Trans>}

View File

@@ -57,7 +57,7 @@ const StyledChevron = styled(ChevronLeft)`
const BackSection = styled.div`
position: absolute;
background-color: ${({ theme }) => theme.backgroundSurface};
width: -webkit-fill-available;
width: fill-available;
margin: 0px 2vw 0px 0px;
padding: 0px 0px 2vh 0px;
color: ${({ theme }) => theme.textSecondary};

View File

@@ -22,9 +22,6 @@ jest.mock('.../../state/application/hooks', () => {
useToggleWalletModal: () => {
return
},
useToggleMetaMaskConnectionErrorModal: () => {
return
},
}
})
@@ -73,8 +70,8 @@ it('loads Wallet Modal on desktop', async () => {
it('loads Wallet Modal on desktop with generic Injected', async () => {
jest.spyOn(connectionUtils, 'getIsInjected').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasMetaMaskExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getHasCoinbaseExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsMetaMaskWallet').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsCoinbaseWallet').mockReturnValue(false)
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Browser Wallet')).toBeInTheDocument()
@@ -85,8 +82,8 @@ it('loads Wallet Modal on desktop with generic Injected', async () => {
it('loads Wallet Modal on desktop with MetaMask installed', async () => {
jest.spyOn(connectionUtils, 'getIsInjected').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasMetaMaskExtensionInstalled').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasCoinbaseExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsMetaMaskWallet').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getIsCoinbaseWallet').mockReturnValue(false)
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('MetaMask')).toBeInTheDocument()
@@ -99,8 +96,8 @@ it('loads Wallet Modal on mobile', async () => {
UserAgentMock.isMobile = true
jest.spyOn(connectionUtils, 'getIsInjected').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getHasMetaMaskExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getHasCoinbaseExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsMetaMaskWallet').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsCoinbaseWallet').mockReturnValue(false)
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Open in Coinbase Wallet')).toBeInTheDocument()
@@ -112,8 +109,8 @@ it('loads Wallet Modal on MetaMask browser', async () => {
UserAgentMock.isMobile = true
jest.spyOn(connectionUtils, 'getIsInjected').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasMetaMaskExtensionInstalled').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasCoinbaseExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsMetaMaskWallet').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getIsCoinbaseWallet').mockReturnValue(false)
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('MetaMask')).toBeInTheDocument()
@@ -124,8 +121,8 @@ it('loads Wallet Modal on Coinbase Wallet browser', async () => {
UserAgentMock.isMobile = true
jest.spyOn(connectionUtils, 'getIsInjected').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getHasMetaMaskExtensionInstalled').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getHasCoinbaseExtensionInstalled').mockReturnValue(true)
jest.spyOn(connectionUtils, 'getIsMetaMaskWallet').mockReturnValue(false)
jest.spyOn(connectionUtils, 'getIsCoinbaseWallet').mockReturnValue(true)
render(<WalletModal pendingTransactions={[]} confirmedTransactions={[]} />)
expect(screen.getByText('Coinbase Wallet')).toBeInTheDocument()

View File

@@ -10,9 +10,9 @@ import { networkConnection } from 'connection'
import {
getConnection,
getConnectionName,
getHasCoinbaseExtensionInstalled,
getHasMetaMaskExtensionInstalled,
getIsCoinbaseWallet,
getIsInjected,
getIsMetaMaskWallet,
} from 'connection/utils'
import usePrevious from 'hooks/usePrevious'
import { useCallback, useEffect, useState } from 'react'
@@ -253,8 +253,8 @@ export default function WalletModal({
function getOptions() {
const isInjected = getIsInjected()
const hasMetaMaskExtension = getHasMetaMaskExtensionInstalled()
const hasCoinbaseExtension = getHasCoinbaseExtensionInstalled()
const hasMetaMaskExtension = getIsMetaMaskWallet()
const hasCoinbaseExtension = getIsCoinbaseWallet()
const isCoinbaseWalletBrowser = isMobile && hasCoinbaseExtension
const isMetaMaskBrowser = isMobile && hasMetaMaskExtension

View File

@@ -1,7 +1,6 @@
import { useWeb3React, Web3ReactHooks, Web3ReactProvider } from '@web3-react/core'
import { Connector } from '@web3-react/types'
import { Connection } from 'connection'
import { setMetMaskErrorHandler } from 'connection'
import { getConnectionName } from 'connection/utils'
import { isSupportedChain } from 'constants/chains'
import { RPC_PROVIDERS } from 'constants/providers'
@@ -9,19 +8,8 @@ import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/tra
import useEagerlyConnect from 'hooks/useEagerlyConnect'
import useOrderedConnections from 'hooks/useOrderedConnections'
import { ReactNode, useEffect, useMemo } from 'react'
import { useToggleMetaMaskConnectionErrorModal } from 'state/application/hooks'
export default function Web3Provider({ children }: { children: ReactNode }) {
// https://github.com/MetaMask/metamask-extension/issues/13375
const toggleMetaMaskConnectionErrorModal = useToggleMetaMaskConnectionErrorModal()
useEffect(() => {
setMetMaskErrorHandler((error) => {
if (error.code === 1013) {
toggleMetaMaskConnectionErrorModal()
}
})
}, [toggleMetaMaskConnectionErrorModal])
useEagerlyConnect()
const connections = useOrderedConnections()
const connectors: [Connector, Web3ReactHooks][] = connections.map(({ hooks, connector }) => [connector, hooks])

View File

@@ -26,6 +26,7 @@ import {
getTokenAddress,
} from 'lib/utils/analytics'
import { useCallback, useState } from 'react'
import { useToggleWalletModal } from 'state/application/hooks'
import { useIsDarkMode } from 'state/user/hooks'
import { computeRealizedPriceImpact } from 'utils/prices'
import { switchChain } from 'utils/switchChain'
@@ -57,6 +58,12 @@ export default function Widget({ token, onTokenChange, onReviewSwapClick }: Widg
const { settings } = useSyncWidgetSettings()
const { transactions } = useSyncWidgetTransactions()
const toggleWalletModal = useToggleWalletModal()
const onConnectWalletClick = useCallback(() => {
toggleWalletModal()
return false // prevents the in-widget wallet modal from opening
}, [toggleWalletModal])
const onSwitchChain = useCallback(
// TODO(WEB-1757): Widget should not break if this rejects - upstream the catch to ignore it.
({ chainId }: AddEthereumChainParameter) => switchChain(connector, Number(chainId)).catch(() => undefined),
@@ -154,6 +161,7 @@ export default function Widget({ token, onTokenChange, onReviewSwapClick }: Widg
theme={theme}
width={WIDGET_WIDTH}
// defaultChainId is excluded - it is always inferred from the passed provider
onConnectWalletClick={onConnectWalletClick}
provider={provider}
onSwitchChain={onSwitchChain}
tokenList={EMPTY_TOKEN_LIST} // prevents loading the default token list, as we use our own token selector UI

View File

@@ -1,5 +1,5 @@
import { Percent } from '@uniswap/sdk-core'
import { Slippage, SwapController, SwapEventHandlers } from '@uniswap/widgets'
import { RouterPreference, Slippage, SwapController, SwapEventHandlers } from '@uniswap/widgets'
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
import { useCallback, useMemo, useState } from 'react'
import { useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'
@@ -37,6 +37,8 @@ export function useSyncWidgetSettings() {
[setAppSlippage]
)
const [routerPreference, onRouterPreferenceChange] = useState(RouterPreference.API)
const onSettingsReset = useCallback(() => {
setWidgetTtl(undefined)
setAppTtl(DEFAULT_DEADLINE_FROM_NOW)
@@ -46,11 +48,15 @@ export function useSyncWidgetSettings() {
const settings: SwapController['settings'] = useMemo(() => {
const auto = appSlippage === 'auto'
return { slippage: { auto, max: widgetSlippage }, transactionTtl: widgetTtl }
}, [widgetSlippage, widgetTtl, appSlippage])
return {
slippage: { auto, max: widgetSlippage },
transactionTtl: widgetTtl,
routerPreference,
}
}, [appSlippage, widgetSlippage, widgetTtl, routerPreference])
const settingsHandlers: SwapEventHandlers = useMemo(
() => ({ onSettingsReset, onSlippageChange, onTransactionDeadlineChange }),
[onSettingsReset, onSlippageChange, onTransactionDeadlineChange]
() => ({ onSettingsReset, onSlippageChange, onTransactionDeadlineChange, onRouterPreferenceChange }),
[onSettingsReset, onSlippageChange, onTransactionDeadlineChange, onRouterPreferenceChange]
)
return { settings: { settings, ...settingsHandlers } }

View File

@@ -1,21 +1,30 @@
import { Theme } from '@uniswap/widgets'
import { darkTheme, lightTheme } from 'theme/colors'
const fonts = {
fontFamily: 'Inter custom',
}
export const LIGHT_THEME = {
export const LIGHT_THEME: Theme = {
// surface
container: lightTheme.backgroundSurface,
interactive: lightTheme.backgroundInteractive,
module: lightTheme.backgroundModule,
accent: lightTheme.accentAction,
dialog: lightTheme.backgroundBackdrop,
accentSoft: lightTheme.accentActionSoft,
container: lightTheme.backgroundSurface,
module: lightTheme.backgroundModule,
interactive: lightTheme.backgroundInteractive,
outline: lightTheme.backgroundOutline,
dialog: lightTheme.backgroundBackdrop,
scrim: lightTheme.backgroundScrim,
// text
onAccent: lightTheme.white,
primary: lightTheme.textPrimary,
secondary: lightTheme.textSecondary,
hint: lightTheme.textTertiary,
onInteractive: lightTheme.accentTextDarkPrimary,
// shadow
deepShadow: lightTheme.deepShadow,
networkDefaultShadow: lightTheme.networkDefaultShadow,
// state
success: lightTheme.accentSuccess,
warning: lightTheme.accentWarning,
@@ -24,18 +33,25 @@ export const LIGHT_THEME = {
...fonts,
}
export const DARK_THEME = {
export const DARK_THEME: Theme = {
// surface
container: darkTheme.backgroundSurface,
interactive: darkTheme.backgroundInteractive,
module: darkTheme.backgroundModule,
accent: darkTheme.accentAction,
dialog: darkTheme.backgroundBackdrop,
accentSoft: darkTheme.accentActionSoft,
container: darkTheme.backgroundSurface,
module: darkTheme.backgroundModule,
interactive: darkTheme.backgroundInteractive,
outline: darkTheme.backgroundOutline,
dialog: darkTheme.backgroundBackdrop,
scrim: darkTheme.backgroundScrim,
// text
onAccent: darkTheme.white,
primary: darkTheme.textPrimary,
secondary: darkTheme.textSecondary,
hint: darkTheme.textTertiary,
onInteractive: darkTheme.accentTextLightPrimary,
// shadow
deepShadow: darkTheme.deepShadow,
networkDefaultShadow: darkTheme.networkDefaultShadow,
// state
success: darkTheme.accentSuccess,
warning: darkTheme.accentWarning,

View File

@@ -25,22 +25,10 @@ export interface Connection {
type: ConnectionType
}
type MetaMaskError = Error & { code: number }
let metaMaskErrorHandler: (error: MetaMaskError) => void | undefined
export function setMetMaskErrorHandler(errorHandler: typeof metaMaskErrorHandler) {
metaMaskErrorHandler = errorHandler
}
function onError(error: Error) {
console.debug(`web3-react error: ${error}`)
}
function onMetaMaskError(error: Error) {
onError(error)
metaMaskErrorHandler?.(error as MetaMaskError)
}
const [web3Network, web3NetworkHooks] = initializeConnector<Network>(
(actions) => new Network({ actions, urlMap: RPC_PROVIDERS, defaultChainId: 1 })
)
@@ -50,9 +38,7 @@ export const networkConnection: Connection = {
type: ConnectionType.NETWORK,
}
const [web3Injected, web3InjectedHooks] = initializeConnector<MetaMask>(
(actions) => new MetaMask({ actions, onError: onMetaMaskError })
)
const [web3Injected, web3InjectedHooks] = initializeConnector<MetaMask>((actions) => new MetaMask({ actions, onError }))
export const injectedConnection: Connection = {
connector: web3Injected,
hooks: web3InjectedHooks,

View File

@@ -12,18 +12,21 @@ export function getIsInjected(): boolean {
return Boolean(window.ethereum)
}
export function getHasMetaMaskExtensionInstalled(): boolean {
return window.ethereum?.isMetaMask ?? false
export function getIsBraveWallet(): boolean {
return window.ethereum?.isBraveWallet ?? false
}
export function getHasCoinbaseExtensionInstalled(): boolean {
export function getIsMetaMaskWallet(): boolean {
// When using Brave browser, `isMetaMask` is set to true when using the built-in wallet
// This function should return true only when using the MetaMask extension
// https://wallet-docs.brave.com/ethereum/wallet-detection#compatability-with-metamask
return (window.ethereum?.isMetaMask ?? false) && !getIsBraveWallet()
}
export function getIsCoinbaseWallet(): boolean {
return window.ethereum?.isCoinbaseWallet ?? false
}
export function getIsMetaMask(connectionType: ConnectionType): boolean {
return connectionType === ConnectionType.INJECTED && getHasMetaMaskExtensionInstalled()
}
const CONNECTIONS = [
gnosisSafeConnection,
injectedConnection,
@@ -56,7 +59,7 @@ export function getConnection(c: Connector | ConnectionType) {
export function getConnectionName(
connectionType: ConnectionType,
hasMetaMaskExtension: boolean = getHasMetaMaskExtensionInstalled()
hasMetaMaskExtension: boolean = getIsMetaMaskWallet()
) {
switch (connectionType) {
case ConnectionType.INJECTED:

View File

@@ -42,7 +42,7 @@ interface L1ChainInfo extends BaseChainInfo {
readonly defaultListUrl?: string
}
export interface L2ChainInfo extends BaseChainInfo {
interface L2ChainInfo extends BaseChainInfo {
readonly networkType: NetworkType.L2
readonly bridge: string
readonly statusPage?: string

View File

@@ -1,6 +0,0 @@
import { useLocation } from 'react-router-dom'
export function useIsLandingPage() {
const { pathname } = useLocation()
return pathname.endsWith('/')
}

View File

@@ -1,16 +0,0 @@
import useInterval from 'lib/hooks/useInterval'
import { useCallback, useState } from 'react'
const useMachineTimeMs = (updateInterval: number): number => {
const [now, setNow] = useState(Date.now())
useInterval(
useCallback(() => {
setNow(Date.now())
}, []),
updateInterval
)
return now
}
export default useMachineTimeMs

View File

@@ -57,7 +57,7 @@ export function useUniversalRouterSwapCallback(
gasEstimate = await provider.estimateGas(tx)
} catch (gasError) {
console.warn(gasError)
throw new InvalidSwapError('Gas estimation failed. Wait a few minutes and try again.')
throw new Error('Your swap is expected to fail')
}
const gasLimit = calculateGasMargin(gasEstimate)
const response = await provider

View File

@@ -3,6 +3,7 @@ import { parseEther } from '@ethersproject/units'
import { Trans } from '@lingui/macro'
import { TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events'
import { Currency } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import Column from 'components/Column'
import Loader from 'components/Loader'
@@ -12,6 +13,7 @@ import { SupportedChainId } from 'constants/chains'
import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken'
import { useCurrency } from 'hooks/Tokens'
import { useBag } from 'nft/hooks/useBag'
import { useTokenInput } from 'nft/hooks/useTokenInput'
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
import { BagStatus } from 'nft/types'
import { ethNumberStandardFormatter, formatWeiToDecimal } from 'nft/utils'
@@ -141,7 +143,9 @@ export const BagFooter = ({
const { account, chainId, connector } = useWeb3React()
const connected = Boolean(account && chainId)
const shouldUsePayWithAnyToken = usePayWithAnyTokenFlag() === PayWithAnyTokenVariant.Enabled
const inputCurrency = useCurrency('ETH')
const inputCurrency = useTokenInput((state) => state.inputCurrency)
const setInputCurrency = useTokenInput((state) => state.setInputCurrency)
const defaultCurrency = useCurrency('ETH')
const setBagExpanded = useBag((state) => state.setBagExpanded)
const [showTokenSelector, toggleTokenSelector] = useReducer((state) => !state, false)
@@ -193,6 +197,7 @@ export const BagFooter = ({
}, [bagStatus, chainId, connected, connector, fetchAssets, setBagExpanded, sufficientBalance, toggleWalletModal])
const isPending = PENDING_BAG_STATUSES.includes(bagStatus)
const activeCurrency = inputCurrency ?? defaultCurrency
return (
<FooterContainer>
@@ -204,9 +209,9 @@ export const BagFooter = ({
<Trans>Pay with</Trans>
</ThemedText.SubHeaderSmall>
<CurrencyInput onClick={toggleTokenSelector}>
<CurrencyLogo currency={inputCurrency} size="24px" />
<CurrencyLogo currency={activeCurrency} size="24px" />
<ThemedText.HeadlineSmall fontWeight={500} lineHeight="24px">
{inputCurrency?.symbol}
{activeCurrency?.symbol}
</ThemedText.HeadlineSmall>
<ChevronDown size={20} color={theme.textSecondary} />
</CurrencyInput>
@@ -216,7 +221,7 @@ export const BagFooter = ({
<Trans>Total</Trans>
</ThemedText.SubHeaderSmall>
<ThemedText.HeadlineSmall>
{formatWeiToDecimal(totalEthPrice.toString())}&nbsp;ETH
{formatWeiToDecimal(totalEthPrice.toString())}&nbsp;{activeCurrency?.symbol ?? 'ETH'}
</ThemedText.HeadlineSmall>
<ThemedText.BodySmall color="textSecondary" lineHeight="20px">{`${ethNumberStandardFormatter(
totalUsdPrice,
@@ -259,7 +264,16 @@ export const BagFooter = ({
</ActionButton>
</TraceEvent>
</Footer>
{showTokenSelector && <BagTokenSelectorModal overlayClick={toggleTokenSelector} />}
{showTokenSelector && (
<BagTokenSelectorModal
selectedCurrency={activeCurrency ?? undefined}
handleCurrencySelect={(currency: Currency) => {
setInputCurrency(currency)
toggleTokenSelector()
}}
overlayClick={toggleTokenSelector}
/>
)}
</FooterContainer>
)
}

View File

@@ -47,7 +47,17 @@ const TokenSelectorContainer = styled(Column)`
}
`
export const BagTokenSelectorModal = ({ overlayClick }: { overlayClick: () => void }) => {
interface BagTokenSelectorModalProps {
selectedCurrency: Currency | undefined
handleCurrencySelect: (currency: Currency) => void
overlayClick: () => void
}
export const BagTokenSelectorModal = ({
selectedCurrency,
handleCurrencySelect,
overlayClick,
}: BagTokenSelectorModalProps) => {
const defaultTokens = useAllTokens()
const [balances, balancesAreLoading] = useAllTokenBalances()
const sortedTokens: Token[] = useMemo(
@@ -90,7 +100,16 @@ export const BagTokenSelectorModal = ({ overlayClick }: { overlayClick: () => vo
</TitleRow>
<TokenSelectorContainer>
{currencies.map((currency) => {
return <CurrencyRow key={currency.isToken ? currency.wrapped.address : currency.name} currency={currency} />
return (
<CurrencyRow
key={currency.isToken ? currency.wrapped.address : currency.name}
currency={currency}
selected={
(!selectedCurrency && currency.isNative) || (!!selectedCurrency && selectedCurrency.equals(currency))
}
selectCurrency={handleCurrencySelect}
/>
)
})}
</TokenSelectorContainer>
</ModalWrapper>

View File

@@ -4,12 +4,15 @@ import Column from 'components/Column'
import CurrencyLogo from 'components/Logo/CurrencyLogo'
import Row from 'components/Row'
import useCurrencyBalance from 'lib/hooks/useCurrencyBalance'
import { Check } from 'react-feather'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
const TokenRow = styled(Row)`
padding: 8px 0px;
gap: 12px;
justify-content: space-between;
cursor: pointer;
`
const TokenInfoRow = styled(Row)`
@@ -24,12 +27,23 @@ const StyledBalanceText = styled(ThemedText.SubHeader)`
text-align: right;
`
export const CurrencyRow = ({ currency }: { currency: Currency }) => {
const StyledCheck = styled(Check)`
color: ${({ theme }) => theme.accentAction};
flex-shrink: 0;
`
interface CurrencyRowProps {
currency: Currency
selected: boolean
selectCurrency: (currency: Currency) => void
}
export const CurrencyRow = ({ currency, selected, selectCurrency }: CurrencyRowProps) => {
const { account } = useWeb3React()
const balance = useCurrencyBalance(account ?? undefined, currency)
return (
<TokenRow>
<TokenRow onClick={() => selectCurrency(currency)}>
<TokenInfoRow>
<CurrencyLogo currency={currency} size="36px" />
<Column>
@@ -42,6 +56,7 @@ export const CurrencyRow = ({ currency }: { currency: Currency }) => {
</Column>
</TokenInfoRow>
{balance && <Balance balance={balance} />}
{selected && <StyledCheck size={20} />}
</TokenRow>
)
}

View File

@@ -0,0 +1,20 @@
import { Currency } from '@uniswap/sdk-core'
import create from 'zustand'
import { devtools } from 'zustand/middleware'
interface TokenInputState {
inputCurrency: Currency | undefined
setInputCurrency: (currency: Currency | undefined) => void
clearInputCurrency: () => void
}
export const useTokenInput = create<TokenInputState>()(
devtools(
(set) => ({
inputCurrency: undefined,
setInputCurrency: (currency) => set(() => ({ inputCurrency: currency })),
clearInputCurrency: () => set(() => ({ inputCurrency: undefined })),
}),
{ name: 'useTokenInput' }
)
)

View File

@@ -20,7 +20,6 @@ import { useAnalyticsReporter } from '../components/analytics'
import ErrorBoundary from '../components/ErrorBoundary'
import { PageTabs } from '../components/NavBar'
import NavBar from '../components/NavBar'
import Polling from '../components/Polling'
import Popups from '../components/Popups'
import { useIsExpertMode } from '../state/user/hooks'
import DarkModeQueryParamReader from '../theme/components/DarkModeQueryParamReader'
@@ -194,7 +193,6 @@ export default function App() {
</HeaderWrapper>
<BodyWrapper>
<Popups />
<Polling />
<TopLevelModals />
<Suspense fallback={<Loader />}>
{isLoaded ? (

View File

@@ -8,8 +8,11 @@ interface Window {
// walletLinkExtension is injected by the Coinbase Wallet extension
walletLinkExtension?: any
ethereum?: {
// value that is populated and returns true by the Coinbase Wallet mobile dapp browser
// set by the Coinbase Wallet mobile dapp browser
isCoinbaseWallet?: true
// set by the Brave browser when using built-in wallet
isBraveWallet?: true
// set by the MetaMask browser extension (also set by Brave browser when using built-in wallet)
isMetaMask?: true
autoRefreshOnNetworkChange?: boolean
}

View File

@@ -93,10 +93,6 @@ export function useCloseModal(): () => void {
return useCallback(() => dispatch(setOpenModal(null)), [dispatch])
}
export function useToggleMetaMaskConnectionErrorModal(): () => void {
return useToggleModal(ApplicationModal.METAMASK_CONNECTION_ERROR)
}
export function useOpenModal(modal: ApplicationModal): () => void {
const dispatch = useAppDispatch()
return useCallback(() => dispatch(setOpenModal(modal)), [dispatch, modal])

View File

@@ -46,7 +46,7 @@ export function swapErrorToUserReadableMessage(error: any): string {
if (reason?.indexOf('undefined is not an object') !== -1) {
return t`An error occurred when trying to execute this swap. You may need to increase your slippage tolerance. If that does not work, there may be an incompatibility with the token you are trading. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.`
}
return t`Unknown error${reason ? `: "${reason}"` : ''}. Try increasing your slippage tolerance.
Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.`
return t`${reason ? reason : 'Unknown error'}. Try increasing your slippage tolerance.
Note: fee-on-transfer and rebase tokens are incompatible with Uniswap V3.`
}
}

View File

@@ -4945,10 +4945,10 @@
react "^18.2.0"
react-dom "^18.2.0"
"@uniswap/conedison@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@uniswap/conedison/-/conedison-1.1.1.tgz#affec246613d1f52da3cdd0571ef8195b7b54d17"
integrity sha512-xFHAcWRrU+/+/BInXy6SRiiNwUG0vxLWsoYgod66wWifUvnjfpItzlvJHUer1OOpLDsz0CL5Fb70vFJOGAGi8w==
"@uniswap/conedison@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@uniswap/conedison/-/conedison-1.2.1.tgz#c3dbfe14f4320fc5c60cde23c4bd70ed8a39c782"
integrity sha512-ir6j7RQOyREXtW5YlmPjskfl7oDeHWtMFai57snThAkKgrb+8KTX5b0a5nbXeIuaW2RNHAaWTGoSoTneIHCAnQ==
"@uniswap/default-token-list@^2.0.0":
version "2.2.0"
@@ -5090,10 +5090,10 @@
resolved "https://registry.yarnpkg.com/@uniswap/token-lists/-/token-lists-1.0.0-beta.30.tgz#2103ca23b8007c59ec71718d34cdc97861c409e5"
integrity sha512-HwY2VvkQ8lNR6ks5NqQfAtg+4IZqz3KV1T8d2DlI8emIn9uMmaoFbIOg0nzjqAVKKnZSbMTRRtUoAh6mmjRvog==
"@uniswap/universal-router-sdk@1.3.0", "@uniswap/universal-router-sdk@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.0.tgz#f44262eafe729651d383f46a647399658d45baf7"
integrity sha512-Q7/Gw059JQDO7exxV791QzghEOiWomdvxvqidozDvkiZE7paIlSWq1vDVF4H3zB2GYy5Hu7HM8krl2l0KS9X5g==
"@uniswap/universal-router-sdk@1.3.4", "@uniswap/universal-router-sdk@^1.3.4":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.4.tgz#7b6b8e30d6faff812f224d32a832385378568160"
integrity sha512-RIWZm48N/fiAssMOj0nMLoeN5JATKOMfbFwyVnCaFHIVMJmKEZtZLKe3QOkl2LMVnQ/nP4LVCDwHU+mdP68jCQ==
dependencies:
"@uniswap/permit2-sdk" "^1.2.0"
"@uniswap/router-sdk" "^1.4.0"
@@ -5194,24 +5194,24 @@
"@uniswap/v3-core" "1.0.0"
"@uniswap/v3-periphery" "^1.0.1"
"@uniswap/widgets@2.25.1":
version "2.25.1"
resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.25.1.tgz#53d03da44587c0851d2f39516d7f9037d0c65b9d"
integrity sha512-Jth8qd7g58W1SVRpSFNiTKjs0HmcOacpxdSKfRSOIJOcYq8vgjZ0k4W3i/bzjf8PDRtLGh4Nn09VLugtIMUVIw==
"@uniswap/widgets@^2.26.0":
version "2.26.0"
resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.26.0.tgz#ed2d2b0965fc2139874a5eaca44c8070184d9e74"
integrity sha512-LIfd3wgJxNiPXduyxXAihOzye5LrayyPDt0/OErSr1hF3BIiQqdVc3KyHDFJ4PC0pCp4+dfE2HPH1FrClO54Uw==
dependencies:
"@babel/runtime" ">=7.17.0"
"@fontsource/ibm-plex-mono" "^4.5.1"
"@fontsource/inter" "^4.5.1"
"@popperjs/core" "^2.4.4"
"@reduxjs/toolkit" "^1.6.1"
"@uniswap/conedison" "^1.1.1"
"@uniswap/conedison" "^1.2.1"
"@uniswap/permit2-sdk" "^1.2.0"
"@uniswap/redux-multicall" "^1.1.8"
"@uniswap/router-sdk" "^1.3.0"
"@uniswap/sdk-core" "^3.0.1"
"@uniswap/smart-order-router" "^2.10.0"
"@uniswap/token-lists" "^1.0.0-beta.30"
"@uniswap/universal-router-sdk" "^1.3.0"
"@uniswap/universal-router-sdk" "^1.3.4"
"@uniswap/v2-sdk" "^3.0.1"
"@uniswap/v3-sdk" "^3.8.2"
"@web3-react/core" "8.0.35-beta.0"
@@ -5792,6 +5792,14 @@
"@metamask/detect-provider" "^1.2.0"
"@web3-react/types" "^8.0.20-beta.0"
"@web3-react/metamask@8.0.29-beta.0":
version "8.0.29-beta.0"
resolved "https://registry.yarnpkg.com/@web3-react/metamask/-/metamask-8.0.29-beta.0.tgz#536536b8d4f22f21d3e109efaa8149939833f21b"
integrity sha512-UPaVmNum6cJ/CwW5WYFMrm6GwiuY1hnuCYB+bV1Bs0xghdag2Laj8/mSfpFCsCHcvg1ZWTcr4bH+WyuYAHgUxw==
dependencies:
"@metamask/detect-provider" "^1.2.0"
"@web3-react/types" "^8.0.20-beta.0"
"@web3-react/network@8.0.27-beta.0":
version "8.0.27-beta.0"
resolved "https://registry.yarnpkg.com/@web3-react/network/-/network-8.0.27-beta.0.tgz#7cb522b02efc9d0f877ac285f350810fbf322292"