Skip to content

Commit

Permalink
Merge pull request #231 from CityOfZion/CU-86a5a7rcf
Browse files Browse the repository at this point in the history
CU-86a5a7rcf-NEON3 - BUG - Values are not calculating by selected coin
  • Loading branch information
thiagocbalducci authored Oct 22, 2024
2 parents 662f62b + 9c9bbf1 commit 716b6c1
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 123 deletions.
78 changes: 33 additions & 45 deletions src/renderer/src/hooks/useBalances.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ExchangeHelper } from '@renderer/helpers/ExchangeHelper'
import { NumberHelper } from '@renderer/helpers/NumberHelper'
import { useCurrencyRatio } from '@renderer/hooks/useCurrencyRatio'
import { bsAggregator } from '@renderer/libs/blockchainService'
import { TBlockchainServiceKey, TNetwork } from '@shared/@types/blockchain'
import {
Expand All @@ -9,48 +10,33 @@ import {
TUseBalancesParams,
TUseBalancesResult,
} from '@shared/@types/query'
import { Query, QueryClient, useQueries, useQuery, useQueryClient } from '@tanstack/react-query'
import { TCurrency } from '@shared/@types/store'
import { QueryClient, useQueries, useQuery, useQueryClient } from '@tanstack/react-query'

import { useCurrencyRatio } from './useCurrencyRatio'
import { fetchExchange } from './useExchange'
import { useSelectedNetworkByBlockchainSelector } from './useSettingsSelector'

export function verifyIfQueryIsBalance(
query: Query,
addressCompare: string[],
blockchainCompare: TBlockchainServiceKey[],
networkIdCompare: string[]
): boolean {
const queryKey = query.queryKey as [string, string, TBlockchainServiceKey, string]

return (
queryKey[0] === 'balance' &&
addressCompare.includes(queryKey[1]) &&
blockchainCompare.includes(queryKey[2]) &&
networkIdCompare.includes(queryKey[3])
)
}
import { useCurrencySelector, useSelectedNetworkByBlockchainSelector } from './useSettingsSelector'

export function buildQueryKeyBalance(
address: string,
blockchain: TBlockchainServiceKey,
network: TNetwork<TBlockchainServiceKey>
): string[] {
return ['balance', address, blockchain, network.id]
network: TNetwork<TBlockchainServiceKey>,
currency: TCurrency
) {
return ['balance', address, blockchain, network.id, currency]
}

const fetchBalance = async (
param: TUseBalancesParams,
network: TNetwork<TBlockchainServiceKey>,
queryClient: QueryClient,
currency: TCurrency,
currencyRatio: number
): Promise<TBalance> => {
try {
const service = bsAggregator.blockchainServicesByName[param.blockchain]
const balance = await service.blockchainDataService.getBalance(param.address)

const tokens = balance.map(balance => balance.token)
const exchange = await fetchExchange(param.blockchain, tokens, network, queryClient, currencyRatio)
const exchange = await fetchExchange(param.blockchain, tokens, network, queryClient, currency, currencyRatio)

const tokensBalances: TTokenBalance[] = []
let exchangeTotal = 0
Expand All @@ -62,6 +48,7 @@ const fetchBalance = async (
param.blockchain,
exchange
)

const amountNumber = NumberHelper.number(balance.amount)
const exchangeAmount = amountNumber * exchangeConvertedPrice

Expand Down Expand Up @@ -94,46 +81,47 @@ const fetchBalance = async (
export function useBalances(params: TUseBalancesParams[]): TUseBalancesResult {
const { networkByBlockchain } = useSelectedNetworkByBlockchainSelector()
const queryClient = useQueryClient()
const currencyRatioQuery = useCurrencyRatio()
const { isLoading: isCurrencyRatioLoading, data: currencyRatio } = useCurrencyRatio()
const { currency } = useCurrencySelector()

const balanceQueries = useQueries({
queries: currencyRatioQuery
? params.map(param => ({
queryKey: buildQueryKeyBalance(param.address, param.blockchain, networkByBlockchain[param.blockchain]),
queryFn: fetchBalance.bind(
null,
param,
networkByBlockchain[param.blockchain],
queryClient,
currencyRatioQuery.data ?? 1
),
}))
: [],
return useQueries({
queries: params.map(param => ({
queryKey: buildQueryKeyBalance(param.address, param.blockchain, networkByBlockchain[param.blockchain], currency),
queryFn: fetchBalance.bind(
null,
param,
networkByBlockchain[param.blockchain],
queryClient,
currency,
currencyRatio
),
enabled: !isCurrencyRatioLoading && typeof currencyRatio === 'number',
})),
combine: results => ({
data: results.map(result => result.data).filter((balance): balance is TBalance => !!balance),
isLoading: currencyRatioQuery.isLoading || results.some(result => result.isLoading),
isLoading: isCurrencyRatioLoading || results.some(result => result.isLoading),
exchangeTotal: results.reduce((acc, result) => acc + (result.data?.exchangeTotal ?? 0), 0),
}),
})

return balanceQueries
}

export function useBalance(balanceParams: TUseBalancesParams | undefined): TUseBalanceResult {
const { networkByBlockchain } = useSelectedNetworkByBlockchainSelector()
const queryClient = useQueryClient()
const currencyRatioQuery = useCurrencyRatio()
const { currency } = useCurrencySelector()
const { isLoading: isCurrencyRatioLoading, data: currencyRatio } = useCurrencyRatio()
const params = balanceParams ?? { address: '', blockchain: 'neo3' }

return useQuery({
queryKey: buildQueryKeyBalance(params.address, params.blockchain, networkByBlockchain[params.blockchain]),
queryKey: buildQueryKeyBalance(params.address, params.blockchain, networkByBlockchain[params.blockchain], currency),
queryFn: fetchBalance.bind(
null,
params,
networkByBlockchain[params.blockchain],
queryClient,
currencyRatioQuery.data ?? 1
currency,
currencyRatio
),
enabled: !!balanceParams && !!currencyRatioQuery?.data,
enabled: !!balanceParams && !isCurrencyRatioLoading && typeof currencyRatio === 'number',
})
}
39 changes: 18 additions & 21 deletions src/renderer/src/hooks/useCurrencyRatio.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
import { useCurrencySelector } from '@renderer/hooks/useSettingsSelector'
import { bsAggregator } from '@renderer/libs/blockchainService'
import { TBlockchainServiceKey } from '@shared/@types/blockchain'
import { TBaseOptions, TUseCurrencyRatioResult } from '@shared/@types/query'
import { TUseCurrencyRatioResult } from '@shared/@types/query'
import { TCurrency } from '@shared/@types/store'
import { useQuery } from '@tanstack/react-query'

import { useCurrencySelector, useSelectedNetworkSelector } from './useSettingsSelector'

// There is no need to get ratio from multiple blockchains
// There is no need to fetch currency ratio from multiple blockchains
const blockchain: TBlockchainServiceKey = 'neo3'

const fetchRatio = async (currency: TCurrency): Promise<number> => {
const fetchCurrencyRatio = async (currency: TCurrency): Promise<number> => {
let currencyRatio = 1

try {
if (currency.label === 'USD') {
return 1
}
if (currency.label !== 'USD') {
const service = bsAggregator.blockchainServicesByName[blockchain]

const service = bsAggregator.blockchainServicesByName[blockchain]
const ratio = await service.exchangeDataService.getCurrencyRatio(currency.label)
return ratio
} catch {
return 1
currencyRatio = await service.exchangeDataService.getCurrencyRatio(currency.label)
}
} catch (error) {
console.error(error)
}

return currencyRatio
}

export function useCurrencyRatio(queryOptions?: TBaseOptions<number>): TUseCurrencyRatioResult {
const { network } = useSelectedNetworkSelector(blockchain)
export function useCurrencyRatio(): TUseCurrencyRatioResult {
const { currency } = useCurrencySelector()

const query = useQuery({
queryKey: ['currency-ratio', currency, network.id],
queryFn: fetchRatio.bind(null, currency),
...queryOptions,
return useQuery({
queryKey: ['currency-ratio', currency],
queryFn: fetchCurrencyRatio.bind(null, currency),
})

return query
}
87 changes: 48 additions & 39 deletions src/renderer/src/hooks/useExchange.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,49 @@
import { useMemo } from 'react'
import { Token, TokenPricesResponse } from '@cityofzion/blockchain-service'
import { UtilsHelper } from '@renderer/helpers/UtilsHelper'
import { useCurrencyRatio } from '@renderer/hooks/useCurrencyRatio'
import { bsAggregator } from '@renderer/libs/blockchainService'
import { TBlockchainServiceKey, TNetwork } from '@shared/@types/blockchain'
import { TExchange, TMultiExchange, TUseExchangeParams, TUseExchangeResult } from '@shared/@types/query'
import { TCurrency } from '@shared/@types/store'
import { Query, QueryClient, useQueries, useQueryClient } from '@tanstack/react-query'
import lodash from 'lodash'

import { useCurrencyRatio } from './useCurrencyRatio'
import { useSelectedNetworkByBlockchainSelector } from './useSettingsSelector'
import { useCurrencySelector, useSelectedNetworkByBlockchainSelector } from './useSettingsSelector'

function buildQueryKey(blockchain: TBlockchainServiceKey, network: TNetwork<TBlockchainServiceKey>, token: Token) {
return ['exchange', blockchain, network.id, UtilsHelper.normalizeHash(token.hash)]
function buildQueryKey(
blockchain: TBlockchainServiceKey,
network: TNetwork<TBlockchainServiceKey>,
currency: TCurrency,
token?: Token
) {
const queryKey = ['exchange', blockchain, network.id, currency]

if (token) queryKey.push(UtilsHelper.normalizeHash(token.hash))

return queryKey
}

function buildExchangeByBlockchainQueryKey(
blockchain: TBlockchainServiceKey,
network: TNetwork<TBlockchainServiceKey>
network: TNetwork<TBlockchainServiceKey>,
currency: TCurrency
) {
return ['exchange-by-blockchain', blockchain, network.id]
return ['exchange-by-blockchain', blockchain, network.id, currency]
}

export async function fetchExchange(
blockchain: TBlockchainServiceKey,
tokens: Token[],
network: TNetwork<TBlockchainServiceKey>,
queryClient: QueryClient,
currency: TCurrency,
currencyRatio: number
) {
const queryCache = queryClient.getQueryCache()

const tokensToFetch = tokens.filter(token => {
const queryKey = buildQueryKey(blockchain, network, token)

const queryKey = buildQueryKey(blockchain, network, currency, token)
const query = queryCache.find({ queryKey, exact: true, stale: false }) as Query<TExchange> | undefined

return !query
Expand All @@ -43,6 +54,7 @@ export async function fetchExchange(
if (tokensToFetch.length > 0) {
try {
const service = bsAggregator.blockchainServicesByName[blockchain]

tokenPrices = await service.exchangeDataService.getTokenPrices({ tokens: tokensToFetch })
} catch {
/* empty */
Expand All @@ -51,7 +63,6 @@ export async function fetchExchange(

tokensToFetch.forEach(token => {
const normalizedHash = UtilsHelper.normalizeHash(token.hash)

const tokenPrice = tokenPrices.find(price => UtilsHelper.normalizeHash(price.token.hash) === normalizedHash)

const queryData: TExchange = {
Expand All @@ -60,28 +71,30 @@ export async function fetchExchange(
convertedPrice: (tokenPrice?.usdPrice ?? 0) * currencyRatio,
}

const queryKey = buildQueryKey(blockchain, network, token)
const queryKey = buildQueryKey(blockchain, network, currency, token)
const defaultedOptions = queryClient.defaultQueryOptions({ queryKey })

queryCache.build(queryClient, defaultedOptions).setData(queryData, { manual: true })
})

const allQueries = queryCache.findAll({
queryKey: ['exchange', blockchain, network.id],
queryKey: buildQueryKey(blockchain, network, currency),
}) as Query<TExchange>[]

const result = {
[blockchain]: new Map(allQueries.map(query => [query.queryKey[3] as string, query.state.data])),
return {
[blockchain]: new Map(
allQueries.map(({ state, queryKey: [_key, _blockchain, _networkId, _currency, token] }) => [token, state.data])
),
}

return result
}

const emptyObject = {}

export function useExchange(params: TUseExchangeParams[]): TUseExchangeResult {
const { networkByBlockchain } = useSelectedNetworkByBlockchainSelector()
const queryClient = useQueryClient()
const { currency } = useCurrencySelector()
const { isLoading: isCurrencyRatioLoading, data: currencyRatio } = useCurrencyRatio()

const tokensToFetchByBlockchain = useMemo(() => {
if (params.length === 0) return
Expand All @@ -101,32 +114,28 @@ export function useExchange(params: TUseExchangeParams[]): TUseExchangeResult {
)
}, [params])

const currencyRatioQuery = useCurrencyRatio()

const query = useQueries({
queries:
tokensToFetchByBlockchain && !currencyRatioQuery.isLoading
? Object.entries(tokensToFetchByBlockchain).map(([blockchain, tokens]) => ({
queryKey: buildExchangeByBlockchainQueryKey(
blockchain as TBlockchainServiceKey,
networkByBlockchain[blockchain]
),
queryFn: fetchExchange.bind(
null,
blockchain as TBlockchainServiceKey,
tokens,
networkByBlockchain[blockchain],
queryClient,
currencyRatioQuery.data ?? 1
),
staleTime: 0,
}))
: [],
return useQueries({
queries: Object.entries(tokensToFetchByBlockchain ?? {}).map(([blockchain, tokens]) => ({
queryKey: buildExchangeByBlockchainQueryKey(
blockchain as TBlockchainServiceKey,
networkByBlockchain[blockchain],
currency
),
queryFn: fetchExchange.bind(
null,
blockchain as TBlockchainServiceKey,
tokens,
networkByBlockchain[blockchain],
queryClient,
currency,
currencyRatio
),
staleTime: 0,
enabled: !isCurrencyRatioLoading && typeof currencyRatio === 'number',
})),
combine: result => ({
isLoading: result.some(query => query.isLoading),
isLoading: isCurrencyRatioLoading || result.some(query => query.isLoading),
data: lodash.assign(emptyObject, ...result.map(query => query.data ?? {})) as TMultiExchange,
}),
})

return query
}
Loading

0 comments on commit 716b6c1

Please sign in to comment.