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')
})
})
})
import { USDC_MAINNET } from '../../src/constants/tokens' import { WETH9 } from '@uniswap/sdk-core'
import { UNI as UNI_MAINNET, USDC_MAINNET } from '../../src/constants/tokens'
import { FeatureFlag } from '../../src/featureFlags/flags/featureFlags'
import { WETH_GOERLI } from '../fixtures/constants' import { WETH_GOERLI } from '../fixtures/constants'
import { getTestSelector } from '../utils' import { getTestSelector } from '../utils'
...@@ -19,9 +22,9 @@ describe('Swap', () => { ...@@ -19,9 +22,9 @@ describe('Swap', () => {
} }
} }
const selectOutput = (tokenSymbol: string) => { const selectToken = (tokenSymbol: string, field: 'input' | 'output') => {
// open token selector... // open token selector...
cy.contains('Select token').click() cy.get(`#swap-currency-${field} .open-currency-select-button`).click()
// select token... // select token...
cy.contains(tokenSymbol).click() cy.contains(tokenSymbol).click()
...@@ -43,6 +46,7 @@ describe('Swap', () => { ...@@ -43,6 +46,7 @@ describe('Swap', () => {
cy.contains('Search name or paste address').should('not.exist') cy.contains('Search name or paste address').should('not.exist')
} }
describe('Swap on main page', () => {
before(() => { before(() => {
cy.visit('/swap', { ethereum: 'hardhat' }) cy.visit('/swap', { ethereum: 'hardhat' })
}) })
...@@ -74,44 +78,12 @@ describe('Swap', () => { ...@@ -74,44 +78,12 @@ describe('Swap', () => {
cy.get('#swap-currency-output .token-amount-input').clear().type('0.0').should('have.value', '0.0') cy.get('#swap-currency-output .token-amount-input').clear().type('0.0').should('have.value', '0.0')
}) })
it('can swap ETH for USDC', () => {
const TOKEN_ADDRESS = USDC_MAINNET.address
const BALANCE_INCREMENT = 1
cy.hardhat().then((hardhat) => {
cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET))
.then((balance) => Number(balance.toFixed(1)))
.then((initialBalance) => {
cy.get('#swap-currency-output .open-currency-select-button').click()
cy.get(getTestSelector('token-search-input')).clear().type(TOKEN_ADDRESS)
cy.contains('USDC').click()
cy.get('#swap-currency-output .token-amount-input').clear().type(BALANCE_INCREMENT.toString())
cy.get('#swap-currency-input .token-amount-input').should('not.equal', '')
cy.get('#swap-button').click()
cy.get('#confirm-swap-or-send').click()
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
cy.then(() => hardhat.provider.send('hardhat_mine', ['0x1', '0xc'])).then(() => {
// ui check
cy.get('#swap-currency-output [data-testid="balance-text"]').should(
'have.text',
`Balance: ${initialBalance + BALANCE_INCREMENT}`
)
// chain state check
cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET))
.then((balance) => Number(balance.toFixed(1)))
.should('eq', initialBalance + BALANCE_INCREMENT)
})
})
})
})
it('should have the correct default input/output and token selection should work', () => { it('should have the correct default input/output and token selection should work', () => {
cy.visit('/swap') cy.visit('/swap')
verifyToken('input', 'ETH') verifyToken('input', 'ETH')
verifyToken('output', null) verifyToken('output', null)
selectOutput('WETH') selectToken('WETH', 'output')
cy.get(getTestSelector('swap-currency-button')).first().click() cy.get(getTestSelector('swap-currency-button')).first().click()
verifyToken('input', 'WETH') verifyToken('input', 'WETH')
...@@ -124,7 +96,7 @@ describe('Swap', () => { ...@@ -124,7 +96,7 @@ describe('Swap', () => {
verifyToken('input', 'WETH') verifyToken('input', 'WETH')
verifyToken('output', null) verifyToken('output', null)
selectOutput('Ether') selectToken('Ether', 'output')
cy.get(getTestSelector('swap-currency-button')).first().click() cy.get(getTestSelector('swap-currency-button')).first().click()
verifyToken('input', 'ETH') verifyToken('input', 'ETH')
...@@ -141,7 +113,7 @@ describe('Swap', () => { ...@@ -141,7 +113,7 @@ describe('Swap', () => {
verifyToken('input', 'WETH') verifyToken('input', 'WETH')
verifyToken('output', null) verifyToken('output', null)
selectOutput('Ether') selectToken('Ether', 'output')
cy.get(getTestSelector('swap-currency-button')).first().click() cy.get(getTestSelector('swap-currency-button')).first().click()
verifyToken('input', 'ETH') verifyToken('input', 'ETH')
...@@ -150,30 +122,11 @@ describe('Swap', () => { ...@@ -150,30 +122,11 @@ describe('Swap', () => {
it('ETH to wETH is same value (wrapped swaps have no price impact)', () => { it('ETH to wETH is same value (wrapped swaps have no price impact)', () => {
cy.visit('/swap') cy.visit('/swap')
selectOutput('WETH') selectToken('WETH', 'output')
cy.get('#swap-currency-input .token-amount-input').clear().type('0.01') cy.get('#swap-currency-input .token-amount-input').clear().type('0.01')
cy.get('#swap-currency-output .token-amount-input').should('have.value', '0.01') cy.get('#swap-currency-output .token-amount-input').should('have.value', '0.01')
}) })
it('should render and dismiss the wallet rejection modal', () => {
cy.visit('/swap', { ethereum: 'hardhat' })
.hardhat()
.then((hardhat) => {
cy.stub(hardhat.wallet, 'sendTransaction').rejects(new Error('user cancelled'))
cy.get('#swap-currency-output .open-currency-select-button').click()
cy.get(getTestSelector('token-search-input')).clear().type(USDC_MAINNET.address)
cy.contains('USDC').click()
cy.get('#swap-currency-output .token-amount-input').clear().type('1')
cy.get('#swap-currency-input .token-amount-input').should('not.equal', '')
cy.get('#swap-button').click()
cy.get('#confirm-swap-or-send').click()
cy.contains('Transaction rejected').should('exist')
cy.contains('Dismiss').click()
cy.contains('Transaction rejected').should('not.exist')
})
})
it('Opens and closes the settings menu', () => { it('Opens and closes the settings menu', () => {
cy.visit('/swap') cy.visit('/swap')
cy.contains('Settings').should('not.exist') cy.contains('Settings').should('not.exist')
...@@ -194,4 +147,103 @@ describe('Swap', () => { ...@@ -194,4 +147,103 @@ describe('Swap', () => {
cy.get('#swap-currency-input .token-amount-input').should('have.value', '') cy.get('#swap-currency-input .token-amount-input').should('have.value', '')
cy.get('#swap-currency-output .token-amount-input').should('not.equal', '') cy.get('#swap-currency-output .token-amount-input').should('not.equal', '')
}) })
it('can swap ETH for USDC', () => {
cy.visit('/swap', { ethereum: 'hardhat' })
const TOKEN_ADDRESS = USDC_MAINNET.address
const BALANCE_INCREMENT = 1
cy.hardhat().then((hardhat) => {
cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET))
.then((balance) => Number(balance.toFixed(1)))
.then((initialBalance) => {
cy.get('#swap-currency-output .open-currency-select-button').click()
cy.get(getTestSelector('token-search-input')).clear().type(TOKEN_ADDRESS)
cy.contains('USDC').click()
cy.get('#swap-currency-output .token-amount-input').clear().type(BALANCE_INCREMENT.toString())
cy.get('#swap-currency-input .token-amount-input').should('not.equal', '')
cy.get('#swap-button').click()
cy.get('#confirm-swap-or-send').click()
cy.get(getTestSelector('dismiss-tx-confirmation')).click()
cy.then(() => hardhat.provider.send('hardhat_mine', ['0x1', '0xc'])).then(() => {
// ui check
cy.get('#swap-currency-output [data-testid="balance-text"]').should(
'have.text',
`Balance: ${initialBalance + BALANCE_INCREMENT}`
)
// chain state check
cy.then(() => hardhat.getBalance(hardhat.wallet.address, USDC_MAINNET))
.then((balance) => Number(balance.toFixed(1)))
.should('eq', initialBalance + BALANCE_INCREMENT)
})
})
})
})
})
describe('Swap on Token Detail Page', () => {
beforeEach(() => {
// On mobile widths, we just link back to /swap instead of rendering the swap component.
cy.viewport(1200, 800)
cy.visit(`/tokens/ethereum/${UNI_MAINNET[1].address}`, {
ethereum: 'hardhat',
featureFlags: [FeatureFlag.removeWidget],
}).then(() => {
cy.wait('@eth_blockNumber')
cy.scrollTo('top')
})
})
it('should have the expected output for a tokens detail page', () => {
verifyAmount('input', '')
verifyToken('input', null)
verifyAmount('output', null)
verifyToken('output', 'UNI')
})
it('should automatically navigate to the new TDP', () => {
selectToken('WETH', 'output')
cy.url().should('include', `${WETH9[1].address}`)
cy.url().should('not.include', `${UNI_MAINNET[1].address}`)
})
it('should not share swap state with the main swap page', () => {
verifyToken('output', 'UNI')
selectToken('WETH', 'input')
cy.visit('/swap', { featureFlags: [FeatureFlag.removeWidget] })
cy.contains('UNI').should('not.exist')
cy.contains('WETH').should('not.exist')
})
it('can enter an amount into input', () => {
cy.get('#swap-currency-input .token-amount-input').clear().type('0.001').should('have.value', '0.001')
})
it('zero swap amount', () => {
cy.get('#swap-currency-input .token-amount-input').clear().type('0.0').should('have.value', '0.0')
})
it('invalid swap amount', () => {
cy.get('#swap-currency-input .token-amount-input').clear().type('\\').should('have.value', '')
})
it('can enter an amount into output', () => {
cy.get('#swap-currency-output .token-amount-input').clear().type('0.001').should('have.value', '0.001')
})
it('zero output amount', () => {
cy.get('#swap-currency-output .token-amount-input').clear().type('0.0').should('have.value', '0.0')
})
it('should show a L2 token even if the user is connected to a different network', () => {
cy.visit('/tokens', { ethereum: 'hardhat', featureFlags: [FeatureFlag.removeWidget] })
cy.get(getTestSelector('tokens-network-filter-selected')).click()
cy.get(getTestSelector('tokens-network-filter-option-arbitrum')).click()
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Arbitrum')
cy.get(getTestSelector('token-table-row-ARB')).click()
verifyToken('output', 'ARB')
cy.contains('Connect to Arbitrum').should('exist')
})
})
}) })
import { getClassContainsSelector, getTestSelector } from '../utils' import { getTestSelector } from '../utils'
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984' const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
describe('Token details', () => { describe('Token details', () => {
before(() => { beforeEach(() => {
cy.visit('/') cy.viewport(1440, 900)
}) })
it('Uniswap token should have all information populated', () => { it('Uniswap token should have all information populated', () => {
...@@ -40,9 +40,6 @@ describe('Token details', () => { ...@@ -40,9 +40,6 @@ describe('Token details', () => {
// Contract address should be displayed // Contract address should be displayed
cy.contains(UNI_ADDRESS).should('exist') 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', () => { it('token with warning and low trading volume should have all information populated', () => {
...@@ -81,36 +78,9 @@ describe('Token details', () => { ...@@ -81,36 +78,9 @@ describe('Token details', () => {
// Contract address should be displayed // Contract address should be displayed
cy.contains('0xa71d0588EAf47f12B13cF8eC750430d21DF04974').should('exist') 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)) // Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e))
cy.get('[data-cy="token-safety-message"]') cy.get('[data-cy="token-safety-message"]')
.should('include.text', 'Warning') .should('include.text', 'Warning')
.and('include.text', "This token isn't traded on leading U.S. centralized exchanges") .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 getTestSelector = (selectorId: string) => `[data-testid=${selectorId}]`
export const getTestSelectorStartsWith = (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 { ...@@ -204,6 +204,7 @@ interface SwapCurrencyInputPanelProps {
renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode renderBalance?: (amount: CurrencyAmount<Currency>) => ReactNode
locked?: boolean locked?: boolean
loading?: boolean loading?: boolean
disabled?: boolean
} }
export default function SwapCurrencyInputPanel({ export default function SwapCurrencyInputPanel({
...@@ -226,6 +227,7 @@ export default function SwapCurrencyInputPanel({ ...@@ -226,6 +227,7 @@ export default function SwapCurrencyInputPanel({
hideInput = false, hideInput = false,
locked = false, locked = false,
loading = false, loading = false,
disabled = false,
...rest ...rest
}: SwapCurrencyInputPanelProps) { }: SwapCurrencyInputPanelProps) {
const [modalOpen, setModalOpen] = useState(false) const [modalOpen, setModalOpen] = useState(false)
...@@ -258,13 +260,13 @@ export default function SwapCurrencyInputPanel({ ...@@ -258,13 +260,13 @@ export default function SwapCurrencyInputPanel({
className="token-amount-input" className="token-amount-input"
value={value} value={value}
onUserInput={onUserInput} onUserInput={onUserInput}
disabled={!chainAllowed} disabled={!chainAllowed || disabled}
$loading={loading} $loading={loading}
/> />
)} )}
<CurrencySelect <CurrencySelect
disabled={!chainAllowed} disabled={!chainAllowed || disabled}
visible={currency !== undefined} visible={currency !== undefined}
selected={!!currency} selected={!!currency}
hideInput={hideInput} hideInput={hideInput}
......
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags' import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails' import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails'
import { useWidgetRemovalFlag, WidgetRemovalVariant } from 'featureFlags/flags/removeWidgetTdp'
import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget' import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc' import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
import { useUpdateAtom } from 'jotai/utils' import { useUpdateAtom } from 'jotai/utils'
...@@ -214,6 +215,12 @@ export default function FeatureFlagModal() { ...@@ -214,6 +215,12 @@ export default function FeatureFlagModal() {
featureFlag={FeatureFlag.detailsV2} featureFlag={FeatureFlag.detailsV2}
label="Use the new details page for nfts" label="Use the new details page for nfts"
/> />
<FeatureFlagOption
variant={WidgetRemovalVariant}
value={useWidgetRemovalFlag()}
featureFlag={FeatureFlag.removeWidget}
label="Swap Component on TDP"
/>
<FeatureFlagGroup name="Debug"> <FeatureFlagGroup name="Debug">
<FeatureFlagOption <FeatureFlagOption
variant={TraceJsonRpcVariant} variant={TraceJsonRpcVariant}
......
...@@ -85,7 +85,7 @@ export function CurrencySearch({ ...@@ -85,7 +85,7 @@ export function CurrencySearch({
} }
}, [isAddressSearch]) }, [isAddressSearch])
const defaultTokens = useDefaultActiveTokens() const defaultTokens = useDefaultActiveTokens(chainId)
const filteredTokens: Token[] = useMemo(() => { const filteredTokens: Token[] = useMemo(() => {
return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery)) return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery))
}, [defaultTokens, debouncedQuery]) }, [defaultTokens, debouncedQuery])
...@@ -123,7 +123,7 @@ export function CurrencySearch({ ...@@ -123,7 +123,7 @@ export function CurrencySearch({
const filteredSortedTokens = useSortTokensByQuery(debouncedQuery, sortedTokens) const filteredSortedTokens = useSortTokensByQuery(debouncedQuery, sortedTokens)
const native = useNativeCurrency() const native = useNativeCurrency(chainId)
const wrapped = native.wrapped const wrapped = native.wrapped
const searchCurrencies: Currency[] = useMemo(() => { const searchCurrencies: Currency[] = useMemo(() => {
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Trace } from '@uniswap/analytics' import { Trace } from '@uniswap/analytics'
import { InterfacePageName } from '@uniswap/analytics-events' import { InterfacePageName } from '@uniswap/analytics-events'
import { Currency, Field } from '@uniswap/widgets' import { Currency } from '@uniswap/widgets'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import CurrencyLogo from 'components/Logo/CurrencyLogo' import CurrencyLogo from 'components/Logo/CurrencyLogo'
import { AboutSection } from 'components/Tokens/TokenDetails/About' import { AboutSection } from 'components/Tokens/TokenDetails/About'
...@@ -26,6 +26,7 @@ import Widget from 'components/Widget' ...@@ -26,6 +26,7 @@ import Widget from 'components/Widget'
import { SwapTokens } from 'components/Widget/inputs' import { SwapTokens } from 'components/Widget/inputs'
import { NATIVE_CHAIN_ID, nativeOnChain } from 'constants/tokens' import { NATIVE_CHAIN_ID, nativeOnChain } from 'constants/tokens'
import { checkWarning } from 'constants/tokenSafety' import { checkWarning } from 'constants/tokenSafety'
import { useWidgetRemovalEnabled } from 'featureFlags/flags/removeWidgetTdp'
import { TokenPriceQuery } from 'graphql/data/__generated__/types-and-hooks' import { TokenPriceQuery } from 'graphql/data/__generated__/types-and-hooks'
import { Chain, TokenQuery, TokenQueryData } from 'graphql/data/Token' import { Chain, TokenQuery, TokenQueryData } from 'graphql/data/Token'
import { QueryToken } from 'graphql/data/Token' import { QueryToken } from 'graphql/data/Token'
...@@ -34,11 +35,15 @@ import { useIsUserAddedTokenOnChain } from 'hooks/Tokens' ...@@ -34,11 +35,15 @@ import { useIsUserAddedTokenOnChain } from 'hooks/Tokens'
import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch' import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch'
import { UNKNOWN_TOKEN_SYMBOL, useTokenFromActiveNetwork } from 'lib/hooks/useCurrency' import { UNKNOWN_TOKEN_SYMBOL, useTokenFromActiveNetwork } from 'lib/hooks/useCurrency'
import { getTokenAddress } from 'lib/utils/analytics' import { getTokenAddress } from 'lib/utils/analytics'
import { Swap } from 'pages/Swap'
import { useCallback, useMemo, useState, useTransition } from 'react' import { useCallback, useMemo, useState, useTransition } from 'react'
import { ArrowLeft } from 'react-feather' import { ArrowLeft } from 'react-feather'
import { useNavigate } from 'react-router-dom' 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 styled from 'styled-components/macro'
import { isAddress } from 'utils' import { isAddress } from 'utils'
import { addressesAreEquivalent } from 'utils/addressesAreEquivalent'
import { OnChangeTimePeriod } from './ChartSection' import { OnChangeTimePeriod } from './ChartSection'
import InvalidTokenDetails from './InvalidTokenDetails' import InvalidTokenDetails from './InvalidTokenDetails'
...@@ -111,6 +116,7 @@ export default function TokenDetails({ ...@@ -111,6 +116,7 @@ export default function TokenDetails({
[urlAddress] [urlAddress]
) )
const { chainId: connectedChainId } = useWeb3React()
const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain] const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain]
const tokenQueryData = tokenQuery.token const tokenQueryData = tokenQuery.token
...@@ -124,11 +130,12 @@ export default function TokenDetails({ ...@@ -124,11 +130,12 @@ export default function TokenDetails({
) )
const { token: detailedToken, didFetchFromChain } = useRelevantToken(address, pageChainId, tokenQueryData) 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 tokenWarning = address ? checkWarning(address) : null
const isBlockedToken = tokenWarning?.canProceed === false const isBlockedToken = tokenWarning?.canProceed === false
const navigate = useNavigate() const navigate = useNavigate()
const widgetRemovalEnabled = useWidgetRemovalEnabled()
// Wrapping navigate in a transition prevents Suspense from unnecessarily showing fallbacks again. // Wrapping navigate in a transition prevents Suspense from unnecessarily showing fallbacks again.
const [isPending, startTokenTransition] = useTransition() const [isPending, startTokenTransition] = useTransition()
...@@ -145,7 +152,6 @@ export default function TokenDetails({ ...@@ -145,7 +152,6 @@ export default function TokenDetails({
[address, crossChainMap, didFetchFromChain, navigate, detailedToken?.isNative] [address, crossChainMap, didFetchFromChain, navigate, detailedToken?.isNative]
) )
useOnGlobalChainSwitch(navigateToTokenForChain) useOnGlobalChainSwitch(navigateToTokenForChain)
const navigateToWidgetSelectedToken = useCallback( const navigateToWidgetSelectedToken = useCallback(
(tokens: SwapTokens) => { (tokens: SwapTokens) => {
const newDefaultToken = tokens[Field.OUTPUT] ?? tokens.default const newDefaultToken = tokens[Field.OUTPUT] ?? tokens.default
...@@ -163,11 +169,39 @@ export default function TokenDetails({ ...@@ -163,11 +169,39 @@ export default function TokenDetails({
[chain, navigate] [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 [continueSwap, setContinueSwap] = useState<{ resolve: (value: boolean | PromiseLike<boolean>) => void }>()
const [openTokenSafetyModal, setOpenTokenSafetyModal] = useState(false) 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 shouldShowSpeedbump = !useIsUserAddedTokenOnChain(address, pageChainId) && tokenWarning !== null
const onReviewSwapClick = useCallback( const onReviewSwapClick = useCallback(
() => new Promise<boolean>((resolve) => (shouldShowSpeedbump ? setContinueSwap({ resolve }) : resolve(true))), () => new Promise<boolean>((resolve) => (shouldShowSpeedbump ? setContinueSwap({ resolve }) : resolve(true))),
...@@ -234,14 +268,26 @@ export default function TokenDetails({ ...@@ -234,14 +268,26 @@ export default function TokenDetails({
<RightPanel onClick={() => isBlockedToken && setOpenTokenSafetyModal(true)}> <RightPanel onClick={() => isBlockedToken && setOpenTokenSafetyModal(true)}>
<div style={{ pointerEvents: isBlockedToken ? 'none' : 'auto' }}> <div style={{ pointerEvents: isBlockedToken ? 'none' : 'auto' }}>
{widgetRemovalEnabled ? (
<Swap
chainId={pageChainId}
prefilledState={{
[Field.INPUT]: { currencyId: inputTokenAddress },
[Field.OUTPUT]: { currencyId: address === NATIVE_CHAIN_ID ? 'ETH' : address },
}}
onCurrencyChange={handleCurrencyChange}
disableTokenInputs={pageChainId !== connectedChainId}
/>
) : (
<Widget <Widget
defaultTokens={{ defaultTokens={{
[Field.INPUT]: inputToken ?? undefined, [Field.INPUT]: widgetInputToken ?? undefined,
default: detailedToken ?? undefined, default: detailedToken ?? undefined,
}} }}
onDefaultTokenChange={navigateToWidgetSelectedToken} onDefaultTokenChange={navigateToWidgetSelectedToken}
onReviewSwapClick={onReviewSwapClick} onReviewSwapClick={onReviewSwapClick}
/> />
)}
</div> </div>
{tokenWarning && <TokenSafetyMessage tokenAddress={address} warning={tokenWarning} />} {tokenWarning && <TokenSafetyMessage tokenAddress={address} warning={tokenWarning} />}
{detailedToken && <BalanceSummary token={detailedToken} />} {detailedToken && <BalanceSummary token={detailedToken} />}
......
...@@ -51,6 +51,8 @@ interface WidgetProps { ...@@ -51,6 +51,8 @@ interface WidgetProps {
onReviewSwapClick?: OnReviewSwapClick 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({ export default function Widget({
defaultTokens, defaultTokens,
width = DEFAULT_WIDGET_WIDTH, width = DEFAULT_WIDGET_WIDTH,
......
...@@ -53,7 +53,7 @@ export function AdvancedSwapDetails({ ...@@ -53,7 +53,7 @@ export function AdvancedSwapDetails({
}: AdvancedSwapDetailsProps) { }: AdvancedSwapDetailsProps) {
const theme = useTheme() const theme = useTheme()
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const { expectedOutputAmount, priceImpact } = useMemo(() => { const { expectedOutputAmount, priceImpact } = useMemo(() => {
return { return {
......
...@@ -515,6 +515,13 @@ export function nativeOnChain(chainId: number): NativeCurrency | Token { ...@@ -515,6 +515,13 @@ export function nativeOnChain(chainId: number): NativeCurrency | Token {
return (cachedNativeCurrency[chainId] = nativeCurrency) 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 } } = { export const TOKEN_SHORTHANDS: { [shorthand: string]: { [chainId in SupportedChainId]?: string } } = {
USDC: { USDC: {
[SupportedChainId.MAINNET]: USDC_MAINNET.address, [SupportedChainId.MAINNET]: USDC_MAINNET.address,
......
...@@ -8,4 +8,5 @@ export enum FeatureFlag { ...@@ -8,4 +8,5 @@ export enum FeatureFlag {
swapWidget = 'swap_widget_replacement_enabled', swapWidget = 'swap_widget_replacement_enabled',
statsigDummy = 'web_dummy_gate_amplitude_id', statsigDummy = 'web_dummy_gate_amplitude_id',
detailsV2 = 'details_v2', 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' ...@@ -13,9 +13,10 @@ import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
import { useUserAddedTokens, useUserAddedTokensOnChain } from '../state/user/hooks' import { useUserAddedTokens, useUserAddedTokensOnChain } from '../state/user/hooks'
import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/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 // reduce token map into standard address <-> Token mapping, optionally include user added tokens
function useTokensFromMap(tokenMap: TokenAddressMap): { [address: string]: Token } { function useTokensFromMap(tokenMap: TokenAddressMap, chainId: Maybe<SupportedChainId>): { [address: string]: Token } {
const { chainId } = useWeb3React()
return useMemo(() => { return useMemo(() => {
if (!chainId) return {} if (!chainId) return {}
...@@ -32,9 +33,9 @@ export function useAllTokensMultichain(): TokenAddressMap { ...@@ -32,9 +33,9 @@ export function useAllTokensMultichain(): TokenAddressMap {
} }
// Returns all tokens from the default list + user added tokens // 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 defaultListTokens = useCombinedActiveList()
const tokensFromMap = useTokensFromMap(defaultListTokens) const tokensFromMap = useTokensFromMap(defaultListTokens, chainId)
const userAddedTokens = useUserAddedTokens() const userAddedTokens = useUserAddedTokens()
return useMemo(() => { return useMemo(() => {
return ( return (
...@@ -66,7 +67,7 @@ export function useUnsupportedTokens(): { [address: string]: Token } { ...@@ -66,7 +67,7 @@ export function useUnsupportedTokens(): { [address: string]: Token } {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const listsByUrl = useAllLists() const listsByUrl = useAllLists()
const unsupportedTokensMap = useUnsupportedTokenList() 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 // checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => { const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
...@@ -110,7 +111,7 @@ export function useSearchInactiveTokenLists(search: string | undefined, minResul ...@@ -110,7 +111,7 @@ export function useSearchInactiveTokenLists(search: string | undefined, minResul
const lists = useAllLists() const lists = useAllLists()
const inactiveUrls = DEFAULT_INACTIVE_LIST_URLS const inactiveUrls = DEFAULT_INACTIVE_LIST_URLS
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const activeTokens = useDefaultActiveTokens() const activeTokens = useDefaultActiveTokens(chainId)
return useMemo(() => { return useMemo(() => {
if (!search || search.trim().length === 0) return [] if (!search || search.trim().length === 0) return []
const tokenFilter = getTokenFilter(search) const tokenFilter = getTokenFilter(search)
...@@ -167,11 +168,13 @@ export function useIsUserAddedTokenOnChain( ...@@ -167,11 +168,13 @@ export function useIsUserAddedTokenOnChain(
// null if loading or null was passed // null if loading or null was passed
// otherwise returns the token // otherwise returns the token
export function useToken(tokenAddress?: string | null): Token | null | undefined { export function useToken(tokenAddress?: string | null): Token | null | undefined {
const tokens = useDefaultActiveTokens() const { chainId } = useWeb3React()
const tokens = useDefaultActiveTokens(chainId)
return useTokenFromMapOrNetwork(tokens, tokenAddress) return useTokenFromMapOrNetwork(tokens, tokenAddress)
} }
export function useCurrency(currencyId?: string | null): Currency | null | undefined { export function useCurrency(currencyId: Maybe<string>, chainId?: SupportedChainId): Currency | null | undefined {
const tokens = useDefaultActiveTokens() const { chainId: connectedChainId } = useWeb3React()
return useCurrencyFromMap(tokens, currencyId) const tokens = useDefaultActiveTokens(chainId ?? connectedChainId)
return useCurrencyFromMap(tokens, chainId ?? connectedChainId, currencyId)
} }
...@@ -81,7 +81,7 @@ export default function useAutoSlippageTolerance( ...@@ -81,7 +81,7 @@ export default function useAutoSlippageTolerance(
const nativeGasPrice = useGasPrice() const nativeGasPrice = useGasPrice()
const gasEstimate = guesstimateGas(trade) const gasEstimate = guesstimateGas(trade)
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const nativeCurrencyPrice = useStablecoinPrice((trade && nativeCurrency) ?? undefined) const nativeCurrencyPrice = useStablecoinPrice((trade && nativeCurrency) ?? undefined)
return useMemo(() => { return useMemo(() => {
......
import { Token } from '@uniswap/sdk-core' import { Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useMemo } from 'react' import { useMemo } from 'react'
import { PositionDetails } from 'types/position' import { PositionDetails } from 'types/position'
import { hasURL } from 'utils/urlChecks' import { hasURL } from 'utils/urlChecks'
...@@ -23,7 +24,8 @@ function getUniqueAddressesFromPositions(positions: PositionDetails[]): string[] ...@@ -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 * 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[] { export function useFilterPossiblyMaliciousPositions(positions: PositionDetails[]): PositionDetails[] {
const activeTokensList = useDefaultActiveTokens() const { chainId } = useWeb3React()
const activeTokensList = useDefaultActiveTokens(chainId)
const nonListPositionTokenAddresses = useMemo( const nonListPositionTokenAddresses = useMemo(
() => getUniqueAddressesFromPositions(positions).filter((address) => !activeTokensList[address]), () => getUniqueAddressesFromPositions(positions).filter((address) => !activeTokensList[address]),
......
...@@ -31,7 +31,8 @@ enum WrapInputError { ...@@ -31,7 +31,8 @@ enum WrapInputError {
} }
export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputError }) { export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputError }) {
const native = useNativeCurrency() const { chainId } = useWeb3React()
const native = useNativeCurrency(chainId)
const wrapped = native?.wrapped const wrapped = native?.wrapped
switch (wrapInputError) { switch (wrapInputError) {
......
...@@ -2,7 +2,7 @@ import { arrayify } from '@ethersproject/bytes' ...@@ -2,7 +2,7 @@ import { arrayify } from '@ethersproject/bytes'
import { parseBytes32String } from '@ethersproject/strings' import { parseBytes32String } from '@ethersproject/strings'
import { Currency, Token } from '@uniswap/sdk-core' import { Currency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/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 { useBytes32TokenContract, useTokenContract } from 'hooks/useContract'
import { NEVER_RELOAD, useSingleCallResult } from 'lib/hooks/multicall' import { NEVER_RELOAD, useSingleCallResult } from 'lib/hooks/multicall'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
...@@ -92,9 +92,12 @@ export function useTokenFromMapOrNetwork(tokens: TokenMap, tokenAddress?: string ...@@ -92,9 +92,12 @@ export function useTokenFromMapOrNetwork(tokens: TokenMap, tokenAddress?: string
* Returns null if currency is loading or null was passed. * Returns null if currency is loading or null was passed.
* Returns undefined if currencyId is invalid or token does not exist. * Returns undefined if currencyId is invalid or token does not exist.
*/ */
export function useCurrencyFromMap(tokens: TokenMap, currencyId?: string | null): Currency | null | undefined { export function useCurrencyFromMap(
const nativeCurrency = useNativeCurrency() tokens: TokenMap,
const { chainId } = useWeb3React() chainId: SupportedChainId | undefined,
currencyId?: string | null
): Currency | null | undefined {
const nativeCurrency = useNativeCurrency(chainId)
const isNative = Boolean(nativeCurrency && currencyId?.toUpperCase() === 'ETH') const isNative = Boolean(nativeCurrency && currencyId?.toUpperCase() === 'ETH')
const shorthandMatchAddress = useMemo(() => { const shorthandMatchAddress = useMemo(() => {
const chain = supportedChainId(chainId) const chain = supportedChainId(chainId)
...@@ -108,6 +111,5 @@ export function useCurrencyFromMap(tokens: TokenMap, currencyId?: string | null) ...@@ -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 // this case so we use our builtin wrapped token instead of wrapped tokens on token lists
const wrappedNative = nativeCurrency?.wrapped const wrappedNative = nativeCurrency?.wrapped
if (wrappedNative?.address?.toUpperCase() === currencyId?.toUpperCase()) return wrappedNative if (wrappedNative?.address?.toUpperCase() === currencyId?.toUpperCase()) return wrappedNative
return isNative ? nativeCurrency : token return isNative ? nativeCurrency : token
} }
import { NativeCurrency, Token } from '@uniswap/sdk-core' import { NativeCurrency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { SupportedChainId } from 'constants/chains' import { SupportedChainId } from 'constants/chains'
import { nativeOnChain } from 'constants/tokens' import { nativeOnChain } from 'constants/tokens'
import { useMemo } from 'react' import { useMemo } from 'react'
export default function useNativeCurrency(): NativeCurrency | Token { export default function useNativeCurrency(chainId: SupportedChainId | null | undefined): NativeCurrency | Token {
const { chainId } = useWeb3React()
return useMemo( return useMemo(
() => () =>
chainId chainId
......
...@@ -183,7 +183,7 @@ const EthValueWrapper = styled.span<{ totalEthListingValue: boolean }>` ...@@ -183,7 +183,7 @@ const EthValueWrapper = styled.span<{ totalEthListingValue: boolean }>`
export const ListPage = () => { export const ListPage = () => {
const { setProfilePageState: setSellPageState } = useProfilePageState() const { setProfilePageState: setSellPageState } = useProfilePageState()
const { provider } = useWeb3React() const { provider, chainId } = useWeb3React()
const isMobile = useIsMobile() const isMobile = useIsMobile()
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING }) const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
const { setGlobalMarketplaces, sellAssets, issues } = useSellAsset( const { setGlobalMarketplaces, sellAssets, issues } = useSellAsset(
...@@ -205,7 +205,7 @@ export const ListPage = () => { ...@@ -205,7 +205,7 @@ export const ListPage = () => {
) )
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets]) const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency) const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
const usdcValue = useStablecoinValue(parsedAmount) const usdcValue = useStablecoinValue(parsedAmount)
const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice) const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice)
......
...@@ -45,7 +45,7 @@ const ListModalWrapper = styled.div` ...@@ -45,7 +45,7 @@ const ListModalWrapper = styled.div`
` `
export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => { export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
const { provider } = useWeb3React() const { provider, chainId } = useWeb3React()
const signer = provider?.getSigner() const signer = provider?.getSigner()
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING }) const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
const sellAssets = useSellAsset((state) => state.sellAssets) const sellAssets = useSellAsset((state) => state.sellAssets)
...@@ -72,7 +72,7 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => { ...@@ -72,7 +72,7 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
(s) => (s === Section.APPROVE ? Section.SIGN : Section.APPROVE), (s) => (s === Section.APPROVE ? Section.SIGN : Section.APPROVE),
Section.APPROVE Section.APPROVE
) )
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency) const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
const usdcValue = useStablecoinValue(parsedAmount) const usdcValue = useStablecoinValue(parsedAmount)
const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice) const usdcAmount = formatCurrencyAmount(usdcValue, NumberType.FiatTokenPrice)
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format' import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format'
import { useWeb3React } from '@web3-react/core'
import Column from 'components/Column' import Column from 'components/Column'
import { ScrollBarStyles } from 'components/Common' import { ScrollBarStyles } from 'components/Common'
import Row from 'components/Row' import Row from 'components/Row'
...@@ -76,7 +77,8 @@ const TweetRow = styled(Row)` ...@@ -76,7 +77,8 @@ const TweetRow = styled(Row)`
export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => { export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => {
const theme = useTheme() const theme = useTheme()
const sellAssets = useSellAsset((state) => state.sellAssets) const sellAssets = useSellAsset((state) => state.sellAssets)
const nativeCurrency = useNativeCurrency() const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency(chainId)
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets]) const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency) const parsedAmount = tryParseCurrencyAmount(totalEthListingValue.toString(), nativeCurrency)
......
...@@ -403,7 +403,7 @@ function PositionPageContent() { ...@@ -403,7 +403,7 @@ function PositionPageContent() {
// flag for receiving WETH // flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false) const [receiveWETH, setReceiveWETH] = useState(false)
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const nativeWrappedSymbol = nativeCurrency.wrapped.symbol const nativeWrappedSymbol = nativeCurrency.wrapped.symbol
// construct Position from details returned // construct Position from details returned
......
...@@ -74,7 +74,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) { ...@@ -74,7 +74,7 @@ function Remove({ tokenId }: { tokenId: BigNumber }) {
// flag for receiving WETH // flag for receiving WETH
const [receiveWETH, setReceiveWETH] = useState(false) const [receiveWETH, setReceiveWETH] = useState(false)
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency(chainId)
const nativeWrappedSymbol = nativeCurrency.wrapped.symbol const nativeWrappedSymbol = nativeCurrency.wrapped.symbol
// burn state // burn state
......
This diff is collapsed.
...@@ -16,8 +16,8 @@ export { ...@@ -16,8 +16,8 @@ export {
// mimics useAllBalances // mimics useAllBalances
export function useAllTokenBalances(): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] { export function useAllTokenBalances(): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] {
const { account } = useWeb3React() const { account, chainId } = useWeb3React()
const allTokens = useDefaultActiveTokens() const allTokens = useDefaultActiveTokens(chainId)
const allTokensArray = useMemo(() => Object.values(allTokens ?? {}), [allTokens]) const allTokensArray = useMemo(() => Object.values(allTokens ?? {}), [allTokens])
const [balances, balancesIsLoading] = useTokenBalancesWithLoadingIndicator(account ?? undefined, allTokensArray) const [balances, balancesIsLoading] = useTokenBalancesWithLoadingIndicator(account ?? undefined, allTokensArray)
return [balances ?? {}, balancesIsLoading] return [balances ?? {}, balancesIsLoading]
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { SupportedChainId } from 'constants/chains'
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance' import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
import { useBestTrade } from 'hooks/useBestTrade' import { useBestTrade } from 'hooks/useBestTrade'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
...@@ -71,7 +72,10 @@ const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = { ...@@ -71,7 +72,10 @@ const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = {
} }
// from the current swap inputs, compute the best trade and return it. // 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 } currencies: { [field in Field]?: Currency | null }
currencyBalances: { [field in Field]?: CurrencyAmount<Currency> } currencyBalances: { [field in Field]?: CurrencyAmount<Currency> }
parsedAmount: CurrencyAmount<Currency> | undefined parsedAmount: CurrencyAmount<Currency> | undefined
...@@ -92,8 +96,8 @@ export function useDerivedSwapInfo(state: SwapState): { ...@@ -92,8 +96,8 @@ export function useDerivedSwapInfo(state: SwapState): {
recipient, recipient,
} = state } = state
const inputCurrency = useCurrency(inputCurrencyId) const inputCurrency = useCurrency(inputCurrencyId, chainId)
const outputCurrency = useCurrency(outputCurrencyId) const outputCurrency = useCurrency(outputCurrencyId, chainId)
const recipientLookup = useENS(recipient ?? undefined) const recipientLookup = useENS(recipient ?? undefined)
const to: string | null = (recipient === null ? account : recipientLookup.address) ?? null const to: string | null = (recipient === null ? account : recipientLookup.address) ?? null
......
...@@ -271,7 +271,7 @@ export function toV2LiquidityToken([tokenA, tokenB]: [Token, Token]): Token { ...@@ -271,7 +271,7 @@ export function toV2LiquidityToken([tokenA, tokenB]: [Token, Token]): Token {
*/ */
export function useTrackedTokenPairs(): [Token, Token][] { export function useTrackedTokenPairs(): [Token, Token][] {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const tokens = useDefaultActiveTokens() const tokens = useDefaultActiveTokens(chainId)
// pinned pairs // pinned pairs
const pinnedPairs = useMemo(() => (chainId ? PINNED_PAIRS[chainId] ?? [] : []), [chainId]) 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 if (!a || !b) return false
return a === b || a.toLowerCase() === b.toLowerCase() return a === b || a.toLowerCase() === b.toLowerCase()
} }
...@@ -4,7 +4,7 @@ import { SupportedChainId } from 'constants/chains' ...@@ -4,7 +4,7 @@ import { SupportedChainId } from 'constants/chains'
* Returns the input chain ID if chain is supported. If not, return undefined * 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 * @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) { if (typeof chainId === 'number' && chainId in SupportedChainId) {
return chainId 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