diff --git a/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte b/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte index 84a0aa5207..c4a78a43d7 100644 --- a/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte +++ b/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte @@ -14,6 +14,7 @@ import { TokenTrackingStatus } from '@core/token' import { selectedAccount } from '@core/account/stores' import { addOrUpdateNftForAccount } from '@core/nfts/stores' + import { persistAndUpdateCollections } from '@core/nfts/actions' let busy = false @@ -43,6 +44,7 @@ const l2Address = getAddressFromAccountForNetwork(account, networkId) const nft = buildNftFromPersistedErc721Nft(persistedNft, l2Address) addOrUpdateNftForAccount(account.index, nft) + await persistAndUpdateCollections(account.index, [nft]) void addNftsToDownloadQueue([nft]) } diff --git a/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte b/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte index 86e0474adb..80a1e6cb28 100644 --- a/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte +++ b/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte @@ -11,7 +11,7 @@ import { handleError } from '@core/error/handlers' import { EvmNetworkId, NetworkNamespace, getEvmNetwork } from '@core/network' import { buildNftFromPersistedErc721Nft } from '@core/nfts' - import { addNftsToDownloadQueue } from '@core/nfts/actions' + import { addNftsToDownloadQueue, persistAndUpdateCollections } from '@core/nfts/actions' import { persistErc721Nft } from '@core/nfts/actions/persistErc721Nft' import { addOrUpdateNftForAccount, ownedNfts } from '@core/nfts/stores' import { TideApi } from '@core/tide/apis' @@ -80,6 +80,7 @@ const nft = buildNftFromPersistedErc721Nft(persistedNft, accountAddress) void addNftsToDownloadQueue([nft]) addOrUpdateNftForAccount(index, nft) + await persistAndUpdateCollections(index, [nft]) } } catch (_) { // Switching account too swiftly results in an error from persistErc721Nft. diff --git a/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte b/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte index bc3b72f4c9..4809cd5ca4 100644 --- a/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte +++ b/packages/desktop/views/dashboard/collectibles/views/CollectiblesDetailsView.svelte @@ -3,9 +3,9 @@ import { Collection, Nft } from '@core/nfts/interfaces' import { NftStandard } from '@core/nfts/enums' import { + activeProfileCollectionsPerAccount, activeProfileNftsPerAccount, getNftByIdForAccount, - selectedAccountCollections, selectedCollectionId, selectedNftId, } from '@core/nfts/stores' @@ -18,7 +18,9 @@ let nft: Nft | undefined let collection: Collection | undefined $: $activeProfileNftsPerAccount, (nft = getNftByIdForAccount($selectedAccountIndex, $selectedNftId)) - $: collection = $selectedCollectionId ? $selectedAccountCollections[$selectedCollectionId] : undefined + $: collection = $selectedCollectionId + ? $activeProfileCollectionsPerAccount[$selectedAccountIndex][$selectedCollectionId] + : undefined $: returnIfNftWasSent($activeProfileNftsPerAccount[$selectedAccountIndex], $time) diff --git a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte index 068bde93a3..95ebd51c39 100644 --- a/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte +++ b/packages/desktop/views/dashboard/collectibles/views/CollectionsGalleryView.svelte @@ -6,8 +6,9 @@ import features from '@features/features' import { SearchInput } from '@ui' import { CollectiblesTabs, CollectionsGallery } from '../components' - import { collectionsSearchTerm, selectedAccountCollections } from '@core/nfts/stores' + import { activeProfileCollectionsPerAccount, collectionsSearchTerm } from '@core/nfts/stores' import { Collections, isVisibleCollection } from '@core/nfts' + import { selectedAccountIndex } from '@core/account/stores' function onReceiveClick(): void { openPopup({ @@ -17,15 +18,20 @@ let queriedCollections: Collections = {} $: $collectionsSearchTerm, - (queriedCollections = Object.fromEntries( - Object.entries($selectedAccountCollections) - .filter(([, collection]) => isVisibleCollection(collection)) - .sort(([, collection1], [, collection2]) => - collection1?.name.toLowerCase().localeCompare(collection2?.name.toLowerCase()) - ) - )) + (queriedCollections = $activeProfileCollectionsPerAccount[$selectedAccountIndex] + ? Object.fromEntries( + Object.entries($activeProfileCollectionsPerAccount[$selectedAccountIndex]) + .filter(([, collection]) => isVisibleCollection(collection)) + .sort(([, collection1], [, collection2]) => + collection1?.name.toLowerCase().localeCompare(collection2?.name.toLowerCase()) + ) + ) + : {}) - $: hasCollections = Object.keys($selectedAccountCollections).length > 0 + $: selectedAccountCollectionsLength = $activeProfileCollectionsPerAccount[$selectedAccountIndex] + ? Object.keys($activeProfileCollectionsPerAccount[$selectedAccountIndex]).length + : 0 + $: hasCollections = selectedAccountCollectionsLength > 0 @@ -33,7 +39,7 @@
{localize('views.collectibles.collectionsGallery.title')} - {String(Object.keys($selectedAccountCollections).length ?? '')} + {String(selectedAccountCollectionsLength ?? '')}
diff --git a/packages/shared/src/lib/core/activity/utils/outputs/getIssuerFromNftOutput.ts b/packages/shared/src/lib/core/activity/utils/outputs/getIssuerFromNftOutput.ts index 64908ec496..bb081d3c50 100644 --- a/packages/shared/src/lib/core/activity/utils/outputs/getIssuerFromNftOutput.ts +++ b/packages/shared/src/lib/core/activity/utils/outputs/getIssuerFromNftOutput.ts @@ -1,6 +1,6 @@ -import { Address, IssuerFeature, NftOutput, FeatureType } from '@iota/sdk/out/types' +import { IssuerFeature, NftOutput, FeatureType } from '@iota/sdk/out/types' -export function getIssuerFromNftOutput(output: NftOutput): Address { +export function getIssuerFromNftOutput(output: NftOutput): { type: number; nftId?: string; aliasId?: string } { const metadata = output.immutableFeatures?.find((feature) => feature.type === FeatureType.Issuer) as IssuerFeature return metadata?.address } diff --git a/packages/shared/src/lib/core/activity/utils/stardust/generateActivitiesFromBasicOutputs.ts b/packages/shared/src/lib/core/activity/utils/stardust/generateActivitiesFromBasicOutputs.ts index a79b18e0e1..60a2558ee0 100644 --- a/packages/shared/src/lib/core/activity/utils/stardust/generateActivitiesFromBasicOutputs.ts +++ b/packages/shared/src/lib/core/activity/utils/stardust/generateActivitiesFromBasicOutputs.ts @@ -1,5 +1,5 @@ import { IAccountState } from '@core/account' -import { buildNftFromNftOutput } from '@core/nfts/actions' +import { buildNftFromNftOutput, persistAndUpdateCollections } from '@core/nfts/actions' import { IWrappedOutput } from '@core/wallet' import { NftOutput, OutputType } from '@iota/sdk/out/types' import { ActivityAction, ActivityDirection } from '../../enums' @@ -58,6 +58,7 @@ export async function generateActivitiesFromBasicOutputs( ) const nft = buildNftFromNftOutput(wrappedInput, networkId, account.depositAddress, false) addOrUpdateNftForAccount(account.index, nft) + await persistAndUpdateCollections(account.index, [nft]) burnedNftInputs.splice(burnedNftInputIndex, 1) } else if (isSelfTransaction && burnedNativeToken) { diff --git a/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts b/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts index c33552080d..26c5c47ed6 100644 --- a/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/utils/fetchIscAssetsForAccount.ts @@ -5,7 +5,7 @@ import { ContractType } from '@core/layer-2/enums' import { getSmartContractHexName, evmAddressToAgentId, getAgentBalanceParameters } from '@core/layer-2/helpers' import { IscChain } from '@core/network' import { isIrc27Nft, getNftsFromNftIds, Nft } from '@core/nfts' -import { addNftsToDownloadQueue } from '@core/nfts/actions' +import { addNftsToDownloadQueue, persistAndUpdateCollections } from '@core/nfts/actions' import { addOrUpdateNftsForAccount, selectedAccountNfts, updateNftsForAccount } from '@core/nfts/stores' import { BASE_TOKEN_ID, ITokenBalance } from '@core/token' import { getOrRequestTokenFromPersistedTokens } from '@core/token/actions' @@ -82,6 +82,7 @@ async function fetchL2Irc27Nfts( const nfts = await getNftsFromNftIds(newNftIds, networkId) addOrUpdateNftsForAccount(account.index, nfts) + await persistAndUpdateCollections(account.index, nfts) const unspendableNfts = nftsForChain .filter((nft) => !nftIds.some((nftId) => nft.id === nftId)) diff --git a/packages/shared/src/lib/core/nfts/actions/buildNftFromNftOutput.ts b/packages/shared/src/lib/core/nfts/actions/buildNftFromNftOutput.ts index e9a327e701..8eeb8cef56 100644 --- a/packages/shared/src/lib/core/nfts/actions/buildNftFromNftOutput.ts +++ b/packages/shared/src/lib/core/nfts/actions/buildNftFromNftOutput.ts @@ -44,11 +44,13 @@ export function buildNftFromNftOutput( const isScam = persistedNft?.isScam ?? (parsedMetadata ? isScamIrc27Nft(parsedMetadata) : false) const expirationTime = getExpirationDateFromOutput(nftOutput)?.getTime() + const collectionId = issuer?.nftId ?? issuer?.aliasId ?? '' return { standard: NftStandard.Irc27, type: parsedMetadata?.type ?? MimeType.TextPlain, id, + collectionId, nftAddress: address, name: parsedMetadata?.name ?? DEFAULT_NFT_NAME, description: parsedMetadata?.description, diff --git a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts index f13575a7cd..50a2294bfb 100644 --- a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts +++ b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts @@ -14,6 +14,7 @@ import { TokenTrackingStatus } from '@core/token' import { IBlockscoutAsset } from '@auxiliary/blockscout/interfaces' import { BlockscoutApi } from '@auxiliary/blockscout/api' import { addOrUpdateNftForAccount } from '../stores' +import { persistAndUpdateCollections } from './persistAndUpdateCollections' export async function checkForUntrackedNfts(account: IAccountState): Promise { if (!features?.collectibles?.erc721?.enabled) { @@ -70,6 +71,7 @@ async function persistNftsFromExplorerAsset( const nft = buildNftFromPersistedErc721Nft(persistedNft, evmAddress) addOrUpdateNftForAccount(account.index, nft) + await persistAndUpdateCollections(account.index, [nft]) return nft } catch (err) { // If we don't have the tokenId we cannot persist the NFT. ERC-721 contracts should implement diff --git a/packages/shared/src/lib/core/nfts/actions/index.ts b/packages/shared/src/lib/core/nfts/actions/index.ts index 6c161aabf6..5c571ee8c8 100644 --- a/packages/shared/src/lib/core/nfts/actions/index.ts +++ b/packages/shared/src/lib/core/nfts/actions/index.ts @@ -3,6 +3,7 @@ export * from './addNftsToDownloadQueue' export * from './buildNftFromNftOutput' export * from './checkForUntrackedNfts' export * from './downloadNextNftInQueue' +export * from './persistAndUpdateCollections' export * from './getPersistedErc721NftsForNetwork' export * from './interruptNftDownloadAfterTimeout' export * from './isNftPersisted' diff --git a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts index e8e269141f..4e4f45283e 100644 --- a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts +++ b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts @@ -9,6 +9,7 @@ import { Nft } from '../interfaces' import { addNftsToDownloadQueue } from './addNftsToDownloadQueue' import { buildNftFromNftOutput } from './buildNftFromNftOutput' import { setNftsForAccount } from '../stores' +import { persistAndUpdateCollections } from './persistAndUpdateCollections' export async function loadNftsForActiveProfile(): Promise { let nftsToDownload: Nft[] = [] @@ -61,6 +62,7 @@ export async function loadNftsForAccount(account: IAccountState): Promise } } setNftsForAccount(account.index, accountNfts) + await persistAndUpdateCollections(account.index, accountNfts) return accountNfts } diff --git a/packages/shared/src/lib/core/nfts/actions/persistAndUpdateCollections.ts b/packages/shared/src/lib/core/nfts/actions/persistAndUpdateCollections.ts new file mode 100644 index 0000000000..d4bb85ce26 --- /dev/null +++ b/packages/shared/src/lib/core/nfts/actions/persistAndUpdateCollections.ts @@ -0,0 +1,24 @@ +import { get } from 'svelte/store' +import { addCollectionsToPersistedCollections, addNftsToCollection, persistedCollections } from '../stores' +import { Nft } from '../interfaces' +import { buildPersistedCollectionFromNft } from '../utils' +import { Collections } from '../types' + +export async function persistAndUpdateCollections(accountIndex: number, nfts: Nft[]): Promise { + const _persistedCollections = get(persistedCollections) + + const collections: Collections = {} + for (const nft of nfts) { + if (!nft.collectionId) { + continue + } + if (!_persistedCollections[nft.collectionId] && !collections[nft.collectionId]) { + const collection = await buildPersistedCollectionFromNft(nft) + if (collection) { + collections[nft.collectionId] = { ...collection, nfts: [] } + } + } + } + addCollectionsToPersistedCollections(Object.values(collections)) + addNftsToCollection(accountIndex, nfts) +} diff --git a/packages/shared/src/lib/core/nfts/interfaces/index.ts b/packages/shared/src/lib/core/nfts/interfaces/index.ts index 0daf27508b..046dda565c 100644 --- a/packages/shared/src/lib/core/nfts/interfaces/index.ts +++ b/packages/shared/src/lib/core/nfts/interfaces/index.ts @@ -5,6 +5,7 @@ export * from './nft-filter.interface' export * from './nft-metadata.interface' export * from './nft.interface' export * from './nft-attribute.interface' +export * from './persisted-collection.interface' export * from './persisted-nft.interface' export * from './persisted-nfts.interface' export * from './soonaverse-attribute.interface' diff --git a/packages/shared/src/lib/core/nfts/interfaces/nft.interface.ts b/packages/shared/src/lib/core/nfts/interfaces/nft.interface.ts index af716bf044..ec31429afb 100644 --- a/packages/shared/src/lib/core/nfts/interfaces/nft.interface.ts +++ b/packages/shared/src/lib/core/nfts/interfaces/nft.interface.ts @@ -27,6 +27,7 @@ export interface IErc721Nft extends IBaseNft { interface IBaseNft { id: string + collectionId?: string type: MimeType networkId: NetworkId name: string diff --git a/packages/shared/src/lib/core/nfts/interfaces/persisted-collection.interface.ts b/packages/shared/src/lib/core/nfts/interfaces/persisted-collection.interface.ts new file mode 100644 index 0000000000..458cc42697 --- /dev/null +++ b/packages/shared/src/lib/core/nfts/interfaces/persisted-collection.interface.ts @@ -0,0 +1,12 @@ +import { IErc721ContractMetadata } from './erc721-contract-metadata.interface' +import { IIrc27Metadata } from './nft-metadata.interface' + +interface IBaseCollection { + id: string +} + +export type PersistedCollection = IPersistedIrc27Collection | IPersistedErc721Collection + +export interface IPersistedIrc27Collection extends IIrc27Metadata, IBaseCollection {} + +export interface IPersistedErc721Collection extends IErc721ContractMetadata, IBaseCollection {} diff --git a/packages/shared/src/lib/core/nfts/stores/active-profile-collections-per-account.store.ts b/packages/shared/src/lib/core/nfts/stores/active-profile-collections-per-account.store.ts new file mode 100644 index 0000000000..5edd5814e1 --- /dev/null +++ b/packages/shared/src/lib/core/nfts/stores/active-profile-collections-per-account.store.ts @@ -0,0 +1,50 @@ +import { Writable, get, writable } from 'svelte/store' +import { persistedCollections } from '.' +import { Collections } from '../types' +import { Nft } from '../interfaces' +import { NftStandard } from '../enums' + +export const collectionsSearchTerm = writable('') + +export const activeProfileCollectionsPerAccount: Writable<{ + [accountIndex: number]: Collections +}> = writable({}) + +export function addNftsToCollection(accountIndex: number, nfts: Nft[]): void { + if (!nfts.length) return + + const $persistedCollections = get(persistedCollections) + activeProfileCollectionsPerAccount.update((state) => { + for (const nft of nfts) { + if (!nft.collectionId || !$persistedCollections[nft.collectionId]) { + continue + } + + if (!state[accountIndex]) { + state[accountIndex] = {} + } + + let collection = state[accountIndex][nft.collectionId] + if (!collection) { + collection = { ...$persistedCollections[nft.collectionId], nfts: [] } + } + + if (collection.nfts.some((_nft) => _nft.id === nft.id) || !nft.isSpendable) { + continue + } + + if (collection.standard === NftStandard.Irc27 && nft.standard === NftStandard.Irc27) { + collection.nfts?.push(nft) + } else if (collection.standard === NftStandard.Erc721 && nft.standard === NftStandard.Erc721) { + collection.nfts?.push(nft) + } + state[accountIndex][nft.collectionId] = collection + } + + return state + }) +} + +export function clearActiveProfileCollectionsPerAccount(): void { + activeProfileCollectionsPerAccount.set({}) +} diff --git a/packages/shared/src/lib/core/nfts/stores/index.ts b/packages/shared/src/lib/core/nfts/stores/index.ts index f7011e66b6..2d4414b2ae 100644 --- a/packages/shared/src/lib/core/nfts/stores/index.ts +++ b/packages/shared/src/lib/core/nfts/stores/index.ts @@ -1,8 +1,9 @@ +export * from './active-profile-collections-per-account.store' export * from './active-profile-nfts-per-account.store' export * from './downloading-nft.store' export * from './nft-download-queue.store' export * from './nft-filter.store' -export * from './selected-account-collections.store' +export * from './persisted-collections.store' export * from './persisted-nfts.store' export * from './selected-account-nfts.store' export * from './selected-collectibles-tabs.store' diff --git a/packages/shared/src/lib/core/nfts/stores/persisted-collections.store.ts b/packages/shared/src/lib/core/nfts/stores/persisted-collections.store.ts new file mode 100644 index 0000000000..758d5bdff0 --- /dev/null +++ b/packages/shared/src/lib/core/nfts/stores/persisted-collections.store.ts @@ -0,0 +1,22 @@ +import { persistent } from '@core/utils/store' +import { Collection } from '../interfaces' +import { PersistedCollections } from '../types' + +export const persistedCollections = persistent('persistedCollections', {}) + +export function addCollectionsToPersistedCollections(collections: Collection[]): void { + persistedCollections.update((state) => { + for (const collection of collections) { + if (state[collection.id]) { + continue + } + + state[collection.id] = collection + } + return state + }) +} + +export function addCollectionToPersistedCollections(collection: Collection): void { + addCollectionsToPersistedCollections([collection]) +} diff --git a/packages/shared/src/lib/core/nfts/stores/selected-account-collections.store.ts b/packages/shared/src/lib/core/nfts/stores/selected-account-collections.store.ts deleted file mode 100644 index f2e3e40800..0000000000 --- a/packages/shared/src/lib/core/nfts/stores/selected-account-collections.store.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { derived, get, Readable, Writable, writable } from 'svelte/store' -import { NftStandard } from '../enums' -import { Nft } from '../interfaces' -import { Collections } from '../types' -import { getCollectionFromNft } from '../utils' -import { ownedNfts, selectedAccountNfts } from './selected-account-nfts.store' -import { isFeatureEnabled } from '@lib/features/utils' - -export const collectionsStore: Writable = 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) => { - const collectionId = - nft.standard === NftStandard.Irc27 - ? nft.issuer?.aliasId ?? nft.issuer?.nftId - : nft.contractMetadata.address - if (!collectionId) { - return - } - - if (collectionsUpdate[collectionId]) { - const existingCollection = collectionsUpdate[collectionId] - if (!existingCollection.nfts.find((existingNft) => existingNft.id === nft.id)) { - if (existingCollection.standard === nft.standard) { - // @ts-expect-error - ignore type error because we are checking the standard of nft and collection match - existingCollection.nfts.push(nft) - } - } - } else { - const collection = await getCollectionFromNft(nft) - if (collection) { - // @ts-expect-error - ignore type error because the collection was generated from the nft - collectionsUpdate[collectionId] = { ...collection, nfts: [nft] } - } - } - }) - ) - collectionsStore.set(collectionsUpdate) -} - -selectedAccountNfts.subscribe((nfts) => { - if (isFeatureEnabled('collectibles.collections')) { - void updateCollections(nfts.filter((nft) => nft.isSpendable)) - } -}) - -export const selectedAccountCollections: Readable = derived( - [collectionsStore, ownedNfts], - ([$collectionsStore, $ownedNfts]) => { - const accountCollections: Collections = {} - for (const collectionId in $collectionsStore) { - const collection = $collectionsStore[collectionId] - const nftsForAccount = collection.nfts.filter((nft) => - $ownedNfts.some((ownedNft) => ownedNft.id === nft.id) - ) - if (nftsForAccount.length > 0) { - // @ts-expect-error - ignore type error because we are filtering the existing nfts for the account - accountCollections[collectionId] = { ...collection, nfts: nftsForAccount } - } else { - delete accountCollections[collectionId] - } - } - return accountCollections - } -) - -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 index 32dae6f7df..df9fe0e495 100644 --- a/packages/shared/src/lib/core/nfts/types/collections.type.ts +++ b/packages/shared/src/lib/core/nfts/types/collections.type.ts @@ -1,3 +1,3 @@ import { Collection } from '../interfaces' -export type Collections = { [key: string]: Collection } +export type Collections = { [collectionId: 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 77e3cbecb6..6e9d96f84e 100644 --- a/packages/shared/src/lib/core/nfts/types/index.ts +++ b/packages/shared/src/lib/core/nfts/types/index.ts @@ -1,3 +1,4 @@ export * from './collections.type' export * from './nft-download-options.type' +export * from './persisted-collections.type' export * from './persisted-nft.type' diff --git a/packages/shared/src/lib/core/nfts/types/persisted-collections.type.ts b/packages/shared/src/lib/core/nfts/types/persisted-collections.type.ts new file mode 100644 index 0000000000..58a859b646 --- /dev/null +++ b/packages/shared/src/lib/core/nfts/types/persisted-collections.type.ts @@ -0,0 +1,3 @@ +import { PersistedCollection } from '../interfaces' + +export type PersistedCollections = { [collectionId: string]: PersistedCollection } diff --git a/packages/shared/src/lib/core/nfts/utils/buildNftFromPersistedErc721Nft.ts b/packages/shared/src/lib/core/nfts/utils/buildNftFromPersistedErc721Nft.ts index 0895967943..cbb97b6e97 100644 --- a/packages/shared/src/lib/core/nfts/utils/buildNftFromPersistedErc721Nft.ts +++ b/packages/shared/src/lib/core/nfts/utils/buildNftFromPersistedErc721Nft.ts @@ -5,9 +5,11 @@ import { isScamErc721Nft } from './isScamErc721Nft' export function buildNftFromPersistedErc721Nft(nft: IPersistedErc721Nft, accountAddress: string): IErc721Nft { const isSpendable = nft.ownerAddress === accountAddress const isScam = nft?.isScam ?? (nft.metadata ? isScamErc721Nft(nft.metadata) : false) + const collectionId = nft.contractMetadata.address return { ...nft, + collectionId, isSpendable, isScam, name: nft.metadata?.name ?? nft.contractMetadata.name ?? DEFAULT_NFT_NAME, diff --git a/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts b/packages/shared/src/lib/core/nfts/utils/buildPersistedCollectionFromNft.ts similarity index 55% rename from packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts rename to packages/shared/src/lib/core/nfts/utils/buildPersistedCollectionFromNft.ts index 2af8ee0fb0..3f00d1057c 100644 --- a/packages/shared/src/lib/core/nfts/utils/getCollectionFromNft.ts +++ b/packages/shared/src/lib/core/nfts/utils/buildPersistedCollectionFromNft.ts @@ -2,26 +2,38 @@ import { getClient } from '@core/profile-manager' import type { AliasOutput, MetadataFeature, NftOutput } from '@iota/sdk' import { FeatureType } from '@iota/sdk/out/types' import { NftStandard } from '../enums' -import { Collection, IErc721Collection, IErc721Nft, IIrc27Collection, IIrc27Nft, Nft } from '../interfaces' +import { + IErc721Nft, + IIrc27Nft, + IPersistedErc721Collection, + IPersistedIrc27Collection, + Nft, + PersistedCollection, +} from '../interfaces' import { parseNftMetadata } from './parseNftMetadata' -export async function getCollectionFromNft(nft: Nft): Promise { +export async function buildPersistedCollectionFromNft(nft: Nft): Promise { if (nft.standard === NftStandard.Irc27) { - return getCollectionForIrc27Nft(nft) + return buildPersistedCollectionForIrc27Nft(nft) } else if (nft.standard === NftStandard.Erc721) { - return getCollectionForErc721Nft(nft) + return buildPersistedCollectionForErc721Nft(nft) } } -async function getCollectionForIrc27Nft(nft: IIrc27Nft): Promise { - const { aliasId = '', nftId = '' } = nft.issuer ?? {} - if (!aliasId && !nftId) { - return +async function buildPersistedCollectionForIrc27Nft(nft: IIrc27Nft): Promise { + if (!nft.collectionId) { + return undefined } + const { aliasId, nftId } = nft.issuer ?? {} + try { const client = await getClient() - const outputId = aliasId ? await client.aliasOutputId(aliasId) : await client.nftOutputId(nftId) + const outputId = aliasId + ? await client.aliasOutputId(aliasId) + : nftId + ? await client.nftOutputId(nftId) + : undefined if (!outputId) { return } @@ -42,12 +54,12 @@ async function getCollectionForIrc27Nft(nft: IIrc27Nft): Promise