From bc68557010e6a23553c622c3f63b7bfa418fa8a0 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:42:48 -0300 Subject: [PATCH 01/35] fix: not updating network data on network changeb --- packages/react/src/hooks/useNetwork.ts | 40 ++++++++++++++++++++++---- packages/react/src/utils/queryKeys.ts | 4 +-- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/react/src/hooks/useNetwork.ts b/packages/react/src/hooks/useNetwork.ts index ddd3d4e3..66bd2e98 100644 --- a/packages/react/src/hooks/useNetwork.ts +++ b/packages/react/src/hooks/useNetwork.ts @@ -1,14 +1,21 @@ -import type { Network } from 'fuels'; +import { keepPreviousData } from '@tanstack/react-query'; +import { FuelConnectorEventTypes, type Network } from 'fuels'; +import { useEffect } from 'react'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; import { useIsConnected } from './useIsConnected'; +const TIMEOUT = 500; + type UseNetwork = { /** * Additional query parameters to customize the behavior of `useNamedQuery`. */ - query?: UseNamedQueryParams<'network', Network | null, Error, Network | null>; + query?: Omit< + UseNamedQueryParams<'network', Network | null, Error, Network | null>, + 'queryKey' | 'queryFn' | 'refetchInterval' + >; }; // @TODO: Add a link to fuel connector's documentation. @@ -29,24 +36,45 @@ type UseNetwork = { export const useNetwork = (params?: UseNetwork) => { const { fuel } = useFuel(); const { isConnected } = useIsConnected(); - return useNamedQuery('network', { - queryKey: QUERY_KEYS.currentNetwork(), + const networkQuery = useNamedQuery('network', { + queryKey: QUERY_KEYS.currentNetwork(isConnected), queryFn: async () => { + const timeout = new Promise((_, reject) => + setTimeout(() => reject('Time out fetching network'), TIMEOUT), + ); const current = await fuel.currentNetwork(); if (!current && isConnected) { throw new Error('Network not found'); } - return current; + // biome-ignore lint/suspicious/noExplicitAny: + return Promise.race([current, timeout as any]); }, placeholderData: null, refetchOnMount: true, refetchInterval: (e) => { if (!e.state.data || e.state.error) { - return 4000; + return TIMEOUT; } return false; }, + retry: (attempts) => { + if (attempts > 10) { + return false; + } + return true; + }, enabled: isConnected, ...params?.query, }); + + useEffect(() => { + const sub = fuel.on(FuelConnectorEventTypes.currentNetwork, () => { + networkQuery.refetch(); + }); + return () => { + sub.unsubscribe(); + }; + }, [fuel, networkQuery.refetch]); + + return networkQuery; }; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 8b86d1cb..054242c5 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -82,8 +82,8 @@ export const QUERY_KEYS = { currentConnector: (): QueryKey => { return QUERY_KEYS.base.concat(['currentConnector']); }, - currentNetwork: (): QueryKey => { - return QUERY_KEYS.base.concat('currentNetwork'); + currentNetwork: (isConnected: boolean | undefined): QueryKey => { + return QUERY_KEYS.base.concat(['currentNetwork', isConnected]); }, isSupportedNetwork: ( connectorName: string | null | undefined, From c3acbda89a91c7e600a82a63d11417e2e6a238a5 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:53:23 -0300 Subject: [PATCH 02/35] fix: useAccount not detecting account switches --- packages/react/src/hooks/useAccount.ts | 19 +++++++++++++++++-- packages/react/src/utils/queryKeys.ts | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/react/src/hooks/useAccount.ts b/packages/react/src/hooks/useAccount.ts index f0ec8b52..0c904387 100644 --- a/packages/react/src/hooks/useAccount.ts +++ b/packages/react/src/hooks/useAccount.ts @@ -1,3 +1,6 @@ +import { keepPreviousData } from '@tanstack/react-query'; +import { FuelConnectorEventTypes } from 'fuels'; +import { useEffect } from 'react'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; @@ -28,8 +31,8 @@ export const useAccount = ( ) => { const { fuel } = useFuel(); - return useNamedQuery('account', { - queryKey: QUERY_KEYS.account(), + const accountQuery = useNamedQuery('account', { + queryKey: QUERY_KEYS.account(fuel.name), queryFn: async () => { try { const currentFuelAccount = await fuel?.currentAccount(); @@ -39,6 +42,18 @@ export const useAccount = ( } }, placeholderData: null, + retry: 5, ...params?.query, }); + + useEffect(() => { + const sub = fuel.on(FuelConnectorEventTypes.currentAccount, () => { + accountQuery.refetch(); + }); + return () => { + sub.unsubscribe(); + }; + }, [fuel, accountQuery.refetch]); + + return accountQuery; }; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 054242c5..a1f555f4 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -4,8 +4,8 @@ import type { NetworkConfig } from '../types'; export const QUERY_KEYS = { base: ['fuel'] as QueryKey, - account: (): QueryKey => { - return QUERY_KEYS.base.concat('account'); + account: (connectorName: string | null | undefined): QueryKey => { + return QUERY_KEYS.base.concat('account', connectorName); }, accounts: (): QueryKey => { return QUERY_KEYS.base.concat('accounts'); From 77a9001b5c95fdaf81aaaf548572e0fa80fa24c3 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:57:10 -0300 Subject: [PATCH 03/35] fix: provider fetching indefinitely or not returning valid provider --- packages/react/src/hooks/useProvider.ts | 69 +++++++++++++++++-------- packages/react/src/utils/queryKeys.ts | 12 ++++- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index dcc4a6bd..3150f3e6 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,7 +1,10 @@ +import { keepPreviousData } from '@tanstack/react-query'; import { Provider } from 'fuels'; +import { useAccount } from 'src/hooks/useAccount'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; +import { useNetwork } from './useNetwork'; type UseProviderParams = { /** @@ -30,32 +33,56 @@ type UseProviderParams = { * ``` */ export const useProvider = (params?: UseProviderParams) => { - const { fuel, networks } = useFuel(); + const { fuel } = useFuel(); + const { network: currentNetwork } = useNetwork(); + const { account } = useAccount(); + return useNamedQuery('provider', { - queryKey: QUERY_KEYS.provider(), + queryKey: QUERY_KEYS.provider(account, currentNetwork), queryFn: async () => { - const currentNetwork = await fuel.currentNetwork(); - const network = networks.find( - (n) => n.chainId === currentNetwork.chainId, - ); - if (!network?.url) { - const provider = await fuel.getProvider(); - console.warn( - 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', - ); - return provider || null; + async function fetchProvider() { + if (!currentNetwork?.url) { + console.warn( + 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', + ); + } + if (account) { + const provider = await fuel.getWallet(account); + return provider.provider || null; + } + if (!currentNetwork?.url) { + return fuel.getProvider(); + } + const provider = await Provider.create(currentNetwork.url); + if (provider.getChainId() !== currentNetwork.chainId) { + throw new Error( + `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${ + currentNetwork.chainId + })`, + ); + } + return provider; + } + + const timeout = new Promise((_, reject) => + setTimeout(() => reject('Time out fetching provider'), 1000), + ) as Promise; + + return Promise.race([fetchProvider(), timeout]); + }, + placeholderData: keepPreviousData, + refetchInterval: (e) => { + if (!e.state.data || e.state.error) { + return 500; } - const provider = await Provider.create(network.url); - if (provider.getChainId() !== currentNetwork.chainId) { - throw new Error( - `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${ - currentNetwork.chainId - })`, - ); + return false; + }, + retry: (attempts) => { + if (attempts > 10) { + return false; } - return provider; + return true; }, - placeholderData: null, ...params?.query, }); }; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index a1f555f4..cb6ade50 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -32,8 +32,16 @@ export const QUERY_KEYS = { networks: (): QueryKey => { return QUERY_KEYS.base.concat('networks'); }, - provider: (): QueryKey => { - return QUERY_KEYS.base.concat('provider'); + provider: ( + currentAccount: string | null, + currentNetwork: Network | null, + ): QueryKey => { + return QUERY_KEYS.base.concat( + 'provider', + currentNetwork?.chainId, + currentNetwork?.url, + currentAccount, + ); }, balance: ( address?: string, From 7bdd70d379b2edfe7d3481786b50e936d3fdcf18 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:08:06 -0300 Subject: [PATCH 04/35] fix: not updating useWallet with account change --- packages/react/src/hooks/useWallet.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/react/src/hooks/useWallet.ts b/packages/react/src/hooks/useWallet.ts index 46b39728..13a47dd4 100644 --- a/packages/react/src/hooks/useWallet.ts +++ b/packages/react/src/hooks/useWallet.ts @@ -1,5 +1,7 @@ import { type Account, Address } from 'fuels'; +import { keepPreviousData } from '@tanstack/react-query'; +import { useAccount } from 'src/hooks/useAccount'; import { type DefinedNamedUseQueryResult, type UseNamedQueryParams, @@ -58,27 +60,29 @@ export function useWallet( params?: UseWalletParamsDeprecated | UseWalletParams, ): DefinedNamedUseQueryResult<'wallet', Account | null, Error> { const { fuel } = useFuel(); - const { provider } = useProvider(); + const providerQuery = useProvider(); + const provider = providerQuery.provider; + const accountData = useAccount(); const _params: UseWalletParams = typeof params === 'string' ? { account: params } : params ?? {}; + const account = _params.account || accountData?.account; return useNamedQuery('wallet', { - queryKey: QUERY_KEYS.wallet(_params.account, provider), + queryKey: QUERY_KEYS.wallet(account, provider), queryFn: async () => { try { - if (!provider) return null; - const accountAddress = - _params.account || (await fuel.currentAccount()) || ''; + if (!provider || !account) return null; // Check if the address is valid - await Address.fromString(accountAddress); - const wallet = await fuel.getWallet(accountAddress); + await Address.fromString(account); + const wallet = await fuel.getWallet(account); wallet.connect(provider); return wallet || null; } catch (_error: unknown) { return null; } }, - placeholderData: null, + enabled: !!account && !!provider, + placeholderData: keepPreviousData, ..._params.query, }); } From 5f6b1acef470cad223f16909fac5919c15b00421 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:11:21 -0300 Subject: [PATCH 05/35] fix: connector not updating on connector change --- .../react/src/hooks/useCurrentConnector.tsx | 23 ++++++++++++++++--- packages/react/src/utils/queryKeys.ts | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/react/src/hooks/useCurrentConnector.tsx b/packages/react/src/hooks/useCurrentConnector.tsx index e4fe3090..bcd25f6d 100644 --- a/packages/react/src/hooks/useCurrentConnector.tsx +++ b/packages/react/src/hooks/useCurrentConnector.tsx @@ -1,4 +1,9 @@ -import type { FuelConnector } from 'fuels'; +import { + type FuelConnector, + FuelConnectorEventType, + FuelConnectorEventTypes, +} from 'fuels'; +import { useEffect } from 'react'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; @@ -35,8 +40,8 @@ export const useCurrentConnector = < query, }: UseCurrentConnectorParams = {}) => { const { fuel } = useFuel(); - return useNamedQuery('currentConnector', { - queryKey: QUERY_KEYS.currentConnector(), + const connectorQuery = useNamedQuery('currentConnector', { + queryKey: QUERY_KEYS.currentConnector(fuel.name), queryFn: async () => { const isConnected = await fuel.isConnected(); if (!isConnected) return null; @@ -45,4 +50,16 @@ export const useCurrentConnector = < placeholderData: null, ...query, }); + + useEffect(() => { + const onChangeConnector = () => { + connectorQuery.refetch(); + }; + fuel.on(FuelConnectorEventTypes.currentConnector, onChangeConnector); + return () => { + fuel.off(FuelConnectorEventTypes.currentConnector, onChangeConnector); + }; + }, [connectorQuery.refetch, fuel]); + + return connectorQuery; }; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index cb6ade50..beadf997 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -87,8 +87,8 @@ export const QUERY_KEYS = { connectorList: (): QueryKey => { return QUERY_KEYS.base.concat('connectorList'); }, - currentConnector: (): QueryKey => { - return QUERY_KEYS.base.concat(['currentConnector']); + currentConnector: (connectorName: string | null | undefined): QueryKey => { + return QUERY_KEYS.base.concat(['currentConnector', connectorName]); }, currentNetwork: (isConnected: boolean | undefined): QueryKey => { return QUERY_KEYS.base.concat(['currentNetwork', isConnected]); From 66ca2dd98efc3574ab8e73a130ed11b9a3e6f983 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:17:42 -0300 Subject: [PATCH 06/35] fix: getChain returning outdate data --- packages/react/src/hooks/useChain.ts | 42 ++++++------------- .../react/src/providers/FuelEventsWatcher.tsx | 1 - packages/react/src/utils/queryKeys.ts | 3 -- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/packages/react/src/hooks/useChain.ts b/packages/react/src/hooks/useChain.ts index ba3a3220..b019419c 100644 --- a/packages/react/src/hooks/useChain.ts +++ b/packages/react/src/hooks/useChain.ts @@ -1,20 +1,10 @@ // should import ChainInfo because of this error: https://github.com/FuelLabs/fuels-ts/issues/1054 // eslint-disable-next-line @typescript-eslint/no-unused-vars import type { ChainInfo } from 'fuels'; -import type { UseNamedQueryParams } from '../core'; - -import { useNamedQuery } from '../core'; -import { QUERY_KEYS } from '../utils'; +import { useMemo } from 'react'; import { useProvider } from './useProvider'; -type UseChainParams = { - /** - * Additional query parameters to customize the behavior of `useNamedQuery`. - */ - query?: UseNamedQueryParams; -}; - // @TODO: Add a link to fuel connector's documentation. /** * A hook that returns the chain info for the current provider. @@ -29,23 +19,17 @@ type UseChainParams = { * console.log(chain); * ``` */ -export const useChain = ( - params?: UseChainParams<'chain', ChainInfo | null>, -) => { - const { provider } = useProvider(); +export const useChain = () => { + const providerData = useProvider(); + const provider = providerData?.provider; - return useNamedQuery('chain', { - queryKey: QUERY_KEYS.chain(), - queryFn: async () => { - try { - const currentFuelChain = await provider?.getChain(); - return currentFuelChain || null; - } catch (_error: unknown) { - return null; - } - }, - placeholderData: null, - enabled: !!provider, - ...params?.query, - }); + return useMemo(() => { + try { + const currentFuelChain = provider?.getChain(); + return { chain: currentFuelChain || null }; + } catch (e) { + console.error(e); + return { provider: null }; + } + }, [provider]); }; diff --git a/packages/react/src/providers/FuelEventsWatcher.tsx b/packages/react/src/providers/FuelEventsWatcher.tsx index 4f726593..0635082b 100644 --- a/packages/react/src/providers/FuelEventsWatcher.tsx +++ b/packages/react/src/providers/FuelEventsWatcher.tsx @@ -56,7 +56,6 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.transactionReceipts(), }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.chain() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); } diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index beadf997..d7f85164 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -23,9 +23,6 @@ export const QUERY_KEYS = { if (typeof chainId !== 'undefined') queryKey.push(chainId); return queryKey; }, - chain: (): QueryKey => { - return QUERY_KEYS.base.concat('chain'); - }, isConnected: (): QueryKey => { return QUERY_KEYS.base.concat('isConnected'); }, From 1ba5e3ddd228a7d5bb6916f59a30eed631023044 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:18:54 -0300 Subject: [PATCH 07/35] feat: add new input parameters to watcher keys --- .../react/src/providers/FuelEventsWatcher.tsx | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/react/src/providers/FuelEventsWatcher.tsx b/packages/react/src/providers/FuelEventsWatcher.tsx index 0635082b..807a1cfc 100644 --- a/packages/react/src/providers/FuelEventsWatcher.tsx +++ b/packages/react/src/providers/FuelEventsWatcher.tsx @@ -10,14 +10,18 @@ export function FuelEventsWatcher() { const queryClient = useQueryClient(); function onCurrentConnectorChange() { - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account() }); + queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account(undefined) }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.isConnected() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.provider() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.provider(null, null), + }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.currentConnector() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.currentConnector(undefined), + }); } async function onConnectorsChange() { @@ -25,22 +29,28 @@ export function FuelEventsWatcher() { queryKey: QUERY_KEYS.connectorList(), exact: true, }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.currentConnector() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.currentConnector(undefined), + }); } function onCurrentAccountChange() { - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account() }); + queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account(undefined) }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); } function onConnectionChange() { - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.currentConnector() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.currentConnector(undefined), + }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.isConnected() }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account() }); + queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account(undefined) }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.provider() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.provider(null, null), + }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); queryClient.resetQueries({ @@ -50,9 +60,13 @@ export function FuelEventsWatcher() { } function onNetworkChange() { - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.currentNetwork() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.currentNetwork(undefined), + }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.networks() }); - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.provider() }); + queryClient.invalidateQueries({ + queryKey: QUERY_KEYS.provider(null, null), + }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.transactionReceipts(), }); @@ -60,7 +74,7 @@ export function FuelEventsWatcher() { } function onAccountsChange() { - queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account() }); + queryClient.invalidateQueries({ queryKey: QUERY_KEYS.account(undefined) }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); } From 1a152708ce3db50c62877783d26986461b89ab2b Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:20:50 -0300 Subject: [PATCH 08/35] fix: avoid including undefined keys --- packages/react/src/utils/queryKeys.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index d7f85164..0a51ba8c 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -33,12 +33,13 @@ export const QUERY_KEYS = { currentAccount: string | null, currentNetwork: Network | null, ): QueryKey => { - return QUERY_KEYS.base.concat( - 'provider', - currentNetwork?.chainId, - currentNetwork?.url, - currentAccount, - ); + const queryKey = QUERY_KEYS.base.concat('provider'); + if (currentNetwork) { + queryKey.push(currentNetwork.chainId); + queryKey.push(currentNetwork.url); + } + if (currentAccount) queryKey.push(currentAccount); + return queryKey; }, balance: ( address?: string, @@ -85,10 +86,14 @@ export const QUERY_KEYS = { return QUERY_KEYS.base.concat('connectorList'); }, currentConnector: (connectorName: string | null | undefined): QueryKey => { - return QUERY_KEYS.base.concat(['currentConnector', connectorName]); + const queryKey = QUERY_KEYS.base.concat('currentConnector'); + if (connectorName) queryKey.push(connectorName); + return queryKey; }, currentNetwork: (isConnected: boolean | undefined): QueryKey => { - return QUERY_KEYS.base.concat(['currentNetwork', isConnected]); + const queryKey = QUERY_KEYS.base.concat('currentNetwork'); + if (isConnected) queryKey.push(isConnected); + return queryKey; }, isSupportedNetwork: ( connectorName: string | null | undefined, From 1348b80e964ed34bd9fb799f9db8acd5c86672c9 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:27:12 -0300 Subject: [PATCH 09/35] feat: avoid destructuring useQuery return data --- packages/react/src/hooks/useNetwork.ts | 4 +++- packages/react/src/hooks/useProvider.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/react/src/hooks/useNetwork.ts b/packages/react/src/hooks/useNetwork.ts index 66bd2e98..9c33275b 100644 --- a/packages/react/src/hooks/useNetwork.ts +++ b/packages/react/src/hooks/useNetwork.ts @@ -35,7 +35,9 @@ type UseNetwork = { */ export const useNetwork = (params?: UseNetwork) => { const { fuel } = useFuel(); - const { isConnected } = useIsConnected(); + const connectedQuery = useIsConnected(); + const isConnected = connectedQuery.isConnected; + const networkQuery = useNamedQuery('network', { queryKey: QUERY_KEYS.currentNetwork(isConnected), queryFn: async () => { diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 3150f3e6..0d6ddbd3 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -34,8 +34,9 @@ type UseProviderParams = { */ export const useProvider = (params?: UseProviderParams) => { const { fuel } = useFuel(); - const { network: currentNetwork } = useNetwork(); + const networkQuery = useNetwork(); const { account } = useAccount(); + const currentNetwork = networkQuery.network; return useNamedQuery('provider', { queryKey: QUERY_KEYS.provider(account, currentNetwork), From ac067ace28aa4a69dc542b2b6277c7073a22879e Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:29:03 -0300 Subject: [PATCH 10/35] fix: import paths --- packages/react/src/hooks/useProvider.ts | 2 +- packages/react/src/hooks/useWallet.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 0d6ddbd3..4b82306f 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,9 +1,9 @@ import { keepPreviousData } from '@tanstack/react-query'; import { Provider } from 'fuels'; -import { useAccount } from 'src/hooks/useAccount'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; +import { useAccount } from './useAccount'; import { useNetwork } from './useNetwork'; type UseProviderParams = { diff --git a/packages/react/src/hooks/useWallet.ts b/packages/react/src/hooks/useWallet.ts index 13a47dd4..af75ea9b 100644 --- a/packages/react/src/hooks/useWallet.ts +++ b/packages/react/src/hooks/useWallet.ts @@ -1,7 +1,6 @@ import { type Account, Address } from 'fuels'; import { keepPreviousData } from '@tanstack/react-query'; -import { useAccount } from 'src/hooks/useAccount'; import { type DefinedNamedUseQueryResult, type UseNamedQueryParams, @@ -9,6 +8,7 @@ import { } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; +import { useAccount } from './useAccount'; import { useProvider } from './useProvider'; type UseWalletParamsDeprecated = string | null; From 57e9b2982c5244bb58536fe15fcfaf960fc7c318 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:29:50 -0300 Subject: [PATCH 11/35] feat: update docs --- packages/docs/.typedoc/hooks-links.json | 18 +++++++++++++++--- .../docs/src/guide/react-hooks/useAccount.md | 2 +- .../docs/src/guide/react-hooks/useChain.md | 2 +- .../guide/react-hooks/useCurrentConnector.md | 2 +- .../guide/react-hooks/useIsSupportedNetwork.md | 2 +- .../docs/src/guide/react-hooks/useNetwork.md | 2 +- .../docs/src/guide/react-hooks/useProvider.md | 2 +- .../docs/src/guide/react-hooks/useWallet.md | 2 +- 8 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/docs/.typedoc/hooks-links.json b/packages/docs/.typedoc/hooks-links.json index cb15d324..67c3a20d 100644 --- a/packages/docs/.typedoc/hooks-links.json +++ b/packages/docs/.typedoc/hooks-links.json @@ -19,13 +19,21 @@ "link": "/guide/react-hooks/useAddNetwork", "items": [] }, - { "text": "useAssets", "link": "/guide/react-hooks/useAssets", "items": [] }, + { + "text": "useAssets", + "link": "/guide/react-hooks/useAssets", + "items": [] + }, { "text": "useBalance", "link": "/guide/react-hooks/useBalance", "items": [] }, - { "text": "useChain", "link": "/guide/react-hooks/useChain", "items": [] }, + { + "text": "useChain", + "link": "/guide/react-hooks/useChain", + "items": [] + }, { "text": "useConnect", "link": "/guide/react-hooks/useConnect", @@ -106,5 +114,9 @@ "link": "/guide/react-hooks/useTransactionResult", "items": [] }, - { "text": "useWallet", "link": "/guide/react-hooks/useWallet", "items": [] } + { + "text": "useWallet", + "link": "/guide/react-hooks/useWallet", + "items": [] + } ] diff --git a/packages/docs/src/guide/react-hooks/useAccount.md b/packages/docs/src/guide/react-hooks/useAccount.md index 8a90eb95..50b7aa34 100644 --- a/packages/docs/src/guide/react-hooks/useAccount.md +++ b/packages/docs/src/guide/react-hooks/useAccount.md @@ -17,6 +17,6 @@ console.log(account); ``` #### Defined in -[packages/react/src/hooks/useAccount.ts:26](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useAccount.ts#L26) +[packages/react/src/hooks/useAccount.ts:29](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useAccount.ts#L29) ___ diff --git a/packages/docs/src/guide/react-hooks/useChain.md b/packages/docs/src/guide/react-hooks/useChain.md index faa98656..2c4b3808 100644 --- a/packages/docs/src/guide/react-hooks/useChain.md +++ b/packages/docs/src/guide/react-hooks/useChain.md @@ -17,6 +17,6 @@ console.log(chain); ``` #### Defined in -[packages/react/src/hooks/useChain.ts:32](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useChain.ts#L32) +[packages/react/src/hooks/useChain.ts:22](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useChain.ts#L22) ___ diff --git a/packages/docs/src/guide/react-hooks/useCurrentConnector.md b/packages/docs/src/guide/react-hooks/useCurrentConnector.md index e397ba9b..304fe711 100644 --- a/packages/docs/src/guide/react-hooks/useCurrentConnector.md +++ b/packages/docs/src/guide/react-hooks/useCurrentConnector.md @@ -23,6 +23,6 @@ console.log(currentConnector); ``` #### Defined in -[packages/react/src/hooks/useCurrentConnector.tsx:31](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useCurrentConnector.tsx#L31) +[packages/react/src/hooks/useCurrentConnector.tsx:36](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useCurrentConnector.tsx#L36) ___ diff --git a/packages/docs/src/guide/react-hooks/useIsSupportedNetwork.md b/packages/docs/src/guide/react-hooks/useIsSupportedNetwork.md index 82e2b17b..85c9312d 100644 --- a/packages/docs/src/guide/react-hooks/useIsSupportedNetwork.md +++ b/packages/docs/src/guide/react-hooks/useIsSupportedNetwork.md @@ -17,6 +17,6 @@ console.log(isSupportedNetwork); ``` #### Defined in -[packages/react/src/hooks/useIsSupportedNetwork.tsx:29](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useIsSupportedNetwork.tsx#L29) +[packages/react/src/hooks/useIsSupportedNetwork.tsx:30](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useIsSupportedNetwork.tsx#L30) ___ diff --git a/packages/docs/src/guide/react-hooks/useNetwork.md b/packages/docs/src/guide/react-hooks/useNetwork.md index 69adc34a..d0e40eb0 100644 --- a/packages/docs/src/guide/react-hooks/useNetwork.md +++ b/packages/docs/src/guide/react-hooks/useNetwork.md @@ -18,6 +18,6 @@ console.log(network); ``` #### Defined in -[packages/react/src/hooks/useNetwork.ts:29](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useNetwork.ts#L29) +[packages/react/src/hooks/useNetwork.ts:36](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useNetwork.ts#L36) ___ diff --git a/packages/docs/src/guide/react-hooks/useProvider.md b/packages/docs/src/guide/react-hooks/useProvider.md index 43adbee0..8e49d17c 100644 --- a/packages/docs/src/guide/react-hooks/useProvider.md +++ b/packages/docs/src/guide/react-hooks/useProvider.md @@ -17,6 +17,6 @@ const { provider } = useProvider(); ``` #### Defined in -[packages/react/src/hooks/useProvider.ts:32](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useProvider.ts#L32) +[packages/react/src/hooks/useProvider.ts:35](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useProvider.ts#L35) ___ diff --git a/packages/docs/src/guide/react-hooks/useWallet.md b/packages/docs/src/guide/react-hooks/useWallet.md index 65f43b46..bb111f18 100644 --- a/packages/docs/src/guide/react-hooks/useWallet.md +++ b/packages/docs/src/guide/react-hooks/useWallet.md @@ -24,4 +24,4 @@ const { wallet } = useWallet(); Use `useWallet({ account })` instead. #### Defined in -[packages/react/src/hooks/useWallet.ts:53](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useWallet.ts#L53) +[packages/react/src/hooks/useWallet.ts:55](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useWallet.ts#L55) From 9573335bb31e02afbe1895ec165f2b352795d9ea Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:38:20 -0300 Subject: [PATCH 12/35] feat: accept custom network and chainId in useProvider --- packages/react/src/hooks/useProvider.ts | 18 ++++++++++-------- .../react/src/providers/FuelEventsWatcher.tsx | 6 +++--- packages/react/src/utils/queryKeys.ts | 9 ++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 4b82306f..e3ee111f 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -7,6 +7,8 @@ import { useAccount } from './useAccount'; import { useNetwork } from './useNetwork'; type UseProviderParams = { + networkUrl?: string; + chainId?: number; /** * Additional query parameters to customize the behavior of `useNamedQuery`. */ @@ -37,12 +39,14 @@ export const useProvider = (params?: UseProviderParams) => { const networkQuery = useNetwork(); const { account } = useAccount(); const currentNetwork = networkQuery.network; + const networkUrl = params?.networkUrl || currentNetwork?.url; + const chainId = params?.chainId || currentNetwork?.chainId; return useNamedQuery('provider', { - queryKey: QUERY_KEYS.provider(account, currentNetwork), + queryKey: QUERY_KEYS.provider(account, networkUrl, chainId), queryFn: async () => { async function fetchProvider() { - if (!currentNetwork?.url) { + if (!networkUrl) { console.warn( 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', ); @@ -51,15 +55,13 @@ export const useProvider = (params?: UseProviderParams) => { const provider = await fuel.getWallet(account); return provider.provider || null; } - if (!currentNetwork?.url) { + if (!networkUrl) { return fuel.getProvider(); } - const provider = await Provider.create(currentNetwork.url); - if (provider.getChainId() !== currentNetwork.chainId) { + const provider = await Provider.create(networkUrl); + if (chainId && provider.getChainId() !== chainId) { throw new Error( - `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${ - currentNetwork.chainId - })`, + `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${chainId})`, ); } return provider; diff --git a/packages/react/src/providers/FuelEventsWatcher.tsx b/packages/react/src/providers/FuelEventsWatcher.tsx index 807a1cfc..9ce00e00 100644 --- a/packages/react/src/providers/FuelEventsWatcher.tsx +++ b/packages/react/src/providers/FuelEventsWatcher.tsx @@ -15,7 +15,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null), + queryKey: QUERY_KEYS.provider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -49,7 +49,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null), + queryKey: QUERY_KEYS.provider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -65,7 +65,7 @@ export function FuelEventsWatcher() { }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.networks() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null), + queryKey: QUERY_KEYS.provider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.transactionReceipts(), diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 0a51ba8c..04533059 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -31,13 +31,12 @@ export const QUERY_KEYS = { }, provider: ( currentAccount: string | null, - currentNetwork: Network | null, + networkUrl: string | undefined | null, + chainId: number | undefined | null, ): QueryKey => { const queryKey = QUERY_KEYS.base.concat('provider'); - if (currentNetwork) { - queryKey.push(currentNetwork.chainId); - queryKey.push(currentNetwork.url); - } + if (networkUrl) queryKey.push(networkUrl); + if (chainId) queryKey.push(chainId); if (currentAccount) queryKey.push(currentAccount); return queryKey; }, From 9fbb44dc8315ca61e7f59071e3bfd57d95806cec Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:46:49 -0300 Subject: [PATCH 13/35] feat: add support for external isFetching to useNamedQuery --- packages/react/src/core/useNamedQuery.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/react/src/core/useNamedQuery.ts b/packages/react/src/core/useNamedQuery.ts index 07ba99f7..d900022b 100644 --- a/packages/react/src/core/useNamedQuery.ts +++ b/packages/react/src/core/useNamedQuery.ts @@ -65,7 +65,7 @@ function createProxyHandler< TName extends string, TData = unknown, TError = DefaultError, ->(name: TName) { +>(name: TName, incomingIsFetching?: boolean) { const handlers: ProxyHandler> = { get(target, prop) { const shouldReplaceData = prop === name; @@ -73,6 +73,10 @@ function createProxyHandler< return Reflect.get(target, 'data'); } + if (prop === 'isFetching') { + return incomingIsFetching || Reflect.get(target, 'isFetching'); + } + return Reflect.get(target, prop); }, }; @@ -97,15 +101,16 @@ export function useNamedQuery< name: TName, options: UseNamedQueryOptions, queryClient?: QueryClient, + fetchingExternal?: boolean, ): DefinedNamedUseQueryResult { const query = useQuery(options, queryClient); const proxy = useMemo(() => { return new Proxy( query, - createProxyHandler(name), + createProxyHandler(name, fetchingExternal), ) as DefinedNamedUseQueryResult; - }, [name, query]); + }, [name, query, fetchingExternal]); return proxy; } From 851fc0227e247e5a29fb35771bdff7e534149fd1 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:58:15 -0300 Subject: [PATCH 14/35] feat: combine isFetching from dependant hooks --- packages/react/src/hooks/useNetwork.ts | 61 +++++++++-------- packages/react/src/hooks/useProvider.ts | 90 +++++++++++++------------ 2 files changed, 81 insertions(+), 70 deletions(-) diff --git a/packages/react/src/hooks/useNetwork.ts b/packages/react/src/hooks/useNetwork.ts index 9c33275b..8b428455 100644 --- a/packages/react/src/hooks/useNetwork.ts +++ b/packages/react/src/hooks/useNetwork.ts @@ -38,36 +38,41 @@ export const useNetwork = (params?: UseNetwork) => { const connectedQuery = useIsConnected(); const isConnected = connectedQuery.isConnected; - const networkQuery = useNamedQuery('network', { - queryKey: QUERY_KEYS.currentNetwork(isConnected), - queryFn: async () => { - const timeout = new Promise((_, reject) => - setTimeout(() => reject('Time out fetching network'), TIMEOUT), - ); - const current = await fuel.currentNetwork(); - if (!current && isConnected) { - throw new Error('Network not found'); - } - // biome-ignore lint/suspicious/noExplicitAny: - return Promise.race([current, timeout as any]); - }, - placeholderData: null, - refetchOnMount: true, - refetchInterval: (e) => { - if (!e.state.data || e.state.error) { - return TIMEOUT; - } - return false; - }, - retry: (attempts) => { - if (attempts > 10) { + const networkQuery = useNamedQuery( + 'network', + { + queryKey: QUERY_KEYS.currentNetwork(isConnected), + queryFn: async () => { + const timeout = new Promise((_, reject) => + setTimeout(() => reject('Time out fetching network'), TIMEOUT), + ); + const current = await fuel.currentNetwork(); + if (!current && isConnected) { + throw new Error('Network not found'); + } + // biome-ignore lint/suspicious/noExplicitAny: + return Promise.race([current, timeout as any]); + }, + placeholderData: null, + refetchOnMount: true, + refetchInterval: (e) => { + if (!e.state.data || e.state.error) { + return TIMEOUT; + } return false; - } - return true; + }, + retry: (attempts) => { + if (attempts > 10) { + return false; + } + return true; + }, + enabled: isConnected, + ...params?.query, }, - enabled: isConnected, - ...params?.query, - }); + undefined, + connectedQuery.isFetching, + ); useEffect(() => { const sub = fuel.on(FuelConnectorEventTypes.currentNetwork, () => { diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index e3ee111f..44608954 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -37,55 +37,61 @@ type UseProviderParams = { export const useProvider = (params?: UseProviderParams) => { const { fuel } = useFuel(); const networkQuery = useNetwork(); - const { account } = useAccount(); + const accountQuery = useAccount(); + const account = accountQuery.account; const currentNetwork = networkQuery.network; const networkUrl = params?.networkUrl || currentNetwork?.url; const chainId = params?.chainId || currentNetwork?.chainId; - return useNamedQuery('provider', { - queryKey: QUERY_KEYS.provider(account, networkUrl, chainId), - queryFn: async () => { - async function fetchProvider() { - if (!networkUrl) { - console.warn( - 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', - ); - } - if (account) { - const provider = await fuel.getWallet(account); - return provider.provider || null; - } - if (!networkUrl) { - return fuel.getProvider(); - } - const provider = await Provider.create(networkUrl); - if (chainId && provider.getChainId() !== chainId) { - throw new Error( - `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${chainId})`, - ); + return useNamedQuery( + 'provider', + { + queryKey: QUERY_KEYS.provider(account, networkUrl, chainId), + queryFn: async () => { + async function fetchProvider() { + if (!networkUrl) { + console.warn( + 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', + ); + } + if (account) { + const provider = await fuel.getWallet(account); + return provider.provider || null; + } + if (!networkUrl) { + return fuel.getProvider(); + } + const provider = await Provider.create(networkUrl); + if (chainId && provider.getChainId() !== chainId) { + throw new Error( + `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${chainId})`, + ); + } + return provider; } - return provider; - } - const timeout = new Promise((_, reject) => - setTimeout(() => reject('Time out fetching provider'), 1000), - ) as Promise; + const timeout = new Promise((_, reject) => + setTimeout(() => reject('Time out fetching provider'), 1000), + ) as Promise; - return Promise.race([fetchProvider(), timeout]); - }, - placeholderData: keepPreviousData, - refetchInterval: (e) => { - if (!e.state.data || e.state.error) { - return 500; - } - return false; - }, - retry: (attempts) => { - if (attempts > 10) { + return Promise.race([fetchProvider(), timeout]); + }, + placeholderData: keepPreviousData, + refetchInterval: (e) => { + if (!e.state.data || e.state.error) { + return 500; + } return false; - } - return true; + }, + retry: (attempts) => { + if (attempts > 10) { + return false; + } + return true; + }, + ...params?.query, }, - ...params?.query, - }); + undefined, + accountQuery.isFetching || networkQuery.isFetching, + ); }; From 8a4e21f95c7dd3c87c650473f0f956f6b89e51e8 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:58:51 -0300 Subject: [PATCH 15/35] chore: update docs --- packages/docs/.typedoc/hooks-links.json | 18 +++--------------- .../docs/src/guide/react-hooks/useProvider.md | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/docs/.typedoc/hooks-links.json b/packages/docs/.typedoc/hooks-links.json index 67c3a20d..cb15d324 100644 --- a/packages/docs/.typedoc/hooks-links.json +++ b/packages/docs/.typedoc/hooks-links.json @@ -19,21 +19,13 @@ "link": "/guide/react-hooks/useAddNetwork", "items": [] }, - { - "text": "useAssets", - "link": "/guide/react-hooks/useAssets", - "items": [] - }, + { "text": "useAssets", "link": "/guide/react-hooks/useAssets", "items": [] }, { "text": "useBalance", "link": "/guide/react-hooks/useBalance", "items": [] }, - { - "text": "useChain", - "link": "/guide/react-hooks/useChain", - "items": [] - }, + { "text": "useChain", "link": "/guide/react-hooks/useChain", "items": [] }, { "text": "useConnect", "link": "/guide/react-hooks/useConnect", @@ -114,9 +106,5 @@ "link": "/guide/react-hooks/useTransactionResult", "items": [] }, - { - "text": "useWallet", - "link": "/guide/react-hooks/useWallet", - "items": [] - } + { "text": "useWallet", "link": "/guide/react-hooks/useWallet", "items": [] } ] diff --git a/packages/docs/src/guide/react-hooks/useProvider.md b/packages/docs/src/guide/react-hooks/useProvider.md index 8e49d17c..49be5cec 100644 --- a/packages/docs/src/guide/react-hooks/useProvider.md +++ b/packages/docs/src/guide/react-hooks/useProvider.md @@ -17,6 +17,6 @@ const { provider } = useProvider(); ``` #### Defined in -[packages/react/src/hooks/useProvider.ts:35](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useProvider.ts#L35) +[packages/react/src/hooks/useProvider.ts:37](https://github.com/fuellabs/fuel-connectors/blob/main/packages/react/src/hooks/useProvider.ts#L37) ___ From fe4531ed5863a58875b323d44002ebbac86b730a Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:22:50 -0300 Subject: [PATCH 16/35] feat: update useWallet when connector changes --- packages/react/src/hooks/useWallet.ts | 5 +++-- packages/react/src/utils/queryKeys.ts | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/react/src/hooks/useWallet.ts b/packages/react/src/hooks/useWallet.ts index af75ea9b..80448f29 100644 --- a/packages/react/src/hooks/useWallet.ts +++ b/packages/react/src/hooks/useWallet.ts @@ -1,6 +1,7 @@ -import { type Account, Address } from 'fuels'; +import { type Account, Address, FuelConnectorEventTypes } from 'fuels'; import { keepPreviousData } from '@tanstack/react-query'; +import { useEffect } from 'react'; import { type DefinedNamedUseQueryResult, type UseNamedQueryParams, @@ -68,7 +69,7 @@ export function useWallet( const account = _params.account || accountData?.account; return useNamedQuery('wallet', { - queryKey: QUERY_KEYS.wallet(account, provider), + queryKey: QUERY_KEYS.wallet(account, fuel.name, provider), queryFn: async () => { try { if (!provider || !account) return null; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 04533059..07dcb5c1 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -52,8 +52,13 @@ export const QUERY_KEYS = { queryKey.push(provider.getChainId()); return queryKey; }, - wallet: (address?: string | null, provider?: Provider | null): QueryKey => { + wallet: ( + address?: string | null, + connectorName?: string | null, + provider?: Provider | null, + ): QueryKey => { const queryKey = QUERY_KEYS.base.concat('wallet'); + if (connectorName) queryKey.push(connectorName); if (address) queryKey.push(address); if (provider?.getChainId?.() !== undefined) queryKey.push(provider.getChainId()); From a9348d27160059681ee58296bcf72d5f7d99f3ac Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:24:54 -0300 Subject: [PATCH 17/35] feat: get provider from wallet --- packages/react/src/hooks/useProvider.ts | 18 ++++++++++-------- packages/react/src/utils/queryKeys.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 44608954..16c21f24 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,9 +1,9 @@ import { keepPreviousData } from '@tanstack/react-query'; import { Provider } from 'fuels'; +import { useWallet } from 'src/hooks/useWallet'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; -import { useAccount } from './useAccount'; import { useNetwork } from './useNetwork'; type UseProviderParams = { @@ -37,8 +37,7 @@ type UseProviderParams = { export const useProvider = (params?: UseProviderParams) => { const { fuel } = useFuel(); const networkQuery = useNetwork(); - const accountQuery = useAccount(); - const account = accountQuery.account; + const walletQuery = useWallet(); const currentNetwork = networkQuery.network; const networkUrl = params?.networkUrl || currentNetwork?.url; const chainId = params?.chainId || currentNetwork?.chainId; @@ -46,7 +45,11 @@ export const useProvider = (params?: UseProviderParams) => { return useNamedQuery( 'provider', { - queryKey: QUERY_KEYS.provider(account, networkUrl, chainId), + queryKey: QUERY_KEYS.provider( + walletQuery.wallet?.address.toString(), + networkUrl, + chainId, + ), queryFn: async () => { async function fetchProvider() { if (!networkUrl) { @@ -54,9 +57,8 @@ export const useProvider = (params?: UseProviderParams) => { 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', ); } - if (account) { - const provider = await fuel.getWallet(account); - return provider.provider || null; + if (walletQuery.wallet) { + return walletQuery.wallet.provider || null; } if (!networkUrl) { return fuel.getProvider(); @@ -92,6 +94,6 @@ export const useProvider = (params?: UseProviderParams) => { ...params?.query, }, undefined, - accountQuery.isFetching || networkQuery.isFetching, + walletQuery.isFetching || networkQuery.isFetching, ); }; diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 07dcb5c1..69b22f47 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -30,7 +30,7 @@ export const QUERY_KEYS = { return QUERY_KEYS.base.concat('networks'); }, provider: ( - currentAccount: string | null, + currentAccount: string | null | undefined, networkUrl: string | undefined | null, chainId: number | undefined | null, ): QueryKey => { From 7de8580539a258b44ac565ea3e9eab8ea37644f4 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:25:29 -0300 Subject: [PATCH 18/35] fix: import path --- packages/react/src/hooks/useProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 16c21f24..e8c10893 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,10 +1,10 @@ import { keepPreviousData } from '@tanstack/react-query'; import { Provider } from 'fuels'; -import { useWallet } from 'src/hooks/useWallet'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; import { useNetwork } from './useNetwork'; +import { useWallet } from './useWallet'; type UseProviderParams = { networkUrl?: string; From 7f17532d3e74f520c96764e500e5d13c2c3982a4 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:50:54 -0300 Subject: [PATCH 19/35] fix: remove useProvider dependency from useWallet --- packages/react/src/hooks/useWallet.ts | 13 ++++--------- packages/react/src/utils/queryKeys.ts | 3 --- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/react/src/hooks/useWallet.ts b/packages/react/src/hooks/useWallet.ts index 80448f29..1ab32d7f 100644 --- a/packages/react/src/hooks/useWallet.ts +++ b/packages/react/src/hooks/useWallet.ts @@ -1,7 +1,6 @@ import { type Account, Address, FuelConnectorEventTypes } from 'fuels'; import { keepPreviousData } from '@tanstack/react-query'; -import { useEffect } from 'react'; import { type DefinedNamedUseQueryResult, type UseNamedQueryParams, @@ -10,7 +9,6 @@ import { import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; import { useAccount } from './useAccount'; -import { useProvider } from './useProvider'; type UseWalletParamsDeprecated = string | null; @@ -61,28 +59,25 @@ export function useWallet( params?: UseWalletParamsDeprecated | UseWalletParams, ): DefinedNamedUseQueryResult<'wallet', Account | null, Error> { const { fuel } = useFuel(); - const providerQuery = useProvider(); - const provider = providerQuery.provider; const accountData = useAccount(); const _params: UseWalletParams = typeof params === 'string' ? { account: params } : params ?? {}; const account = _params.account || accountData?.account; - return useNamedQuery('wallet', { - queryKey: QUERY_KEYS.wallet(account, fuel.name, provider), + queryKey: QUERY_KEYS.wallet(account, fuel.name), queryFn: async () => { try { - if (!provider || !account) return null; + if (!account) return null; // Check if the address is valid await Address.fromString(account); const wallet = await fuel.getWallet(account); - wallet.connect(provider); + wallet.connect(wallet.provider); return wallet || null; } catch (_error: unknown) { return null; } }, - enabled: !!account && !!provider, + enabled: !!account, placeholderData: keepPreviousData, ..._params.query, }); diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 69b22f47..66ea542d 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -55,13 +55,10 @@ export const QUERY_KEYS = { wallet: ( address?: string | null, connectorName?: string | null, - provider?: Provider | null, ): QueryKey => { const queryKey = QUERY_KEYS.base.concat('wallet'); if (connectorName) queryKey.push(connectorName); if (address) queryKey.push(address); - if (provider?.getChainId?.() !== undefined) - queryKey.push(provider.getChainId()); return queryKey; }, transaction: (id?: string): QueryKey => { From 2c086da86f43a9175da688d66fac19308dcba502 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:06:20 -0300 Subject: [PATCH 20/35] feat: create new hook useNetworkProvider --- .../react/src/hooks/useNetworkProvider.ts | 99 +++++++++++++++++++ packages/react/src/hooks/useProvider.ts | 81 ++------------- 2 files changed, 105 insertions(+), 75 deletions(-) create mode 100644 packages/react/src/hooks/useNetworkProvider.ts diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts new file mode 100644 index 00000000..e8c10893 --- /dev/null +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -0,0 +1,99 @@ +import { keepPreviousData } from '@tanstack/react-query'; +import { Provider } from 'fuels'; +import { type UseNamedQueryParams, useNamedQuery } from '../core'; +import { useFuel } from '../providers'; +import { QUERY_KEYS } from '../utils'; +import { useNetwork } from './useNetwork'; +import { useWallet } from './useWallet'; + +type UseProviderParams = { + networkUrl?: string; + chainId?: number; + /** + * Additional query parameters to customize the behavior of `useNamedQuery`. + */ + query?: UseNamedQueryParams< + 'provider', + Provider | null, + Error, + Provider | null + >; +}; + +// @TODO: Add a link to fuel connector's documentation. +/** + * A hook to retrieve the current provider in the connected app. + * + * @returns {object} An object containing: + * - `provider`: The provider data or `null`. + * - {@link https://tanstack.com/query/latest/docs/framework/react/reference/useQuery | `...queryProps`}: Destructured properties from `useQuery` result. + * + * @examples + * To get the current provider: + * ```ts + * const { provider } = useProvider(); + * ``` + */ +export const useProvider = (params?: UseProviderParams) => { + const { fuel } = useFuel(); + const networkQuery = useNetwork(); + const walletQuery = useWallet(); + const currentNetwork = networkQuery.network; + const networkUrl = params?.networkUrl || currentNetwork?.url; + const chainId = params?.chainId || currentNetwork?.chainId; + + return useNamedQuery( + 'provider', + { + queryKey: QUERY_KEYS.provider( + walletQuery.wallet?.address.toString(), + networkUrl, + chainId, + ), + queryFn: async () => { + async function fetchProvider() { + if (!networkUrl) { + console.warn( + 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', + ); + } + if (walletQuery.wallet) { + return walletQuery.wallet.provider || null; + } + if (!networkUrl) { + return fuel.getProvider(); + } + const provider = await Provider.create(networkUrl); + if (chainId && provider.getChainId() !== chainId) { + throw new Error( + `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${chainId})`, + ); + } + return provider; + } + + const timeout = new Promise((_, reject) => + setTimeout(() => reject('Time out fetching provider'), 1000), + ) as Promise; + + return Promise.race([fetchProvider(), timeout]); + }, + placeholderData: keepPreviousData, + refetchInterval: (e) => { + if (!e.state.data || e.state.error) { + return 500; + } + return false; + }, + retry: (attempts) => { + if (attempts > 10) { + return false; + } + return true; + }, + ...params?.query, + }, + undefined, + walletQuery.isFetching || networkQuery.isFetching, + ); +}; diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index e8c10893..18bf9d3e 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,23 +1,13 @@ -import { keepPreviousData } from '@tanstack/react-query'; -import { Provider } from 'fuels'; +import type { Account } from 'fuels'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; -import { useFuel } from '../providers'; -import { QUERY_KEYS } from '../utils'; -import { useNetwork } from './useNetwork'; import { useWallet } from './useWallet'; type UseProviderParams = { - networkUrl?: string; - chainId?: number; /** - * Additional query parameters to customize the behavior of `useNamedQuery`. + * The wallet address used to fetch the provider. If not provided, the current account's address will be used. */ - query?: UseNamedQueryParams< - 'provider', - Provider | null, - Error, - Provider | null - >; + account?: string | null; + query?: UseNamedQueryParams<'wallet', Account | null, Error, Account | null>; }; // @TODO: Add a link to fuel connector's documentation. @@ -35,65 +25,6 @@ type UseProviderParams = { * ``` */ export const useProvider = (params?: UseProviderParams) => { - const { fuel } = useFuel(); - const networkQuery = useNetwork(); - const walletQuery = useWallet(); - const currentNetwork = networkQuery.network; - const networkUrl = params?.networkUrl || currentNetwork?.url; - const chainId = params?.chainId || currentNetwork?.chainId; - - return useNamedQuery( - 'provider', - { - queryKey: QUERY_KEYS.provider( - walletQuery.wallet?.address.toString(), - networkUrl, - chainId, - ), - queryFn: async () => { - async function fetchProvider() { - if (!networkUrl) { - console.warn( - 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', - ); - } - if (walletQuery.wallet) { - return walletQuery.wallet.provider || null; - } - if (!networkUrl) { - return fuel.getProvider(); - } - const provider = await Provider.create(networkUrl); - if (chainId && provider.getChainId() !== chainId) { - throw new Error( - `The provider's chainId (${provider.getChainId()}) does not match the current network's chainId (${chainId})`, - ); - } - return provider; - } - - const timeout = new Promise((_, reject) => - setTimeout(() => reject('Time out fetching provider'), 1000), - ) as Promise; - - return Promise.race([fetchProvider(), timeout]); - }, - placeholderData: keepPreviousData, - refetchInterval: (e) => { - if (!e.state.data || e.state.error) { - return 500; - } - return false; - }, - retry: (attempts) => { - if (attempts > 10) { - return false; - } - return true; - }, - ...params?.query, - }, - undefined, - walletQuery.isFetching || networkQuery.isFetching, - ); + const walletQuery = useWallet(params); + return walletQuery?.wallet; }; From 2e8514b170312346997ce410fd069f4148995881 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:11:03 -0300 Subject: [PATCH 21/35] feat: remove wallet from provider --- .../react/src/hooks/useNetworkProvider.ts | 20 +++---------------- .../react/src/providers/FuelEventsWatcher.tsx | 6 +++--- packages/react/src/utils/queryKeys.ts | 4 +--- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts index e8c10893..9f7cb2a3 100644 --- a/packages/react/src/hooks/useNetworkProvider.ts +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -1,10 +1,8 @@ import { keepPreviousData } from '@tanstack/react-query'; import { Provider } from 'fuels'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; -import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; import { useNetwork } from './useNetwork'; -import { useWallet } from './useWallet'; type UseProviderParams = { networkUrl?: string; @@ -35,9 +33,7 @@ type UseProviderParams = { * ``` */ export const useProvider = (params?: UseProviderParams) => { - const { fuel } = useFuel(); const networkQuery = useNetwork(); - const walletQuery = useWallet(); const currentNetwork = networkQuery.network; const networkUrl = params?.networkUrl || currentNetwork?.url; const chainId = params?.chainId || currentNetwork?.chainId; @@ -45,24 +41,14 @@ export const useProvider = (params?: UseProviderParams) => { return useNamedQuery( 'provider', { - queryKey: QUERY_KEYS.provider( - walletQuery.wallet?.address.toString(), - networkUrl, - chainId, - ), + queryKey: QUERY_KEYS.networkProvider(networkUrl, chainId), queryFn: async () => { async function fetchProvider() { if (!networkUrl) { - console.warn( + throw new Error( 'Please provide a networks with a RPC url configuration to your FuelProvider getProvider will be removed.', ); } - if (walletQuery.wallet) { - return walletQuery.wallet.provider || null; - } - if (!networkUrl) { - return fuel.getProvider(); - } const provider = await Provider.create(networkUrl); if (chainId && provider.getChainId() !== chainId) { throw new Error( @@ -94,6 +80,6 @@ export const useProvider = (params?: UseProviderParams) => { ...params?.query, }, undefined, - walletQuery.isFetching || networkQuery.isFetching, + networkQuery.isFetching, ); }; diff --git a/packages/react/src/providers/FuelEventsWatcher.tsx b/packages/react/src/providers/FuelEventsWatcher.tsx index 9ce00e00..20336bda 100644 --- a/packages/react/src/providers/FuelEventsWatcher.tsx +++ b/packages/react/src/providers/FuelEventsWatcher.tsx @@ -15,7 +15,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -49,7 +49,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -65,7 +65,7 @@ export function FuelEventsWatcher() { }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.networks() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.provider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.transactionReceipts(), diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 66ea542d..72f3b06a 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -29,15 +29,13 @@ export const QUERY_KEYS = { networks: (): QueryKey => { return QUERY_KEYS.base.concat('networks'); }, - provider: ( - currentAccount: string | null | undefined, + networkProvider: ( networkUrl: string | undefined | null, chainId: number | undefined | null, ): QueryKey => { const queryKey = QUERY_KEYS.base.concat('provider'); if (networkUrl) queryKey.push(networkUrl); if (chainId) queryKey.push(chainId); - if (currentAccount) queryKey.push(currentAccount); return queryKey; }, balance: ( From 5c1d2973c3a30b9663b991134833d171f16ec99c Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:13:33 -0300 Subject: [PATCH 22/35] chore: remove unecessary fuel event listeners --- packages/react/src/hooks/useAccount.ts | 13 +------------ packages/react/src/hooks/useCurrentConnector.tsx | 14 +------------- packages/react/src/hooks/useNetwork.ts | 13 +------------ 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/packages/react/src/hooks/useAccount.ts b/packages/react/src/hooks/useAccount.ts index 0c904387..91be750f 100644 --- a/packages/react/src/hooks/useAccount.ts +++ b/packages/react/src/hooks/useAccount.ts @@ -31,7 +31,7 @@ export const useAccount = ( ) => { const { fuel } = useFuel(); - const accountQuery = useNamedQuery('account', { + return useNamedQuery('account', { queryKey: QUERY_KEYS.account(fuel.name), queryFn: async () => { try { @@ -45,15 +45,4 @@ export const useAccount = ( retry: 5, ...params?.query, }); - - useEffect(() => { - const sub = fuel.on(FuelConnectorEventTypes.currentAccount, () => { - accountQuery.refetch(); - }); - return () => { - sub.unsubscribe(); - }; - }, [fuel, accountQuery.refetch]); - - return accountQuery; }; diff --git a/packages/react/src/hooks/useCurrentConnector.tsx b/packages/react/src/hooks/useCurrentConnector.tsx index bcd25f6d..fead2a28 100644 --- a/packages/react/src/hooks/useCurrentConnector.tsx +++ b/packages/react/src/hooks/useCurrentConnector.tsx @@ -40,7 +40,7 @@ export const useCurrentConnector = < query, }: UseCurrentConnectorParams = {}) => { const { fuel } = useFuel(); - const connectorQuery = useNamedQuery('currentConnector', { + return useNamedQuery('currentConnector', { queryKey: QUERY_KEYS.currentConnector(fuel.name), queryFn: async () => { const isConnected = await fuel.isConnected(); @@ -50,16 +50,4 @@ export const useCurrentConnector = < placeholderData: null, ...query, }); - - useEffect(() => { - const onChangeConnector = () => { - connectorQuery.refetch(); - }; - fuel.on(FuelConnectorEventTypes.currentConnector, onChangeConnector); - return () => { - fuel.off(FuelConnectorEventTypes.currentConnector, onChangeConnector); - }; - }, [connectorQuery.refetch, fuel]); - - return connectorQuery; }; diff --git a/packages/react/src/hooks/useNetwork.ts b/packages/react/src/hooks/useNetwork.ts index 8b428455..939c2147 100644 --- a/packages/react/src/hooks/useNetwork.ts +++ b/packages/react/src/hooks/useNetwork.ts @@ -38,7 +38,7 @@ export const useNetwork = (params?: UseNetwork) => { const connectedQuery = useIsConnected(); const isConnected = connectedQuery.isConnected; - const networkQuery = useNamedQuery( + return useNamedQuery( 'network', { queryKey: QUERY_KEYS.currentNetwork(isConnected), @@ -73,15 +73,4 @@ export const useNetwork = (params?: UseNetwork) => { undefined, connectedQuery.isFetching, ); - - useEffect(() => { - const sub = fuel.on(FuelConnectorEventTypes.currentNetwork, () => { - networkQuery.refetch(); - }); - return () => { - sub.unsubscribe(); - }; - }, [fuel, networkQuery.refetch]); - - return networkQuery; }; From f2aea88733e71188ad44311e322442800ed74867 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:16:16 -0300 Subject: [PATCH 23/35] fix: useProvider return type --- packages/react/src/hooks/useProvider.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 18bf9d3e..2088b1c6 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -1,4 +1,5 @@ import type { Account } from 'fuels'; +import { useMemo } from 'react'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useWallet } from './useWallet'; @@ -26,5 +27,8 @@ type UseProviderParams = { */ export const useProvider = (params?: UseProviderParams) => { const walletQuery = useWallet(params); - return walletQuery?.wallet; + return useMemo( + () => ({ provider: walletQuery?.wallet }), + [walletQuery.wallet], + ); }; From ca2c43f0b6ef05e361aeb5a9fbb00f323b20b0e8 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:01 -0300 Subject: [PATCH 24/35] feat: rename hook --- packages/react/src/hooks/useNetworkProvider.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts index 9f7cb2a3..7f91a452 100644 --- a/packages/react/src/hooks/useNetworkProvider.ts +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -11,7 +11,7 @@ type UseProviderParams = { * Additional query parameters to customize the behavior of `useNamedQuery`. */ query?: UseNamedQueryParams< - 'provider', + 'networkProvider', Provider | null, Error, Provider | null @@ -32,14 +32,14 @@ type UseProviderParams = { * const { provider } = useProvider(); * ``` */ -export const useProvider = (params?: UseProviderParams) => { +export const useNetworkProvider = (params?: UseProviderParams) => { const networkQuery = useNetwork(); const currentNetwork = networkQuery.network; const networkUrl = params?.networkUrl || currentNetwork?.url; const chainId = params?.chainId || currentNetwork?.chainId; return useNamedQuery( - 'provider', + 'networkProvider', { queryKey: QUERY_KEYS.networkProvider(networkUrl, chainId), queryFn: async () => { From 36713e83defb300917f2ee22598b589c7daaf510 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:41 -0300 Subject: [PATCH 25/35] fix: provider reference --- packages/react/src/hooks/useProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index 2088b1c6..c90e81dd 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -28,7 +28,7 @@ type UseProviderParams = { export const useProvider = (params?: UseProviderParams) => { const walletQuery = useWallet(params); return useMemo( - () => ({ provider: walletQuery?.wallet }), + () => ({ provider: walletQuery?.wallet?.provider }), [walletQuery.wallet], ); }; From 67564b39c9c9275c5afa4829d6fb1f59113c5371 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:58 -0300 Subject: [PATCH 26/35] chore: update query key reference --- packages/react/src/providers/FuelEventsWatcher.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/providers/FuelEventsWatcher.tsx b/packages/react/src/providers/FuelEventsWatcher.tsx index 20336bda..73e20694 100644 --- a/packages/react/src/providers/FuelEventsWatcher.tsx +++ b/packages/react/src/providers/FuelEventsWatcher.tsx @@ -15,7 +15,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.networkProvider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -49,7 +49,7 @@ export function FuelEventsWatcher() { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.wallet() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.balance() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.networkProvider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.nodeInfo() }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.accounts() }); @@ -65,7 +65,7 @@ export function FuelEventsWatcher() { }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.networks() }); queryClient.invalidateQueries({ - queryKey: QUERY_KEYS.networkProvider(null, null, null), + queryKey: QUERY_KEYS.networkProvider(null, null), }); queryClient.invalidateQueries({ queryKey: QUERY_KEYS.transactionReceipts(), From 8cdca6742b42c604e4f7398cfd298228f2ee8575 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:19:13 -0300 Subject: [PATCH 27/35] feat: export useNetworkProvider hook --- packages/react/src/hooks/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/hooks/index.ts b/packages/react/src/hooks/index.ts index b3da396b..24017b96 100644 --- a/packages/react/src/hooks/index.ts +++ b/packages/react/src/hooks/index.ts @@ -11,6 +11,7 @@ export * from './useConnectors'; export * from './useDisconnect'; export * from './useIsConnected'; export * from './useNetwork'; +export * from './useNetworkProvider'; export * from './useNetworks'; export * from './useNodeInfo'; export * from './useProvider'; From c81515bb0d80fe4335531bbd86ede34a4cea4d79 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:33:33 -0300 Subject: [PATCH 28/35] feat: remove isFetching logic from useNamedQuery --- packages/react/src/core/useNamedQuery.ts | 11 +++-------- packages/react/src/hooks/useAccount.ts | 3 --- packages/react/src/hooks/useNetwork.ts | 5 +---- packages/react/src/hooks/useNetworkProvider.ts | 1 - 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/react/src/core/useNamedQuery.ts b/packages/react/src/core/useNamedQuery.ts index d900022b..07ba99f7 100644 --- a/packages/react/src/core/useNamedQuery.ts +++ b/packages/react/src/core/useNamedQuery.ts @@ -65,7 +65,7 @@ function createProxyHandler< TName extends string, TData = unknown, TError = DefaultError, ->(name: TName, incomingIsFetching?: boolean) { +>(name: TName) { const handlers: ProxyHandler> = { get(target, prop) { const shouldReplaceData = prop === name; @@ -73,10 +73,6 @@ function createProxyHandler< return Reflect.get(target, 'data'); } - if (prop === 'isFetching') { - return incomingIsFetching || Reflect.get(target, 'isFetching'); - } - return Reflect.get(target, prop); }, }; @@ -101,16 +97,15 @@ export function useNamedQuery< name: TName, options: UseNamedQueryOptions, queryClient?: QueryClient, - fetchingExternal?: boolean, ): DefinedNamedUseQueryResult { const query = useQuery(options, queryClient); const proxy = useMemo(() => { return new Proxy( query, - createProxyHandler(name, fetchingExternal), + createProxyHandler(name), ) as DefinedNamedUseQueryResult; - }, [name, query, fetchingExternal]); + }, [name, query]); return proxy; } diff --git a/packages/react/src/hooks/useAccount.ts b/packages/react/src/hooks/useAccount.ts index 91be750f..1632dda0 100644 --- a/packages/react/src/hooks/useAccount.ts +++ b/packages/react/src/hooks/useAccount.ts @@ -1,6 +1,3 @@ -import { keepPreviousData } from '@tanstack/react-query'; -import { FuelConnectorEventTypes } from 'fuels'; -import { useEffect } from 'react'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; diff --git a/packages/react/src/hooks/useNetwork.ts b/packages/react/src/hooks/useNetwork.ts index 939c2147..51d79e7a 100644 --- a/packages/react/src/hooks/useNetwork.ts +++ b/packages/react/src/hooks/useNetwork.ts @@ -1,6 +1,4 @@ -import { keepPreviousData } from '@tanstack/react-query'; -import { FuelConnectorEventTypes, type Network } from 'fuels'; -import { useEffect } from 'react'; +import type { Network } from 'fuels'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; @@ -71,6 +69,5 @@ export const useNetwork = (params?: UseNetwork) => { ...params?.query, }, undefined, - connectedQuery.isFetching, ); }; diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts index 7f91a452..8d9fa727 100644 --- a/packages/react/src/hooks/useNetworkProvider.ts +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -80,6 +80,5 @@ export const useNetworkProvider = (params?: UseProviderParams) => { ...params?.query, }, undefined, - networkQuery.isFetching, ); }; From 9b94ca15a780513c7baa6c8924b87f56b577c3d2 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:49:36 -0300 Subject: [PATCH 29/35] chore: update docs --- packages/react/src/hooks/useNetworkProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts index 8d9fa727..0c2a31e6 100644 --- a/packages/react/src/hooks/useNetworkProvider.ts +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -29,7 +29,7 @@ type UseProviderParams = { * @examples * To get the current provider: * ```ts - * const { provider } = useProvider(); + * const { networkProvider } = useNetworkProvider(); * ``` */ export const useNetworkProvider = (params?: UseProviderParams) => { From 8451756bedd3821e8fc53b7b675eb3ece18c1eea Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:49:59 -0300 Subject: [PATCH 30/35] chore: minor updates to parameter names --- packages/react/src/hooks/useNetworkProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/hooks/useNetworkProvider.ts b/packages/react/src/hooks/useNetworkProvider.ts index 0c2a31e6..ec971b87 100644 --- a/packages/react/src/hooks/useNetworkProvider.ts +++ b/packages/react/src/hooks/useNetworkProvider.ts @@ -4,7 +4,7 @@ import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { QUERY_KEYS } from '../utils'; import { useNetwork } from './useNetwork'; -type UseProviderParams = { +type UseNetworkProviderParams = { networkUrl?: string; chainId?: number; /** @@ -32,7 +32,7 @@ type UseProviderParams = { * const { networkProvider } = useNetworkProvider(); * ``` */ -export const useNetworkProvider = (params?: UseProviderParams) => { +export const useNetworkProvider = (params?: UseNetworkProviderParams) => { const networkQuery = useNetwork(); const currentNetwork = networkQuery.network; const networkUrl = params?.networkUrl || currentNetwork?.url; From 615f5b12a80e6ca0c895b5d36c615f965b793887 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:57:37 -0300 Subject: [PATCH 31/35] feat: make sure specific hooks don't depend on account connection --- packages/react/src/hooks/useChain.ts | 6 +++--- packages/react/src/hooks/useNodeInfo.ts | 6 +++--- packages/react/src/hooks/useTransactionReceipts.ts | 5 +++-- packages/react/src/hooks/useTransactionResult.ts | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/react/src/hooks/useChain.ts b/packages/react/src/hooks/useChain.ts index b019419c..b5f35b95 100644 --- a/packages/react/src/hooks/useChain.ts +++ b/packages/react/src/hooks/useChain.ts @@ -3,7 +3,7 @@ import type { ChainInfo } from 'fuels'; import { useMemo } from 'react'; -import { useProvider } from './useProvider'; +import { useNetworkProvider } from './useNetworkProvider'; // @TODO: Add a link to fuel connector's documentation. /** @@ -20,8 +20,8 @@ import { useProvider } from './useProvider'; * ``` */ export const useChain = () => { - const providerData = useProvider(); - const provider = providerData?.provider; + const providerData = useNetworkProvider(); + const provider = providerData?.networkProvider; return useMemo(() => { try { diff --git a/packages/react/src/hooks/useNodeInfo.ts b/packages/react/src/hooks/useNodeInfo.ts index 4a2ec304..e4ae547e 100644 --- a/packages/react/src/hooks/useNodeInfo.ts +++ b/packages/react/src/hooks/useNodeInfo.ts @@ -4,7 +4,7 @@ import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { QUERY_KEYS } from '../utils'; import type { NodeInfo } from 'fuels'; -import { useProvider } from './useProvider'; +import { useNetworkProvider } from './useNetworkProvider'; type UseNodeInfoParams = { /** @@ -45,8 +45,8 @@ export const useNodeInfo = ({ version = '0.0.0', query: queryParams, }: UseNodeInfoParams = {}) => { - const { provider } = useProvider(); - + const networkProviderQuery = useNetworkProvider(); + const provider = networkProviderQuery.networkProvider; const query = useNamedQuery('nodeInfo', { queryKey: QUERY_KEYS.nodeInfo(provider?.url), queryFn: () => { diff --git a/packages/react/src/hooks/useTransactionReceipts.ts b/packages/react/src/hooks/useTransactionReceipts.ts index 2b0f9615..93b8b6da 100644 --- a/packages/react/src/hooks/useTransactionReceipts.ts +++ b/packages/react/src/hooks/useTransactionReceipts.ts @@ -5,7 +5,7 @@ import type { TransactionResult } from 'fuels'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; import { QUERY_KEYS } from '../utils'; -import { useProvider } from './useProvider'; +import { useNetworkProvider } from './useNetworkProvider'; type UseTransactionReceiptsParams = { /** @@ -35,7 +35,8 @@ export const useTransactionReceipts = ({ txId, query, }: UseTransactionReceiptsParams) => { - const { provider } = useProvider(); + const networkQuery = useNetworkProvider(); + const provider = networkQuery.networkProvider; return useNamedQuery('transactionReceipts', { queryKey: QUERY_KEYS.transactionReceipts(txId, provider), diff --git a/packages/react/src/hooks/useTransactionResult.ts b/packages/react/src/hooks/useTransactionResult.ts index 2007e478..b849dedf 100644 --- a/packages/react/src/hooks/useTransactionResult.ts +++ b/packages/react/src/hooks/useTransactionResult.ts @@ -5,9 +5,8 @@ import { } from 'fuels'; import { type UseNamedQueryParams, useNamedQuery } from '../core'; -import { useFuel } from '../providers'; import { QUERY_KEYS } from '../utils'; -import { useProvider } from './useProvider'; +import { useNetworkProvider } from './useNetworkProvider'; type UseTransactionResultParams< TTransactionType extends TransactionType, @@ -58,7 +57,8 @@ export const useTransactionResult = < txId = '', query = {}, }: UseTransactionResultParams) => { - const { provider } = useProvider(); + const networkProviderQuery = useNetworkProvider(); + const provider = networkProviderQuery.networkProvider; const { name = 'transactionResult', ...options } = query; return useNamedQuery(name, { From 1459bd397c1b6d8baf992bb86ff1dfd0add6d0a5 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:05:02 -0300 Subject: [PATCH 32/35] fix: not updating account status --- packages/react/src/utils/queryKeys.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react/src/utils/queryKeys.ts b/packages/react/src/utils/queryKeys.ts index 72f3b06a..67c5e040 100644 --- a/packages/react/src/utils/queryKeys.ts +++ b/packages/react/src/utils/queryKeys.ts @@ -5,7 +5,9 @@ import type { NetworkConfig } from '../types'; export const QUERY_KEYS = { base: ['fuel'] as QueryKey, account: (connectorName: string | null | undefined): QueryKey => { - return QUERY_KEYS.base.concat('account', connectorName); + const queryKey = QUERY_KEYS.base.concat('account'); + if (connectorName) queryKey.push(connectorName); + return queryKey; }, accounts: (): QueryKey => { return QUERY_KEYS.base.concat('accounts'); From 8b9a882ec9196f726f6dd4bf74a9c953a48e4b4f Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:08:13 -0300 Subject: [PATCH 33/35] chore: changeset --- .changeset/nine-chefs-thank.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/nine-chefs-thank.md diff --git a/.changeset/nine-chefs-thank.md b/.changeset/nine-chefs-thank.md new file mode 100644 index 00000000..8d83a239 --- /dev/null +++ b/.changeset/nine-chefs-thank.md @@ -0,0 +1,6 @@ +--- +"@fuels/react": patch +"docs": patch +--- + +Fixed hooks with outdated data or stuck in loading From 9ebe0443fb841d692f720a572a50096e66c20e97 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:09:47 -0300 Subject: [PATCH 34/35] chore: update memo dependency data --- packages/react/src/hooks/useProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useProvider.ts b/packages/react/src/hooks/useProvider.ts index c90e81dd..4023e20a 100644 --- a/packages/react/src/hooks/useProvider.ts +++ b/packages/react/src/hooks/useProvider.ts @@ -29,6 +29,6 @@ export const useProvider = (params?: UseProviderParams) => { const walletQuery = useWallet(params); return useMemo( () => ({ provider: walletQuery?.wallet?.provider }), - [walletQuery.wallet], + [walletQuery.wallet?.provider], ); }; From 54d7f9443f0a03ed18ef028bebe8e356d671fef3 Mon Sep 17 00:00:00 2001 From: Arthur Geron <3487334+arthurgeron@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:25:46 -0300 Subject: [PATCH 35/35] fix: retry account when invalid --- packages/react/src/hooks/useAccount.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/react/src/hooks/useAccount.ts b/packages/react/src/hooks/useAccount.ts index 1632dda0..a63c0455 100644 --- a/packages/react/src/hooks/useAccount.ts +++ b/packages/react/src/hooks/useAccount.ts @@ -31,15 +31,11 @@ export const useAccount = ( return useNamedQuery('account', { queryKey: QUERY_KEYS.account(fuel.name), queryFn: async () => { - try { - const currentFuelAccount = await fuel?.currentAccount(); - return currentFuelAccount; - } catch (_error: unknown) { - return null; - } + return await fuel?.currentAccount(); }, placeholderData: null, retry: 5, + retryDelay: 100, ...params?.query, }); };