From 0ba5be6935f47ad9aa6dc279b10bba10c555979a Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Mon, 29 Apr 2024 17:48:19 +0100 Subject: [PATCH 01/11] fix: do not update persisted rpc endpoint recursively (#2389) * fix: do not update persisted rpc endpoint recursively * fix: remove problem line --- .../shared/src/lib/core/network/classes/isc-chain.class.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index b2a2c18fee..7774f8fa0e 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -14,8 +14,7 @@ export class IscChain extends BaseEvmNetwork { try { const { rpcEndpoint, aliasAddress, apiEndpoint } = chainConfiguration const _rpcEndpoint = `${rpcEndpoint}/v1/chains/${aliasAddress}/evm` - chainConfiguration.rpcEndpoint = _rpcEndpoint - super(chainConfiguration) + super({ ...chainConfiguration, rpcEndpoint: _rpcEndpoint }) this.aliasAddress = aliasAddress this.apiEndpoint = apiEndpoint From a5681bc65e2501897798ba6a5d5c6471205b5af0 Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Mon, 29 Apr 2024 19:04:37 +0200 Subject: [PATCH 02/11] fix: remove duplicated ownership check (#2393) * filter for network on ownership check * disable feature flag --- packages/desktop/features/network.features.ts | 2 +- .../src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts | 2 +- .../src/lib/core/nfts/actions/updateErc721NftOwnership.ts | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/desktop/features/network.features.ts b/packages/desktop/features/network.features.ts index 7cf79283c1..2d49c92cb9 100644 --- a/packages/desktop/features/network.features.ts +++ b/packages/desktop/features/network.features.ts @@ -12,7 +12,7 @@ const networkFeatures: INetworkFeatures = { }, }, evmNetworks: { - enabled: true, + enabled: false, }, } diff --git a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts index a0102ef16b..758584959b 100644 --- a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts @@ -23,7 +23,7 @@ export function fetchL2BalanceForAccount(profileId: string, account: IAccountSta } if (features.collectibles.erc721.enabled) { - void updateErc721NftsOwnership(account) + void updateErc721NftsOwnership(account, evmNetwork.id) } const l2TokenBalance = isIscChain(evmNetwork) diff --git a/packages/shared/src/lib/core/nfts/actions/updateErc721NftOwnership.ts b/packages/shared/src/lib/core/nfts/actions/updateErc721NftOwnership.ts index cee6632566..b3c65cd83c 100644 --- a/packages/shared/src/lib/core/nfts/actions/updateErc721NftOwnership.ts +++ b/packages/shared/src/lib/core/nfts/actions/updateErc721NftOwnership.ts @@ -5,12 +5,13 @@ import { IErc721Nft } from '../interfaces' import { getAllAccountNfts, persistedNftForActiveProfile, updatePersistedNft } from '../stores' import { getOwnerOfErc721Nft } from '../utils' import { get } from 'svelte/store' +import { NetworkId } from '@core/network' -export async function updateErc721NftsOwnership(account: IAccountState): Promise { +export async function updateErc721NftsOwnership(account: IAccountState, networkId: NetworkId): Promise { try { const trackedErc721Nfts = (getAllAccountNfts()[account.index]?.filter((nft) => { - return nft.standard === NftStandard.Erc721 + return nft.standard === NftStandard.Erc721 && nft.networkId === networkId }) as IErc721Nft[]) ?? [] const promises = trackedErc721Nfts.map(async (nft) => { const updatedOwner = await getOwnerOfErc721Nft(nft) From 9711f05ceb5339360e9ad523b8d70700710341e4 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Mon, 29 Apr 2024 15:20:54 -0300 Subject: [PATCH 03/11] feat: adds collection data in CollectionsGalleryView (#2391) * feat: adds collection data in CollectionsGalleryView * enhancement: getCollectionFromNft * chore: remove unnnecessary console errors * fix: not visible collections --- .../views/CollectionsGalleryView.svelte | 42 +++++++------- .../nfts/interfaces/collection.interface.ts | 10 ++++ .../src/lib/core/nfts/interfaces/index.ts | 1 + .../lib/core/nfts/interfaces/nft.interface.ts | 3 +- .../shared/src/lib/core/nfts/stores/index.ts | 1 + .../selected-account-collections.store.ts | 58 +++++++++++++++++++ .../lib/core/nfts/types/collections.type.ts | 3 + .../shared/src/lib/core/nfts/types/index.ts | 1 + .../core/nfts/utils/getCollectionFromNft.ts | 42 ++++++++++++++ .../shared/src/lib/core/nfts/utils/index.ts | 10 ++-- .../core/nfts/utils/isVisibleCollection.ts | 20 +++++++ 11 files changed, 164 insertions(+), 27 deletions(-) create mode 100644 packages/shared/src/lib/core/nfts/interfaces/collection.interface.ts create mode 100644 packages/shared/src/lib/core/nfts/stores/selected-account-collections.store.ts create mode 100644 packages/shared/src/lib/core/nfts/types/collections.type.ts create mode 100644 packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts create mode 100644 packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts diff --git a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte index e95024b661..28f84f689d 100644 --- a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte +++ b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte @@ -1,13 +1,13 @@ @@ -35,23 +33,25 @@
{localize('views.collectibles.collectionsGallery.title')} - {String(queriedCollections.length ?? '')} + {String(Object.keys($selectedAccountCollections).length ?? '')}
- {#if collections.length} - - + {#if hasCollections} + {/if} {#if features.collectibles.erc721.enabled} {/if}
- {#if collections.length} - {#if queriedCollections.length} + {#if hasCollections} + {#if Object.keys(queriedCollections).length > 0} + {#each Object.keys(queriedCollections) as collection} + {queriedCollections[collection].name} + {/each} {:else}
= writable({}) + +async function updateCollections(nfts: Nft[]): Promise { + const existingCollections = get(collectionsStore) + + if (nfts.length === 0) { + if (Object.keys(existingCollections).length > 0) { + collectionsStore.set({}) + } + return + } + + const collectionsUpdate = { ...existingCollections } + + await Promise.all( + nfts.map(async (nft) => { + if (nft.standard !== NftStandard.Irc27 || !nft.issuer) { + return + } + + const issuerId = nft.issuer.aliasId ?? nft.issuer.nftId + if (!issuerId) { + return + } + + if (!collectionsUpdate[issuerId]) { + const collection = await getCollectionFromNft(nft) + if (collection) { + collectionsUpdate[issuerId] = { ...collection, nfts: [nft] } + } + } else { + const existingNfts = collectionsUpdate[issuerId].nfts + if (!existingNfts.find((existingNft) => existingNft.id === nft.id)) { + collectionsUpdate[issuerId].nfts.push(nft) + } + } + }) + ) + collectionsStore.set(collectionsUpdate) +} + +selectedAccountNfts.subscribe((nfts) => { + void updateCollections(nfts) +}) + +export const selectedAccountCollections: Readable = derived( + collectionsStore, + ($collectionsStore) => $collectionsStore +) + +export const collectionsSearchTerm: Writable = writable('') diff --git a/packages/shared/src/lib/core/nfts/types/collections.type.ts b/packages/shared/src/lib/core/nfts/types/collections.type.ts new file mode 100644 index 0000000000..32dae6f7df --- /dev/null +++ b/packages/shared/src/lib/core/nfts/types/collections.type.ts @@ -0,0 +1,3 @@ +import { Collection } from '../interfaces' + +export type Collections = { [key: string]: Collection } diff --git a/packages/shared/src/lib/core/nfts/types/index.ts b/packages/shared/src/lib/core/nfts/types/index.ts index 3d34a70382..77e3cbecb6 100644 --- a/packages/shared/src/lib/core/nfts/types/index.ts +++ b/packages/shared/src/lib/core/nfts/types/index.ts @@ -1,2 +1,3 @@ +export * from './collections.type' export * from './nft-download-options.type' export * from './persisted-nft.type' diff --git a/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts b/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts new file mode 100644 index 0000000000..232f4d632e --- /dev/null +++ b/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts @@ -0,0 +1,42 @@ +import { NftStandard } from '../enums' +import { Collection, Nft } from '../interfaces' +import { Converter } from '@core/utils' +import { getClient } from '@core/profile-manager' +import type { AliasOutput, MetadataFeature, NftOutput } from '@iota/sdk' +import { FeatureType } from '@iota/sdk/out/types' + +export async function getCollectionFromNft(nft: Nft): Promise { + if (nft.standard !== NftStandard.Irc27) { + return + } + + const { aliasId = '', nftId = '' } = nft.issuer ?? {} + if (!aliasId && !nftId) { + return + } + + try { + const client = await getClient() + const outputId = aliasId ? await client.aliasOutputId(aliasId) : await client.nftOutputId(nftId) + if (!outputId) { + return + } + + const outputResponse = await client.getOutput(outputId) + const output = outputResponse.output as AliasOutput | NftOutput + + const metadataFeature = output.immutableFeatures?.find( + (feature) => feature.type === FeatureType.Metadata + ) as MetadataFeature + + if (!metadataFeature?.data) { + return + } + + const { standard, name, type, uri } = JSON.parse(Converter.hexToUtf8(metadataFeature.data)) + + return { standard, name, type, uri, nfts: [] } + } catch (error) { + console.error('Error retrieving collection from NFT:', error) + } +} diff --git a/packages/shared/src/lib/core/nfts/utils/index.ts b/packages/shared/src/lib/core/nfts/utils/index.ts index 93e479f6d5..f8305f6b34 100644 --- a/packages/shared/src/lib/core/nfts/utils/index.ts +++ b/packages/shared/src/lib/core/nfts/utils/index.ts @@ -1,17 +1,19 @@ export * from './buildNftFromPersistedErc721Nft' +export * from './buildPersistedErc721Nft' export * from './checkIfNftShouldBeDownloaded' +export * from './fetchWithTimeout' +export * from './getCollectionFromNft' +export * from './getFetchableNftUrls' export * from './getFilePathForNft' export * from './getNftsFromNftIds' export * from './getOwnerOfErc721Nft' -export * from './buildPersistedErc721Nft' -export * from './getFetchableNftUrls' export * from './getPrimaryNftUrl' export * from './getSpendableStatusFromUnspentNftOutput' -export * from './fetchWithTimeout' export * from './isIrc27Nft' -export * from './isNftOwnedByAnyAccount' export * from './isNftLocked' +export * from './isNftOwnedByAnyAccount' export * from './isScamIrc27Nft' export * from './isValidNftUri' +export * from './isVisibleCollection' export * from './isVisibleNft' export * from './parseNftMetadata' diff --git a/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts b/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts new file mode 100644 index 0000000000..6c367e4cbd --- /dev/null +++ b/packages/shared/src/lib/core/nfts/utils/isVisibleCollection.ts @@ -0,0 +1,20 @@ +import { get } from 'svelte/store' +import { collectionsSearchTerm } from '../stores' +import { Collection } from '../interfaces' + +export function isVisibleCollection(collection: Collection): boolean { + const searchTerm = get(collectionsSearchTerm) + + if (!isVisibleWithSearchTerm(collection, searchTerm)) { + return false + } + + return true +} + +function isVisibleWithSearchTerm(collection: Collection, searchTerm: string): boolean { + if (searchTerm) { + return collection.name.toLowerCase().includes(searchTerm.toLowerCase()) + } + return true +} From 04fa5bd7db55fc46cba8310112e60b2fcecfbeef Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Mon, 29 Apr 2024 20:34:12 +0200 Subject: [PATCH 04/11] chore: remove evm gas price poll (#2385) * remove evm gas price poll * remove remaininng store * fix types * PR fixes * chore: cleanup --------- Co-authored-by: Tuditi <45079109+Tuditi@users.noreply.github.com> Co-authored-by: Tuditi --- .../views/SelectRecipientView.svelte | 21 ++++++---- .../send-flow/views/SelectTokenView.svelte | 30 +++++++-------- .../actions/canAccountMakeEvmTransaction.ts | 15 ++++---- .../layer-2/actions/getGasPriceForNetwork.ts | 13 ------- .../src/lib/core/layer-2/actions/index.ts | 3 -- .../layer-2/actions/pollEvmChainGasPrices.ts | 38 ------------------- .../layer-2/actions/updateEvmChainGasPrice.ts | 21 ---------- .../stores/evm-chain-gas-prices.store.ts | 23 ----------- .../src/lib/core/layer-2/stores/index.ts | 1 - .../types/evm-chain-gas-prices.type.ts | 5 --- .../src/lib/core/layer-2/types/index.ts | 1 - .../network/classes/base-evm-network.class.ts | 9 +++++ .../interfaces/evm-network.interface.ts | 2 + .../canAccountMakeStardustTransaction.ts | 6 +-- .../profile/actions/active-profile/login.ts | 2 - .../wallet/tests/getOutputParameters.test.ts | 4 -- 16 files changed, 49 insertions(+), 145 deletions(-) delete mode 100644 packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts delete mode 100644 packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts delete mode 100644 packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts delete mode 100644 packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts delete mode 100644 packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte index 3782b581c4..b6da55e5f0 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte @@ -42,17 +42,22 @@ $: selectedNetworkId = selectorOptions[selectedIndex]?.networkId $: selectedRecipient = selectorOptions[selectedIndex]?.selectedRecipient - let hasNetworkRecipientError: boolean = false - $: { + let hasInsufficientFunds = false + $: $sendFlowParameters, void checkFundsForGas() + async function checkFundsForGas(): Promise { + if (!$sendFlowParameters) { + return + } + const originNetworkId = getNetworkIdFromSendFlowParameters($sendFlowParameters) if (originNetworkId && isEvmNetwork(originNetworkId)) { - hasNetworkRecipientError = !canAccountMakeEvmTransaction( + hasInsufficientFunds = !(await canAccountMakeEvmTransaction( $selectedAccountIndex, originNetworkId, - $sendFlowParameters?.type - ) + $sendFlowParameters.type + )) } else { - hasNetworkRecipientError = false + hasInsufficientFunds = false } } @@ -247,13 +252,13 @@ >
- {#if hasNetworkRecipientError} + {#if hasInsufficientFunds} {/if} diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte index a6828e77cd..f26236b463 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte @@ -31,21 +31,21 @@ $: $selectedAccountTokens, searchValue, selectedTab, setFilteredTokenList() - let tokenError: string = '' - $: if ( - selectedToken && - isEvmNetwork(selectedToken.networkId) && - !canAccountMakeEvmTransaction($selectedAccountIndex, selectedToken.networkId, $sendFlowParameters?.type) - ) { - tokenError = localize('error.send.insufficientFundsTransaction') - } else if ( - selectedToken && - isStardustNetwork(selectedToken.networkId) && - !canAccountMakeStardustTransaction($selectedAccountIndex, $sendFlowParameters?.type) - ) { - tokenError = localize('error.send.insufficientFundsTransaction') - } else { - tokenError = '' + let tokenError = '' + $: selectedToken, $sendFlowParameters, void setTokenError() + async function setTokenError(): Promise { + let hasEnoughFunds = true + if (selectedToken && isEvmNetwork(selectedToken.networkId)) { + hasEnoughFunds = await canAccountMakeEvmTransaction( + $selectedAccountIndex, + selectedToken.networkId, + $sendFlowParameters?.type + ) + } else if (selectedToken && isStardustNetwork(selectedToken.networkId)) { + hasEnoughFunds = canAccountMakeStardustTransaction($selectedAccountIndex, $sendFlowParameters?.type) + } + + tokenError = hasEnoughFunds ? '' : localize('error.send.insufficientFundsTransaction') } const tabs = [ diff --git a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts index 1c60281914..0ec9b33882 100644 --- a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts @@ -1,23 +1,22 @@ import { EvmNetworkId } from '@core/network/types' import { SendFlowType } from '@core/wallet/enums' - -import { getEvmChainGasPrice, getLayer2AccountBalanceForToken } from '../stores' - +import { getLayer2AccountBalanceForToken } from '../stores' import { FALLBACK_ESTIMATED_GAS, GAS_LIMIT_MULTIPLIER } from '../constants' import { calculateGasFeeInGlow } from '../helpers' +import { getEvmNetwork } from '@core/network' -export function canAccountMakeEvmTransaction( +export async function canAccountMakeEvmTransaction( accountIndex: number, networkId: EvmNetworkId, - sendFlowType: SendFlowType -): boolean | undefined { + sendFlowType: SendFlowType | undefined +): Promise { const baseTokenAccountBalance = getLayer2AccountBalanceForToken(accountIndex, networkId) const gasLimit = Math.floor( FALLBACK_ESTIMATED_GAS[sendFlowType ?? SendFlowType.BaseCoinTransfer] * GAS_LIMIT_MULTIPLIER ) - const gasPrice = getEvmChainGasPrice(networkId) + const gasPrice = await getEvmNetwork(networkId)?.getGasPrice() if (gasPrice === undefined) { - return undefined + return false } const minimumGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) return baseTokenAccountBalance > minimumGasFee diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts b/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts deleted file mode 100644 index d7fc7e2ba7..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getEvmNetwork } from '@core/network' -import { EvmNetworkId } from '@core/network/types' -import { Converter } from '@core/utils' - -export async function getGasPriceForNetwork(networkId: EvmNetworkId): Promise { - const evmNetwork = getEvmNetwork(networkId) - if (!evmNetwork) { - return undefined - } - - const gasPrice = await evmNetwork.provider.eth.getGasPrice() - return Converter.decimalToHex(Number(gasPrice), true) -} diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 4d26c39bbf..3e38a7a390 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -5,12 +5,9 @@ export * from './checkForUntrackedTokens' export * from './fetchL2BalanceForAccount' export * from './getGasFeeForLayer1ToLayer2Transaction' export * from './generateAndStoreEvmAddressForAccounts' -export * from './getGasPriceForNetwork' export * from './getIscTransferSmartContractData' export * from './getLayer2MetadataForTransfer' export * from './getLayer2NetworkFromAddress' export * from './getNetworkFromAddress' -export * from './pollEvmChainGasPrices' export * from './pollL2BalanceForAccount' export * from './setGasFee' -export * from './updateEvmChainGasPrice' diff --git a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts deleted file mode 100644 index 630ca5534c..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { EvmNetworkId } from '@core/network/types' -import { MILLISECONDS_PER_SECOND } from '@core/utils' -import { updateEvmChainGasPrice } from './updateEvmChainGasPrice' - -const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 60 * MILLISECONDS_PER_SECOND - -const pollIntervalMap: { [id in EvmNetworkId]?: number } = {} - -export function pollEvmChainGasPrice(networkId: EvmNetworkId): void { - if (!networkId || isPollingEvmChainGasPrice(networkId)) { - return - } - void updateEvmChainGasPrice(networkId) - pollIntervalMap[networkId] = window.setInterval(() => { - void updateEvmChainGasPrice(networkId) - }, EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL) -} - -export function pollEvmChainGasPrices(networkIds: EvmNetworkId[]): void { - stopPollingEvmChainGasPrices() - for (const networkId of networkIds) { - pollEvmChainGasPrice(networkId) - } -} - -export function stopPollingEvmChainGasPrices(networkIdsToIgnore?: EvmNetworkId[]): void { - for (const networkId of Object.keys(pollIntervalMap) as EvmNetworkId[]) { - if (!networkIdsToIgnore?.includes(networkId)) { - if (isPollingEvmChainGasPrice(networkId)) { - clearInterval(pollIntervalMap[networkId]) - } - } - } -} - -export function isPollingEvmChainGasPrice(networkId: EvmNetworkId): boolean { - return typeof pollIntervalMap[networkId] === 'number' -} diff --git a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts deleted file mode 100644 index 0816471a16..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { handleError } from '@core/error/handlers' -import { getEvmNetworks } from '@core/network/stores' -import { EvmNetworkId } from '@core/network/types' -import { setEvmChainGasPrice } from '../stores' -import { getGasPriceForNetwork } from './getGasPriceForNetwork' - -export async function updateEvmChainGasPrice(networkId: EvmNetworkId): Promise { - try { - const gasPrice = await getGasPriceForNetwork(networkId) - if (gasPrice) { - setEvmChainGasPrice(BigInt(gasPrice), networkId) - } - } catch (err) { - handleError(err) - } -} - -export async function updateEvmChainGasPrices(): Promise { - const networkIds = getEvmNetworks().map((evmNetwork) => evmNetwork.id) - await Promise.all(networkIds.map((networkId) => updateEvmChainGasPrice(networkId))) -} diff --git a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts deleted file mode 100644 index 25227cc32b..0000000000 --- a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { get, writable } from 'svelte/store' -import { NetworkId } from '@core/network/types' -import { isEvmNetwork } from '@core/network/utils' -import { EvmChainGasPrices } from '../types' - -export const evmChainGasPrices = writable({}) - -export function getEvmChainGasPrice(networkId: NetworkId): bigint | undefined { - return get(evmChainGasPrices)[networkId] -} - -export function setEvmChainGasPrice(price: bigint, networkId: NetworkId): void { - evmChainGasPrices.update((state) => { - if (typeof price === 'bigint' && isEvmNetwork(networkId)) { - return { - ...state, - [networkId]: price, - } - } else { - return state - } - }) -} diff --git a/packages/shared/src/lib/core/layer-2/stores/index.ts b/packages/shared/src/lib/core/layer-2/stores/index.ts index 2c59ed1ce6..7c15aa4d3f 100644 --- a/packages/shared/src/lib/core/layer-2/stores/index.ts +++ b/packages/shared/src/lib/core/layer-2/stores/index.ts @@ -1,2 +1 @@ -export * from './evm-chain-gas-prices.store' export * from './layer2-balances.store' diff --git a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts deleted file mode 100644 index 876a3c8e17..0000000000 --- a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NetworkId } from '@core/network/types' - -export type EvmChainGasPrices = { - [id in NetworkId]?: bigint -} diff --git a/packages/shared/src/lib/core/layer-2/types/index.ts b/packages/shared/src/lib/core/layer-2/types/index.ts index 9b525d20c3..797274a189 100644 --- a/packages/shared/src/lib/core/layer-2/types/index.ts +++ b/packages/shared/src/lib/core/layer-2/types/index.ts @@ -1,6 +1,5 @@ export * from './abi.type' export * from './contract.type' -export * from './evm-chain-gas-prices.type' export * from './evm-transaction-options.type' export * from './evm-transaction-data.type' export * from './layer-2-account-balance.type' diff --git a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts index 631a6461ec..73d478db87 100644 --- a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts @@ -76,6 +76,15 @@ export class BaseEvmNetwork implements IEvmNetwork { return new this.provider.eth.Contract(abi, address) } + async getGasPrice(): Promise { + try { + const gasPrice = await this.provider.eth.getGasPrice() + return BigInt(gasPrice) + } catch { + return undefined + } + } + async getLatestBlock(): Promise { const number = await this.provider.eth.getBlockNumber() return this.provider.eth.getBlock(number) diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts index 80cd3df1ef..28c71ccf55 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts @@ -25,6 +25,8 @@ export interface IEvmNetwork extends IBaseNetwork, IBaseNetworkMetadata { provider: Web3Provider + getGasPrice(): Promise + getContract(type: ContractType, address: string): Contract getLatestBlock(): Promise } diff --git a/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts b/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts index fb20ae08fc..2f9f87d92b 100644 --- a/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts +++ b/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts @@ -4,8 +4,8 @@ import { SendFlowType } from '@core/wallet/enums' export function canAccountMakeStardustTransaction( accountIndex: number, - sendFlowType: SendFlowType -): boolean | undefined { + sendFlowType: SendFlowType | undefined +): boolean { switch (sendFlowType) { case SendFlowType.BaseCoinTransfer: default: { @@ -14,7 +14,7 @@ export function canAccountMakeStardustTransaction( const baseTokenBalance = account?.balances.baseCoin return BigInt(baseTokenBalance?.available ?? 0) > BigInt(0) } else { - return undefined + return false } } } diff --git a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts index e15d866799..5bcf7808e5 100644 --- a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts +++ b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts @@ -4,7 +4,6 @@ import { generateAndStoreActivitiesForAllAccounts } from '@core/activity/actions import { Platform } from '@core/app/classes' import { AppContext } from '@core/app/enums' import { handleError } from '@core/error/handlers' -import { updateEvmChainGasPrices } from '@core/layer-2/actions' import { fetchL2BalanceForAllAccounts } from '@core/layer-2/utils' import { pollLedgerDeviceState } from '@core/ledger/actions' import { pollMarketPrices } from '@core/market/actions' @@ -126,7 +125,6 @@ export async function login(loginOptions?: ILoginOptions): Promise { resetLoginProgress() }, 500) - void updateEvmChainGasPrices() void pollMarketPrices() void updateCirculatingSupplyForActiveProfile() if (Platform.isFeatureFlagEnabled('governance')) { diff --git a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts index 2e131302ea..4d701d3538 100644 --- a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts +++ b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts @@ -96,10 +96,6 @@ jest.mock('../../network/stores/networks.store', () => ({ getIscChain: jest.fn((_) => destinationNetwork), })) -jest.mock('../../layer-2/actions/getGasPriceForNetwork', () => ({ - getGasPriceForNetwork: jest.fn((_) => 1_000_000_000_000n), -})) - jest.mock('../../layer-2/actions/getGasFeeForLayer1ToLayer2Transaction', () => ({ getGasFeeForLayer1ToLayer2Transaction: jest.fn(({ type }) => FALLBACK_ESTIMATED_GAS[type]), })) From 0c12d2a9107214e210718bf1f2108fc6c6fe52da Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Tue, 30 Apr 2024 09:59:30 +0200 Subject: [PATCH 05/11] fix: add fallback icon for networks (#2397) * add fallback icon for networks * fix network summary columns --- .../account-summary/AccountSummaryPane.svelte | 13 ++++++++----- .../components/avatars/NetworkAvatar.svelte | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte b/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte index a437b160bf..5f1950b1c6 100644 --- a/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte +++ b/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte @@ -5,15 +5,18 @@ import { networks } from '@core/network' export let account: IAccountState + + const GRID_COLS = { + 0: 'grid-cols-1', + 1: 'grid-cols-2', + 2: 'grid-cols-3', + 3: 'grid-cols-4', + } import { DEFAULT_NETWORK_ICON } from '@auxiliary/icon' - import { Avatar, Tooltip } from '@bloomwalletio/ui' - import { NetworkId, SupportedNetworkId, getNameFromNetworkId, isSupportedNetworkId } from '@core/network' + import { Avatar, IconName, Tooltip } from '@bloomwalletio/ui' + import { NetworkId, SupportedNetworkId, getNameFromNetworkId } from '@core/network' export let networkId: NetworkId export let networkName: string | undefined = undefined @@ -26,17 +26,19 @@ } let anchor: HTMLElement - $: isSupported = isSupportedNetworkId(networkId) - $: backgroundColor = isSupported ? AVATAR_BACKGROUND_COLOR[networkId] : 'neutral-4' - $: customTextColor = isSupported ? AVATAR_TEXT_COLOR[networkId] : undefined - $: icon = isSupported ? DEFAULT_NETWORK_ICON[networkId] : undefined $: networkName = networkName ? networkName : networkId ? getNameFromNetworkId(networkId) ?? networkId : networkId $: magnify = Object.values(SupportedNetworkId).includes(networkId) - - + {#if showTooltip && networkName} From 781747bbea06cbb078ae18e565cfbceb0d4d199c Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Tue, 30 Apr 2024 10:25:13 +0200 Subject: [PATCH 06/11] fix duplicated nft generation (#2394) --- ...edErc721Nfts.ts => getPersistedErc721NftsForNetwork.ts} | 7 +++++-- packages/shared/src/lib/core/nfts/actions/index.ts | 2 +- .../src/lib/core/nfts/actions/loadNftsForActiveProfile.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) rename packages/shared/src/lib/core/nfts/actions/{getPersistedErc721Nfts.ts => getPersistedErc721NftsForNetwork.ts} (59%) diff --git a/packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts b/packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts similarity index 59% rename from packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts rename to packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts index 5b83de8c32..db8a148913 100644 --- a/packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts +++ b/packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts @@ -3,12 +3,15 @@ import { getActiveProfile } from '@core/profile/stores' import { NftStandard } from '../enums' import { IPersistedErc721Nft } from '../interfaces' import { persistedNfts } from '../stores' +import { NetworkId } from '@core/network' -export function getPersistedErc721Nfts(): IPersistedErc721Nft[] { +export function getPersistedErc721NftsForNetwork(networkId: NetworkId): IPersistedErc721Nft[] { const activeProfileId = getActiveProfile()?.id if (activeProfileId) { const profileNfts = Object.values(get(persistedNfts)[activeProfileId] ?? {}) - return profileNfts.filter(({ standard }) => standard === NftStandard.Erc721) as IPersistedErc721Nft[] + return profileNfts.filter( + ({ standard, networkId: _networkId }) => standard === NftStandard.Erc721 && networkId === networkId + ) as IPersistedErc721Nft[] } else { throw new Error('Unable to get active profile') } diff --git a/packages/shared/src/lib/core/nfts/actions/index.ts b/packages/shared/src/lib/core/nfts/actions/index.ts index fc75891e32..7489b48b4f 100644 --- a/packages/shared/src/lib/core/nfts/actions/index.ts +++ b/packages/shared/src/lib/core/nfts/actions/index.ts @@ -4,7 +4,7 @@ export * from './buildNftFromNftOutput' export * from './checkForUntrackedNfts' export * from './downloadNextNftInQueue' export * from './getNftByIdFromAllAccountNfts' -export * from './getPersistedErc721Nfts' +export * from './getPersistedErc721NftsForNetwork' export * from './interruptNftDownloadAfterTimeout' export * from './isNftPersisted' export * from './loadNftsForActiveProfile' diff --git a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts index 30e2a07751..5e0e46c9e8 100644 --- a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts +++ b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts @@ -13,7 +13,7 @@ import { Nft } from '../interfaces' import { buildNftFromPersistedErc721Nft, getNftsFromNftIds } from '../utils' import { addNftsToDownloadQueue } from './addNftsToDownloadQueue' import { buildNftFromNftOutput } from './buildNftFromNftOutput' -import { getPersistedErc721Nfts } from './getPersistedErc721Nfts' +import { getPersistedErc721NftsForNetwork } from './getPersistedErc721NftsForNetwork' import { setAccountNftsInAllAccountNfts } from './setAccountNftsInAllAccountNfts' export async function loadNftsForActiveProfile(): Promise { @@ -70,7 +70,7 @@ export async function loadNftsForAccount(profileId: string, account: IAccountSta if (!evmAddress) { continue } - const erc721Nfts = getPersistedErc721Nfts() + const erc721Nfts = getPersistedErc721NftsForNetwork(evmNetwork.id) const convertedNfts: Nft[] = erc721Nfts.map((persistedErc721Nft) => buildNftFromPersistedErc721Nft(persistedErc721Nft, evmAddress) ) From 66c07d0474452c15a44e96442e3f075e896874ac Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Tue, 30 Apr 2024 10:44:45 +0200 Subject: [PATCH 07/11] refactor: persisted tokens (#2368) * create persisted dapps store * add verified icon to dapp list * add migrations * add verification icon to edit + details drawer * add comment + fix profile version * PR fixes * refactor token balance * add network to get persisted token * cleanup loadAssets function * refactor loadTokens to load from all networks * add base token to chain config * improve getting basetoken * update migrations * cleanup * add migrations to reset persisted tokens * resolve PR comments * make migration * update migration * update migration for chain config * use URL constructor * fix chainconfiguration * catch uncaught error * only check for owner on relevant network * fix condition * fix: correctly destructure persisted token --------- Co-authored-by: Tuditi <45079109+Tuditi@users.noreply.github.com> Co-authored-by: Tuditi --- .../components/menus/TokenActionsMenu.svelte | 8 +- .../components/menus/TokenListMenu.svelte | 4 +- .../popup/popups/FaucetRequestPopup.svelte | 5 +- .../popup/popups/SyncAccountsPopup.svelte | 4 +- .../popup/popups/TokenInformationPopup.svelte | 14 +-- .../components/AccountNetworkSummary.svelte | 6 +- .../row-sections/ActivityAmountSection.svelte | 40 +++--- .../evm/EvmActivityInformation.svelte | 1 + .../evm/info/EvmGenericInformation.svelte | 6 +- .../StardustActivityInformation.svelte | 2 +- .../info/StardustGenericInformation.svelte | 5 +- .../info/StardustTokenInformation.svelte | 5 +- .../actions/loadAssetsForAllAccounts.ts | 25 ++-- .../setAsyncStatusOfAccountActivities.ts | 4 +- .../selected-account-activities.store.ts | 29 +---- .../activity/utils/convertActvitiesToCsv.ts | 12 +- .../activity/utils/getTokenFromActivity.ts | 41 +----- .../activity/utils/getTokenIdFromActivity.ts | 38 ++++++ .../activity/utils/getTransactionAssets.ts | 10 +- .../src/lib/core/activity/utils/index.ts | 2 + .../core/activity/utils/isVisibleActivity.ts | 2 +- .../outputs/getFormattedAmountFromActivity.ts | 10 +- .../actions/fetchL2BalanceForAccount.ts | 20 +-- .../network/classes/base-evm-network.class.ts | 9 +- .../core/network/classes/evm-network.class.ts | 3 - .../core/network/classes/isc-chain.class.ts | 5 +- .../constants/default-base-token.constant.ts | 28 ++--- ...ault-isc-chains-configurations.constant.ts | 3 + ...-l1-evm-network-configurations.constant.ts | 7 +- .../interfaces/base-network.interface.ts | 2 + .../evm-network-configuration.interface.ts | 4 +- .../stardust-network-metadata.interface.ts | 2 - .../profile/actions/active-profile/login.ts | 4 +- .../constants/profile-version.constant.ts | 2 +- .../alpha/alpha-profile-migration-15-to-16.ts | 1 - .../alpha/alpha-profile-migration-16-to-17.ts | 26 ++++ .../alpha/alpha-profile-migration-map.ts | 2 + .../prod/prod-profile-migration-8-to-9.ts | 12 ++ .../actions/getAccountTokensForAccount.ts | 8 +- .../getOrRequestTokenFromPersistedTokens.ts | 4 +- .../src/lib/core/token/actions/index.ts | 2 +- .../loadTokensForAllAccountBalances.ts | 118 ++++++++++++++++++ .../refreshAccountTokensForActiveProfile.ts | 60 --------- .../interfaces/account-tokens.interface.ts | 2 +- .../interfaces/persisted-tokens.interface.ts | 5 +- .../token/stores/persisted-tokens.store.ts | 71 +++++------ .../stores/selected-account-tokens.store.ts | 13 +- .../addNewTrackedTokenToActiveProfile.ts | 2 +- .../core/wallet/actions/mintNativeToken.ts | 2 +- 49 files changed, 407 insertions(+), 283 deletions(-) create mode 100644 packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts create mode 100644 packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-16-to-17.ts create mode 100644 packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts delete mode 100644 packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts diff --git a/packages/desktop/components/menus/TokenActionsMenu.svelte b/packages/desktop/components/menus/TokenActionsMenu.svelte index 2442922c1c..009c14550f 100644 --- a/packages/desktop/components/menus/TokenActionsMenu.svelte +++ b/packages/desktop/components/menus/TokenActionsMenu.svelte @@ -23,7 +23,7 @@ } function onUnverifyClick(): void { - unverifyToken(token.id, NotVerifiedStatus.Skipped) + unverifyToken(token, NotVerifiedStatus.Skipped) updatePopupProps({ token: { ...token, verification: { verified: false, status: NotVerifiedStatus.Skipped } }, }) @@ -31,7 +31,7 @@ } function onVerifyClick(): void { - verifyToken(token.id, VerifiedStatus.SelfVerified) + verifyToken(token, VerifiedStatus.SelfVerified) updatePopupProps({ token: { ...token, verification: { verified: true, status: VerifiedStatus.SelfVerified } }, }) @@ -39,7 +39,7 @@ } function onUnhideClick(): void { - unhideToken(token.id) + unhideToken(token) hideActivitiesForHiddenTokens() updatePopupProps({ token: { ...token, hidden: false }, @@ -48,7 +48,7 @@ } function onHideClick(): void { - hideToken(token.id) + hideToken(token) hideActivitiesForHiddenTokens() updatePopupProps({ token: { ...token, hidden: true }, diff --git a/packages/desktop/components/menus/TokenListMenu.svelte b/packages/desktop/components/menus/TokenListMenu.svelte index 1b10142fac..8b0611976a 100644 --- a/packages/desktop/components/menus/TokenListMenu.svelte +++ b/packages/desktop/components/menus/TokenListMenu.svelte @@ -3,7 +3,7 @@ import { showNotification } from '@auxiliary/notification' import { IconName, Menu } from '@bloomwalletio/ui' import { localize } from '@core/i18n' - import { refreshAccountTokensForActiveProfile } from '@core/token/actions' + import { loadTokensForAllAccountBalances } from '@core/token/actions' import { PopupId, closePopup, openPopup } from '../../lib/auxiliary/popup' import { fetchL2BalanceForAllAccounts } from '@core/layer-2' @@ -27,7 +27,7 @@ } function refreshTokenMetadata(): void { - refreshAccountTokensForActiveProfile(true) + loadTokensForAllAccountBalances(true) showNotification({ variant: 'success', text: localize('notifications.refreshTokenMetadata.success'), diff --git a/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte b/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte index adce77816c..cdc9b7eb8b 100644 --- a/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte +++ b/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte @@ -6,11 +6,12 @@ import { Error } from '@bloomwalletio/ui' import { handleError } from '@core/error/handlers/handleError' import PopupTemplate from '../PopupTemplate.svelte' - import { getBaseToken } from '@core/profile/actions' let isBusy = false let error: string | undefined + const network = getL1Network() + async function onConfirmClick(): Promise { error = undefined try { @@ -33,7 +34,7 @@ { if (hasUsedWalletFinder) { const profileId = getActiveProfileId() - await refreshAccountTokensForActiveProfile() + await loadTokensForAllAccountBalances() await generateAndStoreActivitiesForAllAccounts(profileId) loadNftsForActiveProfile() } diff --git a/packages/desktop/components/popup/popups/TokenInformationPopup.svelte b/packages/desktop/components/popup/popups/TokenInformationPopup.svelte index dec1772c4e..945270b70f 100644 --- a/packages/desktop/components/popup/popups/TokenInformationPopup.svelte +++ b/packages/desktop/components/popup/popups/TokenInformationPopup.svelte @@ -11,13 +11,13 @@ import { SendFlowRoute, SendFlowRouter, sendFlowRouter } from '@views/dashboard/send-flow' import PopupTemplate from '../PopupTemplate.svelte' - export let token: ITokenWithBalance | undefined + export let token: ITokenWithBalance export let activityId: string | undefined = undefined - $: isNewToken = token?.verification?.status === NotVerifiedStatus.New + $: isNewToken = token.verification?.status === NotVerifiedStatus.New function onSkipClick(): void { - unverifyToken(token?.id, NotVerifiedStatus.Skipped) + unverifyToken(token, NotVerifiedStatus.Skipped) if (activityId) { openPopup({ id: PopupId.ActivityDetails, @@ -31,7 +31,7 @@ } function onVerifyClick(): void { - verifyToken(token?.id, VerifiedStatus.SelfVerified) + verifyToken(token, VerifiedStatus.SelfVerified) if (activityId) { openPopup({ id: PopupId.ActivityDetails, @@ -45,7 +45,7 @@ } function onSendClick(): void { - const sendFlowType = token?.id === BASE_TOKEN_ID ? SendFlowType.BaseCoinTransfer : SendFlowType.TokenTransfer + const sendFlowType = token.id === BASE_TOKEN_ID ? SendFlowType.BaseCoinTransfer : SendFlowType.TokenTransfer setSendFlowParameters({ type: sendFlowType, [sendFlowType]: { @@ -62,7 +62,7 @@
- {#if token?.standard === TokenStandard.Irc30 || token?.standard === TokenStandard.Erc20} + {#if token.standard === TokenStandard.Irc30 || token.standard === TokenStandard.Erc20} {/if}
diff --git a/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte b/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte index ea1dad21d6..98cbf4db9b 100644 --- a/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte +++ b/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte @@ -32,9 +32,9 @@ tokens?.baseCoin?.balance.total ?? BigInt(0), tokens?.baseCoin?.metadata ) - $: fiatBalance = - formatCurrency(getFiatValueFromTokenAmount(BigInt(tokens?.baseCoin?.balance.total ?? 0), tokens?.baseCoin)) ?? - '' + $: fiatBalance = tokens + ? formatCurrency(getFiatValueFromTokenAmount(BigInt(tokens?.baseCoin?.balance.total ?? 0), tokens.baseCoin)) + : '' $: address = getAddressFromAccountForNetwork(account, network.id) $: hasTokens = tokens?.nativeTokens?.length > 0 diff --git a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAmountSection.svelte b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAmountSection.svelte index 2a58b878da..b83c03d53f 100644 --- a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAmountSection.svelte +++ b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/row-sections/ActivityAmountSection.svelte @@ -23,30 +23,27 @@ $: $selectedAccountTokens, (token = getTokenFromActivity(activity)) function getAmount(_activity: Activity): string { - if (_activity.namespace === NetworkNamespace.Stardust) { - if (_activity.type === StardustActivityType.Basic || _activity.type === StardustActivityType.Foundry) { + const { type, namespace } = _activity + + if (namespace === NetworkNamespace.Stardust) { + if (type === StardustActivityType.Basic || type === StardustActivityType.Foundry) { const { rawAmount, tokenId } = _activity.tokenTransfer ?? _activity.baseTokenTransfer ?? {} - return getFormattedAmountFromActivity(rawAmount, tokenId, _activity.direction, _activity.action) - } else if (_activity.type === StardustActivityType.Governance) { + return getFormattedAmountFromActivity(rawAmount, tokenId, _activity) + } else if (type === StardustActivityType.Governance) { const isVotingPowerActivity = _activity.governanceAction === StardustGovernanceAction.DecreaseVotingPower || _activity.governanceAction === StardustGovernanceAction.IncreaseVotingPower return isVotingPowerActivity ? getFormattedVotingPowerFromGovernanceActivity(_activity) : '-' - } else if (_activity.type === StardustActivityType.Nft) { + } else if (type === StardustActivityType.Nft) { return '1 ' + localize('general.nft') } else { return '-' } - } else if (_activity.namespace === NetworkNamespace.Evm) { - if (_activity.type === EvmActivityType.CoinTransfer) { - return getFormattedAmountFromActivity( - _activity.baseTokenTransfer.rawAmount, - BASE_TOKEN_ID, - _activity.direction, - _activity.action - ) + } else if (namespace === NetworkNamespace.Evm) { + if (type === EvmActivityType.CoinTransfer) { + return getFormattedAmountFromActivity(_activity.baseTokenTransfer.rawAmount, BASE_TOKEN_ID, _activity) } else if (isEvmTokenActivity(_activity)) { if ( _activity.tokenTransfer?.standard === NftStandard.Erc721 || @@ -57,8 +54,7 @@ return getFormattedAmountFromActivity( _activity.tokenTransfer.rawAmount, _activity.tokenTransfer.tokenId, - _activity.direction, - _activity.action + _activity ) } } else { @@ -70,10 +66,12 @@ } function getFormattedMarketPrice(_activity: Activity): string | undefined { - if (_activity.namespace === NetworkNamespace.Stardust) { + const { type, namespace } = _activity + + if (namespace === NetworkNamespace.Stardust) { if ( [StardustActivityType.Basic, StardustActivityType.Governance, StardustActivityType.Foundry].includes( - _activity.type + type ) && token ) { @@ -81,16 +79,16 @@ const marketPrice = getFiatValueFromTokenAmount(amount, token) return marketPrice ? formatCurrency(marketPrice) : '-' - } else if (_activity.type === StardustActivityType.Nft) { + } else if (type === StardustActivityType.Nft) { return '-' } else { return undefined } - } else if (_activity.namespace === NetworkNamespace.Evm) { - if (_activity.type === EvmActivityType.CoinTransfer) { + } else if (namespace === NetworkNamespace.Evm) { + if (type === EvmActivityType.CoinTransfer) { const marketPrice = getFiatValueFromTokenAmount(_activity.baseTokenTransfer.rawAmount, token) return marketPrice ? formatCurrency(marketPrice) : '-' - } else if (_activity.type === EvmActivityType.TokenTransfer) { + } else if (type === EvmActivityType.TokenTransfer) { if ( _activity.tokenTransfer?.standard === TokenStandard.Erc20 || _activity.tokenTransfer?.standard === TokenStandard.Irc30 diff --git a/packages/shared/src/components/activities/evm/EvmActivityInformation.svelte b/packages/shared/src/components/activities/evm/EvmActivityInformation.svelte index 14dd78cb5b..774e6177c6 100644 --- a/packages/shared/src/components/activities/evm/EvmActivityInformation.svelte +++ b/packages/shared/src/components/activities/evm/EvmActivityInformation.svelte @@ -53,6 +53,7 @@ {#if selectedTab.key === PopupTab.Transaction} import { Table } from '@bloomwalletio/ui' import { getFormattedTimeStamp, localize } from '@core/i18n' - import { NetworkId } from '@core/network' - import { getBaseToken } from '@core/profile/actions' + import { NetworkId, getNetwork } from '@core/network' import { formatTokenAmountBestMatch } from '@core/token' import { NetworkLabel } from '@ui' export let time: Date + export let sourceNetworkId: NetworkId export let destinationNetworkId: NetworkId export let maxGasFee: bigint | undefined = undefined export let transactionFee: bigint | undefined = undefined @@ -17,7 +17,7 @@ $: formattedTransactionFee = formatAmount(transactionFee) function formatAmount(amount: bigint | undefined): string | undefined { - return amount ? formatTokenAmountBestMatch(amount, getBaseToken()) : undefined + return amount ? formatTokenAmountBestMatch(amount, getNetwork(sourceNetworkId)?.baseToken) : undefined } diff --git a/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte b/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte index 35a970a3a8..40106c9a31 100644 --- a/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte +++ b/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte @@ -52,7 +52,7 @@ case StardustActivityType.Foundry: tabs = getTabItems([PopupTab.Transaction, PopupTab.Foundry, PopupTab.Token]) token = activity.tokenTransfer - ? getPersistedToken(activity.tokenTransfer?.tokenId)?.metadata + ? getPersistedToken(activity.sourceNetworkId, activity.tokenTransfer?.tokenId)?.metadata : undefined break case StardustActivityType.Consolidation: diff --git a/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte b/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte index 95f9894413..7d58394385 100644 --- a/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte +++ b/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte @@ -4,8 +4,7 @@ import { openUrlInBrowser } from '@core/app' import { time } from '@core/app/stores' import { getFormattedTimeStamp, localize } from '@core/i18n' - import { ExplorerEndpoint, getDefaultExplorerUrl } from '@core/network' - import { getBaseToken } from '@core/profile/actions' + import { ExplorerEndpoint, getDefaultExplorerUrl, getNetwork } from '@core/network' import { formatTokenAmountBestMatch } from '@core/token' import { buildUrl } from '@core/utils' import { getTimeDifference } from '@core/utils/time' @@ -32,7 +31,7 @@ } function formatAmount(amount: bigint | undefined): string | undefined { - return amount ? formatTokenAmountBestMatch(amount, getBaseToken()) : undefined + return amount ? formatTokenAmountBestMatch(amount, getNetwork(activity.sourceNetworkId)?.baseToken) : undefined } diff --git a/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte b/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte index e65624d7b2..a22ac80ec9 100644 --- a/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte +++ b/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte @@ -10,7 +10,10 @@ let metadata: IIrc30Metadata | undefined $: metadata = ( - getPersistedToken(activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId)?.metadata + getPersistedToken( + activity.sourceNetworkId, + activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId + )?.metadata ) diff --git a/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts b/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts index 30cf300452..726f1bd358 100644 --- a/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts +++ b/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts @@ -3,25 +3,34 @@ import { IPersistedToken } from '@core/token/interfaces' import { getOrRequestTokenFromPersistedTokens } from '@core/token/actions' import { addPersistedToken } from '@core/token/stores' import { get } from 'svelte/store' -import { StardustActivityType } from '../enums' import { allAccountActivities } from '../stores' +import { NetworkId } from '@core/network/types' +import { getTokenIdFromActivity } from '../utils' export async function loadAssetsForAllActivities(account: IAccountState): Promise { const accountActivities = get(allAccountActivities)[account.index] - const persistedTokens: IPersistedToken[] = [] + const tokens: { [networkId: NetworkId]: IPersistedToken[] } = {} for (const activity of accountActivities) { try { - if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { - const tokenId = activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer?.tokenId - const token = await getOrRequestTokenFromPersistedTokens(tokenId, activity.sourceNetworkId, false) - if (token) { - persistedTokens.push(token) + const tokenId = getTokenIdFromActivity(activity) + if (!tokenId) { + continue + } + + const token = await getOrRequestTokenFromPersistedTokens(tokenId, activity.sourceNetworkId, false) + if (token) { + if (!tokens[activity.sourceNetworkId]) { + tokens[activity.sourceNetworkId] = [] } + tokens[activity.sourceNetworkId].push(token) } } catch (err) { console.error(err) } } - addPersistedToken(...persistedTokens) + + for (const networkId of Object.keys(tokens)) { + addPersistedToken(networkId as NetworkId, ...tokens[networkId]) + } } diff --git a/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts b/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts index 4dd26e33a5..0c989eea6f 100644 --- a/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts +++ b/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts @@ -1,6 +1,6 @@ import { syncBalance } from '@core/account/actions/syncBalance' import { updateNftInAllAccountNftsForAccount } from '@core/nfts/actions' -import { refreshAccountTokensForActiveProfile } from '@core/token/actions' +import { loadTokensForAllAccountBalances } from '@core/token/actions' import { StardustActivityAsyncStatus, ActivityDirection, StardustActivityType } from '../enums' import { allAccountActivities } from '../stores' import { getAsyncStatus } from '../utils/helper' @@ -55,6 +55,6 @@ export function setAsyncStatusOfAccountActivities(time: Date): void { syncBalance(accountIndex) } if (balancesToUpdate.length) { - void refreshAccountTokensForActiveProfile() + void loadTokensForAllAccountBalances() } } diff --git a/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts b/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts index be180d5d8e..741d95cc2d 100644 --- a/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts +++ b/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts @@ -41,7 +41,7 @@ export const queriedActivities: Readable = derived( } const tokenId = _activity.tokenTransfer?.tokenId ?? _activity.baseTokenTransfer.tokenId - const token = containsAssets ? getPersistedToken(tokenId) : undefined + const token = containsAssets ? getPersistedToken(_activity.sourceNetworkId, tokenId) : undefined const hasValidAsset = token?.metadata && isValidIrc30Token(token.metadata) return !_activity.isHidden && hasValidAsset } else if (_activity.namespace === NetworkNamespace.Evm) { @@ -84,20 +84,12 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { fieldsToSearch.push(tokenId) fieldsToSearch.push(String(rawAmount)) - const tokenName = getPersistedToken(tokenId)?.metadata?.name + const tokenName = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata?.name if (tokenName) { fieldsToSearch.push(tokenName) } - fieldsToSearch.push( - getFormattedAmountFromActivity( - rawAmount, - tokenId, - activity.direction, - activity.action, - false - )?.toLowerCase() - ) + fieldsToSearch.push(getFormattedAmountFromActivity(rawAmount, tokenId, activity, false)?.toLowerCase()) } } else if (activity.namespace === NetworkNamespace.Evm) { if (activity.type === EvmActivityType.CoinTransfer) { @@ -107,8 +99,7 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { getFormattedAmountFromActivity( activity.baseTokenTransfer.rawAmount, activity.baseTokenTransfer.tokenId, - activity.direction, - activity.action, + activity, false )?.toLowerCase() ) @@ -119,20 +110,12 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { fieldsToSearch.push(tokenId) if (standard === TokenStandard.Erc20 || standard === TokenStandard.Irc30) { - const tokenName = getPersistedToken(tokenId)?.metadata?.name + const tokenName = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata?.name if (tokenName) { fieldsToSearch.push(tokenName) } - fieldsToSearch.push( - getFormattedAmountFromActivity( - rawAmount, - tokenId, - activity.direction, - activity.action, - false - )?.toLowerCase() - ) + fieldsToSearch.push(getFormattedAmountFromActivity(rawAmount, tokenId, activity, false)?.toLowerCase()) } } } diff --git a/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts b/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts index 047188bb20..bff52b030f 100644 --- a/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts +++ b/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts @@ -98,11 +98,13 @@ function getRowForStardustActivity( let assetTicker: string | undefined let amount: string | undefined - const baseCoinMetadata = getPersistedToken(BASE_TOKEN_ID)?.metadata as IBaseToken + const baseCoinMetadata = getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID)?.metadata as IBaseToken if (activity.type === StardustActivityType.Basic) { if (activity.tokenTransfer) { const tokenId = activity.tokenTransfer.tokenId - const metadata = getPersistedToken(tokenId)?.metadata as IErc20Metadata | IIrc30Metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata as + | IErc20Metadata + | IIrc30Metadata amount = metadata ? formatTokenAmountBestMatch(activity.tokenTransfer.rawAmount, metadata, { round: false, @@ -201,7 +203,7 @@ function getRowForEvmActivity( let assetName: string | undefined let assetTicker: string | undefined let amount: string | undefined - const baseCoinMetadata = getPersistedToken(BASE_TOKEN_ID)?.metadata as IBaseToken + const baseCoinMetadata = getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID)?.metadata as IBaseToken if (activity.type === EvmActivityType.CoinTransfer) { amount = baseCoinMetadata @@ -219,7 +221,9 @@ function getRowForEvmActivity( } else if (isEvmTokenActivity(activity)) { const { standard, tokenId, rawAmount } = activity.tokenTransfer if (standard === TokenStandard.Erc20 || standard === TokenStandard.Irc30) { - const metadata = getPersistedToken(tokenId)?.metadata as IErc20Metadata | IIrc30Metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata as + | IErc20Metadata + | IIrc30Metadata amount = metadata ? formatTokenAmountBestMatch(rawAmount, metadata, { round: false, withUnit: false }) : '' assetId = tokenId diff --git a/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts b/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts index a9c54dbb7b..8d631cf7cb 100644 --- a/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts @@ -1,42 +1,13 @@ -import { BASE_TOKEN_ID, ITokenWithBalance, TokenStandard } from '@core/token' +import { ITokenWithBalance } from '@core/token' import { Activity } from '../types' import { getTokenFromSelectedAccountTokens } from '@core/token/stores' -import { StardustActivityType } from '../enums' -import { NetworkNamespace } from '@core/network' -import { EvmActivityType } from '../enums/evm' -import { isEvmTokenActivity } from './isEvmTokenActivity' +import { getTokenIdFromActivity } from './getTokenIdFromActivity' export function getTokenFromActivity(activity: Activity): ITokenWithBalance | undefined { - if (activity.namespace === NetworkNamespace.Stardust) { - if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { - return getTokenFromSelectedAccountTokens( - activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId, - activity.sourceNetworkId - ) - } else if ( - activity.type === StardustActivityType.Governance || - activity.type === StardustActivityType.Consolidation - ) { - return getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, activity.sourceNetworkId) - } else { - return undefined - } - } else if (activity.namespace === NetworkNamespace.Evm) { - if (activity.type === EvmActivityType.CoinTransfer) { - return getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, activity.sourceNetworkId) - } else if (isEvmTokenActivity(activity)) { - if ( - activity.tokenTransfer.standard === TokenStandard.Erc20 || - activity.tokenTransfer.standard === TokenStandard.Irc30 - ) { - return getTokenFromSelectedAccountTokens(activity.tokenTransfer.tokenId, activity.sourceNetworkId) - } else { - return undefined - } - } else { - return undefined - } - } else { + const tokenId = getTokenIdFromActivity(activity) + if (!tokenId) { return undefined } + + return getTokenFromSelectedAccountTokens(tokenId, activity.sourceNetworkId) } diff --git a/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts b/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts new file mode 100644 index 0000000000..3d7ef4b81c --- /dev/null +++ b/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts @@ -0,0 +1,38 @@ +import { BASE_TOKEN_ID, TokenStandard } from '@core/token' +import { Activity } from '../types' +import { StardustActivityType } from '../enums' +import { NetworkNamespace } from '@core/network' +import { EvmActivityType } from '../enums/evm' +import { isEvmTokenActivity } from './isEvmTokenActivity' + +export function getTokenIdFromActivity(activity: Activity): string | undefined { + if (activity.namespace === NetworkNamespace.Stardust) { + if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { + return activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId + } else if ( + activity.type === StardustActivityType.Governance || + activity.type === StardustActivityType.Consolidation + ) { + return BASE_TOKEN_ID + } else { + return undefined + } + } else if (activity.namespace === NetworkNamespace.Evm) { + if (activity.type === EvmActivityType.CoinTransfer) { + return BASE_TOKEN_ID + } else if (isEvmTokenActivity(activity)) { + if ( + activity.tokenTransfer.standard === TokenStandard.Erc20 || + activity.tokenTransfer.standard === TokenStandard.Irc30 + ) { + return activity.tokenTransfer.tokenId + } else { + return undefined + } + } else { + return undefined + } + } else { + return undefined + } +} diff --git a/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts b/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts index 8aa2eebbad..2f23133cf8 100644 --- a/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts +++ b/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts @@ -17,7 +17,10 @@ export function getTransactionAssets( baseCoinTransfer?: TokenTransferData } | undefined { - const baseCoin = { ...getPersistedToken(BASE_TOKEN_ID), networkId: activity.sourceNetworkId } + const baseCoin = { + ...getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID), + networkId: activity.sourceNetworkId, + } if (!baseCoin) { return undefined @@ -39,7 +42,10 @@ export function getTransactionAssets( } } else if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { const token: IToken | undefined = activity.tokenTransfer?.tokenId - ? { ...getPersistedToken(activity.tokenTransfer.tokenId), networkId: activity.sourceNetworkId } + ? { + ...getPersistedToken(activity.sourceNetworkId, activity.tokenTransfer.tokenId), + networkId: activity.sourceNetworkId, + } : undefined const tokenAmount = activity.tokenTransfer?.rawAmount diff --git a/packages/shared/src/lib/core/activity/utils/index.ts b/packages/shared/src/lib/core/activity/utils/index.ts index c52fea75ce..79cb15498d 100644 --- a/packages/shared/src/lib/core/activity/utils/index.ts +++ b/packages/shared/src/lib/core/activity/utils/index.ts @@ -6,6 +6,8 @@ export * from './getActivityActionPill' export * from './getActivityTileAction' export * from './getActivityTileAsset' export * from './getTransactionAssets' +export * from './getTokenIdFromActivity' +export * from './getTokenFromActivity' export * from './isEvmTokenActivity' export * from './isVisibleActivity' diff --git a/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts b/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts index f4f3a9ab04..baace0f120 100644 --- a/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts @@ -144,7 +144,7 @@ function isVisibleWithActiveAmountFilter(activity: Activity, filter: ActivityFil } else { return true } - const token = getPersistedToken(tokenId) + const token = getPersistedToken(activity.sourceNetworkId, tokenId) if (!token || !token.metadata) { return false diff --git a/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts b/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts index 19e5ba26b6..6d608a5d00 100644 --- a/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts @@ -1,17 +1,19 @@ import { formatTokenAmountBestMatch } from '@core/token' import { ActivityAction, ActivityDirection } from '../../enums' import { getPersistedToken } from '@core/token/stores' +import { Activity } from '@core/activity/types' export function getFormattedAmountFromActivity( rawAmount: bigint, tokenId: string, - direction: ActivityDirection, - action: ActivityAction, + activity: Activity, signed: boolean = true ): string { - const metadata = getPersistedToken(tokenId)?.metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata const amount = metadata ? formatTokenAmountBestMatch(rawAmount, metadata) : '' return `${ - (direction === ActivityDirection.Outgoing || action === ActivityAction.Burn) && signed ? '- ' : '' + (activity.direction === ActivityDirection.Outgoing || activity.action === ActivityAction.Burn) && signed + ? '- ' + : '' }${amount}` } diff --git a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts index 758584959b..7d6c2a98ec 100644 --- a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts @@ -26,16 +26,20 @@ export function fetchL2BalanceForAccount(profileId: string, account: IAccountSta void updateErc721NftsOwnership(account, evmNetwork.id) } - const l2TokenBalance = isIscChain(evmNetwork) - ? await fetchIscAssetsForAccount(profileId, evmAddress, evmNetwork, account) - : {} + try { + const l2TokenBalance = isIscChain(evmNetwork) + ? await fetchIscAssetsForAccount(profileId, evmAddress, evmNetwork, account) + : {} - const erc20Balances = await getErc20BalancesForAddress(evmAddress, evmNetwork) - for (const [tokenId, balance] of Object.entries(erc20Balances)) { - await getOrRequestTokenFromPersistedTokens(tokenId, networkId) - l2TokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance + const erc20Balances = await getErc20BalancesForAddress(evmAddress, evmNetwork) + for (const [tokenId, balance] of Object.entries(erc20Balances)) { + await getOrRequestTokenFromPersistedTokens(tokenId, networkId) + l2TokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance + } + setLayer2AccountBalanceForChain(index, networkId, l2TokenBalance) + } catch (error) { + console.error(error) } - setLayer2AccountBalanceForChain(index, networkId, l2TokenBalance) }) } diff --git a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts index 73d478db87..ce3ba22361 100644 --- a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts @@ -10,6 +10,7 @@ import { EvmNetworkType, NetworkHealth, NetworkNamespace, ChainId } from '../enu import { IBlock, IEvmNetwork, IBaseEvmNetworkConfiguration } from '../interfaces' import { CoinType } from '@iota/sdk/out/types' import { EvmNetworkId, Web3Provider } from '../types' +import { IBaseToken } from '@core/token' import { NETWORK_STATUS_POLL_INTERVAL } from '@core/network/constants' export class BaseEvmNetwork implements IEvmNetwork { @@ -21,6 +22,7 @@ export class BaseEvmNetwork implements IEvmNetwork { public readonly type: EvmNetworkType public readonly coinType: CoinType public readonly name: string + public readonly baseToken: IBaseToken public readonly explorerUrl: string | undefined public readonly rpcEndpoint: string @@ -33,21 +35,24 @@ export class BaseEvmNetwork implements IEvmNetwork { chainId, type, coinType, + baseToken, name, explorerUrl, rpcEndpoint, }: IBaseEvmNetworkConfiguration) { try { - this.provider = new Web3(`${rpcEndpoint}`) + const _rpcEndpoint = new URL(rpcEndpoint).href + this.provider = new Web3(`${_rpcEndpoint}`) this.id = id this.namespace = namespace this.chainId = chainId this.type = type this.coinType = coinType + this.baseToken = baseToken this.name = name this.explorerUrl = explorerUrl - this.rpcEndpoint = rpcEndpoint + this.rpcEndpoint = _rpcEndpoint void this.startStatusPoll() } catch (err) { diff --git a/packages/shared/src/lib/core/network/classes/evm-network.class.ts b/packages/shared/src/lib/core/network/classes/evm-network.class.ts index d789879ef7..bb760d9c42 100644 --- a/packages/shared/src/lib/core/network/classes/evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/evm-network.class.ts @@ -2,12 +2,9 @@ import { IPureEvmNetworkConfiguration } from '../interfaces' import { BaseEvmNetwork } from './base-evm-network.class' export class EvmNetwork extends BaseEvmNetwork { - public readonly symbol: string - constructor(chainConfiguration: IPureEvmNetworkConfiguration) { try { super(chainConfiguration) - this.symbol = chainConfiguration.symbol } catch (err) { console.error(err) throw new Error('Failed to construct isc Chain!') diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index 7774f8fa0e..ddfe4f0508 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -13,13 +13,14 @@ export class IscChain extends BaseEvmNetwork { constructor(chainConfiguration: IIscChainConfiguration) { try { const { rpcEndpoint, aliasAddress, apiEndpoint } = chainConfiguration - const _rpcEndpoint = `${rpcEndpoint}/v1/chains/${aliasAddress}/evm` + const _rpcEndpoint = new URL(`v1/chains/${aliasAddress}/evm`, rpcEndpoint).href + super({ ...chainConfiguration, rpcEndpoint: _rpcEndpoint }) this.aliasAddress = aliasAddress this.apiEndpoint = apiEndpoint - this._chainApi = `${apiEndpoint}v1/chains/${aliasAddress}` + this._chainApi = new URL(`v1/chains/${aliasAddress}`, apiEndpoint).href } catch (err) { console.error(err) throw new Error('Failed to construct isc Chain!') diff --git a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts index 66e1e9ed55..535dcb5a26 100644 --- a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts @@ -3,7 +3,7 @@ import { IBaseToken } from '@core/token/interfaces' import { NetworkId } from '../types' import { SupportedNetworkId } from './supported-network-id.constant' -const DEFAULT_IOTA_BASE_TOKEN: IBaseToken = { +const IOTA_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, name: 'IOTA', tickerSymbol: 'IOTA', @@ -13,7 +13,7 @@ const DEFAULT_IOTA_BASE_TOKEN: IBaseToken = { useMetricPrefix: false, } -const DEFAULT_SHIMMER_BASE_TOKEN: IBaseToken = { +export const SHIMMER_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, name: 'Shimmer', tickerSymbol: 'SMR', @@ -23,20 +23,20 @@ const DEFAULT_SHIMMER_BASE_TOKEN: IBaseToken = { useMetricPrefix: false, } -const DEFAULT_TESTNET_BASE_TOKEN: IBaseToken = { +export const EVM_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, - name: 'Shimmer', - tickerSymbol: 'SMR', - unit: 'SMR', - decimals: 6, - subunit: 'glow', - useMetricPrefix: false, + name: 'Ether', + tickerSymbol: 'ETH', + unit: 'ETH', + decimals: 18, } export const DEFAULT_BASE_TOKEN: Readonly<{ [id in NetworkId]?: IBaseToken }> = { - [SupportedNetworkId.Iota]: DEFAULT_IOTA_BASE_TOKEN, - [SupportedNetworkId.Shimmer]: DEFAULT_SHIMMER_BASE_TOKEN, - [SupportedNetworkId.Testnet]: DEFAULT_TESTNET_BASE_TOKEN, - [SupportedNetworkId.ShimmerEvm]: DEFAULT_SHIMMER_BASE_TOKEN, - [SupportedNetworkId.TestnetEvm]: DEFAULT_TESTNET_BASE_TOKEN, + [SupportedNetworkId.Iota]: IOTA_BASE_TOKEN, + [SupportedNetworkId.Shimmer]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.Testnet]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.ShimmerEvm]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.TestnetEvm]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.Ethereum]: EVM_BASE_TOKEN, + [SupportedNetworkId.Sepolia]: EVM_BASE_TOKEN, } diff --git a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts index 667d08170a..1df6486a9e 100644 --- a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts @@ -1,6 +1,7 @@ import { EvmNetworkType, NetworkNamespace, ChainId } from '../enums' import { IIscChainConfiguration } from '../interfaces' import { StardustNetworkId } from '../types' +import { SHIMMER_BASE_TOKEN } from './default-base-token.constant' import { DEFAULT_COIN_TYPE } from './default-coin-type.constant' import { SupportedIscNetworkId, SupportedNetworkId, SupportedStardustNetworkId } from './supported-network-id.constant' @@ -11,6 +12,7 @@ export const DEFAULT_ISC_CHAINS_CONFIGURATIONS: Readonly<{ [id in StardustNetwor name: 'Shimmer EVM', chainId: ChainId.ShimmerEvm, namespace: NetworkNamespace.Evm, + baseToken: SHIMMER_BASE_TOKEN, coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.ShimmerEvm] ?? 0, aliasAddress: 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', rpcEndpoint: 'https://json-rpc.evm.shimmer.network/', @@ -23,6 +25,7 @@ export const DEFAULT_ISC_CHAINS_CONFIGURATIONS: Readonly<{ [id in StardustNetwor name: 'Testnet EVM', chainId: ChainId.TestnetEvm, namespace: NetworkNamespace.Evm, + baseToken: SHIMMER_BASE_TOKEN, coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.TestnetEvm] ?? 0, aliasAddress: 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', rpcEndpoint: 'https://json-rpc.evm.testnet.shimmer.network/', diff --git a/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts b/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts index df8f1844fd..63add616f2 100644 --- a/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts @@ -4,6 +4,7 @@ import { EvmNetworkId } from '../types' import { DEFAULT_COIN_TYPE } from './default-coin-type.constant' import { SupportedL1EvmNetworkId, SupportedNetworkId } from './supported-network-id.constant' import { DEFAULT_EXPLORER_URLS } from './default-explorer-urls.constant' +import { EVM_BASE_TOKEN } from './default-base-token.constant' export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [key in EvmNetworkId]: IPureEvmNetworkConfiguration @@ -11,8 +12,7 @@ export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [SupportedL1EvmNetworkId.Ethereum]: { type: EvmNetworkType.PureEvm, name: 'Ethereum', - symbol: 'ETH', - ticker: 'ETH', + baseToken: EVM_BASE_TOKEN, id: SupportedL1EvmNetworkId.Ethereum, chainId: ChainId.Ethereum, namespace: NetworkNamespace.Evm, @@ -23,8 +23,7 @@ export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [SupportedL1EvmNetworkId.Sepolia]: { type: EvmNetworkType.PureEvm, name: 'Sepolia Testnet', - symbol: 'ETH', - ticker: 'ETH', + baseToken: EVM_BASE_TOKEN, id: SupportedL1EvmNetworkId.Sepolia, chainId: ChainId.Sepolia, namespace: NetworkNamespace.Evm, diff --git a/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts index ca06979358..af2a84607e 100644 --- a/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts @@ -1,3 +1,4 @@ +import { IBaseToken } from '@core/token' import { Writable } from 'svelte/store' import { NetworkHealth, NetworkNamespace } from '../enums' import { NetworkId } from '../types' @@ -13,5 +14,6 @@ export interface IBaseNetworkMetadata { id: NetworkId namespace: NetworkNamespace name: string + baseToken: IBaseToken coinType: number } diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts index 84a38f3ad8..2559632757 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts @@ -1,6 +1,7 @@ import { CoinType } from '@iota/sdk/out/types' import { EvmNetworkType, NetworkNamespace, ChainId } from '../enums' import { EvmNetworkId } from '../types' +import { IBaseToken } from '@core/token/interfaces' export interface IIscChainConfiguration extends IBaseEvmNetworkConfiguration { type: EvmNetworkType.Isc @@ -10,14 +11,13 @@ export interface IIscChainConfiguration extends IBaseEvmNetworkConfiguration { export interface IPureEvmNetworkConfiguration extends IBaseEvmNetworkConfiguration { type: EvmNetworkType.PureEvm - symbol: string - ticker: string } export interface IBaseEvmNetworkConfiguration { id: EvmNetworkId namespace: NetworkNamespace.Evm chainId: ChainId + baseToken: IBaseToken type: EvmNetworkType coinType: CoinType name: string diff --git a/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts b/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts index 18b6a6664d..3b24d633c0 100644 --- a/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts @@ -1,4 +1,3 @@ -import { IBaseToken } from '@core/token/interfaces' import { IProtocol } from './protocol.interface' import { StardustNetworkId } from '../types' import { NetworkNamespace } from '../enums' @@ -13,6 +12,5 @@ export interface IStardustNetworkMetadata extends IBaseNetworkMetadata { id: StardustNetworkId namespace: NetworkNamespace.Stardust protocol: IProtocol - baseToken: IBaseToken chainConfigurations: IIscChainConfiguration[] } diff --git a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts index 5bcf7808e5..44870af492 100644 --- a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts +++ b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts @@ -17,7 +17,7 @@ import { import { profileManager } from '@core/profile-manager/stores' import { buildProfileManagerOptionsFromProfileData } from '@core/profile-manager/utils' import { routerManager } from '@core/router/stores' -import { refreshAccountTokensForActiveProfile } from '@core/token/actions' +import { loadTokensForAllAccountBalances } from '@core/token/actions' import { SECONDS_PER_MINUTE } from '@core/utils' import { get } from 'svelte/store' import { ProfileType } from '../../enums' @@ -75,7 +75,7 @@ export async function login(loginOptions?: ILoginOptions): Promise { // Step 4: load assets incrementLoginProgress() - await refreshAccountTokensForActiveProfile(_activeProfile.forceAssetRefresh, _activeProfile.forceAssetRefresh) + await loadTokensForAllAccountBalances(_activeProfile.forceAssetRefresh, _activeProfile.forceAssetRefresh) updateActiveProfile({ forceAssetRefresh: false }) await loadNftsForActiveProfile() // checkAndRemoveProfilePicture() diff --git a/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts b/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts index 15b74f935d..5213e73b0e 100644 --- a/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts +++ b/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts @@ -1,7 +1,7 @@ import { AppStage } from '@core/app/enums' export const PROFILE_VERSION: Record = { - [AppStage.ALPHA]: 16, + [AppStage.ALPHA]: 17, [AppStage.BETA]: 1, [AppStage.PROD]: 9, } diff --git a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts index 0652080dbe..e892bb3820 100644 --- a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts +++ b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts @@ -15,6 +15,5 @@ export function alphaProfileMigration15To16(existingProfile: unknown): Promise { + const profile = existingProfile as IPersistedProfile + + profile.evmNetworks = (profile.evmNetworks ?? []).map((evmNetwork) => ({ + ...evmNetwork, + baseToken: DEFAULT_BASE_TOKEN[evmNetwork.id] as IBaseToken, + })) + + const updatedChainConfiguration = (profile.network.chainConfigurations ?? []).map((chain) => ({ + ...chain, + baseToken: DEFAULT_BASE_TOKEN[chain.id] as IBaseToken, + })) + + profile.network = { ...profile.network, chainConfigurations: updatedChainConfiguration } + + persistedTokens.update((state) => { + delete state[profile.id] + return state + }) + return Promise.resolve() +} diff --git a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts index c33fa5f827..07e061c84a 100644 --- a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts +++ b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts @@ -7,6 +7,7 @@ import { alphaProfileMigration12To13 } from './alpha-profile-migration-12-to-13' import { alphaProfileMigration13To14 } from './alpha-profile-migration-13-to-14' import { alphaProfileMigration14To15 } from './alpha-profile-migration-14-to-15' import { alphaProfileMigration15To16 } from './alpha-profile-migration-15-to-16' +import { alphaProfileMigration16To17 } from './alpha-profile-migration-16-to-17' import { alphaProfileMigration2To3 } from './alpha-profile-migration-2-to-3' import { alphaProfileMigration3To4 } from './alpha-profile-migration-3-to-4' import { alphaProfileMigration4To5 } from './alpha-profile-migration-4-to-5' @@ -33,4 +34,5 @@ export const ALPHA_PROFILE_MIGRATION_MAP: ProfileMigrationMap = { 13: alphaProfileMigration13To14, 14: alphaProfileMigration14To15, 15: alphaProfileMigration15To16, + 16: alphaProfileMigration16To17, } diff --git a/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts b/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts index 47542982e6..eb69df554d 100644 --- a/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts +++ b/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts @@ -1,6 +1,9 @@ import { DappVerification } from '@auxiliary/wallet-connect/enums' import { persistDapp, persistedDappNamespaces } from '@auxiliary/wallet-connect/stores' +import { DEFAULT_BASE_TOKEN } from '@core/network/constants' import { IPersistedProfile } from '@core/profile/interfaces' +import { IBaseToken } from '@core/token/interfaces' +import { persistedTokens } from '@core/token/stores' import { get } from 'svelte/store' export function prodProfileMigration8To9(existingProfile: unknown): Promise { @@ -16,5 +19,14 @@ export function prodProfileMigration8To9(existingProfile: unknown): Promise ({ + ...evmNetwork, + baseToken: DEFAULT_BASE_TOKEN[evmNetwork.id] as IBaseToken, + })) + + persistedTokens.update((state) => { + delete state[profile.id] + return state + }) return Promise.resolve() } diff --git a/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts b/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts index 5c7c4cac2b..84202f4846 100644 --- a/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts +++ b/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts @@ -44,7 +44,7 @@ function getAccountAssetForNetwork( marketCurrency: MarketCurrency, networkId: StardustNetworkId ): IAccountTokensPerNetwork { - const persistedBaseCoin = getPersistedToken(BASE_TOKEN_ID) + const persistedBaseCoin = getPersistedToken(networkId, BASE_TOKEN_ID) const baseCoinMarketPrices = marketCoinPrices?.[persistedBaseCoin.metadata?.name?.toLowerCase() ?? ''] const baseCoinMarketPrice = String(baseCoinMarketPrices?.[marketCurrency]) const baseCoinTotal = account?.balances?.baseCoin?.total @@ -67,7 +67,7 @@ function getAccountAssetForNetwork( const nativeTokens: ITokenWithBalance[] = [] const tokens = account?.balances?.nativeTokens ?? [] for (const token of tokens) { - const persistedAsset = getPersistedToken(token.tokenId) + const persistedAsset = getPersistedToken(networkId, token.tokenId) if (persistedAsset && persistedAsset?.metadata && isValidIrc30Token(persistedAsset.metadata)) { nativeTokens.push({ ...persistedAsset, @@ -92,7 +92,7 @@ function getAccountAssetForChain( marketCurrency: MarketCurrency, networkId: EvmNetworkId ): IAccountTokensPerNetwork | undefined { - const persistedBaseCoin = getPersistedToken(BASE_TOKEN_ID) // we use the L1 coin type for now because we assume that the basecoin for L2 is SMR + const persistedBaseCoin = getPersistedToken(networkId, BASE_TOKEN_ID) const baseCoinMarketPrices = marketCoinPrices?.[persistedBaseCoin.metadata?.name?.toLowerCase() ?? ''] let baseCoin = createTokenWithBalanceFromPersistedAsset( persistedBaseCoin, @@ -119,7 +119,7 @@ function getAccountAssetForChain( networkId ) } else { - const persistedAsset = getPersistedToken(tokenId) + const persistedAsset = getPersistedToken(networkId, tokenId) if (persistedAsset && persistedAsset?.metadata && isValidToken(persistedAsset.metadata)) { const assetMarketPrices = marketCoinPrices?.[get(shimmerEvmAddressToCoinGeckoIdMap)?.[tokenId]] const nativeToken = createTokenWithBalanceFromPersistedAsset( diff --git a/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts b/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts index c722a0426d..e53ee2c8ed 100644 --- a/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts +++ b/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts @@ -8,13 +8,13 @@ export async function getOrRequestTokenFromPersistedTokens( networkId: NetworkId, persistTokenIfNotPresent = true ): Promise { - const persistedAsset = getPersistedToken(tokenId) + const persistedAsset = getPersistedToken(networkId, tokenId) if (persistedAsset) { return Promise.resolve(persistedAsset) } else { const tokenToPersist = await requestPersistedToken(tokenId, networkId) if (tokenToPersist && persistTokenIfNotPresent) { - addPersistedToken(tokenToPersist) + addPersistedToken(networkId, tokenToPersist) } return tokenToPersist } diff --git a/packages/shared/src/lib/core/token/actions/index.ts b/packages/shared/src/lib/core/token/actions/index.ts index 956ba1ceb3..c873bd05c3 100644 --- a/packages/shared/src/lib/core/token/actions/index.ts +++ b/packages/shared/src/lib/core/token/actions/index.ts @@ -2,6 +2,6 @@ export * from './getAccountTokensForAccount' export * from './getOrRequestTokenFromPersistedTokens' export * from './getTokenBalance' export * from './isVisibleToken' -export * from './refreshAccountTokensForActiveProfile' +export * from './loadTokensForAllAccountBalances' export * from './removeTrackedTokenFromActiveProfile' export * from './requestPersistedToken' diff --git a/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts b/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts new file mode 100644 index 0000000000..6ee02b453c --- /dev/null +++ b/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts @@ -0,0 +1,118 @@ +import { IEvmNetwork, IStardustNetwork, NetworkId, getEvmNetworks, getL1Network } from '@core/network' +import { activeAccounts, activeProfile } from '@core/profile/stores' +import { get } from 'svelte/store' +import { getOrRequestTokenFromPersistedTokens } from '.' +import { BASE_TOKEN_ID } from '../constants' +import { TokenStandard, VerifiedStatus } from '../enums' +import { IPersistedToken } from '../interfaces' +import { + addPersistedToken, + clearPersistedTokensForActiveProfile, + persistedTokens, +} from '../stores/persisted-tokens.store' +import { TokenVerification } from '../types' +import { getLayer2AccountBalance } from '@core/layer-2/stores' + +export async function loadTokensForAllAccountBalances( + clearPersistedAssets = false, + keepVerificationStatus = false +): Promise { + clearPersistedAssets && clearPersistedTokensForActiveProfile() + + const tokens: { [networkId: NetworkId]: IPersistedToken[] } = {} + const l1StardustNetwork = getL1Network() + const stardustTokens = await loadTokensForStardustNetwork(l1StardustNetwork, keepVerificationStatus) + tokens[l1StardustNetwork.id] = stardustTokens + + for (const network of getEvmNetworks()) { + const evmTokens = await loadTokensForEvmNetwork(network, keepVerificationStatus) + tokens[network.id] = evmTokens + } + + for (const [networkId, assets] of Object.entries(tokens)) { + addPersistedToken(networkId as NetworkId, ...assets) + } +} + +async function loadTokensForStardustNetwork( + network: IStardustNetwork, + keepVerificationStatus: boolean +): Promise { + const storedVerificationStates: { [tokenId: string]: TokenVerification } = keepVerificationStatus + ? getPersistedVerificationStatesForNetwork(network.id) + : {} + + const baseCoin: IPersistedToken = { + id: BASE_TOKEN_ID, + standard: TokenStandard.BaseToken, + metadata: network.baseToken, + hidden: false, + verification: { verified: true, status: VerifiedStatus.Official }, + } + + const tokens: IPersistedToken[] = [] + const accounts = get(activeAccounts) + for (const account of accounts) { + const tokenBalances = account?.balances?.nativeTokens ?? [] + for (const tokenBalance of tokenBalances) { + try { + const token = await getOrRequestTokenFromPersistedTokens(tokenBalance.tokenId, network.id, false) + if (token) { + tokens.push({ + ...token, + verification: storedVerificationStates[token.id] ?? token.verification, + }) + } + } catch (err) { + console.error(err) + } + } + } + return [baseCoin, ...tokens] +} + +async function loadTokensForEvmNetwork( + network: IEvmNetwork, + keepVerificationStatus: boolean +): Promise { + const storedVerificationStates: { [tokenId: string]: TokenVerification } = keepVerificationStatus + ? getPersistedVerificationStatesForNetwork(network.id) + : {} + + const baseCoin: IPersistedToken = { + id: BASE_TOKEN_ID, + standard: TokenStandard.BaseToken, + metadata: network.baseToken, + hidden: false, + verification: { verified: true, status: VerifiedStatus.Official }, + } + + const tokens: IPersistedToken[] = [] + const accounts = get(activeAccounts) + for (const account of accounts) { + const tokenBalances = getLayer2AccountBalance(account.index)?.[network.id] ?? {} + for (const tokenId of Object.keys(tokenBalances)) { + try { + const token = await getOrRequestTokenFromPersistedTokens(tokenId, network.id, false) + if (token) { + tokens.push({ + ...token, + verification: storedVerificationStates[token.id] ?? token.verification, + }) + } + } catch (err) { + console.error(err) + } + } + } + return [baseCoin, ...tokens] +} + +function getPersistedVerificationStatesForNetwork(networkId: NetworkId): { [tokenId: string]: TokenVerification } { + const assets = get(persistedTokens)?.[get(activeProfile)?.id]?.[networkId] ?? {} + const verificationStates: { [tokenId: string]: TokenVerification } = {} + for (const [id, asset] of Object.entries(assets)) { + verificationStates[id] = asset.verification + } + return verificationStates +} diff --git a/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts b/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts deleted file mode 100644 index 4e49e1976e..0000000000 --- a/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { getActiveNetworkId } from '@core/network' -import { getBaseToken } from '@core/profile/actions' -import { activeAccounts, activeProfile } from '@core/profile/stores' -import { get } from 'svelte/store' -import { getOrRequestTokenFromPersistedTokens } from '../actions' -import { BASE_TOKEN_ID } from '../constants' -import { TokenStandard, VerifiedStatus } from '../enums' -import { IPersistedToken } from '../interfaces' -import { - addPersistedToken, - clearPersistedTokensForActiveProfile, - persistedTokens, -} from '../stores/persisted-tokens.store' - -export async function refreshAccountTokensForActiveProfile( - clearPersistedAssets = false, - keepVerificationStatus = false -): Promise { - const storedVerificationStates = {} - if (keepVerificationStatus) { - const assets = get(persistedTokens)?.[get(activeProfile)?.id] ?? {} - for (const [id, asset] of Object.entries(assets)) { - storedVerificationStates[id] = asset.verification - } - } - clearPersistedAssets && clearPersistedTokensForActiveProfile() - - const persistedBaseCoin: IPersistedToken = { - id: BASE_TOKEN_ID, - standard: TokenStandard.BaseToken, - metadata: getBaseToken(), - hidden: false, - verification: { verified: true, status: VerifiedStatus.Official }, - } - - const assets: IPersistedToken[] = [] - const accounts = get(activeAccounts) - for (const account of accounts) { - const tokens = account?.balances?.nativeTokens ?? [] - for (const token of tokens) { - try { - const persistedAsset = await getOrRequestTokenFromPersistedTokens( - token.tokenId, - getActiveNetworkId(), - false - ) - if (persistedAsset) { - if (keepVerificationStatus) { - const verificationStatus = storedVerificationStates[persistedAsset.id] - persistedAsset.verification = verificationStatus - } - assets.push(persistedAsset) - } - } catch (err) { - console.error(err) - } - } - } - addPersistedToken(persistedBaseCoin, ...assets) -} diff --git a/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts b/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts index 410ffc4ebe..a1a4eb1ade 100644 --- a/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts +++ b/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts @@ -6,6 +6,6 @@ export type AccountTokens = { } export interface IAccountTokensPerNetwork { - baseCoin: ITokenWithBalance | undefined + baseCoin: ITokenWithBalance nativeTokens: ITokenWithBalance[] } diff --git a/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts b/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts index 90ccd40c0b..e4a8597f3b 100644 --- a/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts +++ b/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts @@ -1,7 +1,10 @@ +import { NetworkId } from '@core/network/types' import { IPersistedToken } from './persisted-token.interface' export interface IPersistedTokens { [profileId: string]: { - [tokenId: string]: IPersistedToken + [networkId: NetworkId]: { + [tokenId: string]: IPersistedToken + } } } diff --git a/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts b/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts index 6897927aeb..022832f07f 100644 --- a/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts +++ b/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts @@ -1,58 +1,53 @@ -import { activeProfileId } from '@core/profile/stores/active-profile-id.store' -import { activeProfile } from '@core/profile/stores/active-profile.store' +import { getActiveProfileId } from '@core/profile/stores/active-profile-id.store' import { persistent } from '@core/utils/store' import { get } from 'svelte/store' import { NotVerifiedStatus, VerifiedStatus } from '../enums' -import { IPersistedToken, IPersistedTokens } from '../interfaces' +import { IPersistedToken, IPersistedTokens, IToken } from '../interfaces' +import { NetworkId } from '@core/network/types' export const persistedTokens = persistent('persistedTokens', {}) -export function getPersistedToken(tokenId: string): IPersistedToken { - return get(persistedTokens)?.[get(activeProfile)?.id]?.[tokenId] +export function getPersistedToken(networkId: NetworkId, tokenId: string): IPersistedToken { + const profileId = getActiveProfileId() + return get(persistedTokens)?.[profileId]?.[networkId]?.[tokenId] } -export function addPersistedToken(...newPersistedTokens: IPersistedToken[]): void { +export function addPersistedToken(networkId: NetworkId, ...newPersistedTokens: IPersistedToken[]): void { + const profileId = getActiveProfileId() persistedTokens.update((state) => { - if (!state[get(activeProfile).id]) { - state[get(activeProfile).id] = {} + if (!state[profileId]) { + state[profileId] = {} + } + if (!state[profileId][networkId]) { + state[profileId][networkId] = {} } for (const token of newPersistedTokens) { - state[get(activeProfile).id][token.id] = token + state[profileId][networkId][token.id] = token } return state }) } export function clearPersistedTokensForActiveProfile(): void { + const profileId = getActiveProfileId() persistedTokens.update((state) => { - state[get(activeProfile).id] = {} + state[profileId] = {} return state }) } -export function updatePersistedToken(partialPersistedToken: Partial): void { +export function updatePersistedToken(networkId: NetworkId, partialPersistedToken: Partial): void { + const profileId = getActiveProfileId() const tokenId = partialPersistedToken?.id - if (tokenId) { - persistedTokens.update((state) => { - state[get(activeProfile).id][tokenId] = { - ...state[get(activeProfile).id][tokenId], - ...partialPersistedToken, - } + persistedTokens.update((state) => { + if (!tokenId || state[profileId]?.[networkId]?.[tokenId] === undefined) { return state - }) - } -} - -export function removePersistedToken(tokenId: string): void { - const profileId = get(activeProfileId) - if (!profileId) { - return - } - persistedTokens.update((_persistedTokens) => { - if (_persistedTokens?.[profileId]?.[tokenId]) { - delete _persistedTokens[profileId][tokenId] } - return _persistedTokens + state[profileId][networkId][tokenId] = { + ...state[profileId][networkId][tokenId], + ...partialPersistedToken, + } + return state }) } @@ -63,18 +58,18 @@ export function removePersistedTokensForProfile(profileId: string): void { }) } -export function verifyToken(tokenId: string, status: VerifiedStatus): void { - updatePersistedToken({ id: tokenId, verification: { verified: true, status } }) +export function verifyToken(token: IToken, status: VerifiedStatus): void { + updatePersistedToken(token.networkId, { id: token.id, verification: { verified: true, status } }) } -export function unverifyToken(tokenId: string, status: NotVerifiedStatus): void { - updatePersistedToken({ id: tokenId, verification: { verified: false, status } }) +export function unverifyToken(token: IToken, status: NotVerifiedStatus): void { + updatePersistedToken(token.networkId, { id: token.id, verification: { verified: false, status } }) } -export function hideToken(tokenId: string): void { - updatePersistedToken({ id: tokenId, hidden: true }) +export function hideToken(token: IToken): void { + updatePersistedToken(token.networkId, { id: token.id, hidden: true }) } -export function unhideToken(tokenId: string): void { - updatePersistedToken({ id: tokenId, hidden: false }) +export function unhideToken(token: IToken): void { + updatePersistedToken(token.networkId, { id: token.id, hidden: false }) } diff --git a/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts b/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts index 2fd27b78d4..6d962981f6 100644 --- a/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts +++ b/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts @@ -78,11 +78,14 @@ export const visibleSelectedAccountTokens: Readable = derived( const visibleTokens: AccountTokens = {} for (const _networkId of Object.keys($selectedAccountTokens)) { const networkId = _networkId as NetworkId - const visible: IAccountTokensPerNetwork = { - baseCoin: $selectedAccountTokens[networkId]?.baseCoin, - nativeTokens: $selectedAccountTokens[networkId]?.nativeTokens.filter((asset) => !asset.hidden) ?? [], + const tokens = $selectedAccountTokens[networkId] + if (tokens) { + const visible: IAccountTokensPerNetwork = { + baseCoin: tokens.baseCoin, + nativeTokens: tokens.nativeTokens.filter((asset) => !asset.hidden) ?? [], + } + visibleTokens[networkId] = visible } - visibleTokens[networkId] = visible } return visibleTokens } @@ -101,7 +104,7 @@ export function getTokenFromSelectedAccountTokens( if (token) { return token } else { - const persistedToken = getPersistedToken(tokenId) + const persistedToken = getPersistedToken(networkId, tokenId) return persistedToken ? { ...persistedToken, diff --git a/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts b/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts index 01a933e5be..16cb84ce44 100644 --- a/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts +++ b/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts @@ -22,7 +22,7 @@ export function addNewTrackedTokenToActiveProfile( trackedTokens[tokenAddress] = tokenTrackingStatus profile.trackedTokens = { ...trackedTokensOnProfile, [networkId]: trackedTokens } - updatePersistedToken(buildPersistedTokenFromMetadata(tokenAddress, tokenMetadata)) + updatePersistedToken(networkId, buildPersistedTokenFromMetadata(tokenAddress, tokenMetadata)) updateActiveProfile(profile) } } diff --git a/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts b/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts index 26c38f537a..25f83d2a1d 100644 --- a/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts +++ b/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts @@ -37,7 +37,7 @@ export async function mintNativeToken( verified: true, status: VerifiedStatus.SelfVerified, }) - addPersistedToken(persistedAsset) + addPersistedToken(networkId, persistedAsset) await processAndAddToActivities(transaction, account, networkId) From c898e89e8dcffa2bb8b8db5d501599a2e0f1852e Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Tue, 30 Apr 2024 09:29:39 -0300 Subject: [PATCH 08/11] feat: creates CollectionsGallery and CollectionsGalleryItem (#2395) * feat: creates CollectionsGallery and CollectionsGalleryItem * enhancement: NftGalleryItem * refactor: removes duplicated css * fix: stack border radius * fix: change NFT count Pill's color * fix: placeholder width --------- Co-authored-by: Mark Nardi --- .../components/CollectionsGallery.svelte | 63 ++++++++++ .../components/CollectionsGalleryItem.svelte | 78 +++++++++++++ .../collectibles/components/index.ts | 1 + .../views/CollectionsGalleryView.svelte | 7 +- .../molecules/NftGalleryItem.svelte | 109 ++++++++---------- packages/shared/src/locales/en.json | 1 + 6 files changed, 193 insertions(+), 66 deletions(-) create mode 100644 packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte create mode 100644 packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte new file mode 100644 index 0000000000..7722ef0aa8 --- /dev/null +++ b/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte @@ -0,0 +1,63 @@ + + + +
+ {#each item as collection} + {#if collection} + + {:else} +
+ {/if} + {/each} +
+ diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte new file mode 100644 index 0000000000..816018a68a --- /dev/null +++ b/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte @@ -0,0 +1,78 @@ + + + + + diff --git a/packages/desktop/views/dashboard/collectibles/components/index.ts b/packages/desktop/views/dashboard/collectibles/components/index.ts index cb1cd98401..9dfe83c31e 100644 --- a/packages/desktop/views/dashboard/collectibles/components/index.ts +++ b/packages/desktop/views/dashboard/collectibles/components/index.ts @@ -1,3 +1,4 @@ export { default as CollectiblesTabs } from './CollectiblesTabs.svelte' +export { default as CollectionsGallery } from './CollectionsGallery.svelte' export { default as Erc721CollectibleDetails } from './Erc721CollectibleDetails.svelte' export { default as Irc27CollectibleDetails } from './Irc27CollectibleDetails.svelte' diff --git a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte index 28f84f689d..068bde93a3 100644 --- a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte +++ b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte @@ -5,7 +5,7 @@ import { PopupId, openPopup } from '@desktop/auxiliary/popup' import features from '@features/features' import { SearchInput } from '@ui' - import { CollectiblesTabs } from '../components' + import { CollectiblesTabs, CollectionsGallery } from '../components' import { collectionsSearchTerm, selectedAccountCollections } from '@core/nfts/stores' import { Collections, isVisibleCollection } from '@core/nfts' @@ -48,10 +48,7 @@ {#if hasCollections} {#if Object.keys(queriedCollections).length > 0} - - {#each Object.keys(queriedCollections) as collection} - {queriedCollections[collection].name} - {/each} + {:else}
- diff --git a/packages/shared/src/locales/en.json b/packages/shared/src/locales/en.json index 087735e3be..24576b9ee4 100644 --- a/packages/shared/src/locales/en.json +++ b/packages/shared/src/locales/en.json @@ -1637,6 +1637,7 @@ "token": "Token", "unknownToken": "Unknown Token", "nft": "NFT", + "nfts": "{count, plural, one {# NFT} other {# NFTs}}", "type": "Type", "immutableIssuer": "Immutable Issuer", "magicContract": "Magic Contract", From 2fd36c0dec78bc6094872bb587eebd0926806f75 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Tue, 30 Apr 2024 09:47:50 -0300 Subject: [PATCH 09/11] feat: adds CollectionDetails (#2396) * feat: creates CollectionsGallery and CollectionsGalleryItem * enhancement: NftGalleryItem * refactor: removes duplicated css * fix: stack border radius * fix: change NFT count Pill's color * feat: adds CollectionDetails * fix: code cleanup --- .../components/CollectionDetails.svelte | 14 ++++++++++ .../components/CollectionsGallery.svelte | 4 ++- .../components/CollectionsGalleryItem.svelte | 7 +++-- .../collectibles/components/index.ts | 1 + .../views/CollectiblesDetailsView.svelte | 28 ++++++++++++------- .../dashboard/components/Breadcrumbs.svelte | 3 +- .../molecules/NftGalleryItem.svelte | 3 +- .../nfts/interfaces/collection.interface.ts | 1 + .../shared/src/lib/core/nfts/stores/index.ts | 1 + .../nfts/stores/selected-collection.store.ts | 3 ++ .../router/routers/collectibles-router.ts | 2 ++ 11 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 packages/desktop/views/dashboard/collectibles/components/CollectionDetails.svelte create mode 100644 packages/shared/src/lib/core/nfts/stores/selected-collection.store.ts diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectionDetails.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectionDetails.svelte new file mode 100644 index 0000000000..9fd3dede80 --- /dev/null +++ b/packages/desktop/views/dashboard/collectibles/components/CollectionDetails.svelte @@ -0,0 +1,14 @@ + + + diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte index 7722ef0aa8..cdd80a5671 100644 --- a/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte +++ b/packages/desktop/views/dashboard/collectibles/components/CollectionsGallery.svelte @@ -6,7 +6,9 @@ export let collections: Collections - $: collectionsArray = Object.values(collections) + $: collectionsArray = Object.entries(collections).map(([id, collection]) => { + return { id, ...collection } + }) const COLLECTIONS_PER_CHUNK_FOR_SCREEN_SIZE = { sm: 2, diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte index 816018a68a..f3e5fa3cf0 100644 --- a/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte +++ b/packages/desktop/views/dashboard/collectibles/components/CollectionsGalleryItem.svelte @@ -2,13 +2,16 @@ import { Collection } from '@core/nfts' import { AssetPillsForNft, MediaPlaceholder, NetworkAvatar, NftMedia } from '@ui' import { Pill, Text } from '@bloomwalletio/ui' - import { downloadingNftId } from '@core/nfts/stores' + import { downloadingNftId, selectedCollectionId } from '@core/nfts/stores' import { localize } from '@core/i18n' + import { CollectiblesRoute, collectiblesRouter } from '@core/router' export let collection: Collection function onCollectionClick(): void { - return + $selectedCollectionId = collection.id + $collectiblesRouter?.goTo(CollectiblesRoute.Details) + $collectiblesRouter?.setBreadcrumb(collection.name) } diff --git a/packages/desktop/views/dashboard/collectibles/components/index.ts b/packages/desktop/views/dashboard/collectibles/components/index.ts index 9dfe83c31e..af0c61c694 100644 --- a/packages/desktop/views/dashboard/collectibles/components/index.ts +++ b/packages/desktop/views/dashboard/collectibles/components/index.ts @@ -1,4 +1,5 @@ export { default as CollectiblesTabs } from './CollectiblesTabs.svelte' +export { default as CollectionDetails } from './CollectionDetails.svelte' export { default as CollectionsGallery } from './CollectionsGallery.svelte' export { default as Erc721CollectibleDetails } from './Erc721CollectibleDetails.svelte' export { default as Irc27CollectibleDetails } from './Irc27CollectibleDetails.svelte' diff --git a/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte b/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte index 45aaa4643b..a229d8dd67 100644 --- a/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte +++ b/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte @@ -1,21 +1,25 @@ - - {#if nft?.standard === NftStandard.Irc27} - - {:else if nft?.standard === NftStandard.Erc721} - - {/if} - +{#if collection} + +{:else} + + {#if nft?.standard === NftStandard.Irc27} + + {:else if nft?.standard === NftStandard.Erc721} + + {/if} + +{/if} diff --git a/packages/desktop/views/dashboard/components/Breadcrumbs.svelte b/packages/desktop/views/dashboard/components/Breadcrumbs.svelte index dc23e2fec8..ca23898239 100644 --- a/packages/desktop/views/dashboard/components/Breadcrumbs.svelte +++ b/packages/desktop/views/dashboard/components/Breadcrumbs.svelte @@ -6,6 +6,7 @@ CollectiblesRoute, DashboardRoute, GovernanceRoute, + collectiblesBreadcrumb, collectiblesRoute, collectiblesRouter, dashboardRoute, @@ -80,7 +81,7 @@ /> {#if $dashboardRoute === DashboardRoute.Collectibles && $collectiblesRoute !== CollectiblesRoute.Gallery} - + {/if} {#if $dashboardRoute === DashboardRoute.Governance && $governanceRoute !== GovernanceRoute.Proposals} diff --git a/packages/shared/src/components/molecules/NftGalleryItem.svelte b/packages/shared/src/components/molecules/NftGalleryItem.svelte index 0663ea66bc..1c11331963 100644 --- a/packages/shared/src/components/molecules/NftGalleryItem.svelte +++ b/packages/shared/src/components/molecules/NftGalleryItem.svelte @@ -2,7 +2,7 @@ import { Pill, Text, Tooltip, type TextColor } from '@bloomwalletio/ui' import { localize } from '@core/i18n' import { DownloadErrorType, IDownloadMetadata, Nft } from '@core/nfts' - import { downloadingNftId, selectedNftId } from '@core/nfts/stores' + import { downloadingNftId, selectedNftId, selectedCollectionId } from '@core/nfts/stores' import { CollectiblesRoute, collectiblesRouter } from '@core/router' import { MediaPlaceholder, NetworkAvatar, NftMedia } from '@ui' import AssetPillsForNft from '@ui/nfts/AssetPillsForNft.svelte' @@ -19,6 +19,7 @@ : ('brand' as TextColor) function onNftClick(): void { + $selectedCollectionId = undefined $selectedNftId = nft.id $collectiblesRouter?.goTo(CollectiblesRoute.Details) $collectiblesRouter?.setBreadcrumb(nft?.name) diff --git a/packages/shared/src/lib/core/nfts/interfaces/collection.interface.ts b/packages/shared/src/lib/core/nfts/interfaces/collection.interface.ts index 0d392293d2..24aaa2ca8f 100644 --- a/packages/shared/src/lib/core/nfts/interfaces/collection.interface.ts +++ b/packages/shared/src/lib/core/nfts/interfaces/collection.interface.ts @@ -2,6 +2,7 @@ import { NftStandard } from '../enums' import { Nft } from './nft.interface' export interface Collection { + id?: string standard: NftStandard name: string type: string diff --git a/packages/shared/src/lib/core/nfts/stores/index.ts b/packages/shared/src/lib/core/nfts/stores/index.ts index 45c2c513d3..c0b7aa9faf 100644 --- a/packages/shared/src/lib/core/nfts/stores/index.ts +++ b/packages/shared/src/lib/core/nfts/stores/index.ts @@ -6,4 +6,5 @@ export * from './selected-account-collections.store' export * from './persisted-nfts.store' export * from './selected-account-nfts.store' export * from './selected-collectibles-tabs.store' +export * from './selected-collection.store' export * from './selected-nft.store' diff --git a/packages/shared/src/lib/core/nfts/stores/selected-collection.store.ts b/packages/shared/src/lib/core/nfts/stores/selected-collection.store.ts new file mode 100644 index 0000000000..17f55e23bb --- /dev/null +++ b/packages/shared/src/lib/core/nfts/stores/selected-collection.store.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store' + +export const selectedCollectionId = writable(undefined) diff --git a/packages/shared/src/lib/core/router/routers/collectibles-router.ts b/packages/shared/src/lib/core/router/routers/collectibles-router.ts index 0e37bc7b4d..2150121063 100644 --- a/packages/shared/src/lib/core/router/routers/collectibles-router.ts +++ b/packages/shared/src/lib/core/router/routers/collectibles-router.ts @@ -5,6 +5,7 @@ import { CollectiblesRoute } from '../enums' export const collectiblesRouter = writable(undefined) export const collectiblesRoute = writable(undefined) +export const collectiblesBreadcrumb = writable(undefined) export class CollectiblesRouter extends Router { protected breadcrumb: string | undefined @@ -15,6 +16,7 @@ export class CollectiblesRouter extends Router { setBreadcrumb(breadcrumb: string | undefined): void { this.breadcrumb = breadcrumb + collectiblesBreadcrumb.set(breadcrumb) } getBreadcrumb(): string | undefined { From c6f6b5bb2078aceeb764794152fa511ab1ea466c Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Tue, 30 Apr 2024 15:37:19 +0200 Subject: [PATCH 10/11] feat: fetch token balances for evm chains (#2380) * rename L2 to EVM * implement getBalance * check if profileId updated * revert poll interval --------- Co-authored-by: Tuditi <45079109+Tuditi@users.noreply.github.com> --- .../desktop/components/NetworkCard.svelte | 4 +- .../components/menus/TokenListMenu.svelte | 4 +- .../popup/popups/ReceiveAddressPopup.svelte | 6 +- .../components/AccountNetworkSummary.svelte | 4 +- .../account/actions/setSelectedAccount.ts | 4 +- .../actions/tryCreateAdditionalAccount.ts | 4 +- .../actions/fetchEvmBalancesForAccount.ts | 21 ++++++ .../actions/fetchL2BalanceForAccount.ts | 70 ------------------- .../src/lib/core/layer-2/actions/index.ts | 4 +- ...ccount.ts => pollEvmBalancesForAccount.ts} | 8 +-- ...s.ts => fetchEvmBalancesForAllAccounts.ts} | 6 +- .../src/lib/core/layer-2/utils/index.ts | 2 +- .../network/classes/base-evm-network.class.ts | 54 +++++++++++++- .../core/network/classes/isc-chain.class.ts | 19 +++-- .../interfaces/evm-network.interface.ts | 3 + .../profile/actions/active-profile/login.ts | 4 +- 16 files changed, 117 insertions(+), 100 deletions(-) create mode 100644 packages/shared/src/lib/core/layer-2/actions/fetchEvmBalancesForAccount.ts delete mode 100644 packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts rename packages/shared/src/lib/core/layer-2/actions/{pollL2BalanceForAccount.ts => pollEvmBalancesForAccount.ts} (68%) rename packages/shared/src/lib/core/layer-2/utils/{fetchL2BalanceForAllAccounts.ts => fetchEvmBalancesForAllAccounts.ts} (61%) diff --git a/packages/desktop/components/NetworkCard.svelte b/packages/desktop/components/NetworkCard.svelte index 130426b38e..3702067c7a 100644 --- a/packages/desktop/components/NetworkCard.svelte +++ b/packages/desktop/components/NetworkCard.svelte @@ -5,7 +5,7 @@ import { openUrlInBrowser } from '@core/app' import { handleError } from '@core/error/handlers' import { localize } from '@core/i18n' - import { generateAndStoreEvmAddressForAccounts, pollL2BalanceForAccount } from '@core/layer-2/actions' + import { generateAndStoreEvmAddressForAccounts, pollEvmBalancesForAccount } from '@core/layer-2/actions' import { LedgerAppName } from '@core/ledger' import { ExplorerEndpoint, Network, NetworkNamespace, getDefaultExplorerUrl, setSelectedChain } from '@core/network' import { ProfileType } from '@core/profile' @@ -67,7 +67,7 @@ network.coinType, $selectedAccount as IAccountState ) - pollL2BalanceForAccount($activeProfile.id, $selectedAccount as IAccountState) + pollEvmBalancesForAccount($activeProfile.id, $selectedAccount as IAccountState) if ($activeProfile.type === ProfileType.Ledger) { $networkConfigRouter.goTo(NetworkConfigRoute.ConfirmLedgerEvmAddress) } diff --git a/packages/desktop/components/menus/TokenListMenu.svelte b/packages/desktop/components/menus/TokenListMenu.svelte index 8b0611976a..8193c5b511 100644 --- a/packages/desktop/components/menus/TokenListMenu.svelte +++ b/packages/desktop/components/menus/TokenListMenu.svelte @@ -5,12 +5,12 @@ import { localize } from '@core/i18n' import { loadTokensForAllAccountBalances } from '@core/token/actions' import { PopupId, closePopup, openPopup } from '../../lib/auxiliary/popup' - import { fetchL2BalanceForAllAccounts } from '@core/layer-2' + import { fetchEvmBalancesForAllAccounts } from '@core/layer-2' let menu: Menu | undefined = undefined function onSyncTokensClick(): void { - fetchL2BalanceForAllAccounts($activeProfileId as string, true) + fetchEvmBalancesForAllAccounts($activeProfileId as string, true) showNotification({ variant: 'success', text: localize('notifications.syncTokens.success'), diff --git a/packages/desktop/components/popup/popups/ReceiveAddressPopup.svelte b/packages/desktop/components/popup/popups/ReceiveAddressPopup.svelte index cf476411c7..6284d743d1 100644 --- a/packages/desktop/components/popup/popups/ReceiveAddressPopup.svelte +++ b/packages/desktop/components/popup/popups/ReceiveAddressPopup.svelte @@ -5,8 +5,8 @@ import { selectedAccount } from '@core/account/stores' import { setClipboard } from '@core/utils' import { getActiveNetworkId, getNetwork, NetworkId, NetworkNamespace } from '@core/network' - import { generateAndStoreEvmAddressForAccounts, pollL2BalanceForAccount } from '@core/layer-2/actions' - import { activeProfile, activeProfileId } from '@core/profile/stores' + import { generateAndStoreEvmAddressForAccounts, pollEvmBalancesForAccount } from '@core/layer-2/actions' + import { activeProfile } from '@core/profile/stores' import { checkActiveProfileAuth } from '@core/profile/actions' import { LedgerAppName } from '@core/ledger' import PopupTemplate from '../PopupTemplate.svelte' @@ -42,7 +42,7 @@ try { await generateAndStoreEvmAddressForAccounts($activeProfile.type, coinType, account) - pollL2BalanceForAccount($activeProfileId as string, account) + pollEvmBalancesForAccount($activeProfile.id, account) updateNetworkNameAndAddress() } catch (error) { handleError(error) diff --git a/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte b/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte index 98cbf4db9b..9e10f5734b 100644 --- a/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte +++ b/packages/desktop/views/dashboard/wallet/panes/account-summary/components/AccountNetworkSummary.svelte @@ -2,7 +2,7 @@ import { AvatarGroup, Copyable, Text } from '@bloomwalletio/ui' import { FormattedBalance } from '@components' import { formatCurrency, localize } from '@core/i18n' - import { generateAndStoreEvmAddressForAccounts, pollL2BalanceForAccount } from '@core/layer-2/actions' + import { generateAndStoreEvmAddressForAccounts, pollEvmBalancesForAccount } from '@core/layer-2/actions' import { LedgerAppName } from '@core/ledger' import { Network, NetworkNamespace, setSelectedChain } from '@core/network' import { MimeType, Nft } from '@core/nfts' @@ -89,7 +89,7 @@ try { await generateAndStoreEvmAddressForAccounts($activeProfile.type, network.coinType, account) - pollL2BalanceForAccount($activeProfile.id, account) + pollEvmBalancesForAccount($activeProfile.id, account) if ($activeProfile.type === ProfileType.Ledger) { setSelectedChain(network) toggleDashboardDrawer({ diff --git a/packages/shared/src/lib/core/account/actions/setSelectedAccount.ts b/packages/shared/src/lib/core/account/actions/setSelectedAccount.ts index ef1b7a0ec7..682366997a 100644 --- a/packages/shared/src/lib/core/account/actions/setSelectedAccount.ts +++ b/packages/shared/src/lib/core/account/actions/setSelectedAccount.ts @@ -1,5 +1,5 @@ import { updateAccountForConnectedDapps } from '@auxiliary/wallet-connect/actions' -import { pollL2BalanceForAccount } from '@core/layer-2/actions/pollL2BalanceForAccount' +import { pollEvmBalancesForAccount } from '@core/layer-2/actions/pollEvmBalancesForAccount' import { activeAccounts, getActiveProfileId, updateActiveProfile } from '@core/profile/stores' import { clearFilters } from '@core/utils' import { resetSendOptionIndex } from '@core/wallet/stores' @@ -14,7 +14,7 @@ export function setSelectedAccount(index: number): void { updateAccountForConnectedDapps(account) updateActiveProfile({ lastUsedAccountIndex: index }) clearFilters() - pollL2BalanceForAccount(activeProfileId, account) + pollEvmBalancesForAccount(activeProfileId, account) resetSendOptionIndex() } else { throw new Error(`Account with ID ${index} cannot be found!`) diff --git a/packages/shared/src/lib/core/account/actions/tryCreateAdditionalAccount.ts b/packages/shared/src/lib/core/account/actions/tryCreateAdditionalAccount.ts index 8e21558ffe..03126be33f 100644 --- a/packages/shared/src/lib/core/account/actions/tryCreateAdditionalAccount.ts +++ b/packages/shared/src/lib/core/account/actions/tryCreateAdditionalAccount.ts @@ -6,7 +6,7 @@ import { createNewAccount } from './createNewAccount' import { setSelectedAccount } from './setSelectedAccount' import { getActiveProfile } from '@core/profile/stores' import { ProfileType } from '@core/profile' -import { generateAndStoreEvmAddressForAccounts, pollL2BalanceForAccount } from '@core/layer-2/actions' +import { generateAndStoreEvmAddressForAccounts, pollEvmBalancesForAccount } from '@core/layer-2/actions' import { getEvmNetworks } from '@core/network/stores' import { IError } from '@core/error/interfaces' @@ -24,7 +24,7 @@ export async function tryCreateAdditionalAccount(alias: string, color: string): const coinType = getEvmNetworks()[0]?.coinType if (coinType !== undefined) { void generateAndStoreEvmAddressForAccounts(activeProfile.type, coinType, account) - void pollL2BalanceForAccount(activeProfile.id, account) + void pollEvmBalancesForAccount(activeProfile.id, account) } } diff --git a/packages/shared/src/lib/core/layer-2/actions/fetchEvmBalancesForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/fetchEvmBalancesForAccount.ts new file mode 100644 index 0000000000..9c5495af6b --- /dev/null +++ b/packages/shared/src/lib/core/layer-2/actions/fetchEvmBalancesForAccount.ts @@ -0,0 +1,21 @@ +import { IAccountState } from '@core/account/interfaces' +import { getEvmNetworks } from '@core/network/stores' +import { ITokenBalance } from '@core/token' +import { setLayer2AccountBalanceForChain } from '@core/layer-2/stores' +import { activeProfileId } from '@core/profile/stores' +import { get } from 'svelte/store' + +export function fetchEvmBalancesForAccount(profileId: string, account: IAccountState): void { + const evmNetworks = getEvmNetworks() + evmNetworks.forEach(async (evmNetwork) => { + try { + const tokenBalance: ITokenBalance = (await evmNetwork.getBalance(account)) ?? {} + + if (get(activeProfileId) === profileId) { + setLayer2AccountBalanceForChain(account.index, evmNetwork.id, tokenBalance) + } + } catch (error) { + console.error(error) + } + }) +} diff --git a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts deleted file mode 100644 index 7d6c2a98ec..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { IAccountState } from '@core/account/interfaces' -import { ContractType, fetchIscAssetsForAccount } from '@core/layer-2' -import { IEvmNetwork } from '@core/network/interfaces' -import { getEvmNetworks } from '@core/network/stores' -import { updateErc721NftsOwnership } from '@core/nfts/actions' -import { getActiveProfile } from '@core/profile/stores' -import { getOrRequestTokenFromPersistedTokens } from '@core/token/actions' -import { Converter } from '@core/utils/convert' -import { ITokenBalance, TokenTrackingStatus } from '@core/token' -import features from '@features/features' -import { IError } from '@core/error' -import { isIscChain } from '@core/network/utils/isIscChain' -import { setLayer2AccountBalanceForChain } from '@core/layer-2/stores' - -export function fetchL2BalanceForAccount(profileId: string, account: IAccountState): void { - const { evmAddresses, index } = account - const evmNetworks = getEvmNetworks() - evmNetworks.forEach(async (evmNetwork) => { - const { coinType, id: networkId } = evmNetwork - const evmAddress = evmAddresses?.[coinType] - if (!evmAddress) { - return - } - - if (features.collectibles.erc721.enabled) { - void updateErc721NftsOwnership(account, evmNetwork.id) - } - - try { - const l2TokenBalance = isIscChain(evmNetwork) - ? await fetchIscAssetsForAccount(profileId, evmAddress, evmNetwork, account) - : {} - - const erc20Balances = await getErc20BalancesForAddress(evmAddress, evmNetwork) - for (const [tokenId, balance] of Object.entries(erc20Balances)) { - await getOrRequestTokenFromPersistedTokens(tokenId, networkId) - l2TokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance - } - setLayer2AccountBalanceForChain(index, networkId, l2TokenBalance) - } catch (error) { - console.error(error) - } - }) -} - -async function getErc20BalancesForAddress(evmAddress: string, evmNetwork: IEvmNetwork): Promise { - const networkId = evmNetwork.id - const coinType = evmNetwork.coinType - - const trackedTokens = getActiveProfile()?.trackedTokens?.[networkId] ?? {} - const erc20TokenBalances: ITokenBalance = {} - for (const [erc20Address, trackingStatus] of Object.entries(trackedTokens)) { - try { - if (trackingStatus === TokenTrackingStatus.Untracked) { - continue - } - - const contract = evmNetwork?.getContract(ContractType.Erc20, erc20Address) - if (!contract || !coinType) { - continue - } - const rawBalance = await contract.methods.balanceOf(evmAddress).call() - erc20TokenBalances[erc20Address] = Converter.bigIntLikeToBigInt(rawBalance) - } catch (err) { - const error = (err as IError)?.message ?? err - console.error(error) - } - } - return erc20TokenBalances -} diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 3e38a7a390..3c52e199a7 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -2,12 +2,12 @@ export * from './buildUnwrapAssetParameters' export * from './buildUnwrapAssetTargetAddress' export * from './canAccountMakeEvmTransaction' export * from './checkForUntrackedTokens' -export * from './fetchL2BalanceForAccount' +export * from './fetchEvmBalancesForAccount' export * from './getGasFeeForLayer1ToLayer2Transaction' export * from './generateAndStoreEvmAddressForAccounts' export * from './getIscTransferSmartContractData' export * from './getLayer2MetadataForTransfer' export * from './getLayer2NetworkFromAddress' export * from './getNetworkFromAddress' -export * from './pollL2BalanceForAccount' +export * from './pollEvmBalancesForAccount' export * from './setGasFee' diff --git a/packages/shared/src/lib/core/layer-2/actions/pollL2BalanceForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmBalancesForAccount.ts similarity index 68% rename from packages/shared/src/lib/core/layer-2/actions/pollL2BalanceForAccount.ts rename to packages/shared/src/lib/core/layer-2/actions/pollEvmBalancesForAccount.ts index a1b24e38be..4e6b783924 100644 --- a/packages/shared/src/lib/core/layer-2/actions/pollL2BalanceForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/actions/pollEvmBalancesForAccount.ts @@ -1,19 +1,19 @@ import { IAccountState } from '@core/account/interfaces' import { checkForUntrackedNfts } from '@core/nfts/actions' import { LAYER2_TOKENS_POLL_INTERVAL } from '../constants' -import { checkForUntrackedTokens, fetchL2BalanceForAccount } from '.' +import { checkForUntrackedTokens, fetchEvmBalancesForAccount } from '.' import { handleError } from '@core/error/handlers' let pollInterval: number -export function pollL2BalanceForAccount(profileId: string, account: IAccountState): void { +export function pollEvmBalancesForAccount(profileId: string, account: IAccountState): void { try { clearL2TokensPoll() checkForUntrackedTokens(account) void checkForUntrackedNfts(account) - fetchL2BalanceForAccount(profileId, account) + fetchEvmBalancesForAccount(profileId, account) pollInterval = window.setInterval(() => { - fetchL2BalanceForAccount(profileId, account) + fetchEvmBalancesForAccount(profileId, account) }, LAYER2_TOKENS_POLL_INTERVAL) } catch (err) { handleError(err) diff --git a/packages/shared/src/lib/core/layer-2/utils/fetchL2BalanceForAllAccounts.ts b/packages/shared/src/lib/core/layer-2/utils/fetchEvmBalancesForAllAccounts.ts similarity index 61% rename from packages/shared/src/lib/core/layer-2/utils/fetchL2BalanceForAllAccounts.ts rename to packages/shared/src/lib/core/layer-2/utils/fetchEvmBalancesForAllAccounts.ts index 044b7ddf7b..910d4a31d1 100644 --- a/packages/shared/src/lib/core/layer-2/utils/fetchL2BalanceForAllAccounts.ts +++ b/packages/shared/src/lib/core/layer-2/utils/fetchEvmBalancesForAllAccounts.ts @@ -1,14 +1,14 @@ import { get } from 'svelte/store' import { activeAccounts } from '@core/profile/stores' -import { checkForUntrackedTokens, fetchL2BalanceForAccount } from '../actions' +import { checkForUntrackedTokens, fetchEvmBalancesForAccount } from '../actions' import { checkForUntrackedNfts } from '@core/nfts/actions' -export function fetchL2BalanceForAllAccounts(profileId: string, addPreviouslyUntracked?: boolean): void { +export function fetchEvmBalancesForAllAccounts(profileId: string, addPreviouslyUntracked?: boolean): void { for (const account of get(activeAccounts)) { try { checkForUntrackedTokens(account, addPreviouslyUntracked) void checkForUntrackedNfts(account) - fetchL2BalanceForAccount(profileId, account) + fetchEvmBalancesForAccount(profileId, account) } catch (err) { console.error(err) } diff --git a/packages/shared/src/lib/core/layer-2/utils/index.ts b/packages/shared/src/lib/core/layer-2/utils/index.ts index c5a51f1934..6452d3c848 100644 --- a/packages/shared/src/lib/core/layer-2/utils/index.ts +++ b/packages/shared/src/lib/core/layer-2/utils/index.ts @@ -5,7 +5,7 @@ export * from './buildEvmTransactionDataForToken' export * from './calculateEstimatedGasFeeFromTransactionData' export * from './calculateMaxGasFeeFromTransactionData' export * from './fetchIscAssetsForAccount' -export * from './fetchL2BalanceForAllAccounts' +export * from './fetchEvmBalancesForAllAccounts' export * from './getAmountFromEvmTransactionValue' export * from './getEvmTokenMetadata' export * from './getErc20TransferSmartContractData' diff --git a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts index ce3ba22361..6915c9068b 100644 --- a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts @@ -10,8 +10,15 @@ import { EvmNetworkType, NetworkHealth, NetworkNamespace, ChainId } from '../enu import { IBlock, IEvmNetwork, IBaseEvmNetworkConfiguration } from '../interfaces' import { CoinType } from '@iota/sdk/out/types' import { EvmNetworkId, Web3Provider } from '../types' -import { IBaseToken } from '@core/token' import { NETWORK_STATUS_POLL_INTERVAL } from '@core/network/constants' +import { BASE_TOKEN_ID, IBaseToken, ITokenBalance, TokenTrackingStatus } from '@core/token' +import features from '@features/features' +import { updateErc721NftsOwnership } from '@core/nfts/actions' +import { getOrRequestTokenFromPersistedTokens } from '@core/token/actions' +import { IAccountState } from '@core/account' +import { Converter } from '@core/utils' +import { getActiveProfile } from '@core/profile/stores' +import { IError } from '@core/error/interfaces' export class BaseEvmNetwork implements IEvmNetwork { public readonly provider: Web3Provider @@ -94,4 +101,49 @@ export class BaseEvmNetwork implements IEvmNetwork { const number = await this.provider.eth.getBlockNumber() return this.provider.eth.getBlock(number) } + + async getBalance(account: IAccountState): Promise { + const evmAddress = account.evmAddresses?.[this.coinType] + if (!evmAddress) { + return + } + + if (features.collectibles.erc721.enabled) { + void updateErc721NftsOwnership(account, this.id) + } + + const rawBalance = await this.provider.eth.getBalance(evmAddress) + const tokenBalance = { [BASE_TOKEN_ID]: Converter.bigIntLikeToBigInt(rawBalance) } + + const erc20Balances = await this.getErc20BalancesForAddress(evmAddress) + for (const [tokenId, balance] of Object.entries(erc20Balances)) { + await getOrRequestTokenFromPersistedTokens(tokenId, this.id) + tokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance + } + + return tokenBalance + } + + async getErc20BalancesForAddress(evmAddress: string): Promise { + const trackedTokens = getActiveProfile()?.trackedTokens?.[this.id] ?? {} + const erc20TokenBalances: ITokenBalance = {} + for (const [erc20Address, trackingStatus] of Object.entries(trackedTokens)) { + try { + if (trackingStatus === TokenTrackingStatus.Untracked) { + continue + } + + const contract = this.getContract(ContractType.Erc20, erc20Address) + if (!contract || !this.coinType) { + continue + } + const rawBalance = await contract.methods.balanceOf(evmAddress).call() + erc20TokenBalances[erc20Address] = Converter.bigIntLikeToBigInt(rawBalance) + } catch (err) { + const error = (err as IError)?.message ?? err + console.error(error) + } + } + return erc20TokenBalances + } } diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index ddfe4f0508..0fa6b2fb4b 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -1,6 +1,10 @@ -import { IBlock, IIscChainConfiguration, IIscChainMetadata } from '../interfaces' +import { IIscChainConfiguration, IIscChainMetadata } from '../interfaces' import { Converter } from '@core/utils' import { BaseEvmNetwork } from './base-evm-network.class' +import { IAccountState } from '@core/account/interfaces' +import { ITokenBalance } from '@core/token/interfaces' +import { fetchIscAssetsForAccount } from '@core/layer-2/utils' +import { getActiveProfileId } from '@core/profile/stores' export class IscChain extends BaseEvmNetwork { private readonly _chainApi: string @@ -47,9 +51,16 @@ export class IscChain extends BaseEvmNetwork { return (await response.json()) as IIscChainMetadata } - async getLatestBlock(): Promise { - const number = await this.provider.eth.getBlockNumber() - return this.provider.eth.getBlock(number) + async getBalance(account: IAccountState): Promise { + const evmAddress = account.evmAddresses?.[this.coinType] + if (!evmAddress) { + return undefined + } + + const tokenBalance = (await super.getBalance(account)) ?? {} + const iscBalance = (await fetchIscAssetsForAccount(getActiveProfileId(), evmAddress, this, account)) ?? {} + + return { ...tokenBalance, ...iscBalance } } async getGasEstimate(hex: string): Promise { diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts index 28c71ccf55..56bb333f0f 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts @@ -6,6 +6,8 @@ import { EvmNetworkId, Web3Provider } from '../types' import { IBlock } from './block.interface' import { IBaseNetwork, IBaseNetworkMetadata } from './base-network.interface' import { IIscChainMetadata } from './isc-chain-metadata.interface' +import { ITokenBalance } from '@core/token/interfaces' +import { IAccountState } from '@core/account/interfaces' export interface IIscChain extends IEvmNetwork { apiEndpoint: string @@ -26,6 +28,7 @@ export interface IEvmNetwork extends IBaseNetwork, IBaseNetworkMetadata { provider: Web3Provider getGasPrice(): Promise + getBalance(account: IAccountState): Promise getContract(type: ContractType, address: string): Contract getLatestBlock(): Promise diff --git a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts index 44870af492..2aae66ebb8 100644 --- a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts +++ b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts @@ -4,7 +4,7 @@ import { generateAndStoreActivitiesForAllAccounts } from '@core/activity/actions import { Platform } from '@core/app/classes' import { AppContext } from '@core/app/enums' import { handleError } from '@core/error/handlers' -import { fetchL2BalanceForAllAccounts } from '@core/layer-2/utils' +import { fetchEvmBalancesForAllAccounts } from '@core/layer-2/utils' import { pollLedgerDeviceState } from '@core/ledger/actions' import { pollMarketPrices } from '@core/market/actions' import { loadNftsForActiveProfile } from '@core/nfts/actions' @@ -103,7 +103,7 @@ export async function login(loginOptions?: ILoginOptions): Promise { incrementLoginProgress() subscribeToWalletApiEventsForActiveProfile() await startBackgroundSync({ syncIncomingTransactions: true }) - fetchL2BalanceForAllAccounts(id) + fetchEvmBalancesForAllAccounts(_activeProfile.id) void fetchAndPersistTransactionsForAccounts(_activeProfile.id, get(activeAccounts)) // Step 8: finish login From 4f5d52015f678a20f2a7ccd2ee45d49f040bc0df Mon Sep 17 00:00:00 2001 From: Tuditi <45079109+Tuditi@users.noreply.github.com> Date: Tue, 30 Apr 2024 17:09:34 +0200 Subject: [PATCH 11/11] chore: refactor evm network type (#2402) * rename L2 to EVM * implement getBalance * chore: rename EvmNetworkType * check if profileId updated * revert poll interval * refactor: simplify network classes inheritance Co-authored-by: Tuditi --------- Co-authored-by: Mark Nardi Co-authored-by: Nicole O'Brien Co-authored-by: Tuditi --- .../views/NetworkInformationDrawer.svelte | 6 +- .../views/components/AddIscChainForm.svelte | 4 +- .../send-flow/views/SelectTokenView.svelte | 1 + .../components/pills/NetworkTypePill.svelte | 8 +- .../layer-2/actions/getNetworkFromAddress.ts | 6 +- .../utils/buildEvmTransactionDataForNft.ts | 6 +- .../utils/buildEvmTransactionDataForToken.ts | 6 +- .../layer-2/utils/fetchIscAssetsForAccount.ts | 10 +- .../network/classes/base-evm-network.class.ts | 149 ------------------ .../core/network/classes/evm-network.class.ts | 146 ++++++++++++++++- .../core/network/classes/isc-chain.class.ts | 26 ++- .../network/classes/stardust-network.class.ts | 7 +- ...ault-isc-chains-configurations.constant.ts | 6 +- ...-l1-evm-network-configurations.constant.ts | 6 +- .../network/enums/evm-network-type.enum.ts | 4 - .../src/lib/core/network/enums/index.ts | 2 +- .../core/network/enums/network-type.enum.ts | 5 + .../interfaces/base-network.interface.ts | 3 +- .../evm-network-configuration.interface.ts | 8 +- .../interfaces/evm-network.interface.ts | 14 +- .../interfaces/stardust-network.interface.ts | 3 +- .../lib/core/network/stores/networks.store.ts | 4 +- .../core/network/types/evm-network.type.ts | 3 + .../src/lib/core/network/types/index.ts | 1 + .../lib/core/network/types/network.type.ts | 4 +- .../src/lib/core/network/utils/index.ts | 1 - .../src/lib/core/network/utils/isIscChain.ts | 7 - .../wallet/types/send-flow-parameter.type.ts | 1 + 28 files changed, 219 insertions(+), 228 deletions(-) delete mode 100644 packages/shared/src/lib/core/network/classes/base-evm-network.class.ts delete mode 100644 packages/shared/src/lib/core/network/enums/evm-network-type.enum.ts create mode 100644 packages/shared/src/lib/core/network/enums/network-type.enum.ts create mode 100644 packages/shared/src/lib/core/network/types/evm-network.type.ts delete mode 100644 packages/shared/src/lib/core/network/utils/isIscChain.ts diff --git a/packages/desktop/views/dashboard/drawers/network-config/views/NetworkInformationDrawer.svelte b/packages/desktop/views/dashboard/drawers/network-config/views/NetworkInformationDrawer.svelte index 3d21699ee9..a0c49aa00f 100644 --- a/packages/desktop/views/dashboard/drawers/network-config/views/NetworkInformationDrawer.svelte +++ b/packages/desktop/views/dashboard/drawers/network-config/views/NetworkInformationDrawer.svelte @@ -1,6 +1,6 @@