From 6a0670b8ec20de294dc38067cfcdce886267197e Mon Sep 17 00:00:00 2001 From: martinkaintas Date: Thu, 7 Mar 2024 15:02:27 +0200 Subject: [PATCH] feat: extract custom tokens from token balances --- src/composables/fungibleTokens.ts | 48 +++++++++++++++++-- .../ethereum/libs/EthplorerService.ts | 9 +++- src/types/index.ts | 3 ++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/composables/fungibleTokens.ts b/src/composables/fungibleTokens.ts index 277a9b690..ce2064805 100644 --- a/src/composables/fungibleTokens.ts +++ b/src/composables/fungibleTokens.ts @@ -1,6 +1,6 @@ /* eslint-disable no-param-reassign */ -import { watch } from 'vue'; +import { computed, watch } from 'vue'; import BigNumber from 'bignumber.js'; import { Encoding } from '@aeternity/aepp-sdk'; import { toShiftedBigNumber } from '@/utils'; @@ -22,6 +22,7 @@ import { ProtocolAdapterFactory } from '@/lib/ProtocolAdapterFactory'; import FungibleTokenFullInterfaceACI from '@/protocols/aeternity/aci/FungibleTokenFullInterfaceACI.json'; import { aettosToAe, categorizeContractCallTxObject } from '@/protocols/aeternity/helpers'; +import { uniqBy } from 'lodash-es'; import { useAccounts } from './accounts'; import { useAeSdk } from './aeSdk'; import { useTippingContracts } from './tippingContracts'; @@ -33,9 +34,10 @@ let composableInitialized = false; /** * List of all fungible tokens available on user's protocols. + * Does not include custom tokens extracted from user's token balances. * As this list is quite big (hundreds of items) it requires processing optimizations. */ -const tokensAvailable = useStorageRef>( +const defaultTokensAvailable = useStorageRef>( {}, STORAGE_KEYS.fungibleTokenList, ); @@ -48,6 +50,41 @@ const tokenBalances = useStorageRef( STORAGE_KEYS.fungibleTokenBalances, ); +/** + * List of all fungible tokens available on user's protocols. + * Includes tokens from the user's account that are not on the main list. + */ +const tokensAvailable = computed((): ProtocolRecord => { + const uniqueTokens: IToken[] = uniqBy(tokenBalances.value, 'contractId') + .map((tokenBalance) => ({ + contractId: tokenBalance.contractId, + protocol: tokenBalance.protocol, + name: tokenBalance?.name!, + symbol: tokenBalance?.symbol!, + })); + + const customTokensAvailable = uniqueTokens.reduce((customTokens, token) => { + const { contractId, protocol } = token; + if (!customTokens[protocol]) { + customTokens[protocol] = {} as AssetList; + } + if (!defaultTokensAvailable?.value?.[protocol]?.[contractId]) { + customTokens[protocol]![contractId] = token; + } + return customTokens; + }, {} as typeof tokensAvailable.value); + + return Object.values(PROTOCOLS).reduce( + (allTokens, protocol) => { + allTokens[protocol] = { + ...defaultTokensAvailable.value[protocol], + ...customTokensAvailable[protocol], + }; + return allTokens; + }, {} as typeof defaultTokensAvailable.value, + ); +}); + function getProtocolAvailableTokens(protocol: Protocol): AssetList { return tokensAvailable.value[protocol] || {} as AssetList; } @@ -92,7 +129,7 @@ export function useFungibleTokens() { const tokens: IToken[] = (await Promise.all(tokensFetchPromises)).map( (protocolTokens, index) => ( protocolTokens - || Object.values(tokensAvailable.value[protocolsInUse.value[index]] || {}) + || Object.values(defaultTokensAvailable.value[protocolsInUse.value[index]] || {}) ), ).flat(); @@ -102,14 +139,14 @@ export function useFungibleTokens() { return; } - tokensAvailable.value = tokens.reduce((accumulator, token) => { + defaultTokensAvailable.value = tokens.reduce((accumulator, token) => { const { contractId, protocol } = token; if (!accumulator[protocol]) { accumulator[protocol] = {} as AssetList; } accumulator[protocol]![contractId] = token; return accumulator; - }, {} as typeof tokensAvailable.value); + }, {} as typeof defaultTokensAvailable.value); } async function loadTokenBalances() { @@ -147,6 +184,7 @@ export function useFungibleTokens() { async ([address, promise]) => await promise || cachedTokenBalancesByAddress[address] || [], ), )).flat(); + areTokenBalancesUpdating = false; } diff --git a/src/protocols/ethereum/libs/EthplorerService.ts b/src/protocols/ethereum/libs/EthplorerService.ts index 61d67089c..fe9284005 100644 --- a/src/protocols/ethereum/libs/EthplorerService.ts +++ b/src/protocols/ethereum/libs/EthplorerService.ts @@ -84,13 +84,20 @@ export class EthplorerService { return tokens.map(({ rawBalance, - tokenInfo: { address: contractId, decimals }, + tokenInfo: { + address: contractId, + decimals, + name, + symbol, + }, }: any): ITokenBalance => ({ address, amount: rawBalance, contractId: toEthChecksumAddress(contractId), convertedBalance: +toShiftedBigNumber(rawBalance, -decimals).toFixed(2), decimals, + symbol, + name, protocol: PROTOCOLS.ethereum, })) || []; } diff --git a/src/types/index.ts b/src/types/index.ts index ed9ab4be0..1444153f3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -173,6 +173,9 @@ export interface ITokenBalance { /** Amount of the token that is owned */ convertedBalance?: number; protocol: Protocol; + // Allow setting symbol and name so that we can extract custom tokens from balance data + symbol?: string; + name?: string; } /**