diff --git a/packages/checkout/src/hooks/useCheckoutUI/useCryptoPayment.tsx b/packages/checkout/src/hooks/useCheckoutUI/useCryptoPayment.tsx index 2c3cf6911..9c8bab8c2 100644 --- a/packages/checkout/src/hooks/useCheckoutUI/useCryptoPayment.tsx +++ b/packages/checkout/src/hooks/useCheckoutUI/useCryptoPayment.tsx @@ -102,7 +102,7 @@ export const useCryptoPayment = ({ const isApproved: boolean = (allowanceData as bigint) >= BigInt(totalPriceRaw) || isNativeCurrency - const { data: currencyBalanceData, isLoading: currencyBalanceIsLoading } = useGetTokenBalancesSummary({ + const { data: currencyBalanceDataPaginated, isLoading: currencyBalanceIsLoading } = useGetTokenBalancesSummary({ chainIds: [chainId], filter: { accountAddresses: userAddress ? [userAddress] : [], @@ -113,6 +113,8 @@ export const useCryptoPayment = ({ omitMetadata: true }) + const currencyBalanceData = currencyBalanceDataPaginated?.pages?.flatMap(page => page.balances) + const buyCurrencyAddress = currencyAddress const sellCurrencyAddress = selectedCurrencyAddress || '' diff --git a/packages/checkout/src/views/CheckoutSelection/component/OrderSummaryItem.tsx b/packages/checkout/src/views/CheckoutSelection/component/OrderSummaryItem.tsx index 85e0e8a1b..e6755a851 100644 --- a/packages/checkout/src/views/CheckoutSelection/component/OrderSummaryItem.tsx +++ b/packages/checkout/src/views/CheckoutSelection/component/OrderSummaryItem.tsx @@ -11,18 +11,18 @@ interface OrderSummaryItem { } export const OrderSummaryItem = ({ contractAddress, tokenId, quantityRaw, chainId }: OrderSummaryItem) => { - const { data: tokenMetadata, isPending: isPendingTokenMetadata } = useGetTokenMetadata({ + const { data: tokenMetadata, isLoading: isLoadingTokenMetadata } = useGetTokenMetadata({ chainID: String(chainId), contractAddress, tokenIDs: [tokenId] }) - const { data: contractInfo, isPending: isPendingContractInfo } = useGetContractInfo({ + const { data: contractInfo, isLoading: isLoadingContractInfo } = useGetContractInfo({ chainID: String(chainId), contractAddress }) - const isPending = isPendingTokenMetadata || isPendingContractInfo + const isLoading = isLoadingTokenMetadata || isLoadingContractInfo - if (isPending) { + if (isLoading) { return } diff --git a/packages/checkout/src/views/CheckoutSelection/index.tsx b/packages/checkout/src/views/CheckoutSelection/index.tsx index cdd69df5f..96bdfa808 100644 --- a/packages/checkout/src/views/CheckoutSelection/index.tsx +++ b/packages/checkout/src/views/CheckoutSelection/index.tsx @@ -11,6 +11,7 @@ import { TokenImage } from '@0xsequence/design-system' import { useGetTokenBalancesSummary, useGetContractInfo } from '@0xsequence/hooks' +import { useEffect } from 'react' import { zeroAddress, formatUnits } from 'viem' import { useAccount, useConfig } from 'wagmi' @@ -30,21 +31,34 @@ export const CheckoutSelection = () => { const displayCreditCardCheckout = !!creditCardCheckoutSettings const displayCryptoCheckout = !!cryptoCheckoutSettings - const { data: contractInfoData, isLoading: isPendingContractInfo } = useGetContractInfo({ + const { data: contractInfoData, isLoading: isLoadingContractInfo } = useGetContractInfo({ chainID: String(cryptoCheckoutSettings?.chainId || 1), contractAddress: cryptoCheckoutSettings?.coinQuantity?.contractAddress || '' }) - const { data: balancesData, isPending: isPendingBalances } = useGetTokenBalancesSummary({ + const { + data: balancesData, + isLoading: isLoadingBalances, + fetchNextPage: fetchNextBalances, + hasNextPage: hasNextPageBalances, + isFetchingNextPage: isFetchingNextPageBalances + } = useGetTokenBalancesSummary({ chainIds: [cryptoCheckoutSettings?.chainId || 1], filter: { accountAddresses: accountAddress ? [accountAddress] : [], contractStatus: ContractVerificationStatus.ALL, omitNativeBalances: false - } + }, + page: { pageSize: 40 } }) - const isPending = (isPendingContractInfo || isPendingBalances) && cryptoCheckoutSettings + useEffect(() => { + if (hasNextPageBalances && !isFetchingNextPageBalances) { + fetchNextBalances() + } + }, [hasNextPageBalances, isFetchingNextPageBalances]) + + const isLoading = (isLoadingContractInfo || isLoadingBalances || isFetchingNextPageBalances) && cryptoCheckoutSettings const isNativeToken = compareAddress(cryptoCheckoutSettings?.coinQuantity?.contractAddress || '', zeroAddress) const nativeTokenInfo = getNativeTokenInfoByChainId(cryptoCheckoutSettings?.chainId || 1, chains) @@ -52,9 +66,9 @@ export const CheckoutSelection = () => { const coinDecimals = isNativeToken ? nativeTokenInfo.decimals : contractInfoData?.decimals || 0 const coinSymbol = isNativeToken ? nativeTokenInfo.symbol : contractInfoData?.symbol || 'COIN' const coinImageUrl = isNativeToken ? nativeTokenInfo.logoURI : contractInfoData?.logoURI || '' - const coinBalance = balancesData?.find(balance => - compareAddress(balance.contractAddress, cryptoCheckoutSettings?.coinQuantity?.contractAddress || '') - ) + const coinBalance = balancesData?.pages + ?.flatMap(page => page.balances) + .find(balance => compareAddress(balance.contractAddress, cryptoCheckoutSettings?.coinQuantity?.contractAddress || '')) const userBalanceRaw = coinBalance ? coinBalance.balance : '0' const requestedAmountRaw = cryptoCheckoutSettings?.coinQuantity?.amountRequiredRaw || '0' const userBalance = formatUnits(BigInt(userBalanceRaw), coinDecimals) @@ -142,7 +156,7 @@ export const CheckoutSelection = () => { Total - {isPending ? ( + {isLoading ? ( ) : (
@@ -165,7 +179,7 @@ export const CheckoutSelection = () => { onClick={onClickPayWithCard} /> )} - {displayCryptoCheckout && !isInsufficientBalance && !isPending && ( + {displayCryptoCheckout && !isInsufficientBalance && !isLoading && (
{displayCryptoCheckout && (
- {isPending ? ( + {isLoading ? ( ) : ( diff --git a/packages/checkout/src/views/PaymentSelection/PayWithCrypto/index.tsx b/packages/checkout/src/views/PaymentSelection/PayWithCrypto/index.tsx index 6d1a16c3d..54a87c74b 100644 --- a/packages/checkout/src/views/PaymentSelection/PayWithCrypto/index.tsx +++ b/packages/checkout/src/views/PaymentSelection/PayWithCrypto/index.tsx @@ -35,7 +35,13 @@ export const PayWithCrypto = ({ const network = findSupportedNetwork(chain) const chainId = network?.chainId || 137 - const { data: currencyBalanceData, isLoading: currencyBalanceIsLoading } = useGetTokenBalancesSummary({ + const { + data: currencyBalanceData, + isLoading: currencyBalanceIsLoading, + fetchNextPage: fetchNextCurrencyBalance, + hasNextPage: hasNextCurrencyBalance, + isFetchingNextPage: isFetchingNextCurrencyBalance + } = useGetTokenBalancesSummary({ chainIds: [chainId], filter: { accountAddresses: userAddress ? [userAddress] : [], @@ -43,9 +49,16 @@ export const PayWithCrypto = ({ contractWhitelist: [currencyAddress], omitNativeBalances: skipNativeBalanceCheck ?? false }, - omitMetadata: true + omitMetadata: true, + page: { pageSize: 40 } }) + useEffect(() => { + if (hasNextCurrencyBalance && !isFetchingNextCurrencyBalance) { + fetchNextCurrencyBalance() + } + }, [hasNextCurrencyBalance, isFetchingNextCurrencyBalance]) + const { data: currencyInfoData, isLoading: isLoadingCurrencyInfo } = useGetContractInfo({ chainID: String(chainId), contractAddress: currencyAddress @@ -64,7 +77,7 @@ export const PayWithCrypto = ({ { disabled: !enableSwapPayments } ) - const isLoadingOptions = currencyBalanceIsLoading || isLoadingCurrencyInfo || isLoading + const isLoadingOptions = currencyBalanceIsLoading || isFetchingNextCurrencyBalance || isLoadingCurrencyInfo || isLoading const swapsIsLoading = swapPricesIsLoading @@ -114,7 +127,9 @@ export const PayWithCrypto = ({ significantDigits: 6 }) - const balanceInfo = currencyBalanceData?.find(balanceData => compareAddress(currencyAddress, balanceData.contractAddress)) + const balanceInfo = currencyBalanceData?.pages + ?.flatMap(page => page.balances) + .find(balanceData => compareAddress(currencyAddress, balanceData.contractAddress)) const balance: bigint = BigInt(balanceInfo?.balance || '0') // let balanceFormatted = Number(formatUnits(balance, currencyInfoData?.decimals || 0)) diff --git a/packages/checkout/src/views/PaymentSelection/index.tsx b/packages/checkout/src/views/PaymentSelection/index.tsx index edd1109f0..f1ef995e1 100644 --- a/packages/checkout/src/views/PaymentSelection/index.tsx +++ b/packages/checkout/src/views/PaymentSelection/index.tsx @@ -1,14 +1,7 @@ -import { - useAnalyticsContext, - compareAddress, - TRANSACTION_CONFIRMATIONS_DEFAULT, - sendTransactions, - ContractVerificationStatus -} from '@0xsequence/connect' +import { useAnalyticsContext, compareAddress, TRANSACTION_CONFIRMATIONS_DEFAULT, sendTransactions } from '@0xsequence/connect' import { Button, Divider, Text, Spinner } from '@0xsequence/design-system' import { useClearCachedBalances, - useGetTokenBalancesSummary, useGetContractInfo, SwapPricesWithCurrencyInfo, useGetSwapPrices, @@ -72,8 +65,7 @@ export const PaymentSelectionContent = () => { onSuccess = () => {}, onError = () => {}, onClose = () => {}, - supplementaryAnalyticsInfo, - skipNativeBalanceCheck + supplementaryAnalyticsInfo } = selectPaymentSettings const isNativeToken = compareAddress(currencyAddress, zeroAddress) @@ -104,18 +96,6 @@ export const PaymentSelectionContent = () => { } }) - const { data: _currencyBalanceData, isLoading: currencyBalanceIsLoading } = useGetTokenBalancesSummary({ - chainIds: [chainId], - filter: { - accountAddresses: userAddress ? [userAddress] : [], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [currencyAddress], - omitNativeBalances: skipNativeBalanceCheck ?? false - }, - // omitMetadata must be true to avoid a bug - omitMetadata: true - }) - const { data: _currencyInfoData, isLoading: isLoadingCurrencyInfo } = useGetContractInfo({ chainID: String(chainId), contractAddress: currencyAddress @@ -151,15 +131,10 @@ export const PaymentSelectionContent = () => { } ) - const isLoading = (allowanceIsLoading && !isNativeToken) || currencyBalanceIsLoading || isLoadingCurrencyInfo + const isLoading = (allowanceIsLoading && !isNativeToken) || isLoadingCurrencyInfo const isApproved: boolean = (allowanceData as bigint) >= BigInt(price) || isNativeToken - // const balanceInfo = currencyBalanceData?.find(balanceData => compareAddress(currencyAddress, balanceData.contractAddress)) - // const balance: bigint = BigInt(balanceInfo?.balance || '0') - // let balanceFormatted = Number(formatUnits(balance, currencyInfoData?.decimals || 0)) - // balanceFormatted = Math.trunc(Number(balanceFormatted) * 10000) / 10000 - useEffect(() => { clearCachedBalances() }, []) diff --git a/packages/connect/src/components/TxnDetails/TxnDetails.tsx b/packages/connect/src/components/TxnDetails/TxnDetails.tsx index ad9d431db..150da73f6 100644 --- a/packages/connect/src/components/TxnDetails/TxnDetails.tsx +++ b/packages/connect/src/components/TxnDetails/TxnDetails.tsx @@ -1,7 +1,7 @@ import { commons } from '@0xsequence/core' import { Card, GradientAvatar, Skeleton, Text, TokenImage } from '@0xsequence/design-system' -import { useAPIClient, useGetTokenBalancesSummary, useGetTokenMetadata } from '@0xsequence/hooks' -import { ContractType, ContractVerificationStatus } from '@0xsequence/indexer' +import { useAPIClient, useGetSingleTokenBalance, useGetTokenMetadata } from '@0xsequence/hooks' +import { ContractType } from '@0xsequence/indexer' import { useEffect, useState } from 'react' import { formatUnits, zeroAddress } from 'viem' import { useConfig } from 'wagmi' @@ -93,14 +93,10 @@ const TransferItemInfo = ({ address, transferProps, chainId }: TransferItemInfoP const isNFT = transferProps.contractType === ContractType.ERC1155 || transferProps.contractType === ContractType.ERC721 const nativeTokenInfo = getNativeTokenInfoByChainId(chainId, chains) - const { data: balances = [] } = useGetTokenBalancesSummary({ - chainIds: [chainId], - filter: { - accountAddresses: [address], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [contractAddress], - omitNativeBalances: false - } + const { data: tokenBalance } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress: address }) const { data: tokenMetadata } = useGetTokenMetadata({ @@ -109,7 +105,6 @@ const TransferItemInfo = ({ address, transferProps, chainId }: TransferItemInfoP tokenIDs: transferProps.tokenIds ?? [] }) - const tokenBalance = contractAddress ? balances.find(b => compareAddress(b.contractAddress, contractAddress)) : undefined const decimals = isNativeCoin ? nativeTokenInfo.decimals : tokenBalance?.contractInfo?.decimals || 18 const imageUrl = isNativeCoin diff --git a/packages/hooks/README.md b/packages/hooks/README.md index fb65d9808..e39287ad2 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -42,7 +42,7 @@ Sequence hooks are grouped into 5 categories, based on the sequence service they - useGetTokenBalancesSummary - useGetTokenBalancesDetails - useGetTokenBalancesByContract -- useGetSingleTokenBalanceSummary +- useGetSingleTokenBalance ### Metadata @@ -115,14 +115,13 @@ const { data, isLoading, error } = useGetExchangeRate('CAD', { ```tsx import { useGetTransactionHistory } from '@0xsequence/hooks' -const { data, isLoading, error } = useGetTransactionHistory({ - accountAddress: '0x0123456789012345678901234567890123456789', - contractAddress: '0x0123456789012345678901234567890123456789', // optional +const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, error } = useGetTransactionHistory({ + accountAddresses: ['0x0123456789012345678901234567890123456789'], + contractAddresses: ['0x0123456789012345678901234567890123456789'], // optional tokenId: '1', // optional chainId: 1, // optional page: { // optional pageSize: 10, - page: 1 }, { // options param is optional and default values are below @@ -139,7 +138,7 @@ import { useGetTransactionHistorySummary } from '@0xsequence/hooks' const { data, isLoading, error } = useGetTransactionHistorySummary( { - accountAddress: '0x0123456789012345678901234567890123456789', + accountAddresses: ['0x0123456789012345678901234567890123456789'], chainIds: [1] }, { @@ -175,7 +174,7 @@ const { data, isLoading, error } = useGetNativeTokenBalance( import { ContractVerificationStatus } from '@0xsequence/indexer' import { useGetTokenBalancesSummary } from '@0xsequence/hooks' -const { data, isLoading, error } = useGetTokenBalancesSummary( +const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, error } = useGetTokenBalancesSummary( { chainIds: [1], // either use chainIds or networks name networks: ['mainnet'], @@ -189,15 +188,13 @@ const { data, isLoading, error } = useGetTokenBalancesSummary( omitMetadata: false, // optional page: { // optional - pageSize: 10, - page: 1 + pageSize: 10 } }, { // options param is optional and default values are below disabled: false, - retry: true, - hideCollectibles: false + retry: true } ) ``` @@ -208,7 +205,7 @@ const { data, isLoading, error } = useGetTokenBalancesSummary( import { ContractVerificationStatus } from '@0xsequence/indexer' import { useGetTokenBalancesDetails } from '@0xsequence/hooks' -const { data, isLoading, error } = useGetTokenBalancesDetails( +const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, error } = useGetTokenBalancesDetails( { chainIds: [1], // either use chainIds or networks name networks: ['mainnet'], @@ -222,15 +219,13 @@ const { data, isLoading, error } = useGetTokenBalancesDetails( omitMetadata: false, // optional page: { // optional - pageSize: 10, - page: 1 + pageSize: 10 } }, { // options param is optional and default values are below disabled: false, - retry: true, - hideCollectibles: false + retry: true } ) ``` @@ -241,7 +236,7 @@ const { data, isLoading, error } = useGetTokenBalancesDetails( import { ContractVerificationStatus } from '@0xsequence/indexer' import { useGetTokenBalancesByContract } from '@0xsequence/hooks' -const { data, isLoading, error } = useGetTokenBalancesByContract( +const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage, error } = useGetTokenBalancesByContract( { chainIds: [1], // either use chainIds or networks name networks: ['mainnet'], @@ -255,25 +250,23 @@ const { data, isLoading, error } = useGetTokenBalancesByContract( omitMetadata: false, // optional page: { // optional - pageSize: 10, - page: 1 + pageSize: 10 } }, { // options param is optional and default values are below disabled: false, - retry: true, - hideCollectibles: false + retry: true } ) ``` -### useGetSingleTokenBalanceSummary +### useGetSingleTokenBalance ```tsx -import { useGetSingleTokenBalanceSummary } from '@0xsequence/hooks' +import { useGetSingleTokenBalance } from '@0xsequence/hooks' -const { data, isLoading, error } = useGetSingleTokenBalanceSummary({ +const { data, isLoading, error } = useGetSingleTokenBalance({ chainId: 1, accountAddress: '0x9876543210987654321098765432109876543210', contractAddress: '0x0123456789012345678901234567890123456789' diff --git a/packages/hooks/src/constants.ts b/packages/hooks/src/constants.ts index 252c4671b..a76b10886 100644 --- a/packages/hooks/src/constants.ts +++ b/packages/hooks/src/constants.ts @@ -8,7 +8,7 @@ export const QUERY_KEYS = { useGetTransactionHistorySummary: 'useGetTransactionHistorySummary', useGetContractInfo: 'useGetContractInfo', useGetMultipleContractInfo: 'useGetMultipleContractInfo', - useGetSingleTokenBalanceSummary: 'useGetSingleTokenBalanceSummary', + useGetSingleTokenBalance: 'useGetSingleTokenBalance', useGetExchangeRate: 'useGetExchangeRate', useGetCoinPrices: 'useGetCoinPrices', useGetCollectiblePrices: 'useGetCollectiblePrices', diff --git a/packages/hooks/src/hooks/Indexer/useGetTransactionHistory.ts b/packages/hooks/src/hooks/Indexer/useGetTransactionHistory.ts index 384721f93..1a671c63b 100644 --- a/packages/hooks/src/hooks/Indexer/useGetTransactionHistory.ts +++ b/packages/hooks/src/hooks/Indexer/useGetTransactionHistory.ts @@ -1,5 +1,5 @@ -import { GetTransactionHistoryReturn, Page, SequenceIndexer } from '@0xsequence/indexer' -import { InfiniteData, useInfiniteQuery, UseInfiniteQueryResult } from '@tanstack/react-query' +import { Page, SequenceIndexer } from '@0xsequence/indexer' +import { useInfiniteQuery } from '@tanstack/react-query' import { getAddress } from 'viem' import { QUERY_KEYS, time } from '../../constants' @@ -8,15 +8,18 @@ import { HooksOptions } from '../../types' import { useIndexerClient } from './useIndexerClient' interface GetTransactionHistoryArgs { - accountAddress: string - contractAddress?: string + accountAddresses: string[] + contractAddresses?: string[] tokenId?: string page?: Page } +export interface UseGetTransactionHistoryArgs extends GetTransactionHistoryArgs { + chainId: number +} + /** * Return type for the useGetTransactionHistory hook. - * Extends React Query's UseInfiniteQueryResult with transaction history data. * * @property data - The paginated transaction history data * @property data.pages - Array of page results, each containing: @@ -29,28 +32,22 @@ interface GetTransactionHistoryArgs { * - transfers: Optional array of transaction transfers * - timestamp: Transaction timestamp * - page: Pagination information: - * - page: Next page number + * - after: Cursor for the next page * - more: Whether more results exist in the next page * - pageSize: Number of results per page - * @property everything else that react query returns {@link UseInfiniteQueryResult} * */ -export type UseGetTransactionHistoryReturnType = UseInfiniteQueryResult, Error> - -export interface UseGetTransactionHistoryArgs extends GetTransactionHistoryArgs { - chainId: number -} const getTransactionHistory = async ( indexerClient: SequenceIndexer, - { contractAddress, accountAddress, tokenId, page }: GetTransactionHistoryArgs + { accountAddresses, contractAddresses, tokenId, page }: GetTransactionHistoryArgs ) => { const res = await indexerClient.getTransactionHistory({ includeMetadata: true, page, filter: { - accountAddress, - contractAddress, + accountAddresses, + contractAddresses, tokenID: tokenId } }) @@ -98,9 +95,9 @@ const getTransactionHistory = async ( * isFetchingNextPage * } = useGetTransactionHistory({ * chainId: 1, - * accountAddress: '0x123...', + * accountAddresses: ['0x123...'], * // Optional filters: - * // contractAddress: '0x456...', + * // contractAddresses: ['0x456...'], * // tokenId: '1' * }) * @@ -131,10 +128,7 @@ const getTransactionHistory = async ( * } * ``` */ -export const useGetTransactionHistory = ( - args: UseGetTransactionHistoryArgs, - options?: HooksOptions -): UseGetTransactionHistoryReturnType => { +export const useGetTransactionHistory = (args: UseGetTransactionHistoryArgs, options?: HooksOptions) => { const indexerClient = useIndexerClient(args.chainId) return useInfiniteQuery({ @@ -142,20 +136,15 @@ export const useGetTransactionHistory = ( queryFn: ({ pageParam }) => { return getTransactionHistory(indexerClient, { ...args, - page: { page: pageParam } + page: pageParam }) }, getNextPageParam: ({ page }) => { - // Note: must return undefined instead of null to stop the infinite scroll - if (!page.more) { - return undefined - } - - return page?.page || 1 + return page?.more ? page : undefined }, - initialPageParam: 1, + initialPageParam: { pageSize: args.page?.pageSize } as Page, retry: options?.retry ?? true, staleTime: time.oneSecond * 30, - enabled: !!args.chainId && !!args.accountAddress && !options?.disabled + enabled: !!args.chainId && args.accountAddresses.length > 0 && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/Indexer/useGetTransactionHistorySummary.ts b/packages/hooks/src/hooks/Indexer/useGetTransactionHistorySummary.ts index 66a805cad..27ced3745 100644 --- a/packages/hooks/src/hooks/Indexer/useGetTransactionHistorySummary.ts +++ b/packages/hooks/src/hooks/Indexer/useGetTransactionHistorySummary.ts @@ -7,19 +7,20 @@ import { HooksOptions } from '../../types' import { useIndexerClients } from './useIndexerClient' -export type GetTransactionHistorySummaryArgs = - | { accountAddress: string; accountAddresses?: never; chainIds: number[] } - | { accountAddress?: never; accountAddresses: string[]; chainIds: number[] } +export interface GetTransactionHistorySummaryArgs { + accountAddresses: string[] + chainIds: number[] +} const getTransactionHistorySummary = async ( indexerClients: Map, - { accountAddress, accountAddresses }: GetTransactionHistorySummaryArgs + { accountAddresses }: GetTransactionHistorySummaryArgs ): Promise => { const histories = await Promise.all( Array.from(indexerClients.values()).map(indexerClient => indexerClient.getTransactionHistory({ filter: { - accountAddresses: accountAddresses || [accountAddress] + accountAddresses }, includeMetadata: true }) @@ -84,7 +85,7 @@ const getTransactionHistorySummary = async ( * const { address: accountAddress } = useAccount() * const { * data: transactionHistory = [], - * isPending: isPendingTransactionHistory + * isLoading: isLoadingTransactionHistory * } = useGetTransactionHistorySummary({ * accountAddress: accountAddress || '', * chainIds: [1, 137] @@ -129,7 +130,7 @@ export const useGetTransactionHistorySummary = ( refetchOnMount: true, enabled: getTransactionHistorySummaryArgs.chainIds.length > 0 && - !!(getTransactionHistorySummaryArgs.accountAddress || (getTransactionHistorySummaryArgs.accountAddresses?.length ?? 0)) && + getTransactionHistorySummaryArgs.accountAddresses.length > 0 && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/IndexerGateway/useGetNativeTokenBalance.ts b/packages/hooks/src/hooks/IndexerGateway/useGetNativeTokenBalance.ts index e72b134d8..1a749eecb 100644 --- a/packages/hooks/src/hooks/IndexerGateway/useGetNativeTokenBalance.ts +++ b/packages/hooks/src/hooks/IndexerGateway/useGetNativeTokenBalance.ts @@ -9,9 +9,9 @@ import { useIndexerGatewayClient } from './useIndexerGatewayClient' const getNativeTokenBalance = async ( indexerGatewayClient: SequenceIndexerGateway, - getNativeTokenBalanceArgs: IndexerGateway.GetNativeTokenBalanceArgs + args: IndexerGateway.GetNativeTokenBalanceArgs ): Promise => { - const res = await indexerGatewayClient.getNativeTokenBalance(getNativeTokenBalanceArgs) + const res = await indexerGatewayClient.getNativeTokenBalance(args) const balances = res.balances.map(balances => createNativeTokenBalance(balances.chainId, balances.result.accountAddress, balances.result.balance) @@ -51,17 +51,14 @@ const getNativeTokenBalance = async ( * } * ``` */ -export const useGetNativeTokenBalance = ( - getNativeTokenBalanceArgs: IndexerGateway.GetNativeTokenBalanceArgs, - options?: HooksOptions -) => { +export const useGetNativeTokenBalance = (args: IndexerGateway.GetNativeTokenBalanceArgs, options?: HooksOptions) => { const indexerGatewayClient = useIndexerGatewayClient() return useQuery({ - queryKey: [QUERY_KEYS.useGetNativeTokenBalance, getNativeTokenBalanceArgs, options], - queryFn: async () => await getNativeTokenBalance(indexerGatewayClient, getNativeTokenBalanceArgs), + queryKey: [QUERY_KEYS.useGetNativeTokenBalance, args, options], + queryFn: async () => await getNativeTokenBalance(indexerGatewayClient, args), retry: options?.retry ?? true, staleTime: time.oneSecond * 30, - enabled: !!getNativeTokenBalanceArgs.accountAddress && !options?.disabled + enabled: !!args.accountAddress && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalanceSummary.ts b/packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalance.ts similarity index 71% rename from packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalanceSummary.ts rename to packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalance.ts index 3f552070f..28cdc4e20 100644 --- a/packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalanceSummary.ts +++ b/packages/hooks/src/hooks/IndexerGateway/useGetSingleTokenBalance.ts @@ -1,24 +1,21 @@ -import { ContractType, SequenceIndexerGateway } from '@0xsequence/indexer' +import { SequenceIndexerGateway } from '@0xsequence/indexer' import { useQuery } from '@tanstack/react-query' import { ZERO_ADDRESS, QUERY_KEYS, time } from '../../constants' -import { BalanceHookOptions } from '../../types' +import { HooksOptions } from '../../types' import { compareAddress, createNativeTokenBalance } from '../../utils/helpers' import { useIndexerGatewayClient } from './useIndexerGatewayClient' -export interface GetSingleTokenBalanceSummaryArgs { +export interface GetSingleTokenBalanceArgs { chainId: number accountAddress: string contractAddress: string + tokenId?: string } -const getSingleTokenBalanceSummary = async ( - args: GetSingleTokenBalanceSummaryArgs, - indexerGatewayClient: SequenceIndexerGateway, - hideCollectibles: boolean -) => { - const balance = await indexerGatewayClient.getTokenBalancesSummary({ +const getSingleTokenBalance = async (args: GetSingleTokenBalanceArgs, indexerGatewayClient: SequenceIndexerGateway) => { + const balance = await indexerGatewayClient.getTokenBalancesDetails({ chainIds: [args.chainId], filter: { accountAddresses: [args.accountAddress], @@ -27,18 +24,14 @@ const getSingleTokenBalanceSummary = async ( } }) - if (hideCollectibles) { - for (const chainBalance of balance.balances) { - chainBalance.results = chainBalance.results.filter( - result => result.contractType !== ContractType.ERC721 && result.contractType !== ContractType.ERC1155 - ) - } - } - if (compareAddress(args.contractAddress, ZERO_ADDRESS)) { return createNativeTokenBalance(args.chainId, args.accountAddress, balance.nativeBalances[0].results[0].balance) } else { - return balance.balances[0].results[0] + if (args.tokenId) { + return balance.balances[0].results.find(result => result.tokenID === args.tokenId) + } else { + return balance.balances[0].results[0] + } } } @@ -82,13 +75,13 @@ const getSingleTokenBalanceSummary = async ( * } * ``` */ -export const useGetSingleTokenBalanceSummary = (args: GetSingleTokenBalanceSummaryArgs, options?: BalanceHookOptions) => { +export const useGetSingleTokenBalance = (args: GetSingleTokenBalanceArgs, options?: HooksOptions) => { const indexerGatewayClient = useIndexerGatewayClient() return useQuery({ - queryKey: [QUERY_KEYS.useGetSingleTokenBalanceSummary, args, options], + queryKey: [QUERY_KEYS.useGetSingleTokenBalance, args, options], queryFn: async () => { - return await getSingleTokenBalanceSummary(args, indexerGatewayClient, options?.hideCollectibles ?? false) + return await getSingleTokenBalance(args, indexerGatewayClient) }, retry: options?.retry ?? true, staleTime: time.oneSecond * 30, diff --git a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesByContract.ts b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesByContract.ts index 6fd205658..2d249c5f0 100644 --- a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesByContract.ts +++ b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesByContract.ts @@ -1,27 +1,21 @@ -import { ContractType, IndexerGateway, SequenceIndexerGateway, TokenBalance } from '@0xsequence/indexer' -import { useQuery } from '@tanstack/react-query' +import { IndexerGateway, Page, SequenceIndexerGateway } from '@0xsequence/indexer' +import { useInfiniteQuery } from '@tanstack/react-query' import { QUERY_KEYS, time } from '../../constants' -import { BalanceHookOptions } from '../../types' +import { HooksOptions } from '../../types' import { useIndexerGatewayClient } from './useIndexerGatewayClient' const getTokenBalancesByContract = async ( indexerGatewayClient: SequenceIndexerGateway, - getTokenBalancesByContractArgs: IndexerGateway.GetTokenBalancesByContractArgs, - hideCollectibles: boolean -): Promise => { - const res = await indexerGatewayClient.getTokenBalancesByContract(getTokenBalancesByContractArgs) + args: IndexerGateway.GetTokenBalancesByContractArgs +) => { + const res = await indexerGatewayClient.getTokenBalancesByContract(args) - if (hideCollectibles) { - for (const chainBalance of res.balances) { - chainBalance.results = chainBalance.results.filter( - result => result.contractType !== ContractType.ERC721 && result.contractType !== ContractType.ERC1155 - ) - } + return { + balances: res.balances.flatMap(balance => balance.results), + page: res.page } - - return res.balances.flatMap(balance => balance.results) } /** @@ -78,23 +72,20 @@ const getTokenBalancesByContract = async ( * } * ``` */ -export const useGetTokenBalancesByContract = ( - getTokenBalancesByContractArgs: IndexerGateway.GetTokenBalancesByContractArgs, - options?: BalanceHookOptions -) => { +export const useGetTokenBalancesByContract = (args: IndexerGateway.GetTokenBalancesByContractArgs, options?: HooksOptions) => { const indexerGatewayClient = useIndexerGatewayClient() - return useQuery({ - queryKey: [QUERY_KEYS.useGetTokenBalancesByContract, getTokenBalancesByContractArgs, options], - queryFn: async () => { - return await getTokenBalancesByContract( - indexerGatewayClient, - getTokenBalancesByContractArgs, - options?.hideCollectibles ?? false - ) + return useInfiniteQuery({ + queryKey: [QUERY_KEYS.useGetTokenBalancesByContract, args, options], + queryFn: ({ pageParam }) => { + return getTokenBalancesByContract(indexerGatewayClient, { ...args, page: pageParam }) + }, + getNextPageParam: ({ page }) => { + return page?.more ? page : undefined }, + initialPageParam: { pageSize: args.page?.pageSize } as Page, retry: options?.retry ?? true, staleTime: time.oneSecond * 30, - enabled: !!getTokenBalancesByContractArgs.filter.accountAddresses?.[0] && !options?.disabled + enabled: args.filter.contractAddresses.length > 0 && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesDetails.ts b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesDetails.ts index 1b7f3b13f..ed5e14c2f 100644 --- a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesDetails.ts +++ b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesDetails.ts @@ -1,27 +1,18 @@ -import { ContractType, IndexerGateway, SequenceIndexerGateway, TokenBalance } from '@0xsequence/indexer' -import { useQuery } from '@tanstack/react-query' +import { IndexerGateway, Page, SequenceIndexerGateway, TokenBalance } from '@0xsequence/indexer' +import { useInfiniteQuery } from '@tanstack/react-query' import { QUERY_KEYS, time } from '../../constants' -import { BalanceHookOptions } from '../../types' +import { HooksOptions } from '../../types' import { createNativeTokenBalance, sortBalancesByType } from '../../utils/helpers' import { useIndexerGatewayClient } from './useIndexerGatewayClient' const getTokenBalancesDetails = async ( - getTokenBalancesDetailsArgs: IndexerGateway.GetTokenBalancesDetailsArgs, indexerGatewayClient: SequenceIndexerGateway, - hideCollectibles: boolean -): Promise => { + args: IndexerGateway.GetTokenBalancesDetailsArgs +) => { try { - const res = await indexerGatewayClient.getTokenBalancesDetails(getTokenBalancesDetailsArgs) - - if (hideCollectibles) { - for (const chainBalance of res.balances) { - chainBalance.results = chainBalance.results.filter( - result => result.contractType !== ContractType.ERC721 && result.contractType !== ContractType.ERC1155 - ) - } - } + const res = await indexerGatewayClient.getTokenBalancesDetails(args) const nativeTokens: TokenBalance[] = res.nativeBalances.flatMap(nativeChainBalance => nativeChainBalance.results.map(nativeTokenBalance => @@ -33,7 +24,14 @@ const getTokenBalancesDetails = async ( const sortedBalances = sortBalancesByType([...nativeTokens, ...tokens]) - return [...sortedBalances.nativeTokens, ...sortedBalances.erc20Tokens, ...sortedBalances.collectibles] + return { + balances: [ + ...(res.page.after ? [] : [...sortedBalances.nativeTokens]), + ...sortedBalances.erc20Tokens, + ...sortedBalances.collectibles + ], + page: res.page + } } catch (e) { throw e } @@ -131,19 +129,20 @@ const getTokenBalancesDetails = async ( * } * ``` */ -export const useGetTokenBalancesDetails = ( - getTokenBalancesDetailsArgs: IndexerGateway.GetTokenBalancesDetailsArgs, - options?: BalanceHookOptions -) => { +export const useGetTokenBalancesDetails = (args: IndexerGateway.GetTokenBalancesDetailsArgs, options?: HooksOptions) => { const indexerGatewayClient = useIndexerGatewayClient() - return useQuery({ - queryKey: [QUERY_KEYS.useGetTokenBalancesDetails, getTokenBalancesDetailsArgs, options], - queryFn: async () => { - return await getTokenBalancesDetails(getTokenBalancesDetailsArgs, indexerGatewayClient, options?.hideCollectibles ?? false) + return useInfiniteQuery({ + queryKey: [QUERY_KEYS.useGetTokenBalancesDetails, args, options], + queryFn: ({ pageParam }) => { + return getTokenBalancesDetails(indexerGatewayClient, { ...args, page: pageParam }) + }, + getNextPageParam: ({ page }) => { + return page?.more ? page : undefined }, + initialPageParam: { pageSize: args.page?.pageSize } as Page, retry: options?.retry ?? true, staleTime: time.oneSecond * 30, - enabled: !!getTokenBalancesDetailsArgs.filter.accountAddresses[0] && !options?.disabled + enabled: args.filter.accountAddresses.length > 0 && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesSummary.ts b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesSummary.ts index b5e890d15..926e129ac 100644 --- a/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesSummary.ts +++ b/packages/hooks/src/hooks/IndexerGateway/useGetTokenBalancesSummary.ts @@ -1,27 +1,18 @@ -import { ContractType, IndexerGateway, SequenceIndexerGateway, TokenBalance } from '@0xsequence/indexer' -import { useQuery } from '@tanstack/react-query' +import { IndexerGateway, Page, SequenceIndexerGateway, TokenBalance } from '@0xsequence/indexer' +import { useInfiniteQuery } from '@tanstack/react-query' import { QUERY_KEYS, time } from '../../constants' -import { BalanceHookOptions } from '../../types' +import { HooksOptions } from '../../types' import { createNativeTokenBalance, sortBalancesByType } from '../../utils/helpers' import { useIndexerGatewayClient } from './useIndexerGatewayClient' const getTokenBalancesSummary = async ( - getTokenBalancesSummaryArgs: IndexerGateway.GetTokenBalancesSummaryArgs, indexerGatewayClient: SequenceIndexerGateway, - hideCollectibles: boolean -): Promise => { + args: IndexerGateway.GetTokenBalancesSummaryArgs +) => { try { - const res = await indexerGatewayClient.getTokenBalancesSummary(getTokenBalancesSummaryArgs) - - if (hideCollectibles) { - for (const chainBalance of res.balances) { - chainBalance.results = chainBalance.results.filter( - result => result.contractType !== ContractType.ERC721 && result.contractType !== ContractType.ERC1155 - ) - } - } + const res = await indexerGatewayClient.getTokenBalancesSummary(args) const nativeTokens: TokenBalance[] = res.nativeBalances.flatMap(nativeChainBalance => nativeChainBalance.results.map(nativeTokenBalance => @@ -33,7 +24,14 @@ const getTokenBalancesSummary = async ( const sortedBalances = sortBalancesByType([...nativeTokens, ...tokens]) - return [...sortedBalances.nativeTokens, ...sortedBalances.erc20Tokens, ...sortedBalances.collectibles] + return { + balances: [ + ...(res.page.after ? [] : [...sortedBalances.nativeTokens]), + ...sortedBalances.erc20Tokens, + ...sortedBalances.collectibles + ], + page: res.page + } } catch (e) { throw e } @@ -106,19 +104,20 @@ const getTokenBalancesSummary = async ( * } * ``` */ -export const useGetTokenBalancesSummary = ( - getTokenBalancesSummaryArgs: IndexerGateway.GetTokenBalancesSummaryArgs, - options?: BalanceHookOptions -) => { +export const useGetTokenBalancesSummary = (args: IndexerGateway.GetTokenBalancesSummaryArgs, options?: HooksOptions) => { const indexerGatewayClient = useIndexerGatewayClient() - return useQuery({ - queryKey: [QUERY_KEYS.useGetTokenBalancesSummary, getTokenBalancesSummaryArgs, options], - queryFn: async () => { - return await getTokenBalancesSummary(getTokenBalancesSummaryArgs, indexerGatewayClient, options?.hideCollectibles ?? false) + return useInfiniteQuery({ + queryKey: [QUERY_KEYS.useGetTokenBalancesSummary, args, options], + queryFn: ({ pageParam }) => { + return getTokenBalancesSummary(indexerGatewayClient, { ...args, page: pageParam }) + }, + getNextPageParam: ({ page }) => { + return page?.more ? page : undefined }, + initialPageParam: { pageSize: args.page?.pageSize } as Page, retry: options?.retry ?? true, staleTime: time.oneSecond * 30, - enabled: !!getTokenBalancesSummaryArgs.filter.accountAddresses[0] && !options?.disabled + enabled: args.filter.accountAddresses.length > 0 && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/Metadata/useGetContractInfo.ts b/packages/hooks/src/hooks/Metadata/useGetContractInfo.ts index 958c0c669..cabc77c04 100644 --- a/packages/hooks/src/hooks/Metadata/useGetContractInfo.ts +++ b/packages/hooks/src/hooks/Metadata/useGetContractInfo.ts @@ -71,19 +71,16 @@ import { useMetadataClient } from './useMetadataClient' * } * ``` */ -export const useGetContractInfo = ( - getContractInfoArgs: GetContractInfoArgs, - options?: HooksOptions -): UseQueryResult => { +export const useGetContractInfo = (args: GetContractInfoArgs, options?: HooksOptions): UseQueryResult => { const metadataClient = useMetadataClient() return useQuery({ - queryKey: [QUERY_KEYS.useGetContractInfo, getContractInfoArgs, options], + queryKey: [QUERY_KEYS.useGetContractInfo, args, options], queryFn: async () => { - const isNativeToken = compareAddress(ZERO_ADDRESS, getContractInfoArgs.contractAddress) + const isNativeToken = compareAddress(ZERO_ADDRESS, args.contractAddress) - const res = await metadataClient.getContractInfo(getContractInfoArgs) - const network = findSupportedNetwork(getContractInfoArgs.chainID) + const res = await metadataClient.getContractInfo(args) + const network = findSupportedNetwork(args.chainID) return { ...res.contractInfo, @@ -97,6 +94,6 @@ export const useGetContractInfo = ( }, retry: options?.retry ?? true, staleTime: time.oneMinute * 10, - enabled: !!getContractInfoArgs.chainID && !!getContractInfoArgs.contractAddress && !options?.disabled + enabled: !!args.chainID && !!args.contractAddress && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/Metadata/useGetMultipleContractsInfo.ts b/packages/hooks/src/hooks/Metadata/useGetMultipleContractsInfo.ts index 344f24eb5..bc64c89f2 100644 --- a/packages/hooks/src/hooks/Metadata/useGetMultipleContractsInfo.ts +++ b/packages/hooks/src/hooks/Metadata/useGetMultipleContractsInfo.ts @@ -8,10 +8,10 @@ import { useMetadataClient } from './useMetadataClient' const getMultipleContractsInfo = async ( metadataClient: SequenceMetadata, - arg: GetContractInfoArgs[] + args: GetContractInfoArgs[] ): Promise => { try { - const res = await Promise.all(arg.map(a => metadataClient.getContractInfo(a))) + const res = await Promise.all(args.map(a => metadataClient.getContractInfo(a))) return res.map(r => r.contractInfo) } catch (e) { @@ -110,12 +110,12 @@ const getMultipleContractsInfo = async ( * } * ``` */ -export const useGetMultipleContractsInfo = (useGetMultipleContractsInfoArgs: GetContractInfoArgs[], options?: HooksOptions) => { +export const useGetMultipleContractsInfo = (args: GetContractInfoArgs[], options?: HooksOptions) => { const metadataClient = useMetadataClient() return useQuery({ - queryKey: [QUERY_KEYS.useGetMultipleContractInfo, useGetMultipleContractsInfoArgs, options], - queryFn: async () => await getMultipleContractsInfo(metadataClient, useGetMultipleContractsInfoArgs), + queryKey: [QUERY_KEYS.useGetMultipleContractInfo, args, options], + queryFn: async () => await getMultipleContractsInfo(metadataClient, args), retry: options?.retry ?? true, staleTime: time.oneHour, enabled: !options?.disabled diff --git a/packages/hooks/src/hooks/Metadata/useGetTokenMetadata.ts b/packages/hooks/src/hooks/Metadata/useGetTokenMetadata.ts index cc01fde07..ac51db39d 100644 --- a/packages/hooks/src/hooks/Metadata/useGetTokenMetadata.ts +++ b/packages/hooks/src/hooks/Metadata/useGetTokenMetadata.ts @@ -120,15 +120,15 @@ const getTokenMetadata = async (metadataClient: SequenceMetadata, args: GetToken * } * ``` */ -export const useGetTokenMetadata = (getTokenMetadataArgs: GetTokenMetadataArgs, options?: HooksOptions) => { +export const useGetTokenMetadata = (args: GetTokenMetadataArgs, options?: HooksOptions) => { const { env } = useConfig() const metadataClient = useMetadataClient() return useQuery({ - queryKey: [QUERY_KEYS.useGetTokenMetadata, getTokenMetadataArgs, options], - queryFn: () => getTokenMetadata(metadataClient, getTokenMetadataArgs, env.imageProxyUrl), + queryKey: [QUERY_KEYS.useGetTokenMetadata, args, options], + queryFn: () => getTokenMetadata(metadataClient, args, env.imageProxyUrl), retry: options?.retry ?? true, staleTime: time.oneHour, - enabled: !!getTokenMetadataArgs.chainID && !!getTokenMetadataArgs.contractAddress && !options?.disabled + enabled: !!args.chainID && !!args.contractAddress && !options?.disabled }) } diff --git a/packages/hooks/src/hooks/useClearCachedBalances.ts b/packages/hooks/src/hooks/useClearCachedBalances.ts index 1606c0263..b98e3cbf3 100644 --- a/packages/hooks/src/hooks/useClearCachedBalances.ts +++ b/packages/hooks/src/hooks/useClearCachedBalances.ts @@ -8,23 +8,7 @@ export const useClearCachedBalances = () => { return { clearCachedBalances: () => { queryClient.invalidateQueries({ - queryKey: [ - QUERY_KEYS.useGetNativeTokenBalance, - QUERY_KEYS.useGetTokenBalancesSummary, - QUERY_KEYS.useGetTokenBalancesDetails, - QUERY_KEYS.useGetTokenBalancesByContract, - QUERY_KEYS.useGetTokenMetadata, - QUERY_KEYS.useGetTransactionHistory, - QUERY_KEYS.useGetTransactionHistorySummary, - QUERY_KEYS.useGetContractInfo, - QUERY_KEYS.useGetMultipleContractInfo, - QUERY_KEYS.useGetSingleTokenBalanceSummary, - QUERY_KEYS.useGetExchangeRate, - QUERY_KEYS.useGetCoinPrices, - QUERY_KEYS.useGetCollectiblePrices, - QUERY_KEYS.useGetSwapPrices, - QUERY_KEYS.useGetSwapQuote - ] + queryKey: Object.values(QUERY_KEYS) }) } } diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 8fae03838..0a0e8c19c 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -27,10 +27,7 @@ export { // IndexerGateway export { useIndexerGatewayClient } from './hooks/IndexerGateway/useIndexerGatewayClient' export { useGetNativeTokenBalance } from './hooks/IndexerGateway/useGetNativeTokenBalance' -export { - useGetSingleTokenBalanceSummary, - type GetSingleTokenBalanceSummaryArgs -} from './hooks/IndexerGateway/useGetSingleTokenBalanceSummary' +export { useGetSingleTokenBalance, type GetSingleTokenBalanceArgs } from './hooks/IndexerGateway/useGetSingleTokenBalance' export { useGetTokenBalancesByContract } from './hooks/IndexerGateway/useGetTokenBalancesByContract' export { useGetTokenBalancesDetails } from './hooks/IndexerGateway/useGetTokenBalancesDetails' export { useGetTokenBalancesSummary } from './hooks/IndexerGateway/useGetTokenBalancesSummary' diff --git a/packages/hooks/src/tests/Indexer/useGetTransactionHistory.test.ts b/packages/hooks/src/tests/Indexer/useGetTransactionHistory.test.ts index b85e7ef0d..1dfa32e07 100644 --- a/packages/hooks/src/tests/Indexer/useGetTransactionHistory.test.ts +++ b/packages/hooks/src/tests/Indexer/useGetTransactionHistory.test.ts @@ -2,15 +2,15 @@ import { renderHook, waitFor } from '@testing-library/react' import { HttpResponse, http } from 'msw' import { describe, expect, it } from 'vitest' -import { ACCOUNT_ADDRESS } from '../../constants' +import { ACCOUNT_ADDRESS, ZERO_ADDRESS } from '../../constants' import { UseGetTransactionHistoryArgs, useGetTransactionHistory } from '../../hooks/Indexer/useGetTransactionHistory' import { createWrapper } from '../createWrapper' import { server } from '../setup' const getTransactionHistoryArgs: UseGetTransactionHistoryArgs = { chainId: 1, - accountAddress: ACCOUNT_ADDRESS, - contractAddress: '0x0000000000000000000000000000000000000000' + accountAddresses: [ACCOUNT_ADDRESS], + contractAddresses: [ZERO_ADDRESS] } describe('useGetTransactionHistory', () => { @@ -23,7 +23,7 @@ describe('useGetTransactionHistory', () => { expect(result.current.data).toBeDefined() - const value = BigInt(result.current.data!.pages[0].transactions[0].txnHash || '') + const value = BigInt(result.current.data?.pages[0].transactions[0].txnHash || '') expect(value).toBeDefined() }) diff --git a/packages/hooks/src/tests/Indexer/useGetTransactionHistorySummary.test.ts b/packages/hooks/src/tests/Indexer/useGetTransactionHistorySummary.test.ts index eea6e758d..e155a6325 100644 --- a/packages/hooks/src/tests/Indexer/useGetTransactionHistorySummary.test.ts +++ b/packages/hooks/src/tests/Indexer/useGetTransactionHistorySummary.test.ts @@ -11,7 +11,7 @@ import { createWrapper } from '../createWrapper' import { server } from '../setup' const getTransactionHistorySummaryArgs: GetTransactionHistorySummaryArgs = { - accountAddress: ACCOUNT_ADDRESS, + accountAddresses: [ACCOUNT_ADDRESS], chainIds: [1] } diff --git a/packages/hooks/src/tests/IndexerGateway/useGetSingleTokenBalanceSummary.test.ts b/packages/hooks/src/tests/IndexerGateway/useGetSingleTokenBalanceSummary.test.ts index dffba6363..3700d9629 100644 --- a/packages/hooks/src/tests/IndexerGateway/useGetSingleTokenBalanceSummary.test.ts +++ b/packages/hooks/src/tests/IndexerGateway/useGetSingleTokenBalanceSummary.test.ts @@ -3,22 +3,19 @@ import { HttpResponse, http } from 'msw' import { describe, expect, it } from 'vitest' import { ACCOUNT_ADDRESS, ZERO_ADDRESS } from '../../constants' -import { - GetSingleTokenBalanceSummaryArgs, - useGetSingleTokenBalanceSummary -} from '../../hooks/IndexerGateway/useGetSingleTokenBalanceSummary' +import { GetSingleTokenBalanceArgs, useGetSingleTokenBalance } from '../../hooks/IndexerGateway/useGetSingleTokenBalance' import { createWrapper } from '../createWrapper' import { server } from '../setup' -const getTokenBalancesSummaryArgs: GetSingleTokenBalanceSummaryArgs = { +const getTokenBalancesArgs: GetSingleTokenBalanceArgs = { chainId: 1, accountAddress: ACCOUNT_ADDRESS, contractAddress: ZERO_ADDRESS } -describe('useGetSingleTokenBalanceSummary', () => { +describe('useGetSingleTokenBalance', () => { it('should return data with a balance', async () => { - const { result } = renderHook(() => useGetSingleTokenBalanceSummary(getTokenBalancesSummaryArgs), { + const { result } = renderHook(() => useGetSingleTokenBalance(getTokenBalancesArgs), { wrapper: createWrapper() }) @@ -38,7 +35,7 @@ describe('useGetSingleTokenBalanceSummary', () => { }) ) - const { result } = renderHook(() => useGetSingleTokenBalanceSummary(getTokenBalancesSummaryArgs, { retry: false }), { + const { result } = renderHook(() => useGetSingleTokenBalance(getTokenBalancesArgs, { retry: false }), { wrapper: createWrapper() }) diff --git a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesByContract.test.ts b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesByContract.test.ts index 9d53a3c33..7ab0cd484 100644 --- a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesByContract.test.ts +++ b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesByContract.test.ts @@ -26,7 +26,7 @@ describe('useGetTokenBalancesByContract', () => { expect(result.current.data).toBeDefined() - const value = BigInt(result.current.data?.[0].balance || 0) + const value = BigInt(result.current.data?.pages[0].balances[0].balance || 0) expect(value).toBeGreaterThan(0) }) diff --git a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesDetails.test.ts b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesDetails.test.ts index b9fcf1be2..e38c9bb26 100644 --- a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesDetails.test.ts +++ b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesDetails.test.ts @@ -26,7 +26,7 @@ describe('useGetTokenBalancesDetails', () => { expect(result.current.data).toBeDefined() - const value = BigInt(result.current.data![0].balance || 0) + const value = BigInt(result.current.data?.pages[0].balances[0].balance || 0) expect(value).toBeGreaterThan(0) }) diff --git a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesSummary.test.ts b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesSummary.test.ts index 850472bd5..5ae326333 100644 --- a/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesSummary.test.ts +++ b/packages/hooks/src/tests/IndexerGateway/useGetTokenBalancesSummary.test.ts @@ -26,7 +26,7 @@ describe('useGetTokenBalancesSummary', () => { expect(result.current.data).toBeDefined() - const value = BigInt(result.current.data![0].balance || 0) + const value = BigInt(result.current.data?.pages[0].balances[0].balance || 0) expect(value).toBeGreaterThan(0) }) diff --git a/packages/hooks/src/types/hooks.ts b/packages/hooks/src/types/hooks.ts index 1fe953060..ea63da8b5 100644 --- a/packages/hooks/src/types/hooks.ts +++ b/packages/hooks/src/types/hooks.ts @@ -2,7 +2,3 @@ export interface HooksOptions { disabled?: boolean retry?: boolean } - -export interface BalanceHookOptions extends HooksOptions { - hideCollectibles?: boolean -} diff --git a/packages/wallet-widget/src/components/Filter/CollectionsFilter.tsx b/packages/wallet-widget/src/components/Filter/CollectionsFilter.tsx index 6420c1f61..b9529713f 100644 --- a/packages/wallet-widget/src/components/Filter/CollectionsFilter.tsx +++ b/packages/wallet-widget/src/components/Filter/CollectionsFilter.tsx @@ -1,8 +1,6 @@ import { TokenImage, Text } from '@0xsequence/design-system' -import { useGetTokenBalancesSummary } from '@0xsequence/hooks' -import { ContractType } from '@0xsequence/indexer' -import { useSettings } from '../../hooks' +import { useSettings, useGetCollections } from '../../hooks' import { MediaIconWrapper } from '../IconWrappers' import { ListCardSelect } from '../ListCard/ListCardSelect' @@ -10,27 +8,12 @@ export const CollectionsFilter = () => { const { selectedCollectionsObservable, selectedNetworks, selectedWallets, setSelectedCollections } = useSettings() const selectedCollections = selectedCollectionsObservable.get() - const { data: tokens } = useGetTokenBalancesSummary({ + const { data: collections } = useGetCollections({ + accountAddresses: selectedWallets.map(wallet => wallet.address), chainIds: selectedNetworks, - filter: { - accountAddresses: selectedWallets.map(wallet => wallet.address), - omitNativeBalances: true - } + hideUnlistedTokens: true }) - const collections = tokens - ?.filter(token => token.contractType === ContractType.ERC721 || token.contractType === ContractType.ERC1155) - .map(collection => { - return { - contractAddress: collection.contractAddress, - chainId: collection.chainId, - contractInfo: { - name: collection.contractInfo?.name || '', - logoURI: collection.contractInfo?.logoURI || '' - } - } - }) - return (
{collections?.length && collections.length > 1 && ( @@ -41,8 +24,8 @@ export const CollectionsFilter = () => { > ( -
- +
+
))} size="sm" @@ -61,13 +44,9 @@ export const CollectionsFilter = () => { } onClick={collections.length > 1 ? () => setSelectedCollections([collection]) : undefined} > - + - {collection.contractInfo?.name} + {collection.name} ))} diff --git a/packages/wallet-widget/src/components/Filter/FilterMenu.tsx b/packages/wallet-widget/src/components/Filter/FilterMenu.tsx index 29f16d644..c16e22d8a 100644 --- a/packages/wallet-widget/src/components/Filter/FilterMenu.tsx +++ b/packages/wallet-widget/src/components/Filter/FilterMenu.tsx @@ -1,11 +1,9 @@ import { formatAddress, getNetwork, useWallets } from '@0xsequence/connect' import { Text, TokenImage } from '@0xsequence/design-system' -import { useGetTokenBalancesSummary } from '@0xsequence/hooks' -import { ContractType } from '@0xsequence/indexer' import { useObservable } from 'micro-observables' import { useState } from 'react' -import { useSettings } from '../../hooks' +import { useSettings, useGetCollections } from '../../hooks' import { StackedIconTag } from '../IconWrappers' import { ListCardNav } from '../ListCard' import { SlideupDrawer } from '../Select/SlideupDrawer' @@ -32,33 +30,21 @@ export const FilterMenu = ({ onClose: () => void }) => { const { wallets } = useWallets() - const { selectedWalletsObservable, selectedNetworksObservable, selectedCollectionsObservable } = useSettings() + const { selectedWalletsObservable, selectedNetworksObservable, selectedCollectionsObservable, hideUnlistedTokensObservable } = + useSettings() const selectedWallets = useObservable(selectedWalletsObservable) const selectedNetworks = useObservable(selectedNetworksObservable) const selectedCollections = useObservable(selectedCollectionsObservable) + const hideUnlistedTokens = useObservable(hideUnlistedTokensObservable) const [selectedFilter, setSelectedFilter] = useState(FilterType.menu) - const { data: tokens } = useGetTokenBalancesSummary({ + const { data: collections } = useGetCollections({ + accountAddresses: selectedWallets.map(wallet => wallet.address), chainIds: selectedNetworks, - filter: { - accountAddresses: selectedWallets.map(wallet => wallet.address), - omitNativeBalances: true - } + hideUnlistedTokens }) - const collections = tokens - ?.filter(token => token.contractType === ContractType.ERC721 || token.contractType === ContractType.ERC1155) - .map(collection => { - return { - contractAddress: collection.contractAddress, - contractInfo: { - name: collection.contractInfo?.name || '', - logoURI: collection.contractInfo?.logoURI || '' - } - } - }) - const walletsPreview = selectedWallets.length > 1 || wallets.length === 1 ? ( ) : ( - ]} + iconList={[]} label={ - {selectedCollections[0].contractInfo?.name} + {selectedCollections[0].name} } /> diff --git a/packages/wallet-widget/src/components/InfiniteScroll.tsx b/packages/wallet-widget/src/components/InfiniteScroll.tsx index 20588c3b9..8520183f6 100644 --- a/packages/wallet-widget/src/components/InfiniteScroll.tsx +++ b/packages/wallet-widget/src/components/InfiniteScroll.tsx @@ -29,7 +29,7 @@ export const InfiniteScroll = (props: PropsWithChildren) => const { onLoad, hasMore = true, children, resetTrigger } = props const [pageNumber, setPageNumber] = useState(0) - const [isLoading, setLoading] = useState(false) + const [isFetching, setIsFetching] = useState(false) const bottomRef = useRef(null) const isBottom = useIntersectionObserver(bottomRef) @@ -38,18 +38,18 @@ export const InfiniteScroll = (props: PropsWithChildren) => }, [resetTrigger]) useEffect(() => { - if (isBottom && hasMore && !isLoading) { + if (isBottom && hasMore && !isFetching) { handleLoad() } }, [isBottom]) const handleLoad = async () => { - setLoading(true) + setIsFetching(true) await onLoad(pageNumber) setPageNumber(pageNumber => pageNumber + 1) - setLoading(false) + setIsFetching(false) } return ( diff --git a/packages/wallet-widget/src/components/NavigationHeader/index.tsx b/packages/wallet-widget/src/components/NavigationHeader/index.tsx index 7431c823f..7455e85c2 100644 --- a/packages/wallet-widget/src/components/NavigationHeader/index.tsx +++ b/packages/wallet-widget/src/components/NavigationHeader/index.tsx @@ -2,7 +2,7 @@ import { IconButton, ChevronLeftIcon, Text, ModalPrimitive } from '@0xsequence/d import { HEADER_HEIGHT } from '../../constants' import { useNavigationContext } from '../../contexts/Navigation' -import { useNavigation } from '../../hooks/useNavigation' +import { useNavigation } from '../../hooks' interface NavigationHeaderProps { primaryText?: string diff --git a/packages/wallet-widget/src/components/SearchLists/CollectiblesList.tsx b/packages/wallet-widget/src/components/SearchLists/CollectiblesList.tsx index 94fb552a3..8440e4df5 100644 --- a/packages/wallet-widget/src/components/SearchLists/CollectiblesList.tsx +++ b/packages/wallet-widget/src/components/SearchLists/CollectiblesList.tsx @@ -3,20 +3,21 @@ import { TokenBalance } from '@0xsequence/indexer' import Fuse from 'fuse.js' import { useState, useMemo } from 'react' -import { TokenBalanceWithPrice, useGetMoreBalances } from '../../utils' +import { useGetMoreBalances } from '../../hooks' +import { TokenBalanceWithPrice } from '../../utils' import { FilterButton } from '../Filter/FilterButton' import { CollectiblesTab } from './CollectiblesList/CollectiblesTab' export const CollectiblesList = ({ tokenBalancesData, - isPendingTokenBalances, + isLoadingFirstPage, onTokenClick, enableFilters = true, gridColumns = 2 }: { tokenBalancesData: TokenBalance[] - isPendingTokenBalances: boolean + isLoadingFirstPage: boolean onTokenClick: (token: TokenBalanceWithPrice) => void enableFilters?: boolean gridColumns?: number @@ -40,8 +41,6 @@ export const CollectiblesList = ({ } })) - const isPending = isPendingTokenBalances - const fuseOptions = { threshold: 0.1, ignoreLocation: true, @@ -108,7 +107,7 @@ export const CollectiblesList = ({ fetchMoreCollectibleBalances={search ? fetchMoreSearchBalances : fetchMoreBalances} hasMoreCollectibleBalances={search ? hasMoreSearchBalances : hasMoreBalances} isFetchingMoreCollectibleBalances={search ? isFetchingMoreSearchBalances : isFetchingMoreBalances} - isFetchingInitialBalances={isPending} + isFetchingInitialBalances={isLoadingFirstPage} onTokenClick={onTokenClick} gridColumns={gridColumns} /> diff --git a/packages/wallet-widget/src/components/SearchLists/TokenList.tsx b/packages/wallet-widget/src/components/SearchLists/TokenList.tsx index 93f9724dd..298d9bcc7 100644 --- a/packages/wallet-widget/src/components/SearchLists/TokenList.tsx +++ b/packages/wallet-widget/src/components/SearchLists/TokenList.tsx @@ -7,22 +7,21 @@ import Fuse from 'fuse.js' import { useState, useMemo } from 'react' import { useConfig } from 'wagmi' -import { useSettings } from '../../hooks' +import { useSettings, useGetMoreBalances } from '../../hooks' import { computeBalanceFiat, TokenBalanceWithPrice } from '../../utils' -import { useGetMoreBalances } from '../../utils' import { FilterButton } from '../Filter/FilterButton' import { CoinsTab } from './TokenList/CoinsTab' export const TokenList = ({ tokenBalancesData, - isPendingTokenBalances, + isLoadingFirstPage, onTokenClick, includeUserAddress = false, enableFilters = true }: { tokenBalancesData: TokenBalance[] - isPendingTokenBalances: boolean + isLoadingFirstPage: boolean onTokenClick: (token: TokenBalanceWithPrice) => void enableFilters?: boolean includeUserAddress?: boolean @@ -37,14 +36,14 @@ export const TokenList = ({ const coinBalancesUnordered = tokenBalancesData?.filter(b => b.contractType === 'ERC20' || compareAddress(b.contractAddress, ethers.ZeroAddress)) || [] - const { data: coinPrices = [], isPending: isPendingCoinPrices } = useGetCoinPrices( + const { data: coinPrices = [], isLoading: isLoadingCoinPrices } = useGetCoinPrices( coinBalancesUnordered.map(token => ({ chainId: token.chainId, contractAddress: token.contractAddress })) ) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) const coinBalances = coinBalancesUnordered.sort((a, b) => { const fiatA = computeBalanceFiat({ @@ -82,7 +81,7 @@ export const TokenList = ({ } }) - const isPending = isPendingTokenBalances || isPendingCoinPrices || isPendingConversionRate + const isLoading = isLoadingFirstPage || isLoadingCoinPrices || isLoadingConversionRate const fuseOptions = { threshold: 0.1, @@ -148,7 +147,7 @@ export const TokenList = ({ fetchMoreCoinBalances={search ? fetchMoreSearchBalances : fetchMoreBalances} hasMoreCoinBalances={search ? hasMoreSearchBalances : hasMoreBalances} isFetchingMoreCoinBalances={search ? isFetchingMoreSearchBalances : isFetchingMoreBalances} - isFetchingInitialBalances={isPending} + isFetchingInitialBalances={isLoading} onTokenClick={onTokenClick} includeUserAddress={includeUserAddress} /> diff --git a/packages/wallet-widget/src/components/Select/SelectWalletRow.tsx b/packages/wallet-widget/src/components/Select/SelectWalletRow.tsx index c61b90156..61fe2b313 100644 --- a/packages/wallet-widget/src/components/Select/SelectWalletRow.tsx +++ b/packages/wallet-widget/src/components/Select/SelectWalletRow.tsx @@ -1,8 +1,7 @@ import { formatAddress, ConnectedWallet } from '@0xsequence/connect' import { Text } from '@0xsequence/design-system' -import { useSettings } from '../../hooks' -import { useFiatWalletsMap } from '../../hooks/useFiatWalletsMap' +import { useSettings, useFiatWalletsMap } from '../../hooks' import { CopyButton } from '../CopyButton' import { ListCardSelect } from '../ListCard/ListCardSelect' import { WalletAccountGradient } from '../WalletAccountGradient' diff --git a/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/FiatWalletsMapProvider.tsx b/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/FiatWalletsMapProvider.tsx index 24cc1263e..3a5919703 100644 --- a/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/FiatWalletsMapProvider.tsx +++ b/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/FiatWalletsMapProvider.tsx @@ -1,10 +1,10 @@ -import { compareAddress, ContractVerificationStatus, useWallets } from '@0xsequence/connect' -import { useGetExchangeRate, useGetCoinPrices, useGetTokenBalancesDetails } from '@0xsequence/hooks' +import { compareAddress, useWallets } from '@0xsequence/connect' +import { useGetExchangeRate, useGetCoinPrices } from '@0xsequence/hooks' import { useState, ReactNode, useEffect } from 'react' import { zeroAddress, getAddress } from 'viem' import { FiatWalletPair, FiatWalletsMapContextProvider } from '../../../contexts' -import { useSettings } from '../../../hooks' +import { useGetAllTokensDetails, useSettings } from '../../../hooks' import { computeBalanceFiat } from '../../../utils' // Define the provider component @@ -14,32 +14,29 @@ export const FiatWalletsMapProvider = ({ children }: { children: ReactNode }) => const [fiatWalletsMap, setFiatWalletsMap] = useState([]) - const { data: tokenBalancesData, isPending: isTokenBalancesPending } = useGetTokenBalancesDetails({ + const { data: tokenBalancesData, isLoading: isTokenBalancesLoading } = useGetAllTokensDetails({ + accountAddresses: wallets.map(wallet => wallet.address), chainIds: selectedNetworks, - filter: { - accountAddresses: wallets.map(wallet => wallet.address), - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - omitNativeBalances: false - } + hideUnlistedTokens }) const coinBalancesUnordered = tokenBalancesData?.filter(b => b.contractType === 'ERC20' || compareAddress(b.contractAddress, zeroAddress)) || [] - const { data: coinPrices = [], isPending: isCoinPricesPending } = useGetCoinPrices( + const { data: coinPrices = [], isLoading: isCoinPricesLoading } = useGetCoinPrices( coinBalancesUnordered.map(token => ({ chainId: token.chainId, contractAddress: token.contractAddress })) ) - const { data: conversionRate, isPending: isConversionRatePending } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate, isLoading: isConversionRateLoading } = useGetExchangeRate(fiatCurrency.symbol) useEffect(() => { if ( - !isTokenBalancesPending && - !isCoinPricesPending && - !isConversionRatePending && + !isTokenBalancesLoading && + !isCoinPricesLoading && + !isConversionRateLoading && coinBalancesUnordered.length > 0 && coinPrices.length > 0 && conversionRate diff --git a/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/SwapProvider.tsx b/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/SwapProvider.tsx index ba4ae4448..48133325e 100644 --- a/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/SwapProvider.tsx +++ b/packages/wallet-widget/src/components/SequenceWalletProvider/ProviderComponents/SwapProvider.tsx @@ -7,7 +7,7 @@ import { formatUnits, Hex, zeroAddress } from 'viem' import { useAccount, useChainId, useChains, usePublicClient, useWalletClient } from 'wagmi' import { SwapContextProvider } from '../../../contexts/Swap' -import { useNavigation } from '../../../hooks/useNavigation' +import { useNavigation } from '../../../hooks' import { TokenBalanceWithPrice } from '../../../utils' export const SwapProvider = ({ children }: { children: ReactNode }) => { diff --git a/packages/wallet-widget/src/components/TransactionHistoryList/TransactionHistoryItem.tsx b/packages/wallet-widget/src/components/TransactionHistoryList/TransactionHistoryItem.tsx index f2bca266a..36f532aa8 100644 --- a/packages/wallet-widget/src/components/TransactionHistoryList/TransactionHistoryItem.tsx +++ b/packages/wallet-widget/src/components/TransactionHistoryList/TransactionHistoryItem.tsx @@ -36,16 +36,16 @@ export const TransactionHistoryItem = ({ transaction }: TransactionHistoryItemPr } }) - const { data: coinPrices = [], isPending: isPendingCoinPrices } = useGetCoinPrices( + const { data: coinPrices = [], isLoading: isLoadingCoinPrices } = useGetCoinPrices( tokenContractAddresses.map(contractAddress => ({ contractAddress, chainId: transaction.chainId })) ) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isPendingCoinPrices || isPendingConversionRate + const isLoading = isLoadingCoinPrices || isLoadingConversionRate const { transfers } = transaction @@ -168,7 +168,7 @@ export const TransactionHistoryItem = ({ transaction }: TransactionHistoryItemPr {(tokenLogoUri || symbol) && } {getTransferAmountLabel(decimals === 0 ? amount : formatDisplay(amountValue), symbol, transfer.transferType)}
- {isPending && } + {isLoading && } {fiatConversionRate && ( {`${fiatCurrency.sign}${(Number(amountValue) * fiatConversionRate * conversionRate).toFixed(2)}`} diff --git a/packages/wallet-widget/src/components/TransactionHistoryList/index.tsx b/packages/wallet-widget/src/components/TransactionHistoryList/index.tsx index 6a4e9881a..c37f6b46d 100644 --- a/packages/wallet-widget/src/components/TransactionHistoryList/index.tsx +++ b/packages/wallet-widget/src/components/TransactionHistoryList/index.tsx @@ -7,11 +7,11 @@ import { TransactionHistorySkeleton } from './TransactionHistorySkeleton' interface TransactionHistoryListProps { transactions: Transaction[] - isPending: boolean + isLoading: boolean isFetchingNextPage: boolean } -export const TransactionHistoryList = ({ transactions, isPending, isFetchingNextPage }: TransactionHistoryListProps) => { +export const TransactionHistoryList = ({ transactions, isLoading, isFetchingNextPage }: TransactionHistoryListProps) => { type TransactionPeriodId = 'today' | 'yesterday' | 'week' | 'month' | 'year' | 'past' interface TransactionPeriods { @@ -90,7 +90,7 @@ export const TransactionHistoryList = ({ transactions, isPending, isFetchingNext return transactionsByTime }, [transactions]) - if (isPending) { + if (isLoading) { return (
diff --git a/packages/wallet-widget/src/hooks/index.ts b/packages/wallet-widget/src/hooks/index.ts index 41fe21a06..7e601e071 100644 --- a/packages/wallet-widget/src/hooks/index.ts +++ b/packages/wallet-widget/src/hooks/index.ts @@ -1,3 +1,8 @@ export * from './useOpenWalletModal' export * from './useNavigation' export * from './useSettings' +export * from './useFiatWalletsMap' +export * from './useGetAllTokensDetails' +export * from './useGetCollections' +export * from './useGetMoreBalances' +export * from './useSwap' diff --git a/packages/wallet-widget/src/hooks/useGetAllTokensDetails.ts b/packages/wallet-widget/src/hooks/useGetAllTokensDetails.ts new file mode 100644 index 000000000..dc8e450b0 --- /dev/null +++ b/packages/wallet-widget/src/hooks/useGetAllTokensDetails.ts @@ -0,0 +1,43 @@ +import { useGetTokenBalancesDetails } from '@0xsequence/hooks' +import { ContractVerificationStatus } from '@0xsequence/indexer' +import { useEffect } from 'react' + +export const useGetAllTokensDetails = ({ + accountAddresses, + chainIds, + contractWhitelist, + hideUnlistedTokens +}: { + accountAddresses: string[] + chainIds: number[] + contractWhitelist?: string[] + hideUnlistedTokens: boolean +}) => { + const { + data: tokenBalancesData, + isLoading, + fetchNextPage, + hasNextPage, + isFetchingNextPage + } = useGetTokenBalancesDetails({ + chainIds, + filter: { + accountAddresses, + contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, + contractWhitelist: contractWhitelist ?? [], + omitNativeBalances: false + }, + page: { pageSize: 40 } + }) + + useEffect(() => { + if (hasNextPage && !isFetchingNextPage) { + fetchNextPage() + } + }, [hasNextPage, isFetchingNextPage]) + + return { + data: tokenBalancesData?.pages.flatMap(page => page.balances) || [], + isLoading: isLoading + } +} diff --git a/packages/wallet-widget/src/hooks/useGetCollections.ts b/packages/wallet-widget/src/hooks/useGetCollections.ts new file mode 100644 index 000000000..62b353b2f --- /dev/null +++ b/packages/wallet-widget/src/hooks/useGetCollections.ts @@ -0,0 +1,56 @@ +import { useGetTokenBalancesDetails } from '@0xsequence/hooks' +import { ContractType, ContractVerificationStatus } from '@0xsequence/indexer' +import { useEffect } from 'react' + +export const useGetCollections = ({ + accountAddresses, + chainIds, + hideUnlistedTokens +}: { + accountAddresses: string[] + chainIds: number[] + hideUnlistedTokens: boolean +}) => { + const { + data: tokenBalancesData, + isLoading, + fetchNextPage, + hasNextPage, + isFetchingNextPage + } = useGetTokenBalancesDetails({ + chainIds, + filter: { + accountAddresses, + contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, + omitNativeBalances: false + }, + page: { pageSize: 40 } + }) + + useEffect(() => { + if (hasNextPage && !isFetchingNextPage) { + fetchNextPage() + } + }, [hasNextPage, isFetchingNextPage]) + + const collections = tokenBalancesData?.pages + .flatMap(page => page.balances) + .filter(token => token.contractType === ContractType.ERC721 || token.contractType === ContractType.ERC1155) + .map(collectible => { + return { + contractAddress: collectible.contractAddress, + chainId: collectible.chainId, + name: collectible.contractInfo?.name || '', + logoURI: collectible.contractInfo?.logoURI || '' + } + }) + + const uniqueCollections = Array.from( + new Map(collections?.map(collection => [collection?.contractAddress, collection])).values() + ) + + return { + data: uniqueCollections, + isLoading + } +} diff --git a/packages/wallet-widget/src/hooks/useGetMoreBalances.ts b/packages/wallet-widget/src/hooks/useGetMoreBalances.ts new file mode 100644 index 000000000..b52887708 --- /dev/null +++ b/packages/wallet-widget/src/hooks/useGetMoreBalances.ts @@ -0,0 +1,27 @@ +import { useInfiniteQuery } from '@tanstack/react-query' +import { UseInfiniteQueryResult } from '@tanstack/react-query' +import { InfiniteData } from '@tanstack/react-query' + +import { TokenBalanceWithPrice } from '../utils' + +export const useGetMoreBalances = ( + balances: TokenBalanceWithPrice[], + pageSize: number, + options?: { enabled: boolean } +): UseInfiniteQueryResult, Error> => { + return useInfiniteQuery({ + queryKey: ['infiniteBalances', balances], + queryFn: ({ pageParam }) => { + const startIndex = pageParam * pageSize + return balances.slice(startIndex, startIndex + pageSize) + }, + getNextPageParam: (lastPage, allPages) => { + if (lastPage.length < pageSize) { + return undefined + } + return allPages.length + }, + initialPageParam: 0, + enabled: !!balances.length && (options?.enabled ?? true) + }) +} diff --git a/packages/wallet-widget/src/hooks/useSettings.ts b/packages/wallet-widget/src/hooks/useSettings.ts index fbf907373..40b1c488b 100644 --- a/packages/wallet-widget/src/hooks/useSettings.ts +++ b/packages/wallet-widget/src/hooks/useSettings.ts @@ -11,28 +11,23 @@ interface MutableObservable extends Observable { export interface SettingsCollection { contractAddress: string chainId: number - contractInfo: { - name: string - logoURI: string - } + name: string + logoURI: string } interface Settings { - hideCollectibles: boolean hideUnlistedTokens: boolean fiatCurrency: FiatCurrency selectedNetworks: number[] allNetworks: number[] selectedWallets: ConnectedWallet[] selectedCollections: SettingsCollection[] - hideCollectiblesObservable: Observable hideUnlistedTokensObservable: Observable fiatCurrencyObservable: Observable selectedNetworksObservable: Observable selectedWalletsObservable: Observable selectedCollectionsObservable: Observable setFiatCurrency: (newFiatCurrency: FiatCurrency) => void - setHideCollectibles: (newState: boolean) => void setHideUnlistedTokens: (newState: boolean) => void setSelectedWallets: (newWallets: ConnectedWallet[]) => void setSelectedNetworks: (newNetworks: number[]) => void @@ -40,7 +35,6 @@ interface Settings { } type SettingsItems = { - hideCollectiblesObservable: MutableObservable hideUnlistedTokensObservable: MutableObservable fiatCurrencyObservable: MutableObservable selectedWalletsObservable: MutableObservable @@ -56,12 +50,10 @@ let settingsObservables: SettingsItems | null = null * Settings are stored in localStorage and persist across sessions. * * @returns {Settings} Object containing current settings and setter functions: - * - `hideCollectibles`: Whether to hide NFT collectibles in the wallet view * - `hideUnlistedTokens`: Whether to hide unverified tokens * - `fiatCurrency`: Selected fiat currency for value display (e.g., USD, EUR) * - `selectedNetworks`: Array of chain IDs for networks to display * - `setFiatCurrency`: Function to update fiat currency preference - * - `setHideCollectibles`: Function to toggle collectibles visibility * - `setHideUnlistedTokens`: Function to toggle unlisted tokens visibility * - `setSelectedNetworks`: Function to update selected networks * @@ -72,19 +64,12 @@ let settingsObservables: SettingsItems | null = null * // Basic usage in a component * function WalletView() { * const { - * hideCollectibles, * fiatCurrency, * selectedNetworks, - * setHideCollectibles * } = useSettings() * * return ( *
- * * Currency: {fiatCurrency.symbol} *
* ) @@ -101,7 +86,6 @@ export const useSettings = (): Settings => { const getSettingsFromStorage = (): SettingsItems => { let hideUnlistedTokens = true - let hideCollectibles = false let fiatCurrency = defaultFiatCurrency let selectedWallets: ConnectedWallet[] = allWallets let selectedNetworks: number[] = allNetworks @@ -115,9 +99,6 @@ export const useSettings = (): Settings => { if (settings?.hideUnlistedTokens !== undefined) { hideUnlistedTokens = settings?.hideUnlistedTokens } - if (settings?.hideCollectibles !== undefined) { - hideCollectibles = settings?.hideCollectibles - } if (settings?.fiatCurrency !== undefined) { fiatCurrency = settings?.fiatCurrency as FiatCurrency } @@ -160,7 +141,6 @@ export const useSettings = (): Settings => { return { hideUnlistedTokensObservable: observable(hideUnlistedTokens), - hideCollectiblesObservable: observable(hideCollectibles), fiatCurrencyObservable: observable(fiatCurrency), selectedWalletsObservable: observable(selectedWallets), selectedNetworksObservable: observable(selectedNetworks), @@ -193,7 +173,6 @@ export const useSettings = (): Settings => { const { hideUnlistedTokensObservable, - hideCollectiblesObservable, fiatCurrencyObservable, selectedWalletsObservable, selectedNetworksObservable, @@ -205,11 +184,6 @@ export const useSettings = (): Settings => { updateLocalStorage() } - const setHideCollectibles = (newState: boolean) => { - hideCollectiblesObservable.set(newState) - updateLocalStorage() - } - const setFiatCurrency = (newFiatCurrency: FiatCurrency) => { fiatCurrencyObservable.set(newFiatCurrency) updateLocalStorage() @@ -246,7 +220,6 @@ export const useSettings = (): Settings => { const updateLocalStorage = () => { const newSettings = { hideUnlistedTokens: hideUnlistedTokensObservable.get(), - hideCollectibles: hideCollectiblesObservable.get(), fiatCurrency: fiatCurrencyObservable.get(), selectedWallets: selectedWalletsObservable.get(), selectedNetworks: selectedNetworksObservable.get(), @@ -258,20 +231,17 @@ export const useSettings = (): Settings => { return { hideUnlistedTokens: hideUnlistedTokensObservable.get(), - hideCollectibles: hideCollectiblesObservable.get(), fiatCurrency: fiatCurrencyObservable.get(), selectedWallets: selectedWalletsObservable.get(), selectedNetworks: selectedNetworksObservable.get(), allNetworks: allNetworks, selectedCollections: selectedCollectionsObservable.get(), hideUnlistedTokensObservable, - hideCollectiblesObservable, fiatCurrencyObservable, selectedWalletsObservable, selectedNetworksObservable, selectedCollectionsObservable, setFiatCurrency, - setHideCollectibles, setHideUnlistedTokens, setSelectedWallets, setSelectedNetworks, diff --git a/packages/wallet-widget/src/utils/tokens.ts b/packages/wallet-widget/src/utils/tokens.ts index 3642ae695..9d05010d3 100644 --- a/packages/wallet-widget/src/utils/tokens.ts +++ b/packages/wallet-widget/src/utils/tokens.ts @@ -1,8 +1,7 @@ import { Price, TokenPrice } from '@0xsequence/api' import { compareAddress } from '@0xsequence/connect' import { TokenBalance, GetTransactionHistoryReturn, Transaction } from '@0xsequence/indexer' -import { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query' -import { useInfiniteQuery } from '@tanstack/react-query' +import { InfiniteData } from '@tanstack/react-query' import { formatUnits, zeroAddress } from 'viem' export interface TokenBalanceWithPrice extends TokenBalance { @@ -103,25 +102,3 @@ export const flattenPaginatedTransactionHistory = ( return transactionHistory } - -export const useGetMoreBalances = ( - balances: TokenBalanceWithPrice[], - pageSize: number, - options?: { enabled: boolean } -): UseInfiniteQueryResult, Error> => { - return useInfiniteQuery({ - queryKey: ['infiniteBalances', balances], - queryFn: ({ pageParam }) => { - const startIndex = pageParam * pageSize - return balances.slice(startIndex, startIndex + pageSize) - }, - getNextPageParam: (lastPage, allPages) => { - if (lastPage.length < pageSize) { - return undefined - } - return allPages.length - }, - initialPageParam: 0, - enabled: !!balances.length && (options?.enabled ?? true) - }) -} diff --git a/packages/wallet-widget/src/views/CoinDetails/index.tsx b/packages/wallet-widget/src/views/CoinDetails/index.tsx index 74b501a0d..04ab20a7a 100644 --- a/packages/wallet-widget/src/views/CoinDetails/index.tsx +++ b/packages/wallet-widget/src/views/CoinDetails/index.tsx @@ -1,12 +1,6 @@ -import { - compareAddress, - formatDisplay, - getNativeTokenInfoByChainId, - ContractVerificationStatus, - useWallets -} from '@0xsequence/connect' +import { compareAddress, formatDisplay, getNativeTokenInfoByChainId, useWallets } from '@0xsequence/connect' import { Button, SendIcon, SwapIcon, Text, TokenImage } from '@0xsequence/design-system' -import { useGetTokenBalancesSummary, useGetCoinPrices, useGetExchangeRate, useGetTransactionHistory } from '@0xsequence/hooks' +import { useGetCoinPrices, useGetExchangeRate, useGetTransactionHistory, useGetSingleTokenBalance } from '@0xsequence/hooks' import { useEffect } from 'react' import { formatUnits, zeroAddress } from 'viem' import { useConfig } from 'wagmi' @@ -29,8 +23,8 @@ export interface CoinDetailsProps { export const CoinDetails = ({ contractAddress, chainId, accountAddress }: CoinDetailsProps) => { const { chains } = useConfig() const { setNavigation } = useNavigation() + const { fiatCurrency } = useSettings() const { setActiveWallet } = useWallets() - const { fiatCurrency, hideUnlistedTokens } = useSettings() useEffect(() => { setActiveWallet(accountAddress) @@ -40,61 +34,50 @@ export const CoinDetails = ({ contractAddress, chainId, accountAddress }: CoinDe const { data: dataTransactionHistory, - isPending: isPendingTransactionHistory, + isLoading: isLoadingTransactionHistory, fetchNextPage, hasNextPage, isFetchingNextPage } = useGetTransactionHistory({ chainId, - accountAddress: accountAddress || '', - contractAddress + accountAddresses: [accountAddress], + contractAddresses: [contractAddress] }) const transactionHistory = flattenPaginatedTransactionHistory(dataTransactionHistory) - const { data: tokenBalance, isPending: isPendingCoinBalance } = useGetTokenBalancesSummary({ - chainIds: [chainId], - filter: { - accountAddresses: [accountAddress || ''], - contractWhitelist: [contractAddress], - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - omitNativeBalances: false - } + const { data: tokenBalance, isLoading: isLoadingCoinBalance } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress: accountAddress || '' }) - const dataCoinBalance = - tokenBalance && tokenBalance.length > 0 - ? compareAddress(contractAddress, zeroAddress) - ? tokenBalance?.[0] - : tokenBalance?.[1] - : undefined - - const { data: dataCoinPrices, isPending: isPendingCoinPrices } = useGetCoinPrices([ + const { data: dataCoinPrices, isLoading: isLoadingCoinPrices } = useGetCoinPrices([ { chainId, contractAddress } ]) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isPendingCoinBalance || isPendingCoinPrices || isPendingConversionRate + const isLoading = isLoadingCoinBalance || isLoadingCoinPrices || isLoadingConversionRate - if (isPending) { + if (isLoading) { return } const isNativeToken = compareAddress(contractAddress, zeroAddress) - const logo = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).logoURI : dataCoinBalance?.contractInfo?.logoURI - const symbol = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).symbol : dataCoinBalance?.contractInfo?.symbol - const name = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).name : dataCoinBalance?.contractInfo?.name - const decimals = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).decimals : dataCoinBalance?.contractInfo?.decimals - const formattedBalance = formatUnits(BigInt(dataCoinBalance?.balance || '0'), decimals || 18) + const logo = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).logoURI : tokenBalance?.contractInfo?.logoURI + const symbol = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).symbol : tokenBalance?.contractInfo?.symbol + const name = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).name : tokenBalance?.contractInfo?.name + const decimals = isNativeToken ? getNativeTokenInfoByChainId(chainId, chains).decimals : tokenBalance?.contractInfo?.decimals + const formattedBalance = formatUnits(BigInt(tokenBalance?.balance || '0'), decimals || 18) const balanceDisplayed = formatDisplay(formattedBalance) - const coinBalanceFiat = dataCoinBalance + const coinBalanceFiat = tokenBalance ? computeBalanceFiat({ - balance: dataCoinBalance, + balance: tokenBalance, prices: dataCoinPrices || [], conversionRate, decimals: decimals || 18 @@ -149,7 +132,7 @@ export const CoinDetails = ({ contractAddress, chainId, accountAddress }: CoinDe fetchNextPage()} hasMore={hasNextPage}> diff --git a/packages/wallet-widget/src/views/CollectibleDetails/index.tsx b/packages/wallet-widget/src/views/CollectibleDetails/index.tsx index e5853e2ba..73ad8e17b 100644 --- a/packages/wallet-widget/src/views/CollectibleDetails/index.tsx +++ b/packages/wallet-widget/src/views/CollectibleDetails/index.tsx @@ -1,10 +1,10 @@ -import { formatDisplay, ContractVerificationStatus, useWallets } from '@0xsequence/connect' +import { formatDisplay, useWallets } from '@0xsequence/connect' import { Button, Image, NetworkImage, SendIcon, Text } from '@0xsequence/design-system' import { - useGetTokenBalancesDetails, useGetTransactionHistory, useGetCollectiblePrices, - useGetExchangeRate + useGetExchangeRate, + useGetSingleTokenBalance } from '@0xsequence/hooks' import { useEffect } from 'react' import { formatUnits } from 'viem' @@ -39,33 +39,27 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA const { data: dataTransactionHistory, - isPending: isPendingTransactionHistory, + isLoading: isLoadingTransactionHistory, fetchNextPage, hasNextPage, isFetchingNextPage } = useGetTransactionHistory({ chainId, - accountAddress: accountAddress || '', - contractAddress, + accountAddresses: [accountAddress || ''], + contractAddresses: [contractAddress], tokenId }) const transactionHistory = flattenPaginatedTransactionHistory(dataTransactionHistory) - const { data: dataTokens, isPending: isPendingCollectibleBalance } = useGetTokenBalancesDetails({ - filter: { - accountAddresses: accountAddress ? [accountAddress] : [], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [contractAddress], - omitNativeBalances: true - }, - chainIds: [chainId] + const { data: tokenBalance, isLoading: isLoadingCollectibleBalance } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress: accountAddress || '', + tokenId }) - const dataCollectibleBalance = - dataTokens && dataTokens.length > 0 ? dataTokens.find(token => token.tokenID === tokenId) : undefined - - const { data: dataCollectiblePrices, isPending: isPendingCollectiblePrices } = useGetCollectiblePrices([ + const { data: dataCollectiblePrices, isLoading: isLoadingCollectiblePrices } = useGetCollectiblePrices([ { chainId, contractAddress, @@ -73,11 +67,11 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA } ]) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isPendingCollectibleBalance || isPendingCollectiblePrices || isPendingConversionRate + const isLoading = isLoadingCollectibleBalance || isLoadingCollectiblePrices || isLoadingConversionRate - if (isPending) { + if (isLoading) { return } @@ -92,17 +86,17 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA }) } - const collectionLogo = dataCollectibleBalance?.contractInfo?.logoURI - const collectionName = dataCollectibleBalance?.contractInfo?.name || 'Unknown Collection' + const collectionLogo = tokenBalance?.contractInfo?.logoURI + const collectionName = tokenBalance?.contractInfo?.name || 'Unknown Collection' - const decimals = dataCollectibleBalance?.tokenMetadata?.decimals || 0 - const rawBalance = dataCollectibleBalance?.balance || '0' + const decimals = tokenBalance?.tokenMetadata?.decimals || 0 + const rawBalance = tokenBalance?.balance || '0' const balance = formatUnits(BigInt(rawBalance), decimals) const formattedBalance = formatDisplay(Number(balance)) - const valueFiat = dataCollectibleBalance + const valueFiat = tokenBalance ? computeBalanceFiat({ - balance: dataCollectibleBalance, + balance: tokenBalance, prices: dataCollectiblePrices || [], conversionRate, decimals: decimals @@ -138,7 +132,7 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA
- {dataCollectibleBalance?.tokenMetadata?.name || 'Unknown Collectible'} + {tokenBalance?.tokenMetadata?.name || 'Unknown Collectible'} {`#${tokenId}`} @@ -146,7 +140,7 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA
- +
{/* balance */} @@ -177,7 +171,7 @@ export const CollectibleDetails = ({ contractAddress, chainId, tokenId, accountA fetchNextPage()} hasMore={hasNextPage}> diff --git a/packages/wallet-widget/src/views/History.tsx b/packages/wallet-widget/src/views/History.tsx index d7190cb7c..345def50e 100644 --- a/packages/wallet-widget/src/views/History.tsx +++ b/packages/wallet-widget/src/views/History.tsx @@ -21,7 +21,7 @@ export const History = () => { const [search, setSearch] = useState('') - const { data: transactionHistory = [], isPending: isPendingTransactionHistory } = useGetTransactionHistorySummary({ + const { data: transactionHistory = [], isLoading: isLoadingTransactionHistory } = useGetTransactionHistorySummary({ accountAddresses: selectedWallets.map(wallet => wallet.address), chainIds: selectedNetworks }) @@ -145,7 +145,7 @@ export const History = () => {
diff --git a/packages/wallet-widget/src/views/Home/index.tsx b/packages/wallet-widget/src/views/Home/index.tsx index 3feb1bf62..819a36320 100644 --- a/packages/wallet-widget/src/views/Home/index.tsx +++ b/packages/wallet-widget/src/views/Home/index.tsx @@ -11,8 +11,7 @@ import { EllipsisIcon, Skeleton } from '@0xsequence/design-system' -import { useGetCoinPrices, useGetExchangeRate, useGetTokenBalancesDetails } from '@0xsequence/hooks' -import { ContractVerificationStatus } from '@0xsequence/indexer' +import { useGetCoinPrices, useGetExchangeRate } from '@0xsequence/hooks' import { ethers } from 'ethers' import { useObservable } from 'micro-observables' import { AnimatePresence } from 'motion/react' @@ -27,8 +26,7 @@ import { ListCardNavTable } from '../../components/ListCardTable/ListCardNavTabl import { SelectWalletRow } from '../../components/Select/SelectWalletRow' import { SlideupDrawer } from '../../components/Select/SlideupDrawer' import { WalletAccountGradient } from '../../components/WalletAccountGradient' -import { useNavigation, useSettings } from '../../hooks' -import { useFiatWalletsMap } from '../../hooks/useFiatWalletsMap' +import { useNavigation, useSettings, useGetAllTokensDetails, useFiatWalletsMap } from '../../hooks' import { computeBalanceFiat } from '../../utils' import { OperationButtonTemplate } from './OperationButtonTemplate' @@ -72,14 +70,11 @@ export const Home = () => { fetchSignInDisplay() }, [connector]) - const { data: tokenBalancesData, isPending: isTokenBalancesPending } = useGetTokenBalancesDetails({ + const { data: tokenBalancesData, isLoading: isLoadingTokenBalances } = useGetAllTokensDetails({ + accountAddresses: [accountAddress || ''], chainIds: selectedNetworks, - filter: { - accountAddresses: selectedWallets.map(wallet => wallet.address), - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - contractWhitelist: selectedCollections.map(collection => collection.contractAddress), - omitNativeBalances: false - } + contractWhitelist: selectedCollections.map(collection => collection.contractAddress), + hideUnlistedTokens }) const coinBalancesUnordered = @@ -98,16 +93,16 @@ export const Home = () => { return true }) || [] - const { data: coinPrices = [], isPending: isCoinPricesPending } = useGetCoinPrices( + const { data: coinPrices = [], isLoading: isLoadingCoinPrices } = useGetCoinPrices( coinBalancesUnordered.map(token => ({ chainId: token.chainId, contractAddress: token.contractAddress })) ) - const { data: conversionRate, isPending: isConversionRatePending } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isTokenBalancesPending || isCoinPricesPending || isConversionRatePending + const isLoading = isLoadingTokenBalances || isLoadingCoinPrices || isLoadingConversionRate const totalFiatValue = fiatWalletsMap .reduce((acc, wallet) => { @@ -244,7 +239,7 @@ export const Home = () => {
{fiatCurrency.sign} - {isPending ? : `${totalFiatValue}`} + {isLoading ? : `${totalFiatValue}`} { @@ -15,14 +13,11 @@ export const SearchCollectibles = () => { const selectedNetworks = useObservable(selectedNetworksObservable) const selectedCollections = useObservable(selectedCollectionsObservable) - const { data: tokenBalancesData = [], isPending: isPendingTokenBalances } = useGetTokenBalancesDetails({ + const { data: tokenBalancesData = [], isLoading } = useGetAllTokensDetails({ + accountAddresses: selectedWallets.map(wallet => wallet.address), chainIds: selectedNetworks, - filter: { - accountAddresses: selectedWallets.map(wallet => wallet.address), - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - contractWhitelist: selectedCollections.map(collection => collection.contractAddress), - omitNativeBalances: false - } + contractWhitelist: selectedCollections.map(collection => collection.contractAddress), + hideUnlistedTokens }) const isSingleCollectionSelected = selectedCollections.length === 1 @@ -50,7 +45,7 @@ export const SearchCollectibles = () => {
diff --git a/packages/wallet-widget/src/views/Search/SearchTokens.tsx b/packages/wallet-widget/src/views/Search/SearchTokens.tsx index 576aaf1d2..ec732203a 100644 --- a/packages/wallet-widget/src/views/Search/SearchTokens.tsx +++ b/packages/wallet-widget/src/views/Search/SearchTokens.tsx @@ -1,9 +1,8 @@ -import { useGetTokenBalancesSummary } from '@0xsequence/hooks' -import { ContractVerificationStatus } from '@0xsequence/indexer' import { useObservable } from 'micro-observables' import { TokenList } from '../../components/SearchLists' import { useNavigation, useSettings } from '../../hooks' +import { useGetAllTokensDetails } from '../../hooks' import { TokenBalanceWithPrice } from '../../utils' export const SearchTokens = () => { @@ -13,13 +12,10 @@ export const SearchTokens = () => { const selectedWallets = useObservable(selectedWalletsObservable) const selectedNetworks = useObservable(selectedNetworksObservable) - const { data: tokenBalancesData = [], isPending: isPendingTokenBalances } = useGetTokenBalancesSummary({ + const { data: tokenBalancesData, isLoading } = useGetAllTokensDetails({ + accountAddresses: selectedWallets.map(wallet => wallet.address), chainIds: selectedNetworks, - filter: { - accountAddresses: selectedWallets.map(wallet => wallet.address), - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - omitNativeBalances: false - } + hideUnlistedTokens }) const handleTokenClick = (balance: TokenBalanceWithPrice) => { @@ -37,7 +33,7 @@ export const SearchTokens = () => {
diff --git a/packages/wallet-widget/src/views/Send/SendCoin.tsx b/packages/wallet-widget/src/views/Send/SendCoin.tsx index 7745511ca..03c762cf7 100644 --- a/packages/wallet-widget/src/views/Send/SendCoin.tsx +++ b/packages/wallet-widget/src/views/Send/SendCoin.tsx @@ -25,12 +25,12 @@ import { } from '@0xsequence/design-system' import { useClearCachedBalances, - useGetTokenBalancesSummary, useGetCoinPrices, useGetExchangeRate, - useIndexerClient + useIndexerClient, + useGetSingleTokenBalance } from '@0xsequence/hooks' -import { ContractVerificationStatus, TokenBalance } from '@0xsequence/indexer' +import { TokenBalance } from '@0xsequence/indexer' import { useState, ChangeEvent, useRef, useEffect } from 'react' import { encodeFunctionData, formatUnits, parseUnits, toHex, zeroAddress, Hex } from 'viem' import { useAccount, useChainId, useSwitchChain, useConfig, usePublicClient, useWalletClient } from 'wagmi' @@ -83,27 +83,23 @@ export const SendCoin = ({ chainId, contractAddress }: SendCoinProps) => { const checkFeeOptions = useCheckWaasFeeOptions() const [pendingFeeOption, confirmFeeOption, _rejectFeeOption] = useWaasFeeOptions() - const { data: balances = [], isPending: isPendingBalances } = useGetTokenBalancesSummary({ - chainIds: [chainId], - filter: { - accountAddresses: [accountAddress], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [contractAddress], - omitNativeBalances: false - } + const { data: tokenBalance, isLoading: isLoadingBalances } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress }) + const nativeTokenInfo = getNativeTokenInfoByChainId(chainId, chains) - const tokenBalance = (balances as TokenBalance[]).find(b => b.contractAddress === contractAddress) - const { data: coinPrices = [], isPending: isPendingCoinPrices } = useGetCoinPrices([ + const { data: coinPrices = [], isLoading: isLoadingCoinPrices } = useGetCoinPrices([ { chainId, contractAddress } ]) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isPendingBalances || isPendingCoinPrices || isPendingConversionRate + const isLoading = isLoadingBalances || isLoadingCoinPrices || isLoadingConversionRate // Handle fee option confirmation when pendingFeeOption is available useEffect(() => { @@ -117,7 +113,7 @@ export const SendCoin = ({ chainId, contractAddress }: SendCoinProps) => { setIsBackButtonEnabled(!showConfirmation) }, [showConfirmation, setIsBackButtonEnabled]) - if (isPending) { + if (isLoading) { return null } diff --git a/packages/wallet-widget/src/views/Send/SendCollectible.tsx b/packages/wallet-widget/src/views/Send/SendCollectible.tsx index 84895f989..8b7cebffc 100644 --- a/packages/wallet-widget/src/views/Send/SendCollectible.tsx +++ b/packages/wallet-widget/src/views/Send/SendCollectible.tsx @@ -24,8 +24,8 @@ import { Card, useToast } from '@0xsequence/design-system' -import { useGetTokenBalancesDetails, useClearCachedBalances, useIndexerClient } from '@0xsequence/hooks' -import { ContractType, ContractVerificationStatus, TokenBalance } from '@0xsequence/indexer' +import { useClearCachedBalances, useIndexerClient, useGetSingleTokenBalance } from '@0xsequence/hooks' +import { ContractType, TokenBalance } from '@0xsequence/indexer' import { useRef, useState, ChangeEvent, useEffect } from 'react' import { encodeFunctionData, formatUnits, parseUnits, toHex, Hex } from 'viem' import { useAccount, useChainId, useSwitchChain, useConfig, usePublicClient, useWalletClient } from 'wagmi' @@ -79,18 +79,13 @@ export const SendCollectible = ({ chainId, contractAddress, tokenId }: SendColle const checkFeeOptions = useCheckWaasFeeOptions() const [pendingFeeOption, confirmFeeOption, _rejectFeeOption] = useWaasFeeOptions() - const { data: dataTokens, isPending: isPendingBalances } = useGetTokenBalancesDetails({ - filter: { - accountAddresses: [accountAddress], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [contractAddress], - omitNativeBalances: false - }, - chainIds: [chainId] + const { data: tokenBalance, isLoading: isLoadingBalances } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress, + tokenId }) - const tokenBalance = dataTokens && dataTokens.length > 0 ? dataTokens.find(balance => balance.tokenID === tokenId) : undefined - let contractType: ContractType | undefined if (tokenBalance) { contractType = tokenBalance.contractType @@ -122,9 +117,9 @@ export const SendCollectible = ({ chainId, contractAddress, tokenId }: SendColle const nativeTokenInfo = getNativeTokenInfoByChainId(chainId, chains) - const isPending = isPendingBalances + const isLoading = isLoadingBalances - if (isPending) { + if (isLoading) { return null } diff --git a/packages/wallet-widget/src/views/Send/SendGeneral.tsx b/packages/wallet-widget/src/views/Send/SendGeneral.tsx index d0afa9b36..35b26d9d4 100644 --- a/packages/wallet-widget/src/views/Send/SendGeneral.tsx +++ b/packages/wallet-widget/src/views/Send/SendGeneral.tsx @@ -1,11 +1,9 @@ import { useWallets } from '@0xsequence/connect' import { TabsHeader, TabsContent, TabsRoot } from '@0xsequence/design-system' -import { useGetTokenBalancesDetails, useGetTokenBalancesSummary } from '@0xsequence/hooks' -import { ContractVerificationStatus } from '@0xsequence/indexer' import { useState } from 'react' import { CollectiblesList, TokenList } from '../../components/SearchLists' -import { useSettings, useNavigation } from '../../hooks' +import { useSettings, useNavigation, useGetAllTokensDetails } from '../../hooks' import { TokenBalanceWithPrice } from '../../utils/tokens' export const SendGeneral = () => { @@ -16,22 +14,11 @@ export const SendGeneral = () => { const activeWallet = wallets.find(wallet => wallet.isActive) - const { data: tokenBalancesData = [], isPending: isPendingTokenBalances } = useGetTokenBalancesSummary({ + const { data: tokenBalancesData = [], isLoading: isLoadingTokenBalances } = useGetAllTokensDetails({ + accountAddresses: [activeWallet?.address || ''], chainIds: allNetworks, - filter: { - accountAddresses: [activeWallet?.address || ''], - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - omitNativeBalances: false - } - }) - - const { data: collectibleBalancesData = [], isPending: isPendingCollectibleBalances } = useGetTokenBalancesDetails({ - chainIds: allNetworks, - filter: { - accountAddresses: [activeWallet?.address || ''], - contractStatus: hideUnlistedTokens ? ContractVerificationStatus.VERIFIED : ContractVerificationStatus.ALL, - omitNativeBalances: false - } + contractWhitelist: [], + hideUnlistedTokens }) const handleTokenClick = (token: TokenBalanceWithPrice) => { @@ -72,15 +59,15 @@ export const SendGeneral = () => { { const { setNavigation } = useNavigation() diff --git a/packages/wallet-widget/src/views/Swap/CoinInput.tsx b/packages/wallet-widget/src/views/Swap/CoinInput.tsx index 0156940ab..8f7fee68d 100644 --- a/packages/wallet-widget/src/views/Swap/CoinInput.tsx +++ b/packages/wallet-widget/src/views/Swap/CoinInput.tsx @@ -2,8 +2,7 @@ import { Button, NumericInput, Text } from '@0xsequence/design-system' import { ChangeEvent, useEffect, useState } from 'react' import { formatUnits } from 'viem' -import { useSettings } from '../../hooks' -import { useSwap } from '../../hooks/useSwap' +import { useSettings, useSwap } from '../../hooks' import { formatFiatBalance, decimalsToWei } from '../../utils/formatBalance' export const CoinInput = ({ type, disabled }: { type: 'from' | 'to'; disabled?: boolean }) => { diff --git a/packages/wallet-widget/src/views/Swap/CoinSelect.tsx b/packages/wallet-widget/src/views/Swap/CoinSelect.tsx index 6f41a9e24..eb8efc313 100644 --- a/packages/wallet-widget/src/views/Swap/CoinSelect.tsx +++ b/packages/wallet-widget/src/views/Swap/CoinSelect.tsx @@ -5,8 +5,7 @@ import { useChains } from 'wagmi' import { CoinRow } from '../../components/SearchLists/TokenList/CoinRow' import { SlideupDrawer } from '../../components/Select/SlideupDrawer' -import { useSettings } from '../../hooks' -import { useSwap } from '../../hooks/useSwap' +import { useSettings, useSwap } from '../../hooks' import { TokenBalanceWithPrice } from '../../utils' import { formatTokenInfo } from '../../utils/formatBalance' diff --git a/packages/wallet-widget/src/views/Swap/Swap.tsx b/packages/wallet-widget/src/views/Swap/Swap.tsx index b8c1c99a5..aa12b905a 100644 --- a/packages/wallet-widget/src/views/Swap/Swap.tsx +++ b/packages/wallet-widget/src/views/Swap/Swap.tsx @@ -5,8 +5,7 @@ import { useAccount, useChainId } from 'wagmi' import { NetworkSelect } from '../../components/Select/NetworkSelect' import { HEADER_HEIGHT_WITH_LABEL } from '../../constants' -import { useSettings } from '../../hooks' -import { useSwap } from '../../hooks/useSwap' +import { useSettings, useSwap } from '../../hooks' import { CoinInput } from './CoinInput' import { CoinSelect } from './CoinSelect' @@ -40,7 +39,12 @@ export const Swap = () => { } }) - const coinBalances = tokenBalances?.filter(c => c.contractType !== 'ERC1155' && c.contractType !== 'ERC721') || [] + // TODO: add new Lifi endpoints to get buy token as well as supported networks GetLifiChains and GetLifiTokens + + const coinBalances = + tokenBalances?.pages + .flatMap(page => page.balances) + .filter(c => c.contractType !== 'ERC1155' && c.contractType !== 'ERC721') || [] const { data: coinPrices = [] } = useGetCoinPrices( coinBalances.map(token => ({ diff --git a/packages/wallet-widget/src/views/SwapCoin/SwapList.tsx b/packages/wallet-widget/src/views/SwapCoin/SwapList.tsx index 235e467f0..880752e5b 100644 --- a/packages/wallet-widget/src/views/SwapCoin/SwapList.tsx +++ b/packages/wallet-widget/src/views/SwapCoin/SwapList.tsx @@ -95,7 +95,7 @@ export const SwapList = ({ chainId, contractAddress, amount }: SwapListProps) => const quoteFetchInProgress = isLoadingSwapQuote - const isLoading = swapPricesIsLoading || isLoadingCurrencyInfo + const isLoading = swapPricesIsLoading || isLoadingCurrencyInfo || isLoadingSwapQuote const onClickProceed = async () => { if (!userAddress || !publicClient || !walletClient || !connector) { diff --git a/packages/wallet-widget/src/views/SwapCoin/index.tsx b/packages/wallet-widget/src/views/SwapCoin/index.tsx index 1bd89da4d..3bbc0b70f 100644 --- a/packages/wallet-widget/src/views/SwapCoin/index.tsx +++ b/packages/wallet-widget/src/views/SwapCoin/index.tsx @@ -1,7 +1,7 @@ import { compareAddress, getNativeTokenInfoByChainId } from '@0xsequence/connect' import { Button, ChevronRightIcon, Text, NumericInput } from '@0xsequence/design-system' -import { useGetTokenBalancesSummary, useGetCoinPrices, useGetExchangeRate } from '@0xsequence/hooks' -import { ContractVerificationStatus, TokenBalance } from '@0xsequence/indexer' +import { useGetCoinPrices, useGetExchangeRate, useGetSingleTokenBalance } from '@0xsequence/hooks' +import { TokenBalance } from '@0xsequence/indexer' import { useRef, useState, ChangeEvent } from 'react' import { parseUnits, zeroAddress } from 'viem' import { useAccount, useConfig } from 'wagmi' @@ -25,28 +25,23 @@ export const SwapCoin = ({ contractAddress, chainId }: SwapCoinProps) => { const { fiatCurrency } = useSettings() const [amount, setAmount] = useState('0') - const { data: balances = [], isPending: isPendingBalances } = useGetTokenBalancesSummary({ - chainIds: [chainId], - filter: { - accountAddresses: [accountAddress], - contractStatus: ContractVerificationStatus.ALL, - contractWhitelist: [contractAddress], - omitNativeBalances: false - } + const { data: tokenBalance, isLoading: isLoadingBalances } = useGetSingleTokenBalance({ + chainId, + contractAddress, + accountAddress: accountAddress || '' }) const nativeTokenInfo = getNativeTokenInfoByChainId(chainId, chains) - const tokenBalance = (balances as TokenBalance[]).find(b => b.contractAddress === contractAddress) - const { data: coinPrices = [], isPending: isPendingCoinPrices } = useGetCoinPrices([ + const { data: coinPrices = [], isLoading: isLoadingCoinPrices } = useGetCoinPrices([ { chainId, contractAddress } ]) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) - const isPending = isPendingBalances || isPendingCoinPrices || isPendingConversionRate + const isLoading = isLoadingBalances || isLoadingCoinPrices || isLoadingConversionRate const handleChangeAmount = (ev: ChangeEvent) => { const { value } = ev.target @@ -69,7 +64,7 @@ export const SwapCoin = ({ contractAddress, chainId }: SwapCoinProps) => { }) } - if (isPending) { + if (isLoading) { return null } diff --git a/packages/wallet-widget/src/views/TransactionDetails/index.tsx b/packages/wallet-widget/src/views/TransactionDetails/index.tsx index d36c0eafa..5e0498b41 100644 --- a/packages/wallet-widget/src/views/TransactionDetails/index.tsx +++ b/packages/wallet-widget/src/views/TransactionDetails/index.tsx @@ -62,16 +62,16 @@ export const TransactionDetails = ({ transaction }: TransactionDetailProps) => { } }) - const { data: coinPricesData, isPending: isPendingCoinPrices } = useGetCoinPrices(coins) + const { data: coinPricesData, isLoading: isLoadingCoinPrices } = useGetCoinPrices(coins) - const { data: collectiblePricesData, isPending: isPendingCollectiblePrices } = useGetCollectiblePrices(collectibles) + const { data: collectiblePricesData, isLoading: isLoadingCollectiblePrices } = useGetCollectiblePrices(collectibles) - const { data: conversionRate = 1, isPending: isPendingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) + const { data: conversionRate = 1, isLoading: isLoadingConversionRate } = useGetExchangeRate(fiatCurrency.symbol) const arePricesLoading = - (coins.length > 0 && isPendingCoinPrices) || - (collectibles.length > 0 && isPendingCollectiblePrices) || - isPendingConversionRate + (coins.length > 0 && isLoadingCoinPrices) || + (collectibles.length > 0 && isLoadingCollectiblePrices) || + isLoadingConversionRate const nativeTokenInfo = getNativeTokenInfoByChainId(transaction.chainId, chains)