From c6edc67ef07b18356af902daba17f8e18050acb5 Mon Sep 17 00:00:00 2001 From: Christopher Howard Date: Thu, 29 Aug 2024 15:36:07 -0400 Subject: [PATCH 1/3] Implement perceived finality (#6037) * feat: perceived finality initial * fix: update chain id import --- src/hooks/useWatchPendingTxs.ts | 40 ++++++ src/resources/assets/UserAssetsQuery.ts | 47 +++++-- src/state/staleBalances/index.test.ts | 165 ++++++++++++++++++++++++ src/state/staleBalances/index.ts | 99 ++++++++++++++ 4 files changed, 338 insertions(+), 13 deletions(-) create mode 100644 src/state/staleBalances/index.test.ts create mode 100644 src/state/staleBalances/index.ts diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index 8e22b715a99..72ec35f0a93 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -16,6 +16,7 @@ import { Address } from 'viem'; import { nftsQueryKey } from '@/resources/nfts'; import { getNftSortForAddress } from './useNFTsSortBy'; import { ChainId } from '@/networks/types'; +import { staleBalancesStore } from '@/state/staleBalances'; export const useWatchPendingTransactions = ({ address }: { address: string }) => { const { storePendingTransactions, setPendingTransactions } = usePendingTransactionsStore(state => ({ @@ -164,6 +165,7 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => ); const watchPendingTransactions = useCallback(async () => { + const connectedToHardhat = getIsHardhatConnected(); if (!pendingTransactions?.length) return; const updatedPendingTransactions = await Promise.all( pendingTransactions.map((tx: RainbowTransaction) => processPendingTransaction(tx)) @@ -190,6 +192,20 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => const chainIds = RainbowNetworkObjects.filter(networkObject => networkObject.enabled && networkObject.networkType !== 'testnet').map( networkObject => networkObject.id ); + minedTransactions.forEach(tx => { + if (tx.changes?.length) { + tx.changes?.forEach(change => { + processStaleAsset({ asset: change?.asset, address, transactionHash: tx?.hash }); + }); + } else if (tx.asset) { + processStaleAsset({ address, asset: tx.asset, transactionHash: tx?.hash }); + } + }); + + queryClient.refetchQueries({ + queryKey: userAssetsQueryKey({ address, currency: nativeCurrency, connectedToHardhat }), + }); + await queryClient.refetchQueries({ queryKey: consolidatedTransactionsQueryKey({ address, @@ -217,3 +233,27 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => return { watchPendingTransactions }; }; + +function processStaleAsset({ + asset, + address, + transactionHash, +}: { + asset: RainbowTransaction['asset']; + address: string; + transactionHash: string; +}) { + const { addStaleBalance } = staleBalancesStore.getState(); + const chainId = asset?.chainId; + if (asset && typeof chainId === 'number') { + const changedAssetAddress = asset?.address as Address; + addStaleBalance({ + address, + chainId, + info: { + address: changedAssetAddress, + transactionHash, + }, + }); + } +} diff --git a/src/resources/assets/UserAssetsQuery.ts b/src/resources/assets/UserAssetsQuery.ts index 1e0a285e3d5..47db136d5e2 100644 --- a/src/resources/assets/UserAssetsQuery.ts +++ b/src/resources/assets/UserAssetsQuery.ts @@ -11,6 +11,7 @@ import { filterPositionsData, parseAddressAsset } from './assets'; import { fetchHardhatBalances } from './hardhatAssets'; import { AddysAccountAssetsMeta, AddysAccountAssetsResponse, RainbowAddressAssets } from './types'; import { Network } from '@/networks/types'; +import { staleBalancesStore } from '@/state/staleBalances'; // /////////////////////////////////////////////// // Query Types @@ -32,15 +33,26 @@ type UserAssetsQueryKey = ReturnType; // /////////////////////////////////////////////// // Query Function -const fetchUserAssetsForChainIds = async (address: string, currency: NativeCurrencyKey, chainIds: number[]) => { +const fetchUserAssetsForChainIds = async ({ + address, + currency, + chainIds, + staleBalanceParam, +}: { + address: string; + currency: NativeCurrencyKey; + chainIds: number[]; + staleBalanceParam?: string; +}) => { const chainIdsString = chainIds.join(','); - const url = `https://addys.p.rainbow.me/v3/${chainIdsString}/${address}/assets`; + let url = `https://addys.p.rainbow.me/v3/${chainIdsString}/${address}/assets?currency=${currency.toLowerCase()}`; + + if (staleBalanceParam) { + url += url + staleBalanceParam; + } const response = await rainbowFetch(url, { method: 'get', - params: { - currency: currency.toLowerCase(), - }, headers: { Authorization: `Bearer ${ADDYS_API_KEY}`, }, @@ -66,7 +78,10 @@ async function userAssetsQueryFunction({ network => network.id ); - const { erroredChainIds, results } = await fetchAndParseUserAssetsForChainIds(address, currency, chainIds); + staleBalancesStore.getState().clearExpiredData(address); + const staleBalanceParam = staleBalancesStore.getState().getStaleBalancesQueryParam(address); + + const { erroredChainIds, results } = await fetchAndParseUserAssetsForChainIds({ address, currency, chainIds, staleBalanceParam }); let parsedSuccessResults = results; // grab cached data for chain IDs with errors @@ -102,7 +117,7 @@ const retryErroredChainIds = async ( connectedToHardhat: boolean, erroredChainIds: number[] ) => { - const { meta, results } = await fetchAndParseUserAssetsForChainIds(address, currency, erroredChainIds); + const { meta, results } = await fetchAndParseUserAssetsForChainIds({ address, currency, chainIds: erroredChainIds }); let parsedSuccessResults = results; const successChainIds = meta?.chain_ids; @@ -142,12 +157,18 @@ interface AssetsAndMetadata { results: RainbowAddressAssets; } -const fetchAndParseUserAssetsForChainIds = async ( - address: string, - currency: NativeCurrencyKey, - chainIds: number[] -): Promise => { - const data = await fetchUserAssetsForChainIds(address, currency, chainIds); +const fetchAndParseUserAssetsForChainIds = async ({ + address, + currency, + chainIds, + staleBalanceParam, +}: { + address: string; + currency: NativeCurrencyKey; + chainIds: number[]; + staleBalanceParam?: string; +}): Promise => { + const data = await fetchUserAssetsForChainIds({ address, currency, chainIds, staleBalanceParam }); let parsedSuccessResults = parseUserAssetsByChain(data); // filter out positions data diff --git a/src/state/staleBalances/index.test.ts b/src/state/staleBalances/index.test.ts new file mode 100644 index 00000000000..b07e73acb7b --- /dev/null +++ b/src/state/staleBalances/index.test.ts @@ -0,0 +1,165 @@ +import { Address } from 'viem'; + +import { staleBalancesStore } from '.'; +import { DAI_ADDRESS, OP_ADDRESS } from '@/references'; +import { ETH_ADDRESS } from '@rainbow-me/swaps'; +import { ChainId } from '@/networks/types'; + +const TEST_ADDRESS_1 = '0xFOO'; +const TEST_ADDRESS_2 = '0xBAR'; +const THEN = Date.now() - 700000; +const WHEN = Date.now() + 60000; + +test('should be able to add asset information to the staleBalances object', async () => { + const { addStaleBalance, staleBalances } = staleBalancesStore.getState(); + expect(staleBalances).toStrictEqual({}); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.mainnet, + info: { + address: DAI_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: THEN, + }, + }); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.mainnet, + info: { + address: ETH_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }); + const newStaleBalances = staleBalancesStore.getState().staleBalances; + expect(newStaleBalances).toStrictEqual({ + [TEST_ADDRESS_1]: { + [ChainId.mainnet]: { + [DAI_ADDRESS]: { + address: DAI_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: THEN, + }, + [ETH_ADDRESS]: { + address: ETH_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }, + }, + }); +}); + +test('should generate accurate stale balance query params and clear expired data - case #1', async () => { + const { getStaleBalancesQueryParam, clearExpiredData } = staleBalancesStore.getState(); + clearExpiredData(TEST_ADDRESS_1); + const queryParam = getStaleBalancesQueryParam(TEST_ADDRESS_1); + expect(queryParam).toStrictEqual(`&token=${ChainId.mainnet}.${ETH_ADDRESS}`); +}); + +test('should be able to remove expired stale balance and preserve unexpired data', async () => { + const { addStaleBalance, clearExpiredData } = staleBalancesStore.getState(); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.mainnet, + info: { + address: DAI_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: THEN, + }, + }); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.mainnet, + info: { + address: ETH_ADDRESS as Address, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }); + clearExpiredData(TEST_ADDRESS_1); + const newStaleBalances = staleBalancesStore.getState().staleBalances; + expect(newStaleBalances).toStrictEqual({ + [TEST_ADDRESS_1]: { + [ChainId.mainnet]: { + [ETH_ADDRESS]: { + address: ETH_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }, + }, + }); +}); + +test('should preserve data from other addresses when clearing expired data', async () => { + const { addStaleBalance, clearExpiredData } = staleBalancesStore.getState(); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.mainnet, + info: { + address: DAI_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: THEN, + }, + }); + addStaleBalance({ + address: TEST_ADDRESS_2, + chainId: ChainId.mainnet, + info: { + address: ETH_ADDRESS as Address, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }); + clearExpiredData(TEST_ADDRESS_1); + const newStaleBalances = staleBalancesStore.getState().staleBalances; + expect(newStaleBalances).toStrictEqual({ + [TEST_ADDRESS_1]: { + [ChainId.mainnet]: { + [ETH_ADDRESS]: { + address: ETH_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }, + }, + [TEST_ADDRESS_2]: { + [ChainId.mainnet]: { + [ETH_ADDRESS]: { + address: ETH_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }, + }, + }); +}); + +test('should generate accurate stale balance query params and clear expired data - case #2', async () => { + const { getStaleBalancesQueryParam, clearExpiredData } = staleBalancesStore.getState(); + clearExpiredData(TEST_ADDRESS_2); + const queryParam = getStaleBalancesQueryParam(TEST_ADDRESS_2); + expect(queryParam).toStrictEqual(`&token=${ChainId.mainnet}.${ETH_ADDRESS}`); +}); + +test('should generate accurate stale balance query params and clear expired data - case #3', async () => { + const { addStaleBalance, getStaleBalancesQueryParam, clearExpiredData } = staleBalancesStore.getState(); + addStaleBalance({ + address: TEST_ADDRESS_1, + chainId: ChainId.optimism, + info: { + address: OP_ADDRESS, + transactionHash: '0xFOOBAR', + expirationTime: WHEN, + }, + }); + + clearExpiredData(TEST_ADDRESS_1); + const queryParam = getStaleBalancesQueryParam(TEST_ADDRESS_1); + expect(queryParam).toStrictEqual(`&token=${ChainId.mainnet}.${ETH_ADDRESS}&token=${ChainId.optimism}.${OP_ADDRESS}`); + + clearExpiredData(TEST_ADDRESS_2); + const queryParam2 = getStaleBalancesQueryParam(TEST_ADDRESS_2); + expect(queryParam2).toStrictEqual(`&token=${ChainId.mainnet}.${ETH_ADDRESS}`); +}); diff --git a/src/state/staleBalances/index.ts b/src/state/staleBalances/index.ts new file mode 100644 index 00000000000..8a9928aaacb --- /dev/null +++ b/src/state/staleBalances/index.ts @@ -0,0 +1,99 @@ +import { createRainbowStore } from '../internal/createRainbowStore'; + +const TIME_TO_WATCH = 600000; + +interface StaleBalanceInfo { + address: string; + expirationTime?: number; + transactionHash: string; +} + +interface StaleBalances { + [key: string]: StaleBalanceInfo; +} +interface StaleBalancesByChainId { + [key: number]: StaleBalances; +} + +export interface StaleBalancesState { + addStaleBalance: ({ address, chainId, info }: { address: string; chainId: number; info: StaleBalanceInfo }) => void; + clearExpiredData: (address: string) => void; + getStaleBalancesQueryParam: (address: string) => string; + staleBalances: Record; +} + +export const staleBalancesStore = createRainbowStore( + (set, get) => ({ + addStaleBalance: ({ address, chainId, info }: { address: string; chainId: number; info: StaleBalanceInfo }) => { + set(state => { + const { staleBalances } = state; + const staleBalancesForUser = staleBalances[address] || {}; + const staleBalancesForChain = staleBalancesForUser[chainId] || {}; + const newStaleBalancesForChain = { + ...staleBalancesForChain, + [info.address]: { + ...info, + expirationTime: info.expirationTime || Date.now() + TIME_TO_WATCH, + }, + }; + const newStaleBalancesForUser = { + ...staleBalancesForUser, + [chainId]: newStaleBalancesForChain, + }; + return { + staleBalances: { + ...staleBalances, + [address]: newStaleBalancesForUser, + }, + }; + }); + }, + clearExpiredData: (address: string) => { + set(state => { + const { staleBalances } = state; + const staleBalancesForUser = staleBalances[address] || {}; + const newStaleBalancesForUser: StaleBalancesByChainId = { + ...staleBalancesForUser, + }; + for (const c of Object.keys(staleBalancesForUser)) { + const chainId = parseInt(c, 10); + const newStaleBalancesForChain = { + ...(staleBalancesForUser[chainId] || {}), + }; + for (const staleBalance of Object.values(newStaleBalancesForChain)) { + if (typeof staleBalance.expirationTime === 'number' && staleBalance.expirationTime <= Date.now()) { + delete newStaleBalancesForChain[staleBalance.address]; + } + } + newStaleBalancesForUser[chainId] = newStaleBalancesForChain; + } + return { + staleBalances: { + ...staleBalances, + [address]: newStaleBalancesForUser, + }, + }; + }); + }, + getStaleBalancesQueryParam: (address: string) => { + let queryStringFragment = ''; + const { staleBalances } = get(); + const staleBalancesForUser = staleBalances[address]; + for (const c of Object.keys(staleBalancesForUser)) { + const chainId = parseInt(c, 10); + const staleBalancesForChain = staleBalancesForUser[chainId]; + for (const staleBalance of Object.values(staleBalancesForChain)) { + if (typeof staleBalance.expirationTime === 'number') { + queryStringFragment += `&token=${chainId}.${staleBalance.address}`; + } + } + } + return queryStringFragment; + }, + staleBalances: {}, + }), + { + storageKey: 'staleBalances', + version: 0, + } +); From 349bd225abe357795f15b59a1c526edc144c4f46 Mon Sep 17 00:00:00 2001 From: Christopher Howard Date: Thu, 29 Aug 2024 15:36:51 -0400 Subject: [PATCH 2/3] fix: remove p-queue (#6063) * fix: remove p-queue * fix: update yarn lock file --- package.json | 1 - .../firstTransactionTimestampQuery.ts | 8 ++++---- yarn.lock | 20 +------------------ 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 533313474f1..52c229cff23 100644 --- a/package.json +++ b/package.json @@ -193,7 +193,6 @@ "moti": "0.28", "multiformats": "9.6.2", "nanoid": "3.2.0", - "p-queue": "7.2.0", "p-wait-for": "4.1.0", "pako": "2.0.4", "parse-ms": "2.1.0", diff --git a/src/resources/transactions/firstTransactionTimestampQuery.ts b/src/resources/transactions/firstTransactionTimestampQuery.ts index 033c295dad8..c1bbbc42888 100644 --- a/src/resources/transactions/firstTransactionTimestampQuery.ts +++ b/src/resources/transactions/firstTransactionTimestampQuery.ts @@ -1,5 +1,4 @@ import { useQuery } from '@tanstack/react-query'; -import PQueue from 'p-queue/dist'; import { createQueryKey, queryClient, QueryConfig, QueryFunctionArgs, QueryFunctionResult } from '@/react-query'; import { getFirstTransactionTimestamp } from '@/utils/ethereumUtils'; @@ -23,8 +22,6 @@ export type FirstTransactionTimestampQueryKey = ReturnType) { @@ -35,7 +32,10 @@ export async function firstTransactionTimestampQueryFunction({ address = (await fetchENSAddress({ name: addressOrName })) ?? ''; } - const timestamp = address ? await queue.add(async () => getFirstTransactionTimestamp(address)) : null; + let timestamp; + if (address) { + timestamp = await getFirstTransactionTimestamp(address); + } return timestamp ?? null; } diff --git a/yarn.lock b/yarn.lock index 346f7b3376b..9d7df69de4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7976,7 +7976,6 @@ __metadata: multiformats: "npm:9.6.2" nanoid: "npm:3.2.0" node-vibrant: "npm:3.2.1-alpha.1" - p-queue: "npm:7.2.0" p-wait-for: "npm:4.1.0" pako: "npm:2.0.4" parse-ms: "npm:2.1.0" @@ -13163,13 +13162,6 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.7": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b - languageName: node - linkType: hard - "events@npm:3.3.0, events@npm:^3.0.0, events@npm:^3.2.0, events@npm:^3.3.0": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -19590,17 +19582,7 @@ __metadata: languageName: node linkType: hard -"p-queue@npm:7.2.0": - version: 7.2.0 - resolution: "p-queue@npm:7.2.0" - dependencies: - eventemitter3: "npm:^4.0.7" - p-timeout: "npm:^5.0.2" - checksum: 10c0/0dad31488d6afe5c27a84ed00a703eef1ed4387338e0debe8155d36172808c6ae0451be5d88a12aa41f1deb4d3583ecd19e5f6ded5f06c937b01ff828d18c6cb - languageName: node - linkType: hard - -"p-timeout@npm:^5.0.0, p-timeout@npm:^5.0.2": +"p-timeout@npm:^5.0.0": version: 5.1.0 resolution: "p-timeout@npm:5.1.0" checksum: 10c0/1b026cf9d5878c64bec4341ca9cda8ec6b8b3aea8a57885ca0fe2b35753a20d767fb6f9d3aa41e1252f42bc95432c05ea33b6b18f271fb10bfb0789591850a41 From 63aafb9cd0d50669c4363faa25a56479316f078a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Mi=C3=B1o?= Date: Thu, 29 Aug 2024 17:58:23 -0400 Subject: [PATCH 3/3] fix swap test (#6060) * line * use connected to hardhat store hook * rm version * pass connected to hardhat as network object prop * Revert "pass connected to hardhat as network object prop" This reverts commit 9e591cc97f6a007501370990fc574dd675dc3e4d. * test send eth throw * hardhat hook inside rainbowcontext * rm disablesynchronization * temp do not use cached provider * use provider instead of static web3provider in hardhat assets * rm getIsHardhatConnected * rm logs * add disableSynchronization again * use connectedtohardhat * rm ishardhat --- e2e/9_swaps.spec.ts | 5 ++-- e2e/helpers.ts | 5 ++++ .../Swap/components/SwapActionButton.tsx | 9 ++++++- .../screens/Swap/hooks/useAssetsToSell.ts | 8 +++--- .../screens/Swap/providers/swap-provider.tsx | 8 +++--- .../Swap/resources/assets/userAssets.ts | 1 - src/__swaps__/utils/decimalFormatter.ts | 2 +- src/handlers/web3.ts | 26 +++---------------- src/helpers/RainbowContext.tsx | 2 +- src/hooks/useENSRegistrationStepHandler.tsx | 21 ++++++++------- src/hooks/useImportingWallet.ts | 4 +-- src/hooks/useRefreshAccountData.ts | 7 +++-- src/hooks/useWatchPendingTxs.ts | 10 +++---- src/redux/explorer.ts | 6 ++--- src/redux/gas.ts | 15 +++-------- src/resources/assets/hardhatAssets.ts | 5 ++-- src/resources/assets/useSortedUserAssets.ts | 4 +-- src/resources/assets/useUserAsset.ts | 4 +-- src/resources/assets/useUserAssetCount.ts | 4 +-- src/screens/SendSheet.js | 7 ++--- src/state/assets/userAssets.ts | 4 +-- src/state/sync/UserAssetsSync.tsx | 5 ++-- src/utils/ethereumUtils.ts | 5 ++-- src/utils/methodRegistry.ts | 5 ++-- 24 files changed, 77 insertions(+), 95 deletions(-) diff --git a/e2e/9_swaps.spec.ts b/e2e/9_swaps.spec.ts index f899fbdc68f..4655c019275 100644 --- a/e2e/9_swaps.spec.ts +++ b/e2e/9_swaps.spec.ts @@ -20,10 +20,8 @@ import { afterAllcleanApp, fetchElementAttributes, tap, - tapByText, delayTime, swipeUntilVisible, - tapAndLongPressByText, tapAndLongPress, swipe, } from './helpers'; @@ -69,10 +67,11 @@ describe('Swap Sheet Interaction Flow', () => { await tap('token-to-buy-dai-1'); await delayTime('medium'); + const swapInput = await fetchElementAttributes('swap-asset-input'); - expect(swapInput.label).toContain('ETH'); expect(swapInput.label).toContain('10'); + expect(swapInput.label).toContain('ETH'); }); it('Should be able to go to review and execute a swap', async () => { diff --git a/e2e/helpers.ts b/e2e/helpers.ts index dd82d8f2754..7ecb9811fc3 100644 --- a/e2e/helpers.ts +++ b/e2e/helpers.ts @@ -472,6 +472,11 @@ export async function sendETHtoTestWallet() { to: TESTING_WALLET, value: parseEther('20'), }); + await delayTime('long'); + const balance = await provider.getBalance(TESTING_WALLET); + if (balance.lt(parseEther('20'))) { + throw Error('Error sending ETH to test wallet'); + } return true; } diff --git a/src/__swaps__/screens/Swap/components/SwapActionButton.tsx b/src/__swaps__/screens/Swap/components/SwapActionButton.tsx index a6a8d913966..4530a28db5d 100644 --- a/src/__swaps__/screens/Swap/components/SwapActionButton.tsx +++ b/src/__swaps__/screens/Swap/components/SwapActionButton.tsx @@ -139,7 +139,14 @@ function SwapButton({ )} {typeof label !== 'undefined' && ( - + {labelValue} diff --git a/src/__swaps__/screens/Swap/hooks/useAssetsToSell.ts b/src/__swaps__/screens/Swap/hooks/useAssetsToSell.ts index a2d181c9a08..53efd2f9cc1 100644 --- a/src/__swaps__/screens/Swap/hooks/useAssetsToSell.ts +++ b/src/__swaps__/screens/Swap/hooks/useAssetsToSell.ts @@ -10,7 +10,7 @@ import { useUserAssets } from '@/__swaps__/screens/Swap/resources/assets'; import { ParsedAssetsDictByChain, ParsedSearchAsset, UserAssetFilter } from '@/__swaps__/types/assets'; import { useAccountSettings, useDebounce } from '@/hooks'; import { userAssetsStore } from '@/state/assets/userAssets'; -import { getIsHardhatConnected } from '@/handlers/web3'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; const sortBy = (by: UserAssetFilter) => { switch (by) { @@ -22,15 +22,15 @@ const sortBy = (by: UserAssetFilter) => { }; export const useAssetsToSell = () => { - const { accountAddress: currentAddress, nativeCurrency: currentCurrency, network: currentNetwork } = useAccountSettings(); - - const connectedToHardhat = getIsHardhatConnected(); + const { accountAddress: currentAddress, nativeCurrency: currentCurrency } = useAccountSettings(); const filter = userAssetsStore(state => state.filter); const searchQuery = userAssetsStore(state => state.inputSearchQuery); const debouncedAssetToSellFilter = useDebounce(searchQuery, 200); + const { connectedToHardhat } = useConnectedToHardhatStore(); + const { data: userAssets = [] } = useUserAssets( { address: currentAddress as Address, diff --git a/src/__swaps__/screens/Swap/providers/swap-provider.tsx b/src/__swaps__/screens/Swap/providers/swap-provider.tsx index 917e3ee5fa2..7c069fc1a20 100644 --- a/src/__swaps__/screens/Swap/providers/swap-provider.tsx +++ b/src/__swaps__/screens/Swap/providers/swap-provider.tsx @@ -29,7 +29,7 @@ import { SwapAssetType, inputKeys } from '@/__swaps__/types/swap'; import { getDefaultSlippageWorklet, isUnwrapEthWorklet, isWrapEthWorklet, parseAssetAndExtend } from '@/__swaps__/utils/swaps'; import { analyticsV2 } from '@/analytics'; import { LegacyTransactionGasParamAmounts, TransactionGasParamAmounts } from '@/entities'; -import { getFlashbotsProvider, getIsHardhatConnected, getProvider, isHardHat } from '@/handlers/web3'; +import { getFlashbotsProvider, getProvider } from '@/handlers/web3'; import { WrappedAlert as Alert } from '@/helpers/alert'; import { useAccountSettings } from '@/hooks'; import { useAnimatedInterval } from '@/hooks/reanimated/useAnimatedInterval'; @@ -56,6 +56,7 @@ import { useSwapOutputQuotesDisabled } from '../hooks/useSwapOutputQuotesDisable import { SyncGasStateToSharedValues, SyncQuoteSharedValuesToState } from './SyncSwapStateAndSharedValues'; import { performanceTracking, Screens, TimeToSignOperation } from '@/state/performance/performance'; import { getRemoteConfig } from '@/model/remoteConfig'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; const swapping = i18n.t(i18n.l.swap.actions.swapping); const holdToSwap = i18n.t(i18n.l.swap.actions.hold_to_swap); @@ -199,8 +200,7 @@ export const SwapProvider = ({ children }: SwapProviderProps) => { parameters.flashbots && getNetworkObject({ chainId: parameters.chainId }).features.flashbots ? await getFlashbotsProvider() : getProvider({ chainId: parameters.chainId }); - const providerUrl = provider?.connection?.url; - const connectedToHardhat = !!providerUrl && isHardHat(providerUrl); + const connectedToHardhat = useConnectedToHardhatStore.getState().connectedToHardhat; const isBridge = swapsStore.getState().inputAsset?.mainnetAddress === swapsStore.getState().outputAsset?.mainnetAddress; const isDegenModeEnabled = swapsStore.getState().degenMode; @@ -258,7 +258,7 @@ export const SwapProvider = ({ children }: SwapProviderProps) => { }; } - const chainId = getIsHardhatConnected() ? ChainId.hardhat : parameters.chainId; + const chainId = connectedToHardhat ? ChainId.hardhat : parameters.chainId; const { errorMessage } = await performanceTracking.getState().executeFn({ fn: walletExecuteRap, screen: Screens.SWAPS, diff --git a/src/__swaps__/screens/Swap/resources/assets/userAssets.ts b/src/__swaps__/screens/Swap/resources/assets/userAssets.ts index 4b14f675c49..37dc8c9f185 100644 --- a/src/__swaps__/screens/Swap/resources/assets/userAssets.ts +++ b/src/__swaps__/screens/Swap/resources/assets/userAssets.ts @@ -4,7 +4,6 @@ import { Address } from 'viem'; import { QueryConfigWithSelect, QueryFunctionArgs, QueryFunctionResult, createQueryKey, queryClient } from '@/react-query'; -import { getIsHardhatConnected } from '@/handlers/web3'; import { RainbowError, logger } from '@/logger'; import { RainbowFetchClient } from '@/rainbow-fetch'; import { SupportedCurrencyKey, SUPPORTED_CHAIN_IDS } from '@/references'; diff --git a/src/__swaps__/utils/decimalFormatter.ts b/src/__swaps__/utils/decimalFormatter.ts index 5b047b8c677..fc0f9a943ec 100644 --- a/src/__swaps__/utils/decimalFormatter.ts +++ b/src/__swaps__/utils/decimalFormatter.ts @@ -82,7 +82,7 @@ export function valueBasedDecimalFormatter({ // Format the number to add separators and trim trailing zeros const numberFormatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: minimumDecimalPlaces, - maximumFractionDigits: maximumDecimalPlaces, + maximumFractionDigits: maximumDecimalPlaces || 0, useGrouping: !stripSeparators, }); diff --git a/src/handlers/web3.ts b/src/handlers/web3.ts index 75c1dd85022..13416a8aceb 100644 --- a/src/handlers/web3.ts +++ b/src/handlers/web3.ts @@ -166,15 +166,6 @@ export const isL2Chain = ({ chainId }: { chainId: ChainId }): boolean => { return getNetworkObject({ chainId }).networkType === 'layer2'; }; -/** - * @desc Checks whether a provider is HardHat. - * @param providerUrl The provider URL. - * @return Whether or not the provider is HardHat. - */ -export const isHardHat = (providerUrl: string): boolean => { - return providerUrl?.startsWith('http://') && providerUrl?.endsWith('8545'); -}; - /** * @desc Checks if the given network is a testnet. * @param network The network to check. @@ -201,29 +192,18 @@ export const getCachedProviderForNetwork = (chainId: ChainId = ChainId.mainnet): export const getProvider = ({ chainId }: { chainId: number }): StaticJsonRpcProvider => { const cachedProvider = chainsProviders.get(chainId); - if (cachedProvider) { + const networkObject = getNetworkObject({ chainId }); + + if (cachedProvider && cachedProvider?.connection.url === networkObject.rpc()) { return cachedProvider; } - const networkObject = getNetworkObject({ chainId }); - const provider = new StaticJsonRpcProvider(networkObject.rpc(), networkObject.id); chainsProviders.set(chainId, provider); return provider; }; -/** - * @desc Checks if the active network is Hardhat. - * @returns boolean: `true` if connected to Hardhat. - */ -export const getIsHardhatConnected = (): boolean => { - const currentChainId = store.getState().settings.chainId; - const currentProviderUrl = getCachedProviderForNetwork(currentChainId)?.connection?.url; - const connectedToHardhat = !!currentProviderUrl && isHardHat(currentProviderUrl); - return connectedToHardhat; -}; - /** * @desc Sends an arbitrary RPC call using a given provider, or the default * cached provider. diff --git a/src/helpers/RainbowContext.tsx b/src/helpers/RainbowContext.tsx index 44dca36510b..c0734b50313 100644 --- a/src/helpers/RainbowContext.tsx +++ b/src/helpers/RainbowContext.tsx @@ -27,7 +27,7 @@ export default function RainbowContextWrapper({ children }: PropsWithChildren) { // This value is hold here to prevent JS VM from shutting down // on unmounting all shared values. useSharedValue(0); - const setConnectedToHardhat = useConnectedToHardhatStore.getState().setConnectedToHardhat; + const { setConnectedToHardhat } = useConnectedToHardhatStore(); const [config, setConfig] = useState>( Object.entries(defaultConfig).reduce((acc, [key, { value }]) => ({ ...acc, [key]: value }), {}) ); diff --git a/src/hooks/useENSRegistrationStepHandler.tsx b/src/hooks/useENSRegistrationStepHandler.tsx index 5110a579106..f53c8ece33a 100644 --- a/src/hooks/useENSRegistrationStepHandler.tsx +++ b/src/hooks/useENSRegistrationStepHandler.tsx @@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux'; import usePrevious from './usePrevious'; import { useENSRegistration, useInterval } from '.'; import { RegistrationParameters } from '@/entities'; -import { getProvider, isHardHat, web3Provider } from '@/handlers/web3'; +import { getProvider } from '@/handlers/web3'; import { ENS_SECONDS_PADDING, ENS_SECONDS_WAIT, @@ -15,15 +15,16 @@ import { } from '@/helpers/ens'; import { updateTransactionRegistrationParameters } from '@/redux/ensRegistration'; import { ChainId } from '@/networks/types'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; const checkRegisterBlockTimestamp = async ({ registrationParameters, secondsSinceCommitConfirmed, - isTestingHardhat, + connectedToHardhat, }: { registrationParameters: RegistrationParameters; secondsSinceCommitConfirmed: number; - isTestingHardhat: boolean; + connectedToHardhat: boolean; }) => { try { const provider = getProvider({ chainId: ChainId.mainnet }); @@ -34,7 +35,7 @@ const checkRegisterBlockTimestamp = async ({ (secs > ENS_SECONDS_WAIT_WITH_PADDING && secondsSinceCommitConfirmed > ENS_SECONDS_WAIT_WITH_PADDING) || // sometimes the provider.getBlock('latest) takes a long time to update to newest block secondsSinceCommitConfirmed > ENS_SECONDS_WAIT_PROVIDER_PADDING || - isTestingHardhat + connectedToHardhat ) { return true; } @@ -61,12 +62,12 @@ export default function useENSRegistrationStepHandler(observer = true) { -1 ); - const isTestingHardhat = useMemo(() => isHardHat(web3Provider.connection.url), []); + const { connectedToHardhat } = useConnectedToHardhatStore(); const [readyToRegister, setReadyToRegister] = useState(secondsSinceCommitConfirmed > ENS_SECONDS_WAIT); // flag to wait 10 secs before we get the tx block, to be able to simulate not confirmed tx when testing - const shouldLoopForConfirmation = useRef(isTestingHardhat); + const shouldLoopForConfirmation = useRef(connectedToHardhat); const registrationStep = useMemo(() => { if (mode === REGISTRATION_MODES.EDIT) return REGISTRATION_STEPS.EDIT; @@ -100,7 +101,7 @@ export default function useENSRegistrationStepHandler(observer = true) { const now = Date.now(); const msBlockTimestamp = getBlockMsTimestamp(block); // hardhat block timestamp is behind - const timeDifference = isTestingHardhat ? now - msBlockTimestamp : 0; + const timeDifference = connectedToHardhat ? now - msBlockTimestamp : 0; const commitTransactionConfirmedAt = msBlockTimestamp + timeDifference; const secs = differenceInSeconds(now, commitTransactionConfirmedAt); setSecondsSinceCommitConfirmed(secondsSinceCommitConfirmed < 0 ? 0 : secs); @@ -114,7 +115,7 @@ export default function useENSRegistrationStepHandler(observer = true) { shouldLoopForConfirmation.current = false; } return confirmed; - }, [observer, commitTransactionHash, isTestingHardhat, secondsSinceCommitConfirmed, dispatch]); + }, [observer, commitTransactionHash, connectedToHardhat, secondsSinceCommitConfirmed, dispatch]); const startPollingWatchCommitTransaction = useCallback(async () => { if (observer) return; @@ -167,7 +168,7 @@ export default function useENSRegistrationStepHandler(observer = true) { if (!observer && secondsSinceCommitConfirmed % 2 === 0 && secondsSinceCommitConfirmed >= ENS_SECONDS_WAIT && !readyToRegister) { const checkIfReadyToRegister = async () => { const readyToRegister = await checkRegisterBlockTimestamp({ - isTestingHardhat, + connectedToHardhat, registrationParameters, secondsSinceCommitConfirmed, }); @@ -175,7 +176,7 @@ export default function useENSRegistrationStepHandler(observer = true) { }; checkIfReadyToRegister(); } - }, [isTestingHardhat, observer, readyToRegister, registrationParameters, secondsSinceCommitConfirmed]); + }, [connectedToHardhat, observer, readyToRegister, registrationParameters, secondsSinceCommitConfirmed]); useEffect( () => () => { diff --git a/src/hooks/useImportingWallet.ts b/src/hooks/useImportingWallet.ts index d2fce5085a5..1523bae55c4 100644 --- a/src/hooks/useImportingWallet.ts +++ b/src/hooks/useImportingWallet.ts @@ -123,9 +123,9 @@ export default function useImportingWallet({ showImportModal = true } = {}) { // Validate ENS if (isENSAddressFormat(input)) { try { - const web3Provider = getProvider({ chainId: ChainId.mainnet }); + const provider = getProvider({ chainId: ChainId.mainnet }); const [address, avatar] = await Promise.all([ - web3Provider.resolveName(input), + provider.resolveName(input), !avatarUrl && profilesEnabled && fetchENSAvatar(input, { swallowError: true }), ]); if (!address) { diff --git a/src/hooks/useRefreshAccountData.ts b/src/hooks/useRefreshAccountData.ts index 056b3c1af94..f9cb7ab786c 100644 --- a/src/hooks/useRefreshAccountData.ts +++ b/src/hooks/useRefreshAccountData.ts @@ -1,7 +1,6 @@ import delay from 'delay'; import { useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; -import { getIsHardhatConnected } from '@/handlers/web3'; import { walletConnectLoadState } from '../redux/walletconnect'; import { fetchWalletENSAvatars, fetchWalletNames } from '../redux/wallets'; import useAccountSettings from './useAccountSettings'; @@ -16,6 +15,7 @@ import useNftSort from './useNFTsSortBy'; import { Address } from 'viem'; import { addysSummaryQueryKey } from '@/resources/summary/summary'; import useWallets from './useWallets'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; export default function useRefreshAccountData() { const dispatch = useDispatch(); @@ -23,6 +23,7 @@ export default function useRefreshAccountData() { const [isRefreshing, setIsRefreshing] = useState(false); const profilesEnabled = useExperimentalFlag(PROFILES); const { nftSort } = useNftSort(); + const { connectedToHardhat } = useConnectedToHardhatStore(); const { wallets } = useWallets(); @@ -32,8 +33,6 @@ export default function useRefreshAccountData() { ); const fetchAccountData = useCallback(async () => { - const connectedToHardhat = getIsHardhatConnected(); - queryClient.invalidateQueries(nftsQueryKey({ address: accountAddress, sortBy: nftSort })); queryClient.invalidateQueries(positionsQueryKey({ address: accountAddress as Address, currency: nativeCurrency })); queryClient.invalidateQueries(addysSummaryQueryKey({ addresses: allAddresses, currency: nativeCurrency })); @@ -56,7 +55,7 @@ export default function useRefreshAccountData() { logger.error(new RainbowError(`[useRefreshAccountData]: Error refreshing data: ${error}`)); throw error; } - }, [accountAddress, dispatch, nativeCurrency, profilesEnabled]); + }, [accountAddress, allAddresses, connectedToHardhat, dispatch, nativeCurrency, nftSort, profilesEnabled]); const refresh = useCallback(async () => { if (isRefreshing) return; diff --git a/src/hooks/useWatchPendingTxs.ts b/src/hooks/useWatchPendingTxs.ts index 72ec35f0a93..20ddd2169fe 100644 --- a/src/hooks/useWatchPendingTxs.ts +++ b/src/hooks/useWatchPendingTxs.ts @@ -5,7 +5,7 @@ import { userAssetsQueryKey } from '@/resources/assets/UserAssetsQuery'; import { userAssetsQueryKey as swapsUserAssetsQueryKey } from '@/__swaps__/screens/Swap/resources/assets/userAssets'; import { transactionFetchQuery } from '@/resources/transactions/transaction'; import { RainbowError, logger } from '@/logger'; -import { getIsHardhatConnected, getProvider } from '@/handlers/web3'; +import { getProvider } from '@/handlers/web3'; import { consolidatedTransactionsQueryKey } from '@/resources/transactions/consolidatedTransactions'; import { RainbowNetworkObjects } from '@/networks'; import { queryClient } from '@/react-query/queryClient'; @@ -17,12 +17,14 @@ import { nftsQueryKey } from '@/resources/nfts'; import { getNftSortForAddress } from './useNFTsSortBy'; import { ChainId } from '@/networks/types'; import { staleBalancesStore } from '@/state/staleBalances'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; export const useWatchPendingTransactions = ({ address }: { address: string }) => { const { storePendingTransactions, setPendingTransactions } = usePendingTransactionsStore(state => ({ storePendingTransactions: state.pendingTransactions, setPendingTransactions: state.setPendingTransactions, })); + const { connectedToHardhat } = useConnectedToHardhatStore(); const setNonce = useNonceStore(state => state.setNonce); @@ -33,7 +35,6 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => const refreshAssets = useCallback( (_: RainbowTransaction) => { // NOTE: We have two user assets stores right now, so let's invalidate both queries and trigger a refetch - const connectedToHardhat = getIsHardhatConnected(); queryClient.invalidateQueries( userAssetsQueryKey({ address, @@ -50,7 +51,7 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => ); queryClient.invalidateQueries(nftsQueryKey({ address, sortBy: getNftSortForAddress(address) })); }, - [address, nativeCurrency] + [address, connectedToHardhat, nativeCurrency] ); const processFlashbotsTransaction = useCallback(async (tx: RainbowTransaction): Promise => { @@ -165,7 +166,6 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => ); const watchPendingTransactions = useCallback(async () => { - const connectedToHardhat = getIsHardhatConnected(); if (!pendingTransactions?.length) return; const updatedPendingTransactions = await Promise.all( pendingTransactions.map((tx: RainbowTransaction) => processPendingTransaction(tx)) @@ -229,7 +229,7 @@ export const useWatchPendingTransactions = ({ address }: { address: string }) => address, pendingTransactions: newPendingTransactions, }); - }, [address, nativeCurrency, pendingTransactions, processNonces, processPendingTransaction, setPendingTransactions]); + }, [address, connectedToHardhat, nativeCurrency, pendingTransactions, processNonces, processPendingTransaction, setPendingTransactions]); return { watchPendingTransactions }; }; diff --git a/src/redux/explorer.ts b/src/redux/explorer.ts index 39465af9ae5..0892e4b5e8c 100644 --- a/src/redux/explorer.ts +++ b/src/redux/explorer.ts @@ -4,8 +4,8 @@ import { ThunkDispatch } from 'redux-thunk'; import { io, Socket } from 'socket.io-client'; import { getRemoteConfig } from '@/model/remoteConfig'; import { AppGetState, AppState } from './store'; -import { getProvider, isHardHat } from '@/handlers/web3'; import { ChainId } from '@/networks/types'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; // -- Constants --------------------------------------- // const EXPLORER_UPDATE_SOCKETS = 'explorer/EXPLORER_UPDATE_SOCKETS'; @@ -118,9 +118,7 @@ export const explorerInit = () => (dispatch: ThunkDispatch => { const networkObject = getNetworkObject({ chainId }); - const balanceCheckerContract = new Contract(networkObject.balanceCheckerAddress, balanceCheckerContractAbi, web3Provider); + const provider = getProvider({ chainId }); + const balanceCheckerContract = new Contract(networkObject.balanceCheckerAddress, balanceCheckerContractAbi, provider); try { const values = await balanceCheckerContract.balances([address], tokens); const balances: { diff --git a/src/resources/assets/useSortedUserAssets.ts b/src/resources/assets/useSortedUserAssets.ts index 96cd2e91490..b7e80d92c71 100644 --- a/src/resources/assets/useSortedUserAssets.ts +++ b/src/resources/assets/useSortedUserAssets.ts @@ -1,11 +1,11 @@ -import { getIsHardhatConnected } from '@/handlers/web3'; import { useAccountSettings } from '@/hooks'; import { selectSortedUserAssets } from '@/resources/assets/assetSelectors'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; export function useSortedUserAssets() { const { accountAddress, nativeCurrency } = useAccountSettings(); - const connectedToHardhat = getIsHardhatConnected(); + const { connectedToHardhat } = useConnectedToHardhatStore(); return useUserAssets( { diff --git a/src/resources/assets/useUserAsset.ts b/src/resources/assets/useUserAsset.ts index 50f9b072410..bad1a672d05 100644 --- a/src/resources/assets/useUserAsset.ts +++ b/src/resources/assets/useUserAsset.ts @@ -1,14 +1,14 @@ import { ChainId } from '@/networks/types'; -import { getIsHardhatConnected } from '@/handlers/web3'; import { useAccountSettings } from '@/hooks'; import { getNetworkObject } from '@/networks'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; import { selectUserAssetWithUniqueId } from '@/resources/assets/assetSelectors'; import { getUniqueId } from '@/utils/ethereumUtils'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; export function useUserAsset(uniqueId: string) { const { accountAddress, nativeCurrency } = useAccountSettings(); - const connectedToHardhat = getIsHardhatConnected(); + const { connectedToHardhat } = useConnectedToHardhatStore(); return useUserAssets( { diff --git a/src/resources/assets/useUserAssetCount.ts b/src/resources/assets/useUserAssetCount.ts index bd414a8c651..7cf00ced409 100644 --- a/src/resources/assets/useUserAssetCount.ts +++ b/src/resources/assets/useUserAssetCount.ts @@ -1,13 +1,13 @@ -import { getIsHardhatConnected } from '@/handlers/web3'; import { useAccountSettings } from '@/hooks'; import { useUserAssets } from '@/resources/assets/UserAssetsQuery'; import { RainbowAddressAssets } from './types'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; const countSelector = (accountAssets: RainbowAddressAssets) => accountAssets?.length; export function useUserAssetCount() { const { accountAddress, nativeCurrency } = useAccountSettings(); - const connectedToHardhat = getIsHardhatConnected(); + const { connectedToHardhat } = useConnectedToHardhatStore(); return useUserAssets( { diff --git a/src/screens/SendSheet.js b/src/screens/SendSheet.js index 1d7438f1519..3cff2615a5b 100644 --- a/src/screens/SendSheet.js +++ b/src/screens/SendSheet.js @@ -1,5 +1,4 @@ import { useRoute } from '@react-navigation/native'; -import { captureEvent, captureException } from '@sentry/react-native'; import lang from 'i18n-js'; import { isEmpty, isEqual, isString } from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -23,7 +22,6 @@ import { getProvider, isL2Chain, resolveNameOrAddress, - web3Provider, } from '@/handlers/web3'; import { checkIsValidAddressOrDomain, checkIsValidAddressOrDomainFormat, isENSAddressFormat } from '@/helpers/validators'; import { @@ -283,14 +281,13 @@ export default function SendSheet(props) { useEffect(() => { const assetChainId = selected.chainId; if (assetChainId && (assetChainId !== currentChainId || !currentChainId || prevChainId !== currentChainId)) { - let provider = web3Provider; if (chainId === ChainId.goerli) { setCurrentChainId(ChainId.goerli); - provider = getProvider({ chainId: ChainId.goerli }); + const provider = getProvider({ chainId: ChainId.goerli }); setCurrentProvider(provider); } else { setCurrentChainId(assetChainId); - provider = getProvider({ chainId: currentChainId }); + const provider = getProvider({ chainId: currentChainId }); setCurrentProvider(provider); } } diff --git a/src/state/assets/userAssets.ts b/src/state/assets/userAssets.ts index 512dfd56eed..2a97a31f284 100644 --- a/src/state/assets/userAssets.ts +++ b/src/state/assets/userAssets.ts @@ -1,5 +1,4 @@ import { ParsedSearchAsset, UniqueId, UserAssetFilter } from '@/__swaps__/types/assets'; -import { getIsHardhatConnected } from '@/handlers/web3'; import { Address } from 'viem'; import { RainbowError, logger } from '@/logger'; import store from '@/redux/store'; @@ -7,6 +6,7 @@ import { ETH_ADDRESS, SUPPORTED_CHAIN_IDS, supportedNativeCurrencies } from '@/r import { createRainbowStore } from '@/state/internal/createRainbowStore'; import { swapsStore } from '@/state/swaps/swapsStore'; import { ChainId } from '@/networks/types'; +import { useConnectedToHardhatStore } from '../connectedToHardhat'; const SEARCH_CACHE_MAX_ENTRIES = 50; @@ -278,7 +278,7 @@ export const userAssetsStore = createRainbowStore( }); // Ensure all supported chains are in the map with a fallback value of 0 - SUPPORTED_CHAIN_IDS({ testnetMode: getIsHardhatConnected() }).forEach(chainId => { + SUPPORTED_CHAIN_IDS({ testnetMode: useConnectedToHardhatStore.getState().connectedToHardhat }).forEach(chainId => { if (!unsortedChainBalances.has(chainId)) { unsortedChainBalances.set(chainId, 0); idsByChain.set(chainId, []); diff --git a/src/state/sync/UserAssetsSync.tsx b/src/state/sync/UserAssetsSync.tsx index e97b968911d..4c8c379c775 100644 --- a/src/state/sync/UserAssetsSync.tsx +++ b/src/state/sync/UserAssetsSync.tsx @@ -4,21 +4,22 @@ import { userAssetsStore } from '@/state/assets/userAssets'; import { useSwapsStore } from '@/state/swaps/swapsStore'; import { selectUserAssetsList, selectorFilterByUserChains } from '@/__swaps__/screens/Swap/resources/_selectors/assets'; import { ParsedSearchAsset } from '@/__swaps__/types/assets'; -import { getIsHardhatConnected } from '@/handlers/web3'; import { useUserAssets } from '@/__swaps__/screens/Swap/resources/assets'; import { ChainId } from '@/networks/types'; +import { useConnectedToHardhatStore } from '../connectedToHardhat'; export const UserAssetsSync = function UserAssetsSync() { const { accountAddress: currentAddress, nativeCurrency: currentCurrency } = useAccountSettings(); const userAssetsWalletAddress = userAssetsStore(state => state.associatedWalletAddress); const isSwapsOpen = useSwapsStore(state => state.isSwapsOpen); + const { connectedToHardhat } = useConnectedToHardhatStore(); useUserAssets( { address: currentAddress as Address, currency: currentCurrency, - testnetMode: getIsHardhatConnected(), + testnetMode: connectedToHardhat, }, { enabled: !isSwapsOpen || userAssetsWalletAddress !== currentAddress, diff --git a/src/utils/ethereumUtils.ts b/src/utils/ethereumUtils.ts index 9d96405b93f..00ac9f63577 100644 --- a/src/utils/ethereumUtils.ts +++ b/src/utils/ethereumUtils.ts @@ -24,7 +24,7 @@ import { SelectedGasFee, } from '@/entities'; import { getOnchainAssetBalance } from '@/handlers/assets'; -import { getIsHardhatConnected, getProvider, isTestnetChain, toHex } from '@/handlers/web3'; +import { getProvider, isTestnetChain, toHex } from '@/handlers/web3'; import { convertRawAmountToDecimalFormat, fromWei, greaterThan, isZero, subtract, add } from '@/helpers/utilities'; import { Navigation } from '@/navigation'; import { parseAssetNative } from '@/parsers'; @@ -51,6 +51,7 @@ import { } from '@/resources/assets/externalAssetsQuery'; import { ChainId, Network } from '@/networks/types'; import { AddressOrEth } from '@/__swaps__/types/assets'; +import { useConnectedToHardhatStore } from '@/state/connectedToHardhat'; const getNetworkNativeAsset = ({ chainId }: { chainId: ChainId }) => { const nativeAssetAddress = getNetworkObject({ chainId }).nativeCurrency.address; @@ -121,7 +122,7 @@ const getAsset = (accountAssets: Record, uniqueId: E const getUserAssetFromCache = (uniqueId: string) => { const { accountAddress, nativeCurrency } = store.getState().settings; - const connectedToHardhat = getIsHardhatConnected(); + const connectedToHardhat = useConnectedToHardhatStore.getState().connectedToHardhat; const cache = queryClient.getQueryCache(); diff --git a/src/utils/methodRegistry.ts b/src/utils/methodRegistry.ts index 082b1b7c39c..21abc903164 100644 --- a/src/utils/methodRegistry.ts +++ b/src/utils/methodRegistry.ts @@ -1,5 +1,5 @@ import { Contract } from '@ethersproject/contracts'; -import { web3Provider } from '../handlers/web3'; +import { getProvider } from '../handlers/web3'; import namesOverrides from '../references/method-names-overrides.json'; import methodRegistryABI from '../references/method-registry-abi.json'; import { metadataClient } from '@/graphql'; @@ -17,7 +17,8 @@ export const methodRegistryLookupAndParse = async (methodSignatureBytes: any, ch if (data?.contractFunction?.text) { signature = data.contractFunction.text; } else { - const registry = new Contract(METHOD_REGISTRY_ADDRESS, methodRegistryABI, web3Provider); + const provider = getProvider({ chainId }); + const registry = new Contract(METHOD_REGISTRY_ADDRESS, methodRegistryABI, provider); signature = await registry.entries(methodSignatureBytes); }