@crypto-dex-sdk/parachains-amplitude
Version:
Zenlink Parachains Impl for Amplitude
119 lines (101 loc) • 3.84 kB
text/typescript
import type { ParachainId } from '@crypto-dex-sdk/chain'
import type { Token, Type } from '@crypto-dex-sdk/currency'
import type { QueryableStorageEntry } from '@polkadot/api/types'
import type { OrmlTokensAccountData } from '@zenlink-types/bifrost/interfaces'
import type { BalanceMap } from './types'
import { Amount } from '@crypto-dex-sdk/currency'
import { isZenlinkAddress } from '@crypto-dex-sdk/format'
import { JSBI } from '@crypto-dex-sdk/math'
import { useAccount, useApi, useCallMulti, useNativeBalancesAll } from '@crypto-dex-sdk/polkadot'
import { useMemo } from 'react'
import { addressToNodeCurrency, isNativeCurrency } from '../../libs'
interface UseBalancesParams {
account: string | undefined
currencies: (Type | undefined)[]
chainId?: ParachainId
enabled?: boolean
}
type UseBalances = (params: UseBalancesParams) => {
data: BalanceMap
isLoading: boolean
isError: boolean
}
export const useBalances: UseBalances = ({
chainId,
account,
currencies,
enabled = true,
}) => {
const api = useApi(chainId)
const { isAccount } = useAccount()
const nativeBalancesAll = useNativeBalancesAll(chainId, account, enabled)
const validatedTokens = useMemo(
() =>
currencies.filter(
(currency): currency is Token => {
return !!chainId && !!currency && isZenlinkAddress(currency.wrapped.address)
},
),
[chainId, currencies],
)
const balances = useCallMulti<OrmlTokensAccountData[]>({
chainId,
calls: (api && isAccount(account))
? validatedTokens
.map(currency => [api.query.tokens.accounts, [account, addressToNodeCurrency(currency.wrapped.address)]])
.filter((call): call is [QueryableStorageEntry<'promise'>, [string, any]] => Boolean(call[0]))
: [],
options: { enabled: enabled && Boolean(api && isAccount(account)) },
})
const balanceMap: BalanceMap = useMemo(() => {
const result: BalanceMap = {}
if (balances.length !== validatedTokens.length)
return result
for (let i = 0; i < validatedTokens.length; i++) {
const value = balances[i]?.free.toString()
const amount = value ? JSBI.BigInt(value.toString()) : undefined
if (!result[validatedTokens[i].address])
result[validatedTokens[i].address] = Amount.fromRawAmount(validatedTokens[i], '0')
if (amount)
result[validatedTokens[i].address] = Amount.fromRawAmount(validatedTokens[i], amount)
else
result[validatedTokens[i].address] = Amount.fromRawAmount(validatedTokens[i], '0')
if (isNativeCurrency(validatedTokens[i]))
result[validatedTokens[i].wrapped.address] = Amount.fromRawAmount(validatedTokens[i], nativeBalancesAll?.availableBalance.toString() || '0')
}
return result
}, [balances, nativeBalancesAll?.availableBalance, validatedTokens])
return useMemo(() => ({
data: balanceMap,
isLoading: isAccount(account) && (!nativeBalancesAll || !balances.length),
isError: !isAccount(account),
}), [balanceMap, isAccount, account, nativeBalancesAll, balances.length])
}
interface UseBalanceParams {
account: string | undefined
currency: Type | undefined
chainId?: ParachainId
enabled?: boolean
}
type UseBalance = (params: UseBalanceParams) => Pick<ReturnType<typeof useBalances>, 'isError' | 'isLoading'> & {
data: Amount<Type> | undefined
}
export const useBalance: UseBalance = ({
chainId,
account,
currency,
enabled,
}) => {
const currencies = useMemo(() => [currency], [currency])
const { data, isLoading, isError } = useBalances({ chainId, currencies, account, enabled })
return useMemo(() => {
const balance = currency
? data?.[currency.wrapped.address]
: undefined
return {
isError,
isLoading,
data: balance,
}
}, [isError, isLoading, currency, data])
}