From c04ef53863fbe6c209c22ddb0b9e1641b7dfc5c5 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Fri, 13 Sep 2024 14:56:44 +0200 Subject: [PATCH] fix: avoid unwanted background simulation refetches (#1082) * fix: background simulation refetches * fix: avoid background refetches for claimable and rewards queries * refactor: use onlyExplicitRefetch instead of staleTime --- .../pool/actions/unstake/UnstakeProvider.tsx | 12 +++++++----- .../portfolio/PortfolioClaim/useBalRewards.tsx | 7 ++++++- .../PortfolioClaim/useClaimableBalances.ts | 7 ++++++- .../contracts/useManagedErc20Transaction.ts | 3 +++ .../contracts/useManagedSendTransaction.ts | 4 +++- .../web3/contracts/useManagedTransaction.ts | 3 +++ .../components/modals/ActionModalFooter.tsx | 5 ++++- lib/shared/utils/queries.ts | 18 +++++++++++++++++- 8 files changed, 49 insertions(+), 10 deletions(-) diff --git a/lib/modules/pool/actions/unstake/UnstakeProvider.tsx b/lib/modules/pool/actions/unstake/UnstakeProvider.tsx index 5c81d51bf..449462e99 100644 --- a/lib/modules/pool/actions/unstake/UnstakeProvider.tsx +++ b/lib/modules/pool/actions/unstake/UnstakeProvider.tsx @@ -7,7 +7,7 @@ import { useUserAccount } from '@/lib/modules/web3/UserAccountProvider' import { LABELS } from '@/lib/shared/labels' import { useMandatoryContext } from '@/lib/shared/utils/contexts' import { isDisabledWithReason } from '@/lib/shared/utils/functions/isDisabledWithReason' -import { bn } from '@/lib/shared/utils/numbers' +import { bn, isZero } from '@/lib/shared/utils/numbers' import { HumanAmount } from '@balancer/sdk' import { createContext, PropsWithChildren, useEffect, useMemo, useState } from 'react' import { PoolListItem } from '../../pool.types' @@ -57,10 +57,12 @@ export function _useUnstake() { const unstakeTxHash = transactionSteps.lastTransaction?.result?.data?.transactionHash - const { isDisabled, disabledReason } = isDisabledWithReason([ - !isConnected, - LABELS.walletNotConnected, - ]) + const hasRewardAmounts = rewardAmounts.some(amount => !isZero(amount.humanAmount)) + + const { isDisabled, disabledReason } = isDisabledWithReason( + [!isConnected, LABELS.walletNotConnected], + [isZero(amountOut) && !hasRewardAmounts, "There's no staked amount to be unstaked"] + ) /** * Side-effects diff --git a/lib/modules/portfolio/PortfolioClaim/useBalRewards.tsx b/lib/modules/portfolio/PortfolioClaim/useBalRewards.tsx index 679b4e795..0f0293cf3 100644 --- a/lib/modules/portfolio/PortfolioClaim/useBalRewards.tsx +++ b/lib/modules/portfolio/PortfolioClaim/useBalRewards.tsx @@ -14,6 +14,7 @@ import { ClaimablePool } from '../../pool/actions/claim/ClaimProvider' import { balancerV2GaugeV5Abi } from '../../web3/contracts/abi/generated' import { WriteContractParameters } from 'wagmi/actions' import { compact } from 'lodash' +import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' export interface BalTokenReward { balance: bigint @@ -64,7 +65,11 @@ export function useBalTokenRewards(pools: ClaimablePool[]) { } = useReadContracts({ allowFailure: true, contracts: contractCalls, - query: { enabled: isConnected && !!pools.length }, + query: { + enabled: isConnected && !!pools.length, + // In chains like polygon, we don't want background refetches while waiting for min block confirmations + ...onlyExplicitRefetch, + }, }) const balRewardsData = useMemo(() => { diff --git a/lib/modules/portfolio/PortfolioClaim/useClaimableBalances.ts b/lib/modules/portfolio/PortfolioClaim/useClaimableBalances.ts index 55cd27881..359ee4677 100644 --- a/lib/modules/portfolio/PortfolioClaim/useClaimableBalances.ts +++ b/lib/modules/portfolio/PortfolioClaim/useClaimableBalances.ts @@ -11,6 +11,7 @@ import { BPT_DECIMALS } from '../../pool/pool.constants' import { ClaimablePool } from '../../pool/actions/claim/ClaimProvider' import { GqlChain, GqlPoolStakingGaugeReward } from '@/lib/shared/services/api/generated/graphql' import { groupBy, uniqBy } from 'lodash' +import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' interface ClaimableRewardRef { tokenAddress: Address @@ -76,7 +77,11 @@ export function useClaimableBalances(pools: ClaimablePool[]) { const { data, refetch, isLoading, status }: UseReadContractsReturnType = useReadContracts({ contracts: claimableRewardContractCalls, - query: { enabled: isConnected }, + query: { + enabled: isConnected, + // In chains like polygon, we don't want background refetches while waiting for min block confirmations + ...onlyExplicitRefetch, + }, }) // Format claimable rewards data diff --git a/lib/modules/web3/contracts/useManagedErc20Transaction.ts b/lib/modules/web3/contracts/useManagedErc20Transaction.ts index e721bbc16..22dbce9b5 100644 --- a/lib/modules/web3/contracts/useManagedErc20Transaction.ts +++ b/lib/modules/web3/contracts/useManagedErc20Transaction.ts @@ -17,6 +17,7 @@ import { TransactionExecution, TransactionSimulation, WriteAbiMutability } from import { useOnTransactionConfirmation } from './useOnTransactionConfirmation' import { useOnTransactionSubmission } from './useOnTransactionSubmission' import { getWaitForReceiptTimeout } from './wagmi-helpers' +import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' type Erc20Abi = typeof erc20Abi @@ -60,6 +61,8 @@ export function useManagedErc20Transaction({ query: { enabled: enabled && !shouldChangeNetwork, meta: simulationMeta, + // In chains like polygon, we don't want background refetches while waiting for min block confirmations + ...onlyExplicitRefetch, }, }) diff --git a/lib/modules/web3/contracts/useManagedSendTransaction.ts b/lib/modules/web3/contracts/useManagedSendTransaction.ts index 65b25e73d..62ab598ac 100644 --- a/lib/modules/web3/contracts/useManagedSendTransaction.ts +++ b/lib/modules/web3/contracts/useManagedSendTransaction.ts @@ -18,6 +18,7 @@ import { useRecentTransactions } from '../../transactions/RecentTransactionsProv import { mainnet } from 'viem/chains' import { useTxHash } from '../safe.hooks' import { getWaitForReceiptTimeout } from './wagmi-helpers' +import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' export type ManagedSendTransactionInput = { labels: TransactionLabels @@ -41,7 +42,8 @@ export function useManagedSendTransaction({ query: { enabled: !!txConfig && !shouldChangeNetwork, meta: gasEstimationMeta, - refetchOnWindowFocus: false, + // In chains like polygon, we don't want background refetches while waiting for min block confirmations + ...onlyExplicitRefetch, }, }) diff --git a/lib/modules/web3/contracts/useManagedTransaction.ts b/lib/modules/web3/contracts/useManagedTransaction.ts index d4579cdbf..9853fd876 100644 --- a/lib/modules/web3/contracts/useManagedTransaction.ts +++ b/lib/modules/web3/contracts/useManagedTransaction.ts @@ -15,6 +15,7 @@ import { useOnTransactionSubmission } from './useOnTransactionSubmission' import { captureWagmiExecutionError } from '@/lib/shared/utils/query-errors' import { useTxHash } from '../safe.hooks' import { getWaitForReceiptTimeout } from './wagmi-helpers' +import { onlyExplicitRefetch } from '@/lib/shared/utils/queries' type IAbiMap = typeof AbiMap type AbiMapKey = keyof typeof AbiMap @@ -53,6 +54,8 @@ export function useManagedTransaction({ query: { enabled: enabled && !shouldChangeNetwork, meta: txSimulationMeta, + // In chains like polygon, we don't want background refetches while waiting for min block confirmations + ...onlyExplicitRefetch, }, }) diff --git a/lib/shared/components/modals/ActionModalFooter.tsx b/lib/shared/components/modals/ActionModalFooter.tsx index 6cf8d290d..b3b307349 100644 --- a/lib/shared/components/modals/ActionModalFooter.tsx +++ b/lib/shared/components/modals/ActionModalFooter.tsx @@ -75,7 +75,10 @@ export function ActionModalFooter({ isSuccess, currentStep, returnLabel, returnA transition={{ duration: 0.3 }} style={{ width: '100%' }} > - {currentStep.renderAction()} + + {/* Keep currentStep?. optional chaining cause some edge cases require it */} + {currentStep?.renderAction()} + )} diff --git a/lib/shared/utils/queries.ts b/lib/shared/utils/queries.ts index 7e77cd6d7..9b6b85de7 100644 --- a/lib/shared/utils/queries.ts +++ b/lib/shared/utils/queries.ts @@ -1,6 +1,22 @@ import { UseQueryResult } from '@tanstack/react-query' -// When you only want a query to refetch when the key changes or refetch is called. +/* + When you only want a query to refetch when the key changes or refetch is explicitly called. + + Why no background refetches? Example where background refetches can be harmful: + Polygon: + 1. The user is waiting for a Tx confirmation and goes to another tab + 2. The tx is confirmed but has less than minConfirmations + 3. The user comes back to balancer tab, which triggers a background react-query for the simulation (only if staleTime: 0) + 5. The new simulation background query fails cause the tx is already confirmed (we get misleading sentry errors cause there was not a real error) + 6. The tx reaches > minConfirmations so the flow can be finished successfully (however, point 5. can temporarily alter the UI and send wrong Sentry logs) + + Setting refetchOnWindowFocus to false will avoid background refetches like the ones in the previous example. + + More info: + https://tanstack.com/query/v5/docs/framework/react/guides/window-focus-refetching + https://tkdodo.eu/blog/practical-react-query +*/ export const onlyExplicitRefetch = { refetchOnMount: false, refetchOnReconnect: false,