UNPKG

@ledgerhq/coin-hedera

Version:
99 lines (87 loc) 3.56 kB
import type { Balance } from "@ledgerhq/coin-module-framework/api/types"; import { getCryptoAssetsStore } from "@ledgerhq/cryptoassets/state"; import { LedgerAPI4xx } from "@ledgerhq/errors"; import { promiseAllBatched } from "@ledgerhq/live-promise"; import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets"; import BigNumber from "bignumber.js"; import hederaCoinConfig from "../config"; import { HederaAddAccountError } from "../errors"; import { apiClient } from "../network/api"; import { getERC20BalancesForAccountV2 } from "../network/utils"; export async function getBalance(currency: CryptoCurrency, address: string): Promise<Balance[]> { try { const coinConfig = hederaCoinConfig.getCoinConfig(currency.id); // Fetch only the specific staked node (or nothing at all for non-staking // accounts) instead of paginating the full /network/nodes list. The // validator lookup is chained on the account promise so it still runs // concurrently with the token fetches. const mirrorAccountPromise = apiClient.getAccount(address); const validatorPromise = mirrorAccountPromise.then(account => typeof account.staked_node_id === "number" && account.staked_node_id >= 0 ? apiClient.getNode(account.staked_node_id) : null, ); const [mirrorAccount, mirrorTokens, erc20TokenBalances, validator] = await Promise.all([ mirrorAccountPromise, apiClient.getAccountTokens(address), coinConfig.useHgraphForErc20 ? getERC20BalancesForAccountV2(address) : Promise.resolve([]), validatorPromise, ]); const mixedTokens = [...mirrorTokens, ...erc20TokenBalances]; const nativeBalance: Balance = { asset: { type: "native" }, value: BigInt(mirrorAccount.balance.balance), ...(validator && { stake: { uid: address, address, asset: { type: "native" }, state: "active", amount: BigInt(mirrorAccount.balance.balance) + BigInt(mirrorAccount.pending_reward), amountDeposited: BigInt(mirrorAccount.balance.balance), amountRewarded: BigInt(mirrorAccount.pending_reward), delegate: validator.node_account_id, details: { overstaked: BigInt(validator.stake) >= BigInt(validator.max_stake), }, }, }), }; const tokenBalances = await promiseAllBatched( 3, mixedTokens, async (item): Promise<Balance | null> => { const tokenAddress = "token_id" in item ? item.token_id : item.token.contractAddress; const calToken = await getCryptoAssetsStore().findTokenByAddressInCurrency( tokenAddress, currency.id, ); if (!calToken || !calToken.units.length) { return null; } const roundedValue = new BigNumber(item.balance).toFixed(0); return { value: BigInt(roundedValue), asset: { type: calToken.tokenType, assetReference: calToken.contractAddress, assetOwner: address, name: calToken.name, unit: calToken.units[0], }, }; }, ); const balances: Balance[] = [nativeBalance, ...tokenBalances].filter( (balance): balance is Balance => balance !== null, ); return balances; } catch (err) { const isNonExistentAccount = err instanceof HederaAddAccountError || (err instanceof LedgerAPI4xx && err.status === 404); if (isNonExistentAccount) { return []; } throw err; } }