ci(release): publish latest release

parent aa949db3
IPFS hash of the deployment: IPFS hash of the deployment:
- CIDv0: `QmWqSfbLDY22q6duTWFocMGoy317SVW13YLpc1yrkrHoeJ` - CIDv0: `QmSx41VP5fQ6sZTMUmtCBn74MEsfmxA1Y7X6jNw7CLMJyx`
- CIDv1: `bafybeid6hw4k6jbgyrrwnqtzrgszxdpwotrphjy2nys4mssjakpzbsbztm` - CIDv1: `bafybeiceqbv4zz2qxq34hgptfzhv7bbtfzif2cdqnn4hpc23vsbcbn6w7m`
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org). The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
...@@ -10,15 +10,15 @@ You can also access the Uniswap Interface from an IPFS gateway. ...@@ -10,15 +10,15 @@ You can also access the Uniswap Interface from an IPFS gateway.
Your Uniswap settings are never remembered across different URLs. Your Uniswap settings are never remembered across different URLs.
IPFS gateways: IPFS gateways:
- https://bafybeid6hw4k6jbgyrrwnqtzrgszxdpwotrphjy2nys4mssjakpzbsbztm.ipfs.dweb.link/ - https://bafybeiceqbv4zz2qxq34hgptfzhv7bbtfzif2cdqnn4hpc23vsbcbn6w7m.ipfs.dweb.link/
- https://bafybeid6hw4k6jbgyrrwnqtzrgszxdpwotrphjy2nys4mssjakpzbsbztm.ipfs.cf-ipfs.com/ - https://bafybeiceqbv4zz2qxq34hgptfzhv7bbtfzif2cdqnn4hpc23vsbcbn6w7m.ipfs.cf-ipfs.com/
- [ipfs://QmWqSfbLDY22q6duTWFocMGoy317SVW13YLpc1yrkrHoeJ/](ipfs://QmWqSfbLDY22q6duTWFocMGoy317SVW13YLpc1yrkrHoeJ/) - [ipfs://QmSx41VP5fQ6sZTMUmtCBn74MEsfmxA1Y7X6jNw7CLMJyx/](ipfs://QmSx41VP5fQ6sZTMUmtCBn74MEsfmxA1Y7X6jNw7CLMJyx/)
## 5.35.0 (2024-06-13) ### 5.35.1 (2024-06-14)
### Features ### Bug Fixes
* **web:** Add ZKsync - prod (#9083) 90c6c69 * **web:** Revert 8059 fallback to gql (token balances) - prod (#9094) 8ce2c94
web/5.35.0 web/5.35.1
\ No newline at end of file \ No newline at end of file
import { SwapEventName } from '@uniswap/analytics-events' import { SwapEventName } from '@uniswap/analytics-events'
import { ChainId } from '@uniswap/sdk-core' import { ChainId } from '@uniswap/sdk-core'
import { FeatureFlags } from 'uniswap/src/features/gating/flags'
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens' import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
import { getBalance, getTestSelector } from '../../utils' import { getBalance, getTestSelector } from '../../utils'
...@@ -101,22 +100,5 @@ describe('Swap', () => { ...@@ -101,22 +100,5 @@ describe('Swap', () => {
getBalance(USDC_MAINNET).should('eq', finalBalance) getBalance(USDC_MAINNET).should('eq', finalBalance)
}) })
}) })
describe('multichain balances', () => {
it('shows balances for disconnected chains', () => {
cy.hardhat().then((hardhat) => {
cy.visit('/swap', {
featureFlags: [{ flag: FeatureFlags.MultichainUX, value: true }],
})
cy.get('#swap-currency-input .open-currency-select-button').click()
cy.get(getTestSelector('chain-selector')).last().click()
cy.contains('Arbitrum').click()
const sendSpy = cy.spy(hardhat.provider, 'send')
cy.wrap(sendSpy).should('not.be.calledWith', 'wallet_switchEthereumChain')
cy.get(getTestSelector('common-base-USDC')).click()
cy.get('#swap-currency-input').contains(`Balance: 0.002`)
})
})
})
}) })
}) })
...@@ -272,7 +272,7 @@ const SwapCurrencyInputPanel = forwardRef<HTMLInputElement, SwapCurrencyInputPan ...@@ -272,7 +272,7 @@ const SwapCurrencyInputPanel = forwardRef<HTMLInputElement, SwapCurrencyInputPan
const account = useAccount() const account = useAccount()
const { chainId } = useSwapAndLimitContext() const { chainId } = useSwapAndLimitContext()
const chainAllowed = useIsSupportedChainId(chainId) const chainAllowed = useIsSupportedChainId(chainId)
const selectedCurrencyBalance = useCurrencyBalance(account.address, currency ?? undefined, chainId) const selectedCurrencyBalance = useCurrencyBalance(account.address, currency ?? undefined)
const theme = useTheme() const theme = useTheme()
const { formatCurrencyAmount } = useFormatter() const { formatCurrencyAmount } = useFormatter()
......
...@@ -92,7 +92,7 @@ it('renders currency rows correctly with balances', () => { ...@@ -92,7 +92,7 @@ it('renders currency rows correctly with balances', () => {
isAddressSearch="" isAddressSearch=""
showCurrencyAmount showCurrencyAmount
balances={{ balances={{
[`1-${DAI.address.toLowerCase()}`]: { usdValue: 2, balance: 2 }, [DAI.address.toLowerCase()]: { usdValue: 2, balance: 2 },
}} }}
/> />
) )
......
...@@ -15,7 +15,6 @@ import { ThemedText } from 'theme/components' ...@@ -15,7 +15,6 @@ import { ThemedText } from 'theme/components'
import Trace from 'uniswap/src/features/telemetry/Trace' import Trace from 'uniswap/src/features/telemetry/Trace'
import { WalletEventName } from 'uniswap/src/features/telemetry/constants' import { WalletEventName } from 'uniswap/src/features/telemetry/constants'
import { shortenAddress } from 'utilities/src/addresses' import { shortenAddress } from 'utilities/src/addresses'
import { currencyKey } from 'utils/currencyKey'
import { NumberType, useFormatter } from 'utils/formatNumbers' import { NumberType, useFormatter } from 'utils/formatNumbers'
import { useIsUserAddedToken } from '../../../hooks/Tokens' import { useIsUserAddedToken } from '../../../hooks/Tokens'
import { TokenFromList } from '../../../state/lists/tokenFromList' import { TokenFromList } from '../../../state/lists/tokenFromList'
...@@ -26,16 +25,16 @@ import { MouseoverTooltip, TooltipSize } from '../../Tooltip' ...@@ -26,16 +25,16 @@ import { MouseoverTooltip, TooltipSize } from '../../Tooltip'
import { LoadingRows, MenuItem } from '../styled' import { LoadingRows, MenuItem } from '../styled'
import { scrollbarStyle } from './index.css' import { scrollbarStyle } from './index.css'
function currencyListRowKey(data: Currency | CurrencyListRow): string { function currencyKey(data: Currency | CurrencyListRow): string {
if (data instanceof CurrencyListSectionTitle) { if (data instanceof CurrencyListSectionTitle) {
return data.label return data.label
} }
if (data instanceof CurrencyListRow) { if (data instanceof CurrencyListRow) {
return currencyKey(data.currency!) return data.currency?.isToken ? data.currency.address : 'ETHER'
} }
return currencyKey(data) return data.isToken ? data.address : 'ETHER'
} }
const ROW_ITEM_SIZE = 56 const ROW_ITEM_SIZE = 56
...@@ -156,7 +155,7 @@ export function CurrencyRow({ ...@@ -156,7 +155,7 @@ export function CurrencyRow({
showAddress?: boolean showAddress?: boolean
}) { }) {
const account = useAccount() const account = useAccount()
const key = currencyListRowKey(currency) const key = currencyKey(currency)
const customAdded = useIsUserAddedToken(currency) const customAdded = useIsUserAddedToken(currency)
const warning = useTokenWarning(currency?.isNative ? undefined : currency?.address, currency.chainId) const warning = useTokenWarning(currency?.isNative ? undefined : currency?.address, currency.chainId)
const isBlockedToken = !!warning && !warning.canProceed const isBlockedToken = !!warning && !warning.canProceed
...@@ -327,11 +326,12 @@ export default function CurrencyList({ ...@@ -327,11 +326,12 @@ export default function CurrencyList({
} }
const currency: Currency = row.currency const currency: Currency = row.currency
const key = currencyKey(currency)
const balance = const balance =
tryParseCurrencyAmount(String(balances[key]?.balance ?? 0), currency) ?? tryParseCurrencyAmount(
CurrencyAmount.fromRawAmount(currency, 0) String(balances[currency.isNative ? 'ETH' : currency.address?.toLowerCase()]?.balance ?? 0),
currency
) ?? CurrencyAmount.fromRawAmount(currency, 0)
const isSelected = Boolean(currency && selectedCurrency && selectedCurrency.equals(currency)) const isSelected = Boolean(currency && selectedCurrency && selectedCurrency.equals(currency))
const otherSelected = Boolean(currency && otherCurrency && otherCurrency.equals(currency)) const otherSelected = Boolean(currency && otherCurrency && otherCurrency.equals(currency))
...@@ -375,7 +375,7 @@ export default function CurrencyList({ ...@@ -375,7 +375,7 @@ export default function CurrencyList({
const itemKey = useCallback((index: number, data: typeof currencies) => { const itemKey = useCallback((index: number, data: typeof currencies) => {
const currency = data[index] const currency = data[index]
return currencyListRowKey(currency) return currencyKey(currency)
}, []) }, [])
return ( return (
......
...@@ -21,7 +21,6 @@ import { isAddress } from 'utilities/src/addresses' ...@@ -21,7 +21,6 @@ import { isAddress } from 'utilities/src/addresses'
import { useAccount } from 'hooks/useAccount' import { useAccount } from 'hooks/useAccount'
import { useSwapAndLimitContext } from 'state/swap/hooks' import { useSwapAndLimitContext } from 'state/swap/hooks'
import { currencyKey } from 'utils/currencyKey'
import Column from '../Column' import Column from '../Column'
import Row, { RowBetween } from '../Row' import Row, { RowBetween } from '../Row'
import CommonBases from './CommonBases' import CommonBases from './CommonBases'
...@@ -225,8 +224,12 @@ export function CurrencySearch({ ...@@ -225,8 +224,12 @@ export function CurrencySearch({
isAddressSearch isAddressSearch
)} )}
balance={ balance={
tryParseCurrencyAmount(String(balanceMap[currencyKey(searchCurrency)]?.balance ?? 0), searchCurrency) ?? tryParseCurrencyAmount(
CurrencyAmount.fromRawAmount(searchCurrency, 0) String(
balanceMap[searchCurrency.isNative ? 'ETH' : searchCurrency.address?.toLowerCase()]?.balance ?? 0
),
searchCurrency
) ?? CurrencyAmount.fromRawAmount(searchCurrency, 0)
} }
/> />
</Column> </Column>
......
...@@ -21,7 +21,6 @@ import { ...@@ -21,7 +21,6 @@ import {
useTopTokensQuery, useTopTokensQuery,
} from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import { isSameAddress } from 'utilities/src/addresses' import { isSameAddress } from 'utilities/src/addresses'
import { currencyKey } from 'utils/currencyKey'
interface CurrencySearchParams { interface CurrencySearchParams {
searchQuery?: string searchQuery?: string
...@@ -141,8 +140,11 @@ export function useCurrencySearchResults({ ...@@ -141,8 +140,11 @@ export function useCurrencySearchResults({
// Filter out tokens with balances so they aren't duplicated when we merge below. // Filter out tokens with balances so they aren't duplicated when we merge below.
const filteredListTokens = fullBaseList.filter((token) => { const filteredListTokens = fullBaseList.filter((token) => {
const key = currencyKey(token) if (token.isNative) {
return !(key in balanceMap) return !((token.symbol ?? 'ETH') in balanceMap)
} else {
return !(token.address?.toLowerCase() in balanceMap)
}
}) })
if (balancesLoading) { if (balancesLoading) {
...@@ -162,13 +164,12 @@ export function useCurrencySearchResults({ ...@@ -162,13 +164,12 @@ export function useCurrencySearchResults({
// This is where we apply extra filtering based on the callsite's // This is where we apply extra filtering based on the callsite's
// customization, on top of the basic searchQuery filtering. // customization, on top of the basic searchQuery filtering.
const currencyFilter = (currency: Currency) => { const currencyFilter = (currency: Currency) => {
const key = currencyKey(currency)
if (filters?.onlyShowCurrenciesWithBalance) { if (filters?.onlyShowCurrenciesWithBalance) {
if (currency.isNative) { if (currency.isNative) {
return balanceMap[key]?.usdValue > 0 return balanceMap[currency.symbol ?? 'ETH']?.usdValue > 0
} }
return balanceMap[key]?.usdValue > 0 return balanceMap[currency.address?.toLowerCase()]?.usdValue > 0
} }
if (currency.isNative && filters?.disableNonToken) { if (currency.isNative && filters?.disableNonToken) {
...@@ -180,7 +181,7 @@ export function useCurrencySearchResults({ ...@@ -180,7 +181,7 @@ export function useCurrencySearchResults({
if (selectedCurrency?.equals(currency) || otherSelectedCurrency?.equals(currency)) { if (selectedCurrency?.equals(currency) || otherSelectedCurrency?.equals(currency)) {
return true return true
} }
return balanceMap[key]?.usdValue > 0 return balanceMap[currency.address.toLowerCase()]?.usdValue > 0
} }
return true return true
......
...@@ -5,13 +5,12 @@ import { ReactNode, useState } from 'react' ...@@ -5,13 +5,12 @@ import { ReactNode, useState } from 'react'
import { X } from 'react-feather' import { X } from 'react-feather'
import styled from 'styled-components' import styled from 'styled-components'
import { ThemedText } from 'theme/components' import { ThemedText } from 'theme/components'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
import { useTokenBalance } from 'lib/hooks/useCurrencyBalance'
import { Text } from 'ui/src' import { Text } from 'ui/src'
import { logger } from 'utilities/src/logger/logger' import { logger } from 'utilities/src/logger/logger'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
import { UNI } from '../../constants/tokens' import { UNI } from '../../constants/tokens'
import useENS from '../../hooks/useENS' import useENS from '../../hooks/useENS'
import { useTokenBalance } from '../../state/connection/hooks'
import { useDelegateCallback } from '../../state/governance/hooks' import { useDelegateCallback } from '../../state/governance/hooks'
import AddressInputPanel from '../AddressInputPanel' import AddressInputPanel from '../AddressInputPanel'
import { ButtonPrimary } from '../Button' import { ButtonPrimary } from '../Button'
......
import { ChainId, SOCKS_CONTROLLER_ADDRESSES, Token } from '@uniswap/sdk-core' import { ChainId, SOCKS_CONTROLLER_ADDRESSES, Token } from '@uniswap/sdk-core'
import { useAccount } from 'hooks/useAccount' import { useAccount } from 'hooks/useAccount'
import { useTokenBalance } from 'lib/hooks/useCurrencyBalance'
import { useMemo } from 'react' import { useMemo } from 'react'
import { useTokenBalance } from 'state/connection/hooks'
// technically a 721, not an ERC20, but suffices for our purposes // technically a 721, not an ERC20, but suffices for our purposes
const SOCKS = new Token(ChainId.MAINNET, SOCKS_CONTROLLER_ADDRESSES[ChainId.MAINNET], 0) const SOCKS = new Token(ChainId.MAINNET, SOCKS_CONTROLLER_ADDRESSES[ChainId.MAINNET], 0)
......
...@@ -67,11 +67,11 @@ describe('useTokenBalances', () => { ...@@ -67,11 +67,11 @@ describe('useTokenBalances', () => {
} as any) } as any)
const { balanceMap, loading } = renderHook(() => useTokenBalances()).result.current const { balanceMap, loading } = renderHook(() => useTokenBalances()).result.current
expect(balanceMap).toEqual({ expect(balanceMap).toEqual({
'1-0x123': { '0x123': {
balance: 123, balance: 123,
usdValue: 123, usdValue: 123,
}, },
'1-native': { ETH: {
balance: 123, balance: 123,
usdValue: 123, usdValue: 123,
}, },
......
import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider' import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider'
import { supportedChainIdFromGQLChain } from 'graphql/data/util'
import { useAccount } from 'hooks/useAccount'
import { TokenBalances } from 'lib/hooks/useTokenList/sorting' import { TokenBalances } from 'lib/hooks/useTokenList/sorting'
import { useMemo } from 'react' import { useMemo } from 'react'
import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import { currencyKeyFromGraphQL } from 'utils/currencyKey'
/** export function useTokenBalances(): {
* Returns the user's token balances via graphql as a map and list.
*/
export function useTokenBalances({ cacheOnly }: { cacheOnly?: boolean } = {}): {
balanceMap: TokenBalances balanceMap: TokenBalances
balanceList: readonly (PortfolioTokenBalancePartsFragment | undefined)[] balanceList: readonly (PortfolioTokenBalancePartsFragment | undefined)[]
loading: boolean loading: boolean
} { } {
const { data, loading } = useTokenBalancesQuery({ cacheOnly }) const { chainId } = useAccount()
const { data, loading } = useTokenBalancesQuery()
return useMemo(() => { return useMemo(() => {
const balanceList = data?.portfolios?.[0]?.tokenBalances ?? [] const balanceList = data?.portfolios?.[0]?.tokenBalances ?? []
const balanceMap = const balanceMap =
balanceList?.reduce((balanceMap, tokenBalance) => { balanceList?.reduce((balanceMap, tokenBalance) => {
if (!tokenBalance?.token) { const address =
return balanceMap tokenBalance?.token?.standard === 'ERC20'
} ? tokenBalance.token?.address?.toLowerCase()
: tokenBalance?.token?.symbol ?? 'ETH'
const key = currencyKeyFromGraphQL({ if (
address: tokenBalance.token.address, tokenBalance?.token?.chain &&
chain: tokenBalance.token.chain, supportedChainIdFromGQLChain(tokenBalance.token?.chain) === chainId &&
standard: tokenBalance.token.standard, address
}) ) {
if (tokenBalance.denominatedValue?.value !== undefined) { const usdValue = tokenBalance.denominatedValue?.value ?? 0
const usdValue = tokenBalance.denominatedValue?.value const balance = tokenBalance.quantity ?? 0
const balance = tokenBalance.quantity balanceMap[address] = { usdValue, balance }
balanceMap[key] = { usdValue, balance: balance ?? 0 }
} }
return balanceMap return balanceMap
}, {} as TokenBalances) ?? {} }, {} as TokenBalances) ?? {}
return { balanceMap, balanceList, loading } return { balanceMap, balanceList, loading }
}, [data?.portfolios, loading]) }, [chainId, data?.portfolios, loading])
} }
import { Interface } from '@ethersproject/abi'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useMemo } from 'react'
import { useTokenBalances } from 'hooks/useTokenBalances'
import { currencyKey } from 'utils/currencyKey'
import { Interface } from '@ethersproject/abi'
import { useMultipleContractSingleData, useSingleContractMultipleData } from 'lib/hooks/multicall' import { useMultipleContractSingleData, useSingleContractMultipleData } from 'lib/hooks/multicall'
import { useMemo } from 'react'
import ERC20ABI from 'uniswap/src/abis/erc20.json' import ERC20ABI from 'uniswap/src/abis/erc20.json'
import { Erc20Interface } from 'uniswap/src/abis/types/Erc20' import { Erc20Interface } from 'uniswap/src/abis/types/Erc20'
...@@ -18,7 +14,7 @@ import { useInterfaceMulticall } from '../../hooks/useContract' ...@@ -18,7 +14,7 @@ import { useInterfaceMulticall } from '../../hooks/useContract'
/** /**
* Returns a map of the given addresses to their eventually consistent ETH balances. * Returns a map of the given addresses to their eventually consistent ETH balances.
*/ */
function useNativeCurrencyBalances(uncheckedAddresses?: (string | undefined)[]): { export function useNativeCurrencyBalances(uncheckedAddresses?: (string | undefined)[]): {
[address: string]: CurrencyAmount<Currency> | undefined [address: string]: CurrencyAmount<Currency> | undefined
} { } {
const { chainId } = useAccount() const { chainId } = useAccount()
...@@ -57,18 +53,14 @@ const tokenBalancesGasRequirement = { gasRequired: 185_000 } ...@@ -57,18 +53,14 @@ const tokenBalancesGasRequirement = { gasRequired: 185_000 }
/** /**
* Returns a map of token addresses to their eventually consistent token balances for a single account. * Returns a map of token addresses to their eventually consistent token balances for a single account.
*/ */
export function useRpcTokenBalancesWithLoadingIndicator( export function useTokenBalancesWithLoadingIndicator(
address?: string, address?: string,
tokens?: (Token | undefined)[], tokens?: (Token | undefined)[]
skip?: boolean
): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] { ): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] {
const { chainId } = useAccount() const { chainId } = useAccount()
const validatedTokens: Token[] = useMemo( const validatedTokens: Token[] = useMemo(
() => () => tokens?.filter((t?: Token): t is Token => isAddress(t?.address) !== false && t?.chainId === chainId) ?? [],
skip [chainId, tokens]
? []
: tokens?.filter((t?: Token): t is Token => isAddress(t?.address) !== false && t?.chainId === chainId) ?? [],
[chainId, tokens, skip]
) )
const validatedTokenAddresses = useMemo(() => validatedTokens.map((vt) => vt.address), [validatedTokens]) const validatedTokenAddresses = useMemo(() => validatedTokens.map((vt) => vt.address), [validatedTokens])
...@@ -100,14 +92,30 @@ export function useRpcTokenBalancesWithLoadingIndicator( ...@@ -100,14 +92,30 @@ export function useRpcTokenBalancesWithLoadingIndicator(
) )
} }
function useRpcTokenBalances( export function useTokenBalances(
address?: string, address?: string,
tokens?: (Token | undefined)[] tokens?: (Token | undefined)[]
): { [tokenAddress: string]: CurrencyAmount<Token> | undefined } { ): { [tokenAddress: string]: CurrencyAmount<Token> | undefined } {
return useRpcTokenBalancesWithLoadingIndicator(address, tokens)[0] return useTokenBalancesWithLoadingIndicator(address, tokens)[0]
}
// get the balance for a single token/account combo
export function useTokenBalance(account?: string, token?: Token): CurrencyAmount<Token> | undefined {
const tokenBalances = useTokenBalances(
account,
useMemo(() => [token], [token])
)
if (!token) {
return undefined
}
return tokenBalances[token.address]
} }
function useRpcCurrencyBalances( /**
* Returns balances for tokens on currently-connected chainId via RPC.
* See useTokenBalancesQuery for multichain portfolio balances via GQL.
*/
export function useCurrencyBalances(
account?: string, account?: string,
currencies?: (Currency | undefined)[] currencies?: (Currency | undefined)[]
): (CurrencyAmount<Currency> | undefined)[] { ): (CurrencyAmount<Currency> | undefined)[] {
...@@ -117,7 +125,7 @@ function useRpcCurrencyBalances( ...@@ -117,7 +125,7 @@ function useRpcCurrencyBalances(
) )
const { chainId } = useAccount() const { chainId } = useAccount()
const tokenBalances = useRpcTokenBalances(account, tokens) const tokenBalances = useTokenBalances(account, tokens)
const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies]) const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies])
const ethBalance = useNativeCurrencyBalances(useMemo(() => (containsETH ? [account] : []), [containsETH, account])) const ethBalance = useNativeCurrencyBalances(useMemo(() => (containsETH ? [account] : []), [containsETH, account]))
...@@ -139,77 +147,12 @@ function useRpcCurrencyBalances( ...@@ -139,77 +147,12 @@ function useRpcCurrencyBalances(
) )
} }
/**
* Returns raw balances as CurrencyAmounts for tokens in users balanceMap via graphql.
* Balances from graphql are used as a fallback when user is not connected to chain.
* Currently they're returned from graphql formatted so we need to convert to the base unit.
*/
function useGqlCurrencyBalances(
account?: string,
currencies?: (Currency | undefined)[]
): (CurrencyAmount<Currency> | undefined)[] {
const { balanceMap } = useTokenBalances({ cacheOnly: true })
return useMemo(() => {
if (!account || !currencies) {
return []
}
return currencies.map((currency) => {
if (!currency) {
return undefined
}
const key = currencyKey(currency)
const balance = balanceMap[key]
if (balance) {
const balanceQuantityRaw = JSBI.BigInt(Math.floor(balance.balance * Math.pow(10, currency.decimals ?? 18)))
return CurrencyAmount.fromRawAmount(currency, balanceQuantityRaw)
} else {
return CurrencyAmount.fromRawAmount(currency, 0)
}
})
}, [account, balanceMap, currencies])
}
/**
* Returns balances for tokens on currently-connected chainId via RPC.
* Falls back to graphql TokenBalances if user is not connected to chain, a.k.a !isSynced.
*/
export function useCurrencyBalances(
account?: string,
currencies?: (Currency | undefined)[],
chainId?: number
): (CurrencyAmount<Currency> | undefined)[] {
const { chainId: providerChainId } = useAccount()
const isSynced = chainId === providerChainId
const gqlCurrencyBalances = useGqlCurrencyBalances(account, currencies)
const rpcCurrencyBalances = useRpcCurrencyBalances(account, currencies)
return useMemo(() => {
if (!account || !currencies) {
return []
}
return isSynced ? rpcCurrencyBalances : gqlCurrencyBalances
}, [account, currencies, isSynced, gqlCurrencyBalances, rpcCurrencyBalances])
}
// get the balance for a single token/account combo
export function useTokenBalance(account?: string, token?: Token): CurrencyAmount<Token> | undefined {
return useCurrencyBalance(account, token) as CurrencyAmount<Token> | undefined
}
export default function useCurrencyBalance( export default function useCurrencyBalance(
account?: string, account?: string,
currency?: Currency, currency?: Currency
chainId?: number
): CurrencyAmount<Currency> | undefined { ): CurrencyAmount<Currency> | undefined {
return useCurrencyBalances( return useCurrencyBalances(
account, account,
useMemo(() => [currency], [currency]), useMemo(() => [currency], [currency])
chainId
)[0] )[0]
} }
...@@ -2,7 +2,6 @@ import { ChainId, Token } from '@uniswap/sdk-core' ...@@ -2,7 +2,6 @@ import { ChainId, Token } from '@uniswap/sdk-core'
import { nativeOnChain } from 'constants/tokens' import { nativeOnChain } from 'constants/tokens'
import { supportedChainIdFromGQLChain } from 'graphql/data/util' import { supportedChainIdFromGQLChain } from 'graphql/data/util'
import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import { currencyKey } from 'utils/currencyKey'
import { SplitOptions, splitHiddenTokens } from 'utils/splitHiddenTokens' import { SplitOptions, splitHiddenTokens } from 'utils/splitHiddenTokens'
/** Sorts currency amounts (descending). */ /** Sorts currency amounts (descending). */
...@@ -21,8 +20,8 @@ export type TokenBalances = { [tokenAddress: string]: { usdValue: number; balanc ...@@ -21,8 +20,8 @@ export type TokenBalances = { [tokenAddress: string]: { usdValue: number; balanc
/** Sorts tokens by currency amount (descending), then safety, then symbol (ascending). */ /** Sorts tokens by currency amount (descending), then safety, then symbol (ascending). */
function tokenComparator(balances: TokenBalances, a: Token, b: Token) { function tokenComparator(balances: TokenBalances, a: Token, b: Token) {
const aAddress = currencyKey(a) const aAddress = a.isNative ? 'ETH' : a.address?.toLowerCase()
const bAddress = currencyKey(b) const bAddress = b.isNative ? 'ETH' : b.address?.toLowerCase()
// Sorts by balances // Sorts by balances
const balanceComparison = balanceComparator(balances[aAddress]?.usdValue, balances[bAddress]?.usdValue) const balanceComparison = balanceComparator(balances[aAddress]?.usdValue, balances[bAddress]?.usdValue)
if (balanceComparison !== 0) { if (balanceComparison !== 0) {
......
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { parseEther } from '@ethersproject/units'
import { ChainId, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { ChainId, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import { UNIVERSAL_ROUTER_ADDRESS } from '@uniswap/universal-router-sdk' import { UNIVERSAL_ROUTER_ADDRESS } from '@uniswap/universal-router-sdk'
import { getURAddress, useNftUniversalRouterAddress } from 'graphql/data/nft/NftUniversalRouterAddress' import { getURAddress, useNftUniversalRouterAddress } from 'graphql/data/nft/NftUniversalRouterAddress'
import { useAccount } from 'hooks/useAccount' import { useAccount } from 'hooks/useAccount'
import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance' import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance'
import useCurrencyBalance, { useTokenBalance } from 'lib/hooks/useCurrencyBalance' import { useTokenBalance } from 'lib/hooks/useCurrencyBalance'
import { useBag } from 'nft/hooks' import { useBag, useWalletBalance } from 'nft/hooks'
import { useBagTotalEthPrice } from 'nft/hooks/useBagTotalEthPrice' import { useBagTotalEthPrice } from 'nft/hooks/useBagTotalEthPrice'
import useDerivedPayWithAnyTokenSwapInfo from 'nft/hooks/useDerivedPayWithAnyTokenSwapInfo' import useDerivedPayWithAnyTokenSwapInfo from 'nft/hooks/useDerivedPayWithAnyTokenSwapInfo'
import usePayWithAnyTokenSwap from 'nft/hooks/usePayWithAnyTokenSwap' import usePayWithAnyTokenSwap from 'nft/hooks/usePayWithAnyTokenSwap'
...@@ -17,7 +18,6 @@ import { TEST_TOKEN_1, TEST_TRADE_EXACT_INPUT, USE_CONNECTED_ACCOUNT, toCurrency ...@@ -17,7 +18,6 @@ import { TEST_TOKEN_1, TEST_TRADE_EXACT_INPUT, USE_CONNECTED_ACCOUNT, toCurrency
import { mocked } from 'test-utils/mocked' import { mocked } from 'test-utils/mocked'
import { render, screen } from 'test-utils/render' import { render, screen } from 'test-utils/render'
import { nativeOnChain } from 'constants/tokens'
import { BagFooter } from './BagFooter' import { BagFooter } from './BagFooter'
jest.mock('hooks/useAccount', () => ({ jest.mock('hooks/useAccount', () => ({
...@@ -25,6 +25,7 @@ jest.mock('hooks/useAccount', () => ({ ...@@ -25,6 +25,7 @@ jest.mock('hooks/useAccount', () => ({
})) }))
jest.mock('nft/hooks/useBagTotalEthPrice') jest.mock('nft/hooks/useBagTotalEthPrice')
jest.mock('nft/hooks/useWalletBalance')
jest.mock('nft/hooks/useBag') jest.mock('nft/hooks/useBag')
jest.mock('nft/hooks/useTokenInput') jest.mock('nft/hooks/useTokenInput')
jest.mock('lib/hooks/useCurrencyBalance') jest.mock('lib/hooks/useCurrencyBalance')
...@@ -59,7 +60,12 @@ describe('BagFooter.tsx', () => { ...@@ -59,7 +60,12 @@ describe('BagFooter.tsx', () => {
itemsInBag: [], itemsInBag: [],
}) as ReturnType<typeof useBag> }) as ReturnType<typeof useBag>
mocked(useBagTotalEthPrice).mockReturnValue(BigNumber.from(12)) mocked(useBagTotalEthPrice).mockReturnValue(BigNumber.from(12))
mocked(useCurrencyBalance).mockReturnValue(CurrencyAmount.fromRawAmount(nativeOnChain(ChainId.MAINNET), 100)) mocked(useWalletBalance).mockReturnValue({
address: '',
balance: '100',
weiBalance: parseEther('0'),
provider: undefined,
})
mocked(usePermit2Allowance).mockReturnValue({ mocked(usePermit2Allowance).mockReturnValue({
state: AllowanceState.ALLOWED, state: AllowanceState.ALLOWED,
...@@ -126,7 +132,12 @@ describe('BagFooter.tsx', () => { ...@@ -126,7 +132,12 @@ describe('BagFooter.tsx', () => {
}) })
it('insufficient balance', () => { it('insufficient balance', () => {
mocked(useCurrencyBalance).mockReturnValue(CurrencyAmount.fromRawAmount(nativeOnChain(ChainId.MAINNET), 0)) mocked(useWalletBalance).mockReturnValue({
address: '',
balance: '0',
weiBalance: parseEther('0'),
provider: undefined,
})
renderBagFooter() renderBagFooter()
const buyButton = getBuyButton() const buyButton = getBuyButton()
......
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { formatEther } from '@ethersproject/units' import { formatEther, parseEther } from '@ethersproject/units'
import { InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' import { InterfaceElementName, NFTEventName } from '@uniswap/analytics-events'
import { ChainId, Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { ChainId, Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks' import { useAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks'
...@@ -19,7 +19,7 @@ import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance' ...@@ -19,7 +19,7 @@ import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance'
import { useStablecoinValue } from 'hooks/useStablecoinPrice' import { useStablecoinValue } from 'hooks/useStablecoinPrice'
import { useSwitchChain } from 'hooks/useSwitchChain' import { useSwitchChain } from 'hooks/useSwitchChain'
import { Trans, t } from 'i18n' import { Trans, t } from 'i18n'
import useCurrencyBalance, { useTokenBalance } from 'lib/hooks/useCurrencyBalance' import { useTokenBalance } from 'lib/hooks/useCurrencyBalance'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { useBag } from 'nft/hooks/useBag' import { useBag } from 'nft/hooks/useBag'
import { useBagTotalEthPrice } from 'nft/hooks/useBagTotalEthPrice' import { useBagTotalEthPrice } from 'nft/hooks/useBagTotalEthPrice'
...@@ -29,6 +29,7 @@ import usePayWithAnyTokenSwap from 'nft/hooks/usePayWithAnyTokenSwap' ...@@ -29,6 +29,7 @@ import usePayWithAnyTokenSwap from 'nft/hooks/usePayWithAnyTokenSwap'
import { PriceImpact, usePriceImpact } from 'nft/hooks/usePriceImpact' import { PriceImpact, usePriceImpact } from 'nft/hooks/usePriceImpact'
import { useSubscribeTransactionState } from 'nft/hooks/useSubscribeTransactionState' import { useSubscribeTransactionState } from 'nft/hooks/useSubscribeTransactionState'
import { useTokenInput } from 'nft/hooks/useTokenInput' import { useTokenInput } from 'nft/hooks/useTokenInput'
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
import { BagStatus } from 'nft/types' import { BagStatus } from 'nft/types'
import { PropsWithChildren, useEffect, useMemo, useState } from 'react' import { PropsWithChildren, useEffect, useMemo, useState } from 'react'
import { AlertTriangle, ChevronDown } from 'react-feather' import { AlertTriangle, ChevronDown } from 'react-feather'
...@@ -38,9 +39,6 @@ import { ThemedText } from 'theme/components' ...@@ -38,9 +39,6 @@ import { ThemedText } from 'theme/components'
import Trace from 'uniswap/src/features/telemetry/Trace' import Trace from 'uniswap/src/features/telemetry/Trace'
import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send'
import { NumberType, useFormatter } from 'utils/formatNumbers' import { NumberType, useFormatter } from 'utils/formatNumbers'
import { NATIVE_CHAIN_ID } from 'constants/tokens'
import JSBI from 'jsbi'
import { BuyButtonStateData, BuyButtonStates, getBuyButtonStateData } from './ButtonStates' import { BuyButtonStateData, BuyButtonStates, getBuyButtonStateData } from './ButtonStates'
const FooterContainer = styled.div` const FooterContainer = styled.div`
...@@ -332,9 +330,7 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) = ...@@ -332,9 +330,7 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) =
const fiatValueTradeOutput = useStablecoinValue(parsedOutputAmount) const fiatValueTradeOutput = useStablecoinValue(parsedOutputAmount)
const usdcValue = usingPayWithAnyToken ? fiatValueTradeInput : fiatValueTradeOutput const usdcValue = usingPayWithAnyToken ? fiatValueTradeInput : fiatValueTradeOutput
const nativeCurrency = useCurrency(NATIVE_CHAIN_ID) const { balance: balanceInEth } = useWalletBalance()
const nativeCurencyBalance = useCurrencyBalance(account.address ?? undefined, nativeCurrency)
const sufficientBalance = useMemo(() => { const sufficientBalance = useMemo(() => {
if (!connected || account.chainId !== ChainId.MAINNET) { if (!connected || account.chainId !== ChainId.MAINNET) {
return undefined return undefined
...@@ -350,22 +346,8 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) = ...@@ -350,22 +346,8 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) =
return !inputCurrencyBalance.lessThan(inputAmount) return !inputCurrencyBalance.lessThan(inputAmount)
} }
if (!nativeCurrency) { return parseEther(balanceInEth).gte(totalEthPrice)
return undefined }, [connected, account.chainId, inputCurrency, balanceInEth, totalEthPrice, trade?.inputAmount, inputCurrencyBalance])
}
const totalEthPriceCurrencyAmount = CurrencyAmount.fromRawAmount(nativeCurrency, JSBI.BigInt(totalEthPrice))
return nativeCurencyBalance?.greaterThan(totalEthPriceCurrencyAmount)
}, [
connected,
account.chainId,
inputCurrency,
nativeCurrency,
totalEthPrice,
nativeCurencyBalance,
trade?.inputAmount,
inputCurrencyBalance,
])
useEffect(() => { useEffect(() => {
setBagStatus(BagStatus.ADDING_TO_BAG) setBagStatus(BagStatus.ADDING_TO_BAG)
......
...@@ -8,7 +8,7 @@ import { Column, Row } from 'nft/components/Flex' ...@@ -8,7 +8,7 @@ import { Column, Row } from 'nft/components/Flex'
import { CrossIcon } from 'nft/components/icons' import { CrossIcon } from 'nft/components/icons'
import { FilterSidebar } from 'nft/components/profile/view/FilterSidebar' import { FilterSidebar } from 'nft/components/profile/view/FilterSidebar'
import { subhead } from 'nft/css/common.css' import { subhead } from 'nft/css/common.css'
import { useBag, useFiltersExpanded, useSellAsset, useWalletCollections } from 'nft/hooks' import { useBag, useFiltersExpanded, useSellAsset, useWalletBalance, useWalletCollections } from 'nft/hooks'
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css' import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
import { WalletCollection } from 'nft/types' import { WalletCollection } from 'nft/types'
import { Dispatch, SetStateAction, Suspense, useCallback, useEffect, useMemo, useState } from 'react' import { Dispatch, SetStateAction, Suspense, useCallback, useEffect, useMemo, useState } from 'react'
...@@ -18,7 +18,6 @@ import styled from 'styled-components' ...@@ -18,7 +18,6 @@ import styled from 'styled-components'
import { useInfiniteQuery } from '@tanstack/react-query' import { useInfiniteQuery } from '@tanstack/react-query'
import { useIsMobile } from 'hooks/screenSize' import { useIsMobile } from 'hooks/screenSize'
import { useAccount } from 'hooks/useAccount'
import { getOSCollectionsInfiniteQueryOptions } from 'nft/queries/openSea/OSCollectionsFetcher' import { getOSCollectionsInfiniteQueryOptions } from 'nft/queries/openSea/OSCollectionsFetcher'
import { EmptyWalletModule } from './EmptyWalletContent' import { EmptyWalletModule } from './EmptyWalletContent'
import * as styles from './ProfilePage.css' import * as styles from './ProfilePage.css'
...@@ -54,7 +53,7 @@ const FILTER_SIDEBAR_WIDTH = 300 ...@@ -54,7 +53,7 @@ const FILTER_SIDEBAR_WIDTH = 300
const PADDING = 16 const PADDING = 16
export const ProfilePage = () => { export const ProfilePage = () => {
const account = useAccount() const { address } = useWalletBalance()
const walletCollections = useWalletCollections((state) => state.walletCollections) const walletCollections = useWalletCollections((state) => state.walletCollections)
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections) const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
const { resetSellAssets } = useSellAsset(({ reset }) => ({ const { resetSellAssets } = useSellAsset(({ reset }) => ({
...@@ -71,7 +70,7 @@ export const ProfilePage = () => { ...@@ -71,7 +70,7 @@ export const ProfilePage = () => {
hasNextPage, hasNextPage,
isFetchingNextPage, isFetchingNextPage,
isSuccess, isSuccess,
} = useInfiniteQuery(getOSCollectionsInfiniteQueryOptions(account.address ?? '')) } = useInfiniteQuery(getOSCollectionsInfiniteQueryOptions(address))
const ownerCollections = useMemo( const ownerCollections = useMemo(
() => (isSuccess ? ownerCollectionsData?.pages.map((page) => page.data).flat() : null), () => (isSuccess ? ownerCollectionsData?.pages.map((page) => page.data).flat() : null),
...@@ -163,7 +162,7 @@ const ProfilePageNfts = ({ ...@@ -163,7 +162,7 @@ const ProfilePageNfts = ({
isFiltersExpanded: boolean isFiltersExpanded: boolean
setFiltersExpanded: (filtersExpanded: boolean) => void setFiltersExpanded: (filtersExpanded: boolean) => void
}) => { }) => {
const account = useAccount() const { address } = useWalletBalance()
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters) const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
const collectionFilters = useWalletCollections((state) => state.collectionFilters) const collectionFilters = useWalletCollections((state) => state.collectionFilters)
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters) const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
...@@ -177,7 +176,7 @@ const ProfilePageNfts = ({ ...@@ -177,7 +176,7 @@ const ProfilePageNfts = ({
loading, loading,
hasNext, hasNext,
loadMore, loadMore,
} = useNftBalance(account.address ?? '', collectionFilters, [], DEFAULT_WALLET_ASSET_QUERY_AMOUNT) } = useNftBalance(address, collectionFilters, [], DEFAULT_WALLET_ASSET_QUERY_AMOUNT)
const { gridX } = useSpring({ const { gridX } = useSpring({
gridX: isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING, gridX: isFiltersExpanded ? FILTER_SIDEBAR_WIDTH : -PADDING,
......
...@@ -16,4 +16,5 @@ export { useSendTransaction } from './useSendTransaction' ...@@ -16,4 +16,5 @@ export { useSendTransaction } from './useSendTransaction'
export { useSubscribeScrollState } from './useSubscribeScrollState' export { useSubscribeScrollState } from './useSubscribeScrollState'
export { useTransactionResponse } from './useTransactionResponse' export { useTransactionResponse } from './useTransactionResponse'
export { useNativeUsdPrice, useUsdPriceofNftAsset } from './useUsdPrice' export { useNativeUsdPrice, useUsdPriceofNftAsset } from './useUsdPrice'
export { useWalletBalance } from './useWalletBalance'
export { useWalletCollections } from './useWalletCollections' export { useWalletCollections } from './useWalletCollections'
import { BigNumber } from '@ethersproject/bignumber'
import type { Web3Provider } from '@ethersproject/providers'
import { parseEther } from '@ethersproject/units'
import { useWeb3React } from '@web3-react/core'
import { useAccount } from 'hooks/useAccount'
import { useNativeCurrencyBalances } from 'state/connection/hooks'
interface WalletBalanceProps {
address: string
balance: string
weiBalance: BigNumber
provider?: Web3Provider
}
export function useWalletBalance(): WalletBalanceProps {
const account = useAccount()
const { provider } = useWeb3React()
const balanceString =
useNativeCurrencyBalances(account.address ? [account.address] : [])?.[account.address ?? '']?.toSignificant(3) ||
'0'
return account.address
? {
address: account.address,
balance: balanceString,
weiBalance: parseEther(balanceString),
provider,
}
: {
address: '',
balance: '0',
weiBalance: parseEther('0'),
provider: undefined,
}
}
...@@ -15,13 +15,12 @@ import { ReactNode, useMemo } from 'react' ...@@ -15,13 +15,12 @@ import { ReactNode, useMemo } from 'react'
import { Text } from 'rebass' import { Text } from 'rebass'
import styled, { useTheme } from 'styled-components' import styled, { useTheme } from 'styled-components'
import { BackArrowLink, StyledInternalLink, ThemedText } from 'theme/components' import { BackArrowLink, StyledInternalLink, ThemedText } from 'theme/components'
import { useRpcTokenBalancesWithLoadingIndicator } from 'lib/hooks/useCurrencyBalance'
import { LightCard } from '../../components/Card' import { LightCard } from '../../components/Card'
import { AutoColumn } from '../../components/Column' import { AutoColumn } from '../../components/Column'
import QuestionHelper from '../../components/QuestionHelper' import QuestionHelper from '../../components/QuestionHelper'
import { AutoRow } from '../../components/Row' import { AutoRow } from '../../components/Row'
import { Dots } from '../../components/swap/styled' import { Dots } from '../../components/swap/styled'
import { useTokenBalancesWithLoadingIndicator } from '../../state/connection/hooks'
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks' import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
export const MigrateHeader = styled(ThemedText.H1Small)` export const MigrateHeader = styled(ThemedText.H1Small)`
...@@ -90,10 +89,7 @@ export default function MigrateV2() { ...@@ -90,10 +89,7 @@ export default function MigrateV2() {
}, [tokenPairsWithLiquidityTokens]) }, [tokenPairsWithLiquidityTokens])
// fetch pair balances // fetch pair balances
const [pairBalances, fetchingPairBalances] = useRpcTokenBalancesWithLoadingIndicator( const [pairBalances, fetchingPairBalances] = useTokenBalancesWithLoadingIndicator(account.address, allLiquidityTokens)
account.address,
allLiquidityTokens
)
// filter for v2 liquidity tokens that the user has a balance in // filter for v2 liquidity tokens that the user has a balance in
const tokenPairsWithV2Balance = useMemo(() => { const tokenPairsWithV2Balance = useMemo(() => {
......
...@@ -3,7 +3,6 @@ import { Pair } from '@uniswap/v2-sdk' ...@@ -3,7 +3,6 @@ import { Pair } from '@uniswap/v2-sdk'
import { V2Unsupported } from 'components/V2Unsupported' import { V2Unsupported } from 'components/V2Unsupported'
import { useAccount } from 'hooks/useAccount' import { useAccount } from 'hooks/useAccount'
import { useNetworkSupportsV2 } from 'hooks/useNetworkSupportsV2' import { useNetworkSupportsV2 } from 'hooks/useNetworkSupportsV2'
import { useTokenBalances } from 'hooks/useTokenBalances'
import { Trans } from 'i18n' import { Trans } from 'i18n'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { PoolVersionMenu } from 'pages/Pool/shared' import { PoolVersionMenu } from 'pages/Pool/shared'
...@@ -15,7 +14,6 @@ import styled, { useTheme } from 'styled-components' ...@@ -15,7 +14,6 @@ import styled, { useTheme } from 'styled-components'
import { ExternalLink, HideSmall, ThemedText } from 'theme/components' import { ExternalLink, HideSmall, ThemedText } from 'theme/components'
import { ProtocolVersion } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { ProtocolVersion } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks'
import Trace from 'uniswap/src/features/telemetry/Trace' import Trace from 'uniswap/src/features/telemetry/Trace'
import { currencyKey } from 'utils/currencyKey'
import { ButtonOutlined, ButtonPrimary, ButtonSecondary } from '../../components/Button' import { ButtonOutlined, ButtonPrimary, ButtonSecondary } from '../../components/Button'
import Card from '../../components/Card' import Card from '../../components/Card'
import { AutoColumn } from '../../components/Column' import { AutoColumn } from '../../components/Column'
...@@ -26,6 +24,7 @@ import { CardBGImage, CardNoise, CardSection, DataCard } from '../../components/ ...@@ -26,6 +24,7 @@ import { CardBGImage, CardNoise, CardSection, DataCard } from '../../components/
import { Dots } from '../../components/swap/styled' import { Dots } from '../../components/swap/styled'
import { BIG_INT_ZERO } from '../../constants/misc' import { BIG_INT_ZERO } from '../../constants/misc'
import { useV2Pairs } from '../../hooks/useV2Pairs' import { useV2Pairs } from '../../hooks/useV2Pairs'
import { useTokenBalancesWithLoadingIndicator } from '../../state/connection/hooks'
import { useStakingInfo } from '../../state/stake/hooks' import { useStakingInfo } from '../../state/stake/hooks'
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks' import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
...@@ -100,16 +99,22 @@ export default function Pool() { ...@@ -100,16 +99,22 @@ export default function Pool() {
() => trackedTokenPairs.map((tokens) => ({ liquidityToken: toV2LiquidityToken(tokens), tokens })), () => trackedTokenPairs.map((tokens) => ({ liquidityToken: toV2LiquidityToken(tokens), tokens })),
[trackedTokenPairs] [trackedTokenPairs]
) )
const { balanceMap, loading: fetchingV2PairBalances } = useTokenBalances() const liquidityTokens = useMemo(
() => tokenPairsWithLiquidityTokens.map((tpwlt) => tpwlt.liquidityToken),
[tokenPairsWithLiquidityTokens]
)
const [v2PairsBalances, fetchingV2PairBalances] = useTokenBalancesWithLoadingIndicator(
account.address,
liquidityTokens
)
// fetch the reserves for all V2 pools in which the user has a balance // fetch the reserves for all V2 pools in which the user has a balance
const liquidityTokensWithBalances = useMemo( const liquidityTokensWithBalances = useMemo(
() => () =>
tokenPairsWithLiquidityTokens.filter(({ liquidityToken }) => { tokenPairsWithLiquidityTokens.filter(({ liquidityToken }) =>
const liquidityTokenKey = currencyKey(liquidityToken) v2PairsBalances[liquidityToken.address]?.greaterThan('0')
return balanceMap[liquidityTokenKey]?.balance > 0 ),
}), [tokenPairsWithLiquidityTokens, v2PairsBalances]
[tokenPairsWithLiquidityTokens, balanceMap]
) )
const v2Pairs = useV2Pairs(liquidityTokensWithBalances.map(({ tokens }) => tokens)) const v2Pairs = useV2Pairs(liquidityTokensWithBalances.map(({ tokens }) => tokens))
......
...@@ -60,7 +60,6 @@ import { maxAmountSpend } from 'utils/maxAmountSpend' ...@@ -60,7 +60,6 @@ import { maxAmountSpend } from 'utils/maxAmountSpend'
import { largerPercentValue } from 'utils/percent' import { largerPercentValue } from 'utils/percent'
import { computeRealizedPriceImpact, warningSeverity } from 'utils/prices' import { computeRealizedPriceImpact, warningSeverity } from 'utils/prices'
import { didUserReject } from 'utils/swapErrorToUserReadableMessage' import { didUserReject } from 'utils/swapErrorToUserReadableMessage'
import { getIsReviewableQuote } from '.' import { getIsReviewableQuote } from '.'
import { OutputTaxTooltipBody } from './TaxTooltipBody' import { OutputTaxTooltipBody } from './TaxTooltipBody'
...@@ -240,12 +239,10 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF ...@@ -240,12 +239,10 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF
swapError: undefined, swapError: undefined,
swapResult: undefined, swapResult: undefined,
}) })
const previousConnectedChainId = usePrevious(connectedChainId) const previousConnectedChainId = usePrevious(connectedChainId)
const previousPrefilledState = usePrevious(prefilledState) const previousPrefilledState = usePrevious(prefilledState)
useEffect(() => { useEffect(() => {
if (multichainUXEnabled) {
return
}
const chainChanged = previousConnectedChainId && previousConnectedChainId !== connectedChainId const chainChanged = previousConnectedChainId && previousConnectedChainId !== connectedChainId
const prefilledInputChanged = const prefilledInputChanged =
previousPrefilledState?.inputCurrency && previousPrefilledState?.inputCurrency &&
...@@ -265,7 +262,6 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF ...@@ -265,7 +262,6 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF
} }
}, [ }, [
connectedChainId, connectedChainId,
multichainUXEnabled,
prefilledState.inputCurrency, prefilledState.inputCurrency,
prefilledState?.outputCurrency, prefilledState?.outputCurrency,
previousConnectedChainId, previousConnectedChainId,
...@@ -464,7 +460,6 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF ...@@ -464,7 +460,6 @@ export function SwapForm({ disableTokenInputs = false, onCurrencyChange }: SwapF
const inputCurrency = currencies[Field.INPUT] ?? undefined const inputCurrency = currencies[Field.INPUT] ?? undefined
const selectChain = useSelectChain() const selectChain = useSelectChain()
const switchingChain = useAppSelector((state) => state.wallets.switchingChain) const switchingChain = useAppSelector((state) => state.wallets.switchingChain)
const targetChain = switchingChain ? switchingChain : undefined const targetChain = switchingChain ? switchingChain : undefined
const switchingChainIsSupported = useIsSupportedChainId(targetChain) const switchingChainIsSupported = useIsSupportedChainId(targetChain)
......
...@@ -106,7 +106,7 @@ export function Swap({ ...@@ -106,7 +106,7 @@ export function Swap({
{/* TODO: Move SwapContextProvider inside Swap tab ONLY after SwapHeader removes references to trade / autoSlippage */} {/* TODO: Move SwapContextProvider inside Swap tab ONLY after SwapHeader removes references to trade / autoSlippage */}
<SwapAndLimitContext.Consumer> <SwapAndLimitContext.Consumer>
{({ currentTab }) => ( {({ currentTab }) => (
<SwapContextProvider multichainUXEnabled={multichainUXEnabled}> <SwapContextProvider>
<Flex width="100%"> <Flex width="100%">
<SwapWrapper isDark={isDark} className={className} id="swap-page"> <SwapWrapper isDark={isDark} className={className} id="swap-page">
<SwapHeader compact={compact || !screenSize.sm} syncTabToUrl={syncTabToUrl} /> <SwapHeader compact={compact || !screenSize.sm} syncTabToUrl={syncTabToUrl} />
......
...@@ -8,9 +8,9 @@ import { useAppDispatch, useAppSelector } from 'state/hooks' ...@@ -8,9 +8,9 @@ import { useAppDispatch, useAppSelector } from 'state/hooks'
import { AppState } from 'state/reducer' import { AppState } from 'state/reducer'
import { useAccount } from 'hooks/useAccount' import { useAccount } from 'hooks/useAccount'
import useCurrencyBalance from 'lib/hooks/useCurrencyBalance'
import { useTotalSupply } from '../../hooks/useTotalSupply' import { useTotalSupply } from '../../hooks/useTotalSupply'
import { useV2Pair } from '../../hooks/useV2Pairs' import { useV2Pair } from '../../hooks/useV2Pairs'
import { useTokenBalances } from '../connection/hooks'
import { Field, typeInput } from './actions' import { Field, typeInput } from './actions'
export function useBurnState(): AppState['burn'] { export function useBurnState(): AppState['burn'] {
...@@ -38,7 +38,8 @@ export function useDerivedBurnInfo( ...@@ -38,7 +38,8 @@ export function useDerivedBurnInfo(
const [, pair] = useV2Pair(currencyA, currencyB) const [, pair] = useV2Pair(currencyA, currencyB)
// balances // balances
const userLiquidity = useCurrencyBalance(account.address, pair?.liquidityToken) as CurrencyAmount<Token> const relevantTokenBalances = useTokenBalances(account.address, [pair?.liquidityToken])
const userLiquidity: undefined | CurrencyAmount<Token> = relevantTokenBalances?.[pair?.liquidityToken?.address ?? '']
const [tokenA, tokenB] = [currencyA?.wrapped, currencyB?.wrapped] const [tokenA, tokenB] = [currencyA?.wrapped, currencyB?.wrapped]
const tokens = { const tokens = {
......
export { default as useCurrencyBalance, useCurrencyBalances, useTokenBalance } from 'lib/hooks/useCurrencyBalance' export {
default as useCurrencyBalance,
useCurrencyBalances,
useNativeCurrencyBalances,
useTokenBalance,
useTokenBalances,
useTokenBalancesWithLoadingIndicator,
} from 'lib/hooks/useCurrencyBalance'
...@@ -12,7 +12,6 @@ import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance' ...@@ -12,7 +12,6 @@ import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { useMemo } from 'react' import { useMemo } from 'react'
import { SendState } from 'state/send/SendContext' import { SendState } from 'state/send/SendContext'
import { useSwapAndLimitContext } from 'state/swap/hooks'
import { useUnitagByAddress, useUnitagByName } from 'uniswap/src/features/unitags/hooks' import { useUnitagByAddress, useUnitagByName } from 'uniswap/src/features/unitags/hooks'
import { isAddress } from 'utilities/src/addresses' import { isAddress } from 'utilities/src/addresses'
import { useCreateTransferTransaction } from 'utils/transfer' import { useCreateTransferTransaction } from 'utils/transfer'
...@@ -42,7 +41,6 @@ export type SendInfo = { ...@@ -42,7 +41,6 @@ export type SendInfo = {
export function useDerivedSendInfo(state: SendState): SendInfo { export function useDerivedSendInfo(state: SendState): SendInfo {
const account = useAccount() const account = useAccount()
const { provider } = useWeb3React() const { provider } = useWeb3React()
const { chainId } = useSwapAndLimitContext()
const { exactAmountToken, exactAmountFiat, inputInFiat, inputCurrency, recipient, validatedRecipientData } = state const { exactAmountToken, exactAmountFiat, inputInFiat, inputCurrency, recipient, validatedRecipientData } = state
const { unitag: recipientInputUnitag } = useUnitagByName(validatedRecipientData ? undefined : recipient) const { unitag: recipientInputUnitag } = useUnitagByName(validatedRecipientData ? undefined : recipient)
...@@ -80,7 +78,7 @@ export function useDerivedSendInfo(state: SendState): SendInfo { ...@@ -80,7 +78,7 @@ export function useDerivedSendInfo(state: SendState): SendInfo {
unitag?.username, unitag?.username,
]) ])
const nativeCurrency = useCurrency(NATIVE_CHAIN_ID, chainId) const nativeCurrency = useCurrency(NATIVE_CHAIN_ID, account.chainId)
const [inputCurrencyBalance, nativeCurencyBalance] = useCurrencyBalances( const [inputCurrencyBalance, nativeCurencyBalance] = useCurrencyBalances(
account.address, account.address,
useMemo(() => [inputCurrency, nativeCurrency], [inputCurrency, nativeCurrency]) useMemo(() => [inputCurrency, nativeCurrency], [inputCurrency, nativeCurrency])
...@@ -94,21 +92,21 @@ export function useDerivedSendInfo(state: SendState): SendInfo { ...@@ -94,21 +92,21 @@ export function useDerivedSendInfo(state: SendState): SendInfo {
const transferInfo = useMemo(() => { const transferInfo = useMemo(() => {
return { return {
provider, provider,
account: account.address, address: account.address,
chainId, chaindId: account.chainId,
currencyAmount: parsedTokenAmount, currencyAmount: parsedTokenAmount,
toAddress: recipientData?.address, toAddress: recipientData?.address,
} }
}, [account.address, chainId, parsedTokenAmount, provider, recipientData?.address]) }, [account.address, account.chainId, parsedTokenAmount, provider, recipientData?.address])
const transferTransaction = useCreateTransferTransaction(transferInfo) const transferTransaction = useCreateTransferTransaction(transferInfo)
const gasFee = useTransactionGasFee(transferTransaction, GasSpeed.Normal, !transferTransaction) const gasFee = useTransactionGasFee(transferTransaction, GasSpeed.Normal, !transferTransaction)
const gasFeeCurrencyAmount = useMemo(() => { const gasFeeCurrencyAmount = useMemo(() => {
if (!chainId || !gasFee?.value) { if (!account.chainId || !gasFee?.value) {
return undefined return undefined
} }
return CurrencyAmount.fromRawAmount(nativeOnChain(chainId), gasFee.value) return CurrencyAmount.fromRawAmount(nativeOnChain(account.chainId), gasFee.value)
}, [chainId, gasFee?.value]) }, [account.chainId, gasFee?.value])
const inputError = useMemo(() => { const inputError = useMemo(() => {
const insufficientBalance = parsedTokenAmount && inputCurrencyBalance?.lessThan(parsedTokenAmount) const insufficientBalance = parsedTokenAmount && inputCurrencyBalance?.lessThan(parsedTokenAmount)
......
...@@ -3,7 +3,6 @@ import { useAccount } from 'hooks/useAccount' ...@@ -3,7 +3,6 @@ import { useAccount } from 'hooks/useAccount'
import usePrevious from 'hooks/usePrevious' import usePrevious from 'hooks/usePrevious'
import { PropsWithChildren, useEffect, useMemo, useState } from 'react' import { PropsWithChildren, useEffect, useMemo, useState } from 'react'
import { SwapTab } from 'uniswap/src/types/screens/interface' import { SwapTab } from 'uniswap/src/types/screens/interface'
import { useDerivedSwapInfo } from './hooks' import { useDerivedSwapInfo } from './hooks'
import { CurrencyState, SwapAndLimitContext, SwapContext, SwapState, initialSwapState } from './types' import { CurrencyState, SwapAndLimitContext, SwapContext, SwapState, initialSwapState } from './types'
...@@ -37,25 +36,6 @@ export function SwapAndLimitContextProvider({ ...@@ -37,25 +36,6 @@ export function SwapAndLimitContextProvider({
const account = useAccount() const account = useAccount()
const previousConnectedChainId = usePrevious(account.chainId) const previousConnectedChainId = usePrevious(account.chainId)
const previousInitialInputCurrency = usePrevious(initialInputCurrency)
const previousInitialOutputCurrency = usePrevious(initialOutputCurrency)
useEffect(() => {
if (!multichainUXEnabled) {
return
}
if (previousInitialInputCurrency && previousInitialInputCurrency !== initialInputCurrency) {
setCurrencyState((prev) => ({ ...prev, inputCurrency: initialInputCurrency }))
}
}, [
multichainUXEnabled,
initialInputCurrency,
initialOutputCurrency,
previousInitialInputCurrency,
previousInitialOutputCurrency,
])
const previousPrefilledState = usePrevious(prefilledState) const previousPrefilledState = usePrevious(prefilledState)
useEffect(() => { useEffect(() => {
...@@ -112,13 +92,7 @@ export function SwapAndLimitContextProvider({ ...@@ -112,13 +92,7 @@ export function SwapAndLimitContextProvider({
return <SwapAndLimitContext.Provider value={value}>{children}</SwapAndLimitContext.Provider> return <SwapAndLimitContext.Provider value={value}>{children}</SwapAndLimitContext.Provider>
} }
export function SwapContextProvider({ export function SwapContextProvider({ children }: { children: React.ReactNode }) {
multichainUXEnabled,
children,
}: {
multichainUXEnabled?: boolean
children: React.ReactNode
}) {
const [swapState, setSwapState] = useState<SwapState>({ const [swapState, setSwapState] = useState<SwapState>({
...initialSwapState, ...initialSwapState,
}) })
...@@ -129,13 +103,10 @@ export function SwapContextProvider({ ...@@ -129,13 +103,10 @@ export function SwapContextProvider({
useEffect(() => { useEffect(() => {
const chainChanged = previousConnectedChainId && previousConnectedChainId !== connectedChainId const chainChanged = previousConnectedChainId && previousConnectedChainId !== connectedChainId
if (multichainUXEnabled) {
return
}
if (chainChanged) { if (chainChanged) {
setSwapState((prev) => ({ ...prev, typedValue: '' })) setSwapState((prev) => ({ ...prev, typedValue: '' }))
} }
}, [connectedChainId, previousConnectedChainId, multichainUXEnabled]) }, [connectedChainId, previousConnectedChainId])
return <SwapContext.Provider value={{ swapState, setSwapState, derivedSwapInfo }}>{children}</SwapContext.Provider> return <SwapContext.Provider value={{ swapState, setSwapState, derivedSwapInfo }}>{children}</SwapContext.Provider>
} }
...@@ -127,9 +127,8 @@ export function useSwapActionHandlers(): { ...@@ -127,9 +127,8 @@ export function useSwapActionHandlers(): {
// 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): SwapInfo { export function useDerivedSwapInfo(state: SwapState): SwapInfo {
const account = useAccount() const account = useAccount()
const { chainId } = useSwapAndLimitContext() const nativeCurrency = useNativeCurrency(account.chainId)
const nativeCurrency = useNativeCurrency(chainId) const balance = useCurrencyBalance(account.address, nativeCurrency)
const balance = useCurrencyBalance(account.address, nativeCurrency, chainId)
const { const {
currencyState: { inputCurrency, outputCurrency }, currencyState: { inputCurrency, outputCurrency },
...@@ -143,8 +142,7 @@ export function useDerivedSwapInfo(state: SwapState): SwapInfo { ...@@ -143,8 +142,7 @@ export function useDerivedSwapInfo(state: SwapState): SwapInfo {
const relevantTokenBalances = useCurrencyBalances( const relevantTokenBalances = useCurrencyBalances(
account.address, account.address,
useMemo(() => [inputCurrency ?? undefined, outputCurrency ?? undefined], [inputCurrency, outputCurrency]), useMemo(() => [inputCurrency ?? undefined, outputCurrency ?? undefined], [inputCurrency, outputCurrency])
chainId
) )
const isExactIn: boolean = independentField === Field.INPUT const isExactIn: boolean = independentField === Field.INPUT
......
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