diff --git a/lib/modules/pool/actions/add-liquidity/form/AddLiquidityForm.tsx b/lib/modules/pool/actions/add-liquidity/form/AddLiquidityForm.tsx index 10d0b5b3b..8ace18282 100644 --- a/lib/modules/pool/actions/add-liquidity/form/AddLiquidityForm.tsx +++ b/lib/modules/pool/actions/add-liquidity/form/AddLiquidityForm.tsx @@ -48,6 +48,7 @@ import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider' import { ConnectWallet } from '@/lib/modules/web3/ConnectWallet' import { BalAlert } from '@/lib/shared/components/alerts/BalAlert' import { SafeAppAlert } from '@/lib/shared/components/alerts/SafeAppAlert' +import { useTokens } from '@/lib/modules/tokens/TokensProvider' // small wrapper to prevent out of context error export function AddLiquidityForm() { @@ -87,6 +88,7 @@ function AddLiquidityMainForm() { const { setValidationError } = useTokenInputsValidation() const { balanceFor, isBalancesLoading } = useTokenBalances() const { isConnected } = useUserAccount() + const { startTokenPricePolling } = useTokens() useEffect(() => { setPriceImpact(priceImpactQuery.data) @@ -148,6 +150,13 @@ function AddLiquidityMainForm() { } }, [addLiquidityTxHash]) + function onModalClose() { + // restart polling for token prices when modal is closed again + startTokenPricePolling() + + previewModalDisclosure.onClose() + } + return ( @@ -259,7 +268,7 @@ function AddLiquidityMainForm() { finalFocusRef={nextBtn} isOpen={previewModalDisclosure.isOpen} onOpen={previewModalDisclosure.onOpen} - onClose={previewModalDisclosure.onClose} + onClose={onModalClose} /> {!!validTokens.length && ( { + if (isOpen) { + // stop polling for token prices when modal is opened to prevent unwanted re-renders + stopTokenPricePolling() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen]) + useEffect(() => { if (addLiquidityTxHash && !window.location.pathname.includes(addLiquidityTxHash)) { window.history.replaceState({}, '', `./add-liquidity/${addLiquidityTxHash}`) diff --git a/lib/modules/pool/actions/remove-liquidity/form/RemoveLiquidityForm.tsx b/lib/modules/pool/actions/remove-liquidity/form/RemoveLiquidityForm.tsx index 40edd71fa..a542f2d1c 100644 --- a/lib/modules/pool/actions/remove-liquidity/form/RemoveLiquidityForm.tsx +++ b/lib/modules/pool/actions/remove-liquidity/form/RemoveLiquidityForm.tsx @@ -34,7 +34,7 @@ import { parseUnits } from 'viem' import { SimulationError } from '@/lib/shared/components/errors/SimulationError' import { InfoIcon } from '@/lib/shared/components/icons/InfoIcon' import { SafeAppAlert } from '@/lib/shared/components/alerts/SafeAppAlert' - +import { useTokens } from '@/lib/modules/tokens/TokensProvider' const TABS: ButtonGroupOption[] = [ { value: 'proportional', @@ -70,6 +70,7 @@ export function RemoveLiquidityForm() { const { redirectToPoolPage } = usePoolRedirect(pool) const nextBtn = useRef(null) const [activeTab, setActiveTab] = useState(TABS[0]) + const { startTokenPricePolling } = useTokens() useEffect(() => { setPriceImpact(priceImpactQuery.data) @@ -91,6 +92,9 @@ export function RemoveLiquidityForm() { } const onModalClose = () => { + // restart polling for token prices when modal is closed again + startTokenPricePolling() + if (transactionSteps.lastTransactionConfirmingOrConfirmed) { // If the transaction is confirming or confirmed, it's very likely that // they no longer have a pool balance. To be safe, always redirect to the diff --git a/lib/modules/pool/actions/remove-liquidity/modal/RemoveLiquidityModal.tsx b/lib/modules/pool/actions/remove-liquidity/modal/RemoveLiquidityModal.tsx index d10ff34dc..452b9b1cf 100644 --- a/lib/modules/pool/actions/remove-liquidity/modal/RemoveLiquidityModal.tsx +++ b/lib/modules/pool/actions/remove-liquidity/modal/RemoveLiquidityModal.tsx @@ -18,6 +18,7 @@ import { useOnUserAccountChanged } from '@/lib/modules/web3/useOnUserAccountChan import { RemoveLiquiditySummary } from './RemoveLiquiditySummary' import { useRemoveLiquidityReceipt } from '@/lib/modules/transactions/transaction-steps/receipts/receipt.hooks' import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider' +import { useTokens } from '@/lib/modules/tokens/TokensProvider' type Props = { isOpen: boolean @@ -38,6 +39,7 @@ export function RemoveLiquidityModal({ const { pool, chain } = usePool() const { redirectToPoolPage } = usePoolRedirect(pool) const { userAddress } = useUserAccount() + const { stopTokenPricePolling } = useTokens() const receiptProps = useRemoveLiquidityReceipt({ chain, @@ -47,6 +49,14 @@ export function RemoveLiquidityModal({ useResetStepIndexOnOpen(isOpen, transactionSteps) + useEffect(() => { + if (isOpen) { + // stop polling for token prices when modal is opened to prevent unwanted re-renders + stopTokenPricePolling() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen]) + useEffect(() => { if (removeLiquidityTxHash && !window.location.pathname.includes(removeLiquidityTxHash)) { window.history.replaceState({}, '', `./remove-liquidity/${removeLiquidityTxHash}`) diff --git a/lib/modules/swap/SwapDetails.tsx b/lib/modules/swap/SwapDetails.tsx index 28e3cb5e4..4d8400ceb 100644 --- a/lib/modules/swap/SwapDetails.tsx +++ b/lib/modules/swap/SwapDetails.tsx @@ -19,7 +19,7 @@ export function OrderRoute() { const queryData = simulationQuery.data as SdkSimulateSwapResponse const orderRouteVersion = queryData ? queryData.protocolVersion : 2 - const hopCount = queryData?.routes[0]?.hops?.length ?? 0 + const hopCount = queryData ? queryData.routes[0]?.hops?.length : 0 return ( diff --git a/lib/modules/swap/SwapForm.tsx b/lib/modules/swap/SwapForm.tsx index e2f0018ca..5fb100a55 100644 --- a/lib/modules/swap/SwapForm.tsx +++ b/lib/modules/swap/SwapForm.tsx @@ -37,6 +37,7 @@ import { parseSwapError } from './swap.helpers' import { useUserAccount } from '../web3/UserAccountProvider' import { ConnectWallet } from '../web3/ConnectWallet' import { SafeAppAlert } from '@/lib/shared/components/alerts/SafeAppAlert' +import { useTokens } from '../tokens/TokensProvider' export function SwapForm() { const { @@ -70,6 +71,7 @@ export function SwapForm() { const finalRefTokenOut = useRef(null) const isMounted = useIsMounted() const { isConnected } = useUserAccount() + const { startTokenPricePolling } = useTokens() const isLoadingSwaps = simulationQuery.isLoading const isLoading = isLoadingSwaps || !isMounted @@ -98,7 +100,11 @@ export function SwapForm() { } function onModalClose() { + // restart polling for token prices when modal is closed again + startTokenPricePolling() + previewModalDisclosure.onClose() + if (swapTxHash) { resetSwapAmounts() replaceUrlPath() diff --git a/lib/modules/swap/modal/SwapModal.tsx b/lib/modules/swap/modal/SwapModal.tsx index b015863fb..2ece65953 100644 --- a/lib/modules/swap/modal/SwapModal.tsx +++ b/lib/modules/swap/modal/SwapModal.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ 'use client' import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalProps } from '@chakra-ui/react' @@ -18,6 +19,7 @@ import { useOnUserAccountChanged } from '../../web3/useOnUserAccountChanged' import { SwapSummary } from './SwapSummary' import { useSwapReceipt } from '../../transactions/transaction-steps/receipts/receipt.hooks' import { useUserAccount } from '../../web3/UserAccountProvider' +import { useTokens } from '../../tokens/TokensProvider' type Props = { isOpen: boolean @@ -35,6 +37,7 @@ export function SwapPreviewModal({ const { isDesktop } = useBreakpoints() const initialFocusRef = useRef(null) const { userAddress } = useUserAccount() + const { stopTokenPricePolling } = useTokens() const { transactionSteps, swapAction, isWrap, selectedChain, swapTxHash, hasQuoteContext } = useSwap() @@ -51,9 +54,15 @@ export function SwapPreviewModal({ if (!isWrap && swapTxHash && !window.location.pathname.includes(swapTxHash)) { window.history.pushState({}, '', `/swap/${chainToSlugMap[selectedChain]}/${swapTxHash}`) } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [swapTxHash]) + useEffect(() => { + if (isOpen) { + // stop polling for token prices when modal is opened to prevent unwanted re-renders + stopTokenPricePolling() + } + }, [isOpen]) + useOnUserAccountChanged(onClose) return ( diff --git a/lib/modules/tokens/TokensProvider.tsx b/lib/modules/tokens/TokensProvider.tsx index 13bf7ceb7..5fc8549ed 100644 --- a/lib/modules/tokens/TokensProvider.tsx +++ b/lib/modules/tokens/TokensProvider.tsx @@ -14,7 +14,7 @@ import { import { isSameAddress } from '@/lib/shared/utils/addresses' import { useMandatoryContext } from '@/lib/shared/utils/contexts' import { bn, Numberish } from '@/lib/shared/utils/numbers' -import { useQuery } from '@apollo/experimental-nextjs-app-support/ssr' +import { useQuery } from '@apollo/client' import { Dictionary, zipObject } from 'lodash' import { createContext, PropsWithChildren, useCallback } from 'react' import { Address } from 'viem' @@ -31,24 +31,27 @@ export function _useTokens( variables: GetTokensQueryVariables ) { const skipQuery = useSkipInitialQuery(variables) + const pollInterval = mins(3).toMs() // skip initial fetch on mount so that initialData is used const { data: tokensData } = useQuery(GetTokensDocument, { variables, skip: skipQuery, }) - const { data: tokenPricesData, loading: isLoadingTokenPrices } = useQuery( - GetTokenPricesDocument, - { - variables, - // The server provides us with an initial data set, but we immediately reload the potentially - // stale data to ensure the prices we show are up to date. Every 3 mins, we requery token prices - initialFetchPolicy: 'no-cache', - nextFetchPolicy: 'cache-and-network', - pollInterval: mins(3).toMs(), - notifyOnNetworkStatusChange: true, - } - ) + const { + data: tokenPricesData, + loading: isLoadingTokenPrices, + startPolling, + stopPolling, + } = useQuery(GetTokenPricesDocument, { + variables, + // The server provides us with an initial data set, but we immediately reload the potentially + // stale data to ensure the prices we show are up to date. Every 3 mins, we requery token prices + initialFetchPolicy: 'no-cache', + nextFetchPolicy: 'cache-and-network', + pollInterval, + notifyOnNetworkStatusChange: true, + }) const tokens = tokensData?.tokens || initTokenData.tokens const prices = tokenPricesData?.tokenPrices || initTokenPricesData.tokenPrices @@ -153,6 +156,8 @@ export function _useTokens( usdValueForToken, calcWeightForBalance, calcTotalUsdValue, + startTokenPricePolling: () => startPolling(pollInterval), + stopTokenPricePolling: stopPolling, } }