Commit ca60caf6 authored by eddie's avatar eddie Committed by GitHub

feat: use Swap Component on TDP (#6332)

* test: swap flow cypress tests

* fix: use default parameter

* feat: use Swap Component on TDP

* feat: auto nav for TDP tokens

* chore: merge

* chore: merge

* chore: merge

* chore: merge

* fix: remove extra inputCurrency URL parsing logic

* fix: undo last change

* fix: pass expected chain id to swap component

* fix: search for default tokens on unconnected networks if needed

* test: e2e test for l2 token

* fix: delete irrelevant tests

* fix: address comments

* fix: lint error

* test: update TDP e2e tests

* fix: use pageChainId for filter

* fix: rename chainId

* fix: typecheck

* fix: chainId bug

* fix: chainId required fixes

* fix: bad merge in e2e test

* fix: remove unused test util

* fix: remove unnecessary variable

* fix: token defaults

* fix: address comments

* fix: address comments and fix tests

* fix: e2e test formatting, remove Maybe<>

* fix: remove unused variable

* fix: use feature flag for swap component on TDP

* fix: back button
parent 252acef1
import { FeatureFlag } from '../../src/featureFlags/flags/featureFlags'
import { getClassContainsSelector, getTestSelector } from '../utils'
const UNI_GOERLI = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
const WETH_GOERLI = '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'
describe('swap widget integration tests', () => {
const verifyInputToken = (inputText: string) => {
cy.get(getClassContainsSelector('TokenButtonRow')).first().contains(inputText)
}
const verifyOutputToken = (outputText: string) => {
cy.get(getClassContainsSelector('TokenButtonRow')).last().contains(outputText)
}
const selectOutputAndSwitch = (outputText: string) => {
// open token selector...
cy.contains('Select token').click()
// select token...
cy.contains(outputText).click({ force: true })
cy.get('body')
.then(($body) => {
if ($body.find(getTestSelector('TokenSafetyWrapper')).length) {
return 'I understand'
}
return 'You pay' // Just click on a random element as a no-op
})
.then((selector) => {
cy.contains(selector).click()
})
// token selector should close...
cy.contains('Search name or paste address').should('not.exist')
cy.get(getClassContainsSelector('ReverseButton')).first().click()
}
describe('widget on swap page', () => {
beforeEach(() => {
cy.viewport(1200, 800)
})
it('should have the correct default input/output and token selection should work', () => {
cy.visit('/swap', { featureFlags: [FeatureFlag.swapWidget] }).then(() => {
cy.wait('@eth_blockNumber')
verifyInputToken('ETH')
verifyOutputToken('Select token')
selectOutputAndSwitch('WETH')
verifyInputToken('WETH')
verifyOutputToken('ETH')
})
})
it('should have the correct default input from URL params ', () => {
cy.visit(`/swap?inputCurrency=${WETH_GOERLI}`, {
featureFlags: [FeatureFlag.swapWidget],
}).then(() => {
cy.wait('@eth_blockNumber')
})
verifyInputToken('WETH')
verifyOutputToken('Select token')
selectOutputAndSwitch('Ether')
verifyInputToken('ETH')
verifyOutputToken('WETH')
})
it('should have the correct default output from URL params ', () => {
cy.visit(`/swap?outputCurrency=${WETH_GOERLI}`, {
featureFlags: [FeatureFlag.swapWidget],
}).then(() => {
cy.wait('@eth_blockNumber')
})
verifyInputToken('Select token')
verifyOutputToken('WETH')
cy.get(getClassContainsSelector('ReverseButton')).first().click()
verifyInputToken('WETH')
verifyOutputToken('Select token')
selectOutputAndSwitch('Ether')
verifyInputToken('ETH')
verifyOutputToken('WETH')
})
})
describe('widget on Token Detail Page', () => {
beforeEach(() => {
cy.viewport(1200, 800)
cy.visit(`/tokens/ethereum/${UNI_GOERLI}`, { featureFlags: [FeatureFlag.swapWidget] }).then(() => {
cy.wait('@eth_blockNumber')
})
})
it('should have the expected output for a tokens detail page', () => {
verifyOutputToken('UNI')
cy.contains('Connect to Ethereum').should('exist')
})
})
})
This diff is collapsed.
import { getClassContainsSelector, getTestSelector } from '../utils'
import { getTestSelector } from '../utils'
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
describe('Token details', () => {
before(() => {
cy.visit('/')
beforeEach(() => {
cy.viewport(1440, 900)
})
it('Uniswap token should have all information populated', () => {
......@@ -40,9 +40,6 @@ describe('Token details', () => {
// Contract address should be displayed
cy.contains(UNI_ADDRESS).should('exist')
// Swap widget should have this token pre-selected as the “destination” token
cy.get(getTestSelector('token-select')).should('include.text', 'UNI')
})
it('token with warning and low trading volume should have all information populated', () => {
......@@ -81,36 +78,9 @@ describe('Token details', () => {
// Contract address should be displayed
cy.contains('0xa71d0588EAf47f12B13cF8eC750430d21DF04974').should('exist')
// Swap widget should have this token pre-selected as the “destination” token
cy.get(getTestSelector('token-select')).should('include.text', 'QOM')
// Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e))
cy.get('[data-cy="token-safety-message"]')
.should('include.text', 'Warning')
.and('include.text', "This token isn't traded on leading U.S. centralized exchanges")
})
describe('Swap on Token Detail Page', () => {
const verifyOutputToken = (outputText: string) => {
cy.get(getClassContainsSelector('TokenButtonRow')).last().contains(outputText)
}
beforeEach(() => {
// On mobile widths, we just link back to /swap instead of rendering the swap component.
cy.viewport(1200, 800)
cy.visit(`/tokens/goerli/${UNI_ADDRESS}`).then(() => {
cy.wait('@eth_blockNumber')
})
})
it('should have the expected output for a tokens detail page', () => {
verifyOutputToken('UNI')
})
it('should not share swap state with the main swap page', () => {
verifyOutputToken('UNI')
cy.visit('/swap')
cy.contains('UNI').should('not.exist')
})
})
})
export const getTestSelector = (selectorId: string) => `[data-testid=${selectorId}]`
export const getTestSelectorStartsWith = (selectorId: string) => `[data-testid^=${selectorId}]`
export const getClassContainsSelector = (selectorId: string) => `[class*=${selectorId}]`
......@@ -204,6 +204,7 @@ interface SwapCurrencyInputPanelProps {
renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode
locked?: boolean
loading?: boolean
disabled?: boolean
}
export default function SwapCurrencyInputPanel({
......@@ -226,6 +227,7 @@ export default function SwapCurrencyInputPanel({
hideInput = false,
locked = false,
loading = false,
disabled = false,
...rest
}: SwapCurrencyInputPanelProps) {
const [modalOpen, setModalOpen] = useState(false)
......@@ -258,13 +260,13 @@ export default function SwapCurrencyInputPanel({
className="token-amount-input"
value={value}
onUserInput={onUserInput}
disabled={!chainAllowed}
disabled={!chainAllowed || disabled}
$loading={loading}
/>
)}
<CurrencySelect
disabled={!chainAllowed}
disabled={!chainAllowed || disabled}
visible={currency !== undefined}
selected={!!currency}
hideInput={hideInput}
......
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails'
import { useWidgetRemovalFlag, WidgetRemovalVariant } from 'featureFlags/flags/removeWidgetTdp'
import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
import { useUpdateAtom } from 'jotai/utils'
......@@ -214,6 +215,12 @@ export default function FeatureFlagModal() {
featureFlag={FeatureFlag.detailsV2}
label="Use the new details page for nfts"
/>
<FeatureFlagOption
variant={WidgetRemovalVariant}
value={useWidgetRemovalFlag()}
featureFlag={FeatureFlag.removeWidget}
label="Swap Component on TDP"
/>
<FeatureFlagGroup name="Debug">
<FeatureFlagOption
variant={TraceJsonRpcVariant}
......
......@@ -85,7 +85,7 @@ export function CurrencySearch({
}
}, [isAddressSearch])
const defaultTokens = useDefaultActiveTokens()
const defaultTokens = useDefaultActiveTokens(chainId)
const filteredTokens: Token[] = useMemo(() => {
return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery))
}, [defaultTokens, debouncedQuery])
......@@ -123,7 +123,7 @@ export function CurrencySearch({
const filteredSortedTokens = useSortTokensByQuery(debouncedQuery, sortedTokens)
const native = useNativeCurrency()
const native = useNativeCurrency(chainId)
const wrapped = native.wrapped
const searchCurrencies: Currency[] = useMemo(() => {
......
import { Trans } from '@lingui/macro'
import { Trace } from '@uniswap/analytics'
import { InterfacePageName } from '@uniswap/analytics-events'
import { Currency, Field } from '@uniswap/widgets'
import { Currency } from '@uniswap/widgets'
import { useWeb3React } from '@web3-react/core'
import CurrencyLogo from 'components/Logo/CurrencyLogo'
import { AboutSection } from 'components/Tokens/TokenDetails/About'
......@@ -26,6 +26,7 @@ import Widget from 'components/Widget'
import { SwapTokens } from 'components/Widget/inputs'
import { NATIVE_CHAIN_ID, nativeOnChain } from 'constants/tokens'
import { checkWarning } from 'constants/tokenSafety'
import { useWidgetRemovalEnabled } from 'featureFlags/flags/removeWidgetTdp'
import { TokenPriceQuery } from 'graphql/data/__generated__/types-and-hooks'
import { Chain, TokenQuery, TokenQueryData } from 'graphql/data/Token'
import { QueryToken } from 'graphql/data/Token'
......@@ -34,11 +35,15 @@ import { useIsUserAddedTokenOnChain } from 'hooks/Tokens'
import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch'
import { UNKNOWN_TOKEN_SYMBOL, useTokenFromActiveNetwork } from 'lib/hooks/useCurrency'
import { getTokenAddress } from 'lib/utils/analytics'
import { Swap } from 'pages/Swap'
import { useCallback, useMemo, useState, useTransition } from 'react'
import { ArrowLeft } from 'react-feather'
import { useNavigate } from 'react-router-dom'
import { Field } from 'state/swap/actions'
import { SwapState } from 'state/swap/reducer'
import styled from 'styled-components/macro'
import { isAddress } from 'utils'
import { addressesAreEquivalent } from 'utils/addressesAreEquivalent'
import { OnChangeTimePeriod } from './ChartSection'
import InvalidTokenDetails from './InvalidTokenDetails'
......@@ -111,6 +116,7 @@ export default function TokenDetails({
[urlAddress]
)
const { chainId: connectedChainId } = useWeb3React()
const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain]
const tokenQueryData = tokenQuery.token
......@@ -124,11 +130,12 @@ export default function TokenDetails({
)
const { token: detailedToken, didFetchFromChain } = useRelevantToken(address, pageChainId, tokenQueryData)
const { token: inputToken } = useRelevantToken(inputTokenAddress, pageChainId, undefined)
const { token: widgetInputToken } = useRelevantToken(inputTokenAddress, pageChainId, undefined)
const tokenWarning = address ? checkWarning(address) : null
const isBlockedToken = tokenWarning?.canProceed === false
const navigate = useNavigate()
const widgetRemovalEnabled = useWidgetRemovalEnabled()
// Wrapping navigate in a transition prevents Suspense from unnecessarily showing fallbacks again.
const [isPending, startTokenTransition] = useTransition()
......@@ -145,7 +152,6 @@ export default function TokenDetails({
[address, crossChainMap, didFetchFromChain, navigate, detailedToken?.isNative]
)
useOnGlobalChainSwitch(navigateToTokenForChain)
const navigateToWidgetSelectedToken = useCallback(
(tokens: SwapTokens) => {
const newDefaultToken = tokens[Field.OUTPUT] ?? tokens.default
......@@ -163,11 +169,39 @@ export default function TokenDetails({
[chain, navigate]
)
const handleCurrencyChange = useCallback(
(tokens: Pick<SwapState, Field.INPUT | Field.OUTPUT>) => {
if (
addressesAreEquivalent(tokens[Field.INPUT]?.currencyId, address) ||
addressesAreEquivalent(tokens[Field.OUTPUT]?.currencyId, address)
) {
return
}
const newDefaultTokenID = tokens[Field.OUTPUT]?.currencyId ?? tokens[Field.INPUT]?.currencyId
startTokenTransition(() =>
navigate(
getTokenDetailsURL({
// The function falls back to "NATIVE" if the address is null
address: newDefaultTokenID === 'ETH' ? null : newDefaultTokenID,
chain,
inputAddress:
// If only one token was selected before we navigate, then it was the default token and it's being replaced.
// On the new page, the *new* default token becomes the output, and we don't have another option to set as the input token.
tokens[Field.INPUT] && tokens[Field.INPUT]?.currencyId !== newDefaultTokenID
? tokens[Field.INPUT]?.currencyId
: null,
})
)
)
},
[address, chain, navigate]
)
const [continueSwap, setContinueSwap] = useState<{ resolve: (value: boolean | PromiseLike<boolean>) => void }>()
const [openTokenSafetyModal, setOpenTokenSafetyModal] = useState(false)
// Show token safety modal if Swap-reviewing a warning token, at all times if the current token is blocked
const shouldShowSpeedbump = !useIsUserAddedTokenOnChain(address, pageChainId) && tokenWarning !== null
const onReviewSwapClick = useCallback(
() => new Promise<boolean>((resolve) => (shouldShowSpeedbump ? setContinueSwap({ resolve }) : resolve(true))),
......@@ -234,14 +268,26 @@ export default function TokenDetails({
<RightPanel onClick={() => isBlockedToken && setOpenTokenSafetyModal(true)}>
<div style={{ pointerEvents: isBlockedToken ? 'none' : 'auto' }}>
<Widget
defaultTokens={{
[Field.INPUT]: inputToken ?? undefined,
default: detailedToken ?? undefined,
}}
onDefaultTokenChange={navigateToWidgetSelectedToken}
onReviewSwapClick={onReviewSwapClick}
/>
{widgetRemovalEnabled ? (
<Swap
chainId={pageChainId}
prefilledState={{
[Field.INPUT]: { currencyId: inputTokenAddress },
[Field.OUTPUT]: { currencyId: address === NATIVE_CHAIN_ID ? 'ETH' : address },
}}
onCurrencyChange={handleCurrencyChange}
disableTokenInputs={pageChainId !== connectedChainId}
/>
) : (
<Widget
defaultTokens={{
[Field.INPUT]: widgetInputToken ?? undefined,
default: detailedToken ?? undefined,
}}
onDefaultTokenChange={navigateToWidgetSelectedToken}
onReviewSwapClick={onReviewSwapClick}
/>
)}
</div>
{tokenWarning && <TokenSafetyMessage tokenAddress={address} warning={tokenWarning} />}
{detailedToken && <BalanceSummary token={detailedToken} />}
......
......@@ -51,6 +51,8 @@ interface WidgetProps {
onReviewSwapClick?: OnReviewSwapClick
}
// TODO: Remove this component once the TDP is fully migrated to the swap component.
// eslint-disable-next-line import/no-unused-modules
export default function Widget({
defaultTokens,
width = DEFAULT_WIDGET_WIDTH,
......
......@@ -53,7 +53,7 @@ export function AdvancedSwapDetails({
}: AdvancedSwapDetailsProps) {
const theme = useTheme()
const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const { expectedOutputAmount, priceImpact } = useMemo(() => {
return {
......
......@@ -515,6 +515,13 @@ export function nativeOnChain(chainId: number): NativeCurrency | Token {
return (cachedNativeCurrency[chainId] = nativeCurrency)
}
export function getSwapCurrencyId(currency: Currency): string {
if (currency.isToken) {
return currency.address
}
return NATIVE_CHAIN_ID
}
export const TOKEN_SHORTHANDS: { [shorthand: string]: { [chainId in SupportedChainId]?: string } } = {
USDC: {
[SupportedChainId.MAINNET]: USDC_MAINNET.address,
......
......@@ -8,4 +8,5 @@ export enum FeatureFlag {
swapWidget = 'swap_widget_replacement_enabled',
statsigDummy = 'web_dummy_gate_amplitude_id',
detailsV2 = 'details_v2',
removeWidget = 'remove_widget_tdp',
}
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function useWidgetRemovalFlag(): BaseVariant {
return useBaseFlag(FeatureFlag.removeWidget, BaseVariant.Control)
}
export function useWidgetRemovalEnabled(): boolean {
return useWidgetRemovalFlag() === BaseVariant.Enabled
}
export { BaseVariant as WidgetRemovalVariant }
......@@ -13,9 +13,10 @@ import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
import { useUserAddedTokens, useUserAddedTokensOnChain } from '../state/user/hooks'
import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks'
type Maybe<T> = T | null | undefined
// reduce token map into standard address <-> Token mapping, optionally include user added tokens
function useTokensFromMap(tokenMap: TokenAddressMap): { [address: string]: Token } {
const { chainId } = useWeb3React()
function useTokensFromMap(tokenMap: TokenAddressMap, chainId: Maybe<SupportedChainId>): { [address: string]: Token } {
return useMemo(() => {
if (!chainId) return {}
......@@ -32,9 +33,9 @@ export function useAllTokensMultichain(): TokenAddressMap {
}
// Returns all tokens from the default list + user added tokens
export function useDefaultActiveTokens(): { [address: string]: Token } {
export function useDefaultActiveTokens(chainId: Maybe<SupportedChainId>): { [address: string]: Token } {
const defaultListTokens = useCombinedActiveList()
const tokensFromMap = useTokensFromMap(defaultListTokens)
const tokensFromMap = useTokensFromMap(defaultListTokens, chainId)
const userAddedTokens = useUserAddedTokens()
return useMemo(() => {
return (
......@@ -66,7 +67,7 @@ export function useUnsupportedTokens(): { [address: string]: Token } {
const { chainId } = useWeb3React()
const listsByUrl = useAllLists()
const unsupportedTokensMap = useUnsupportedTokenList()
const unsupportedTokens = useTokensFromMap(unsupportedTokensMap)
const unsupportedTokens = useTokensFromMap(unsupportedTokensMap, chainId)
// checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
......@@ -110,7 +111,7 @@ export function useSearchInactiveTokenLists(search: string | undefined, minResul
const lists = useAllLists()
const inactiveUrls = DEFAULT_INACTIVE_LIST_URLS
const { chainId } = useWeb3React()
const activeTokens = useDefaultActiveTokens()
const activeTokens = useDefaultActiveTokens(chainId)
return useMemo(() => {
if (!search || search.trim().length === 0) return []
const tokenFilter = getTokenFilter(search)
......@@ -167,11 +168,13 @@ export function useIsUserAddedTokenOnChain(
// null if loading or null was passed
// otherwise returns the token
export function useToken(tokenAddress?: string | null): Token | null | undefined {
const tokens = useDefaultActiveTokens()
const { chainId } = useWeb3React()
const tokens = useDefaultActiveTokens(chainId)
return useTokenFromMapOrNetwork(tokens, tokenAddress)
}
export function useCurrency(currencyId?: string | null): Currency | null | undefined {
const tokens = useDefaultActiveTokens()
return useCurrencyFromMap(tokens, currencyId)
export function useCurrency(currencyId: Maybe<string>, chainId?: SupportedChainId): Currency | null | undefined {
const { chainId: connectedChainId } = useWeb3React()
const tokens = useDefaultActiveTokens(chainId ?? connectedChainId)
return useCurrencyFromMap(tokens, chainId ?? connectedChainId, currencyId)
}
......@@ -81,7 +81,7 @@ export default function useAutoSlippageTolerance(
const nativeGasPrice = useGasPrice()
const gasEstimate = guesstimateGas(trade)
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const nativeCurrencyPrice = useStablecoinPrice((trade && nativeCurrency) ?? undefined)
return useMemo(() => {
......
import { Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useMemo } from 'react'
import { PositionDetails } from 'types/position'
import { hasURL } from 'utils/urlChecks'
......@@ -23,7 +24,8 @@ function getUniqueAddressesFromPositions(positions: PositionDetails[]): string[]
* The hope is that this approach removes the cheapest version of the attack without punishing non-malicious url symbols
*/
export function useFilterPossiblyMaliciousPositions(positions: PositionDetails[]): PositionDetails[] {
const activeTokensList = useDefaultActiveTokens()
const { chainId } = useWeb3React()
const activeTokensList = useDefaultActiveTokens(chainId)
const nonListPositionTokenAddresses = useMemo(
() => getUniqueAddressesFromPositions(positions).filter((address) => !activeTokensList[address]),
......
......@@ -31,7 +31,8 @@ enum WrapInputError {
}
export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputError }) {
const native = useNativeCurrency()
const { chainId } = useWeb3React()
const native = useNativeCurrency(chainId)
const wrapped = native?.wrapped
switch (wrapInputError) {
......
......@@ -2,7 +2,7 @@ import { arrayify } from '@ethersproject/bytes'
import { parseBytes32String } from '@ethersproject/strings'
import { Currency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { isSupportedChain } from 'constants/chains'
import { isSupportedChain, SupportedChainId } from 'constants/chains'
import { useBytes32TokenContract, useTokenContract } from 'hooks/useContract'
import { NEVER_RELOAD, useSingleCallResult } from 'lib/hooks/multicall'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
......@@ -92,9 +92,12 @@ export function useTokenFromMapOrNetwork(tokens: TokenMap, tokenAddress?: string
* Returns null if currency is loading or null was passed.
* Returns undefined if currencyId is invalid or token does not exist.
*/
export function useCurrencyFromMap(tokens: TokenMap, currencyId?: string | null): Currency | null | undefined {
const nativeCurrency = useNativeCurrency()
const { chainId } = useWeb3React()
export function useCurrencyFromMap(
tokens: TokenMap,
chainId: SupportedChainId | undefined,
currencyId?: string | null
): Currency | null | undefined {
const nativeCurrency = useNativeCurrency(chainId)
const isNative = Boolean(nativeCurrency && currencyId?.toUpperCase() === 'ETH')
const shorthandMatchAddress = useMemo(() => {
const chain = supportedChainId(chainId)
......@@ -108,6 +111,5 @@ export function useCurrencyFromMap(tokens: TokenMap, currencyId?: string | null)
// 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
}
import { NativeCurrency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { SupportedChainId } from 'constants/chains'
import { nativeOnChain } from 'constants/tokens'
import { useMemo } from 'react'
export default function useNativeCurrency(): NativeCurrency | Token {
const { chainId } = useWeb3React()
export default function useNativeCurrency(chainId: SupportedChainId | null | undefined): NativeCurrency | Token {
return useMemo(
() =>
chainId
......
......@@ -183,7 +183,7 @@ const EthValueWrapper = styled.span<{ totalEthListingValue: boolean }>`
export const ListPage = () => {
const { setProfilePageState: setSellPageState } = useProfilePageState()
const { provider } = useWeb3React()
const { provider, chainId } = useWeb3React()
const isMobile = useIsMobile()
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
const { setGlobalMarketplaces, sellAssets, issues } = useSellAsset(
......@@ -205,7 +205,7 @@ export const ListPage = () => {
)
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
const usdcValue = useStablecoinValue(parsedAmount)
const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice)
......
......@@ -45,7 +45,7 @@ const ListModalWrapper = styled.div`
`
export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
const { provider } = useWeb3React()
const { provider, chainId } = useWeb3React()
const signer = provider?.getSigner()
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
const sellAssets = useSellAsset((state) => state.sellAssets)
......@@ -72,7 +72,7 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
(s) => (s === Section.APPROVE ? Section.SIGN : Section.APPROVE),
Section.APPROVE
)
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
const usdcValue = useStablecoinValue(parsedAmount)
const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice)
......
import { Trans } from '@lingui/macro'
import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format'
import { useWeb3React } from '@web3-react/core'
import Column from 'components/Column'
import { ScrollBarStyles } from 'components/Common'
import Row from 'components/Row'
......@@ -76,7 +77,8 @@ const TweetRow = styled(Row)`
export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => {
const theme = useTheme()
const sellAssets = useSellAsset((state) => state.sellAssets)
const nativeCurrency = useNativeCurrency()
const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency(chainId)
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
......
......@@ -403,7 +403,7 @@ function PositionPageContent() {
// flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false)
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const nativeWrappedSymbol = nativeCurrency.wrapped.symbol
// construct Position from details returned
......
......@@ -74,7 +74,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
// flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false)
const nativeCurrency = useNativeCurrency()
const nativeCurrency = useNativeCurrency(chainId)
const nativeWrappedSymbol = nativeCurrency.wrapped.symbol
// burn state
......
This diff is collapsed.
......@@ -16,8 +16,8 @@ export {
// mimics useAllBalances
export function useAllTokenBalances(): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] {
const { account } = useWeb3React()
const allTokens = useDefaultActiveTokens()
const { account, chainId } = useWeb3React()
const allTokens = useDefaultActiveTokens(chainId)
const allTokensArray = useMemo(() => Object.values(allTokens ?? {}), [allTokens])
const [balances, balancesIsLoading] = useTokenBalancesWithLoadingIndicator(account ?? undefined, allTokensArray)
return [balances ?? {}, balancesIsLoading]
......
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { SupportedChainId } from 'constants/chains'
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
import { useBestTrade } from 'hooks/useBestTrade'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
......@@ -71,7 +72,10 @@ const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = {
}
// from the current swap inputs, compute the best trade and return it.
export function useDerivedSwapInfo(state: SwapState): {
export function useDerivedSwapInfo(
state: SwapState,
chainId: SupportedChainId | undefined
): {
currencies: { [field in Field]?: Currency | null }
currencyBalances: { [field in Field]?: CurrencyAmount<Currency> }
parsedAmount: CurrencyAmount<Currency> | undefined
......@@ -92,8 +96,8 @@ export function useDerivedSwapInfo(state: SwapState): {
recipient,
} = state
const inputCurrency = useCurrency(inputCurrencyId)
const outputCurrency = useCurrency(outputCurrencyId)
const inputCurrency = useCurrency(inputCurrencyId, chainId)
const outputCurrency = useCurrency(outputCurrencyId, chainId)
const recipientLookup = useENS(recipient ?? undefined)
const to: string | null = (recipient === null ? account : recipientLookup.address) ?? null
......
......@@ -271,7 +271,7 @@ export function toV2LiquidityToken([tokenA, tokenB]: [Token, Token]): Token {
*/
export function useTrackedTokenPairs(): [Token, Token][] {
const { chainId } = useWeb3React()
const tokens = useDefaultActiveTokens()
const tokens = useDefaultActiveTokens(chainId)
// pinned pairs
const pinnedPairs = useMemo(() => (chainId ? PINNED_PAIRS[chainId] ?? [] : []), [chainId])
......
export function addressesAreEquivalent(a?: string, b?: string) {
export function addressesAreEquivalent(a: string | null | undefined, b: string | null | undefined) {
if (!a || !b) return false
return a === b || a.toLowerCase() === b.toLowerCase()
}
......@@ -4,7 +4,7 @@ import { SupportedChainId } from 'constants/chains'
* Returns the input chain ID if chain is supported. If not, return undefined
* @param chainId a chain ID, which will be returned if it is a supported chain ID
*/
export function supportedChainId(chainId: number | undefined): SupportedChainId | undefined {
export function supportedChainId(chainId: number | null | undefined): SupportedChainId | undefined {
if (typeof chainId === 'number' && chainId in SupportedChainId) {
return chainId
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment