From ae4b3806b76a452eda4939043487173bdf8f2f30 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 12:27:52 -0300 Subject: [PATCH 01/19] enhancement: adds stringify parameter to add whitespaces in metadata json of mint nft --- .../shared/components/popups/MintNftConfirmationPopup.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/components/popups/MintNftConfirmationPopup.svelte b/packages/shared/components/popups/MintNftConfirmationPopup.svelte index 389d513c27..ddb86ca18c 100644 --- a/packages/shared/components/popups/MintNftConfirmationPopup.svelte +++ b/packages/shared/components/popups/MintNftConfirmationPopup.svelte @@ -69,7 +69,7 @@ From 7feeaa5d91e93457a2a3245ec9186f50dab5dada Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 12:28:52 -0300 Subject: [PATCH 02/19] enhancement: adds whitespace-pre-wrap class only for metadata in GenericActivityInformation --- .../molecules/activity-info/GenericActivityInformation.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte index 5bbbde15ef..8db5ab5d70 100644 --- a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte +++ b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte @@ -84,6 +84,7 @@ tooltipText={value.isTooltipVisible ? localize(`tooltips.transactionDetails.${activity?.direction}.${key}`) : undefined} + classes={key === 'metadata' ? 'whitespace-pre-wrap' : ''} /> {/each} {#if activity.asyncData?.claimingTransactionId} From d2e196d32ed19ce3bf7b66395abd5f8b97838d7b Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 12:59:01 -0300 Subject: [PATCH 03/19] enhancement: adds validation for nft metadata --- .../lib/core/nfts/utils/parseNftMetadata.ts | 129 +++++++++++++++--- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts index b7acf6f8a5..8f31cf27c0 100644 --- a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts +++ b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts @@ -1,23 +1,112 @@ -import { IIrc27Metadata, MimeType } from '@core/nfts' +import { handleError } from '@core/error/handlers/handleError' +import { networkHrp } from '@core/network' +import { IIrc27Metadata, MimeType, SupportedMimeType } from '@core/nfts' +import { isValidUrl, validateBech32Address } from '@core/utils' import { Converter } from '@core/utils/convert' +import { TokenStandard } from '@core/wallet' +import { get } from 'svelte/store' -export function parseNftMetadata(metadata: string): IIrc27Metadata { - const parsedData = metadata ? JSON.parse(Converter.hexToUtf8(metadata)) : {} - - // TODO: Add some validation that everything is correct - const parsedMetadata: IIrc27Metadata = { - standard: parsedData.standard, - version: parsedData.version, - type: parsedData.type as MimeType, - uri: parsedData.uri, - name: parsedData.name, - collectionId: parsedData.collectionId, - collectionName: parsedData.collectionName, - royalties: parsedData.royalties, - issuerName: parsedData.issuerName, - description: parsedData.description, - attributes: parsedData.attributes, - } - - return parsedMetadata +export function parseNftMetadata(metadata: string): IIrc27Metadata | string { + const convertedData = Converter.hexToUtf8(metadata) + if (!convertedData.includes(`"type":"${TokenStandard.IRC27}"`)) { + return convertedData + } + + try { + const parsedData = metadata ? JSON.parse(Converter.hexToUtf8(metadata)) : {} + validate(parsedData) + const parsedMetadata: IIrc27Metadata = { + standard: parsedData.standard, + version: parsedData.version, + type: parsedData.type as MimeType, + uri: parsedData.uri, + name: parsedData.name, + collectionId: parsedData.collectionId, + collectionName: parsedData.collectionName, + royalties: parsedData.royalties, + issuerName: parsedData.issuerName, + description: parsedData.description, + attributes: parsedData.attributes, + } + return parsedMetadata + } catch (error) { + handleError(error) + } +} + +function validate(data: IIrc27Metadata): void { + if (!data.standard || data.standard !== TokenStandard.IRC27) { + throw 'Invalid standard, must be "IRC27"' + } + + if (!Object.keys(SupportedMimeType).includes(data.type)) { + throw 'Invalid MimeType, check if the file type is supported' + } + + if (data.name.length === 0) { + throw 'Empty name, it is a required field' + } + + if (data.uri.length === 0) { + throw 'Empty URI' + } else if (!isValidUrl(data.uri)) { + throw 'Invalid URI' + } + + if (data.royalties) { + validateRoyalties(data) + } + + if (data.attributes) { + validateAttributes(data) + } +} + +function validateRoyalties(data: IIrc27Metadata): void { + const isKeysValid = Object.keys(data.royalties).every((key) => !validateBech32Address(get(networkHrp), key)) + if (!isKeysValid) { + throw `Invalid royalty address, must be a valid ${get(networkHrp)} address where royalties will be sent to.` + } + + const isValuesValid = Object.values(data.royalties).every((value) => value >= 0 && value <= 1) + if (!isValuesValid) { + throw 'Invalid royalty value, it must be a numeric decimal representative of the percentage required ie. 0.05' + } + + const isSumValid = Object.values(data.royalties).reduce((acc, val) => acc + val, 0) <= 1 + if (!isSumValid) { + throw 'Invalid royalty value, the sum of all royalties must be less than or equal to 1' + } +} + +function validateAttributes(data: IIrc27Metadata): void { + if (!Array.isArray(data.attributes)) { + throw 'Attributes must be an array' + } + const isArrayOfObjects = data.attributes.every( + (attribute) => typeof attribute === 'object' && !Array.isArray(attribute) && attribute !== null + ) + if (!isArrayOfObjects) { + throw 'Attributes must be an array of objects' + } + const isKeysValid = data.attributes.every( + (attribute) => + Object.keys(attribute).every((key) => key === 'trait_type' || key === 'value') && + Object.keys(attribute).filter((key) => key === 'trait_type').length === 1 && + Object.keys(attribute).filter((key) => key === 'value').length === 1 + ) + if (!isKeysValid) { + throw 'Invalid key, attributes must have the keys "trait_type" and "value"' + } + const isValuesValid = data.attributes.every( + (attribute) => + (typeof attribute.trait_type === 'string' && + attribute.trait_type.length > 0 && + typeof attribute.value === 'string' && + attribute.value.length > 0) || + typeof attribute.value === 'number' + ) + if (!isValuesValid) { + throw 'Invalid value, "trait_type" must be a non empty string and "value" must be a non empty string or a number' + } } From b9a3d4624cf3ded71d5dce9625602ff3f98c62ab Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 19:25:20 -0300 Subject: [PATCH 04/19] enhancement: partial type of activity prop --- packages/shared/components/molecules/ActivityInformation.svelte | 2 +- packages/shared/components/molecules/NftActivityDetails.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/components/molecules/ActivityInformation.svelte b/packages/shared/components/molecules/ActivityInformation.svelte index f7acdf04de..bfbc651aa3 100644 --- a/packages/shared/components/molecules/ActivityInformation.svelte +++ b/packages/shared/components/molecules/ActivityInformation.svelte @@ -7,7 +7,7 @@ } from 'shared/components' import { ActivityType, Activity } from '@core/wallet' - export let activity: Activity + export let activity: Partial = {} enum Tab { Transaction = 'general.transaction', diff --git a/packages/shared/components/molecules/NftActivityDetails.svelte b/packages/shared/components/molecules/NftActivityDetails.svelte index 3784870cd0..e2f80fc9b7 100644 --- a/packages/shared/components/molecules/NftActivityDetails.svelte +++ b/packages/shared/components/molecules/NftActivityDetails.svelte @@ -7,7 +7,7 @@ import { Icon as IconEnum } from '@lib/auxiliary/icon' - export let activity: Activity + export let activity: Partial = {} $: isTimelocked = activity?.asyncData?.timelockDate > $time From 68e7289c8242ffd8756a9b51fcb79c331bcb34e9 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 19:26:58 -0300 Subject: [PATCH 05/19] feat: adds NftMetadataInformation component --- .../NftMetadataInformation.svelte | 77 +++++++++++++++++++ .../molecules/activity-info/index.js | 1 + 2 files changed, 78 insertions(+) create mode 100644 packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte new file mode 100644 index 0000000000..ae0fe7afaf --- /dev/null +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -0,0 +1,77 @@ + + +{#each Object.entries(nftMetadataDetailsList) as [key, value]} + +{/each} diff --git a/packages/shared/components/molecules/activity-info/index.js b/packages/shared/components/molecules/activity-info/index.js index 35d263bee7..3d71e76d39 100644 --- a/packages/shared/components/molecules/activity-info/index.js +++ b/packages/shared/components/molecules/activity-info/index.js @@ -1,3 +1,4 @@ export { default as AliasActivityInformation } from './AliasActivityInformation' export { default as GenericActivityInformation } from './GenericActivityInformation' export { default as NftActivityInformation } from './NftActivityInformation' +export { default as NftMetadataInformation } from './NftMetadataInformation' From ab810cb15be9134c75f3fc301bddb4a2fc149b9e Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 19:32:26 -0300 Subject: [PATCH 06/19] feat: adds metadata tab --- .../shared/components/molecules/ActivityInformation.svelte | 6 +++++- .../molecules/activity-info/NftMetadataInformation.svelte | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/shared/components/molecules/ActivityInformation.svelte b/packages/shared/components/molecules/ActivityInformation.svelte index bfbc651aa3..88a14596d9 100644 --- a/packages/shared/components/molecules/ActivityInformation.svelte +++ b/packages/shared/components/molecules/ActivityInformation.svelte @@ -6,6 +6,7 @@ NftActivityInformation, } from 'shared/components' import { ActivityType, Activity } from '@core/wallet' + import NftMetadataInformation from './activity-info/NftMetadataInformation.svelte' export let activity: Partial = {} @@ -13,6 +14,7 @@ Transaction = 'general.transaction', Alias = 'general.alias', Nft = 'general.nft', + Metadata = 'general.metadata', } let tabs: Tab[] = [] @@ -24,7 +26,7 @@ tabs = [Tab.Transaction, Tab.Alias] break case ActivityType.Nft: - tabs = [Tab.Transaction, Tab.Nft] + tabs = [Tab.Transaction, Tab.Nft, Tab.Metadata] break } @@ -41,5 +43,7 @@ {:else if activeTab === Tab.Nft} + {:else if activeTab === Tab.Metadata} + {/if} diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index ae0fe7afaf..7fc4401438 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -3,9 +3,9 @@ import { localize } from '@core/i18n' import { IIrc27Metadata, parseNftMetadata } from '@core/nfts' - import { NftActivity } from '@core/wallet' + import { Activity } from '@core/wallet' - export let activity: NftActivity + export let activity: Partial = {} type NftMetadataDetailsList = { [key in keyof IIrc27Metadata]: { From 1fd1763ac4becc96b88b26bb473387f798c1921f Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Thu, 17 Nov 2022 19:34:35 -0300 Subject: [PATCH 07/19] fix: only show metadata in transaction tab when it is not nft --- .../activity-info/GenericActivityInformation.svelte | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte index 8db5ab5d70..0232817553 100644 --- a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte +++ b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte @@ -2,14 +2,14 @@ import { KeyValueBox } from 'shared/components' import { formatDate, localize } from '@core/i18n' import { activeProfile } from '@core/profile' - import { formatTokenAmountPrecise, BaseActivity } from '@core/wallet' + import { Activity, formatTokenAmountPrecise, NftActivity } from '@core/wallet' import { BASE_TOKEN } from '@core/network' import { getOfficialExplorerUrl } from '@core/network/utils' import { Platform } from '@core/app' import { truncateString } from '@core/utils' import { setClipboard } from '@core/utils' - export let activity: BaseActivity + export let activity: Activity const explorerUrl = getOfficialExplorerUrl($activeProfile?.networkProtocol, $activeProfile?.networkType) @@ -34,9 +34,10 @@ ...(activity.time && { transactionTime: { data: formattedTransactionTime }, }), - ...(activity.metadata && { - metadata: { data: activity.metadata, isTooltipVisible: true }, - }), + ...(activity.metadata && + !(activity as NftActivity).nftId && { + metadata: { data: activity.metadata, isTooltipVisible: true }, + }), ...(activity.tag && { tag: { data: activity.tag, isTooltipVisible: true }, }), From 5441dad64f914da20862311c31cc6338c16e3c33 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 12:30:36 -0300 Subject: [PATCH 08/19] fix: correct use of nft metadata --- .../activity-info/GenericActivityInformation.svelte | 10 ++++------ .../activity-info/NftMetadataInformation.svelte | 11 ++++++----- .../shared/lib/core/nfts/interfaces/nft.interface.ts | 2 +- .../lib/core/nfts/utils/buildNftFromNftOutput.ts | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte index 0232817553..f746d3727c 100644 --- a/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte +++ b/packages/shared/components/molecules/activity-info/GenericActivityInformation.svelte @@ -2,7 +2,7 @@ import { KeyValueBox } from 'shared/components' import { formatDate, localize } from '@core/i18n' import { activeProfile } from '@core/profile' - import { Activity, formatTokenAmountPrecise, NftActivity } from '@core/wallet' + import { Activity, formatTokenAmountPrecise } from '@core/wallet' import { BASE_TOKEN } from '@core/network' import { getOfficialExplorerUrl } from '@core/network/utils' import { Platform } from '@core/app' @@ -34,10 +34,9 @@ ...(activity.time && { transactionTime: { data: formattedTransactionTime }, }), - ...(activity.metadata && - !(activity as NftActivity).nftId && { - metadata: { data: activity.metadata, isTooltipVisible: true }, - }), + ...(activity.metadata && { + metadata: { data: activity.metadata, isTooltipVisible: true }, + }), ...(activity.tag && { tag: { data: activity.tag, isTooltipVisible: true }, }), @@ -85,7 +84,6 @@ tooltipText={value.isTooltipVisible ? localize(`tooltips.transactionDetails.${activity?.direction}.${key}`) : undefined} - classes={key === 'metadata' ? 'whitespace-pre-wrap' : ''} /> {/each} {#if activity.asyncData?.claimingTransactionId} diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index 7fc4401438..d2346f422b 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -2,8 +2,9 @@ import { KeyValueBox } from 'shared/components' import { localize } from '@core/i18n' - import { IIrc27Metadata, parseNftMetadata } from '@core/nfts' - import { Activity } from '@core/wallet' + import { getNftByIdFromAllAccountNfts, IIrc27Metadata } from '@core/nfts' + import { Activity, NftActivity } from '@core/wallet' + import { selectedAccountIndex } from '@core/account' export let activity: Partial = {} @@ -14,8 +15,8 @@ } } - $: nftMetadata = parseNftMetadata(activity?.metadata) - $: nftMetadataDetailsList = createNftMetadataDetailsList(nftMetadata) + $: storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) + $: nftMetadataDetailsList = createNftMetadataDetailsList(storedNft?.parsedMetadata) function createNftMetadataDetailsList( metadata: IIrc27Metadata | string @@ -71,7 +72,7 @@ ? localize(`tooltips.transactionDetails.nftMetadata.${key}`) : ''} valueText={JSON.stringify(value, null, 2)} - isCopyable classes="whitespace-pre-wrap" + isCopyable /> {/each} diff --git a/packages/shared/lib/core/nfts/interfaces/nft.interface.ts b/packages/shared/lib/core/nfts/interfaces/nft.interface.ts index cfdf845fcc..7e62eb1634 100644 --- a/packages/shared/lib/core/nfts/interfaces/nft.interface.ts +++ b/packages/shared/lib/core/nfts/interfaces/nft.interface.ts @@ -6,6 +6,6 @@ export interface INft { name: string issuer: AddressTypes metadata: string - parsedMetadata?: IIrc27Metadata + parsedMetadata?: IIrc27Metadata | string isOwned: boolean } diff --git a/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts b/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts index f67696e6ad..48cae0ce79 100644 --- a/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts +++ b/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts @@ -11,7 +11,7 @@ export function buildNftFromNftOutput(nftOutput: INftOutput, outputId: string, i const parsedMetadata = parseNftMetadata(metadata) return { id, - name: parsedMetadata?.name ?? DEFAULT_NFT_NAME, + name: typeof parsedMetadata === 'string' ? DEFAULT_NFT_NAME : (parsedMetadata?.name ?? DEFAULT_NFT_NAME), issuer, isOwned, metadata, From 15403364831aca28132418c7d54720e77f7b30da Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 19:36:12 -0300 Subject: [PATCH 09/19] fix: only show metadata tab if it has parsed metadata --- .../molecules/ActivityInformation.svelte | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/shared/components/molecules/ActivityInformation.svelte b/packages/shared/components/molecules/ActivityInformation.svelte index 88a14596d9..082d8e33e2 100644 --- a/packages/shared/components/molecules/ActivityInformation.svelte +++ b/packages/shared/components/molecules/ActivityInformation.svelte @@ -5,8 +5,10 @@ AliasActivityInformation, NftActivityInformation, } from 'shared/components' - import { ActivityType, Activity } from '@core/wallet' + import { ActivityType, Activity, NftActivity } from '@core/wallet' import NftMetadataInformation from './activity-info/NftMetadataInformation.svelte' + import { getNftByIdFromAllAccountNfts } from '@core/nfts' + import { selectedAccountIndex } from '@core/account' export let activity: Partial = {} @@ -17,17 +19,29 @@ Metadata = 'general.metadata', } + let hasMetadata = false + $: { + const storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) + hasMetadata = !!storedNft?.parsedMetadata + } + let tabs: Tab[] = [] - switch (activity.type) { - case ActivityType.Transaction: - tabs = [Tab.Transaction] - break - case ActivityType.Alias: - tabs = [Tab.Transaction, Tab.Alias] - break - case ActivityType.Nft: - tabs = [Tab.Transaction, Tab.Nft, Tab.Metadata] - break + $: { + switch (activity.type) { + case ActivityType.Transaction: + tabs = [Tab.Transaction] + break + case ActivityType.Alias: + tabs = [Tab.Transaction, Tab.Alias] + break + case ActivityType.Nft: + tabs = [ + Tab.Transaction, + Tab.Nft, + ... hasMetadata ? [Tab.Metadata] : [], + ] + break + } } let activeTab = Tab.Transaction From cfcd881dd47c17769a283767740e2c84c98fc33f Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 19:55:04 -0300 Subject: [PATCH 10/19] fix: only show immutable issuer and other optional values if they are fulfilled --- .../molecules/activity-info/NftActivityInformation.svelte | 4 +++- packages/shared/locales/en.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/shared/components/molecules/activity-info/NftActivityInformation.svelte b/packages/shared/components/molecules/activity-info/NftActivityInformation.svelte index 336dbd5227..26592c1705 100644 --- a/packages/shared/components/molecules/activity-info/NftActivityInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftActivityInformation.svelte @@ -18,5 +18,7 @@ {#each Object.entries(detailsList) as [key, value]} - + {#if value} + + {/if} {/each} diff --git a/packages/shared/locales/en.json b/packages/shared/locales/en.json index 0c7f8a04ed..17bba4f795 100644 --- a/packages/shared/locales/en.json +++ b/packages/shared/locales/en.json @@ -572,7 +572,8 @@ "royalties": "Royalties", "issuerName": "Issuer Name", "description": "Description", - "attributes": "Attributes" + "attributes": "Attributes", + "metadata": "Metadata" } } }, From ab4abf200a0f2266c034051af74f04eb67358fc7 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 19:55:46 -0300 Subject: [PATCH 11/19] fix: expression to identify IRC27 metadata --- packages/shared/lib/core/nfts/utils/parseNftMetadata.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts index 8f31cf27c0..9cbc9f6497 100644 --- a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts +++ b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts @@ -8,8 +8,8 @@ import { get } from 'svelte/store' export function parseNftMetadata(metadata: string): IIrc27Metadata | string { const convertedData = Converter.hexToUtf8(metadata) - if (!convertedData.includes(`"type":"${TokenStandard.IRC27}"`)) { - return convertedData + if (!convertedData.includes(`"standard":"${TokenStandard.IRC27}"`)) { + return JSON.stringify(JSON.parse(convertedData), null, 2) } try { From e4708f7c32cae06757946a54b177dacf0f74cf71 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 19:56:35 -0300 Subject: [PATCH 12/19] fix: display of text and styling --- .../activity-info/NftMetadataInformation.svelte | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index d2346f422b..0b31c00123 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -68,11 +68,12 @@ {#each Object.entries(nftMetadataDetailsList) as [key, value]} {/each} From 7a860b4ebfdcc92fe0aab7eddeab163636fef176 Mon Sep 17 00:00:00 2001 From: Jean Ribeiro Date: Fri, 18 Nov 2022 20:12:21 -0300 Subject: [PATCH 13/19] enhancement: nft metadata in MintNftConfirmationPopup --- .../activity-info/NftMetadataInformation.svelte | 3 ++- .../components/popups/MintNftConfirmationPopup.svelte | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index 0b31c00123..cef405355b 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -7,6 +7,7 @@ import { selectedAccountIndex } from '@core/account' export let activity: Partial = {} + export let nftMetadata: Partial = {} type NftMetadataDetailsList = { [key in keyof IIrc27Metadata]: { @@ -16,7 +17,7 @@ } $: storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) - $: nftMetadataDetailsList = createNftMetadataDetailsList(storedNft?.parsedMetadata) + $: nftMetadataDetailsList = createNftMetadataDetailsList(storedNft?.parsedMetadata ?? nftMetadata as IIrc27Metadata) function createNftMetadataDetailsList( metadata: IIrc27Metadata | string diff --git a/packages/shared/components/popups/MintNftConfirmationPopup.svelte b/packages/shared/components/popups/MintNftConfirmationPopup.svelte index ddb86ca18c..acfebef11e 100644 --- a/packages/shared/components/popups/MintNftConfirmationPopup.svelte +++ b/packages/shared/components/popups/MintNftConfirmationPopup.svelte @@ -1,9 +1,9 @@ diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index 4db8652a7f..3d186b06b0 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -18,7 +18,7 @@ $: storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) $: nftMetadataDetailsList = createNftMetadataDetailsList( - storedNft?.parsedMetadata ?? (nftMetadata as IIrc27Metadata) + storedNft?.parsedMetadata ?? storedNft?.metadata ?? (nftMetadata as IIrc27Metadata) ) function createNftMetadataDetailsList( @@ -47,9 +47,6 @@ ...(metadata?.uri && { uri: { data: metadata.uri }, }), - ...(metadata?.collectionId && { - collectionId: { data: metadata.collectionId, isTooltipVisible: true }, - }), ...(metadata?.collectionName && { collectionName: { data: metadata.collectionName }, }), diff --git a/packages/shared/lib/core/nfts/interfaces/nft.interface.ts b/packages/shared/lib/core/nfts/interfaces/nft.interface.ts index 7e62eb1634..cfdf845fcc 100644 --- a/packages/shared/lib/core/nfts/interfaces/nft.interface.ts +++ b/packages/shared/lib/core/nfts/interfaces/nft.interface.ts @@ -6,6 +6,6 @@ export interface INft { name: string issuer: AddressTypes metadata: string - parsedMetadata?: IIrc27Metadata | string + parsedMetadata?: IIrc27Metadata isOwned: boolean } diff --git a/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts b/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts index 10656a1c49..4e43846119 100644 --- a/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts +++ b/packages/shared/lib/core/nfts/utils/buildNftFromNftOutput.ts @@ -11,7 +11,7 @@ export function buildNftFromNftOutput(nftOutput: INftOutput, outputId: string, i const parsedMetadata = parseNftMetadata(metadata) return { id, - name: typeof parsedMetadata === 'string' ? DEFAULT_NFT_NAME : parsedMetadata?.name ?? DEFAULT_NFT_NAME, + name: parsedMetadata?.name ?? DEFAULT_NFT_NAME, issuer, isOwned, metadata, diff --git a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts index db1c6437c8..fdb9574134 100644 --- a/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts +++ b/packages/shared/lib/core/nfts/utils/parseNftMetadata.ts @@ -5,14 +5,10 @@ import { Converter } from '@core/utils/convert' import { TokenStandard } from '@core/wallet' import { get } from 'svelte/store' -export function parseNftMetadata(metadata: string): IIrc27Metadata | string { +export function parseNftMetadata(metadata: string): IIrc27Metadata { try { const convertedData = Converter.hexToUtf8(metadata) - if (!convertedData.includes(`"standard":"${TokenStandard.IRC27}"`)) { - return JSON.stringify(JSON.parse(convertedData), null, 2) - } - - const parsedData = metadata ? JSON.parse(Converter.hexToUtf8(metadata)) : {} + const parsedData = metadata ? JSON.parse(convertedData) : {} validate(parsedData) const parsedMetadata: IIrc27Metadata = { standard: parsedData.standard, @@ -52,42 +48,42 @@ function validate(data: IIrc27Metadata): void { } if (data.royalties) { - validateRoyalties(data) + validateRoyalties(data.royalties) } if (data.attributes) { - validateAttributes(data) + validateAttributes(data.attributes) } } -function validateRoyalties(data: IIrc27Metadata): void { - const isKeysValid = Object.keys(data.royalties).every((key) => !validateBech32Address(get(networkHrp), key)) +function validateRoyalties(royalties: unknown): void { + const isKeysValid = Object.keys(royalties).every((key) => !validateBech32Address(get(networkHrp), key)) if (!isKeysValid) { throw `Invalid royalty address, must be a valid ${get(networkHrp)} address where royalties will be sent to.` } - const isValuesValid = Object.values(data.royalties).every((value) => value >= 0 && value <= 1) + const isValuesValid = Object.values(royalties).every((value) => value >= 0 && value <= 1) if (!isValuesValid) { throw 'Invalid royalty value, it must be a numeric decimal representative of the percentage required ie. 0.05' } - const isSumValid = Object.values(data.royalties).reduce((acc, val) => acc + val, 0) <= 1 + const isSumValid = Object.values(royalties).reduce((acc, val) => acc + val, 0) <= 1 if (!isSumValid) { throw 'Invalid royalty value, the sum of all royalties must be less than or equal to 1' } } -function validateAttributes(data: IIrc27Metadata): void { - if (!Array.isArray(data.attributes)) { +function validateAttributes(attributes: unknown): void { + if (!Array.isArray(attributes)) { throw 'Attributes must be an array' } - const isArrayOfObjects = data.attributes.every( + const isArrayOfObjects = attributes.every( (attribute) => typeof attribute === 'object' && !Array.isArray(attribute) && attribute !== null ) if (!isArrayOfObjects) { throw 'Attributes must be an array of objects' } - const isKeysValid = data.attributes.every( + const isKeysValid = attributes.every( (attribute) => Object.keys(attribute).every((key) => key === 'trait_type' || key === 'value') && Object.keys(attribute).filter((key) => key === 'trait_type').length === 1 && @@ -96,7 +92,7 @@ function validateAttributes(data: IIrc27Metadata): void { if (!isKeysValid) { throw 'Invalid key, attributes must have the keys "trait_type" and "value"' } - const isValuesValid = data.attributes.every( + const isValuesValid = attributes.every( (attribute) => (typeof attribute.trait_type === 'string' && attribute.trait_type.length > 0 && From 9293edcf33ae3a86bcffeddc09558a8836a21960 Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Mon, 21 Nov 2022 18:21:33 +0100 Subject: [PATCH 19/19] fix: fix component props + types Co-authored-by: Jean Ribeiro --- .../molecules/ActivityInformation.svelte | 17 ++++++++++------- .../molecules/NftActivityDetails.svelte | 4 ++-- .../NftMetadataInformation.svelte | 19 +++++++++++++------ .../popups/MintNftConfirmationPopup.svelte | 6 +++--- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/packages/shared/components/molecules/ActivityInformation.svelte b/packages/shared/components/molecules/ActivityInformation.svelte index 49a31e4fa7..37c7820dcc 100644 --- a/packages/shared/components/molecules/ActivityInformation.svelte +++ b/packages/shared/components/molecules/ActivityInformation.svelte @@ -4,13 +4,13 @@ GenericActivityInformation, AliasActivityInformation, NftActivityInformation, + NftMetadataInformation, } from 'shared/components' - import { ActivityType, Activity, NftActivity } from '@core/wallet' - import NftMetadataInformation from './activity-info/NftMetadataInformation.svelte' + import { ActivityType, Activity } from '@core/wallet' import { getNftByIdFromAllAccountNfts } from '@core/nfts' import { selectedAccountIndex } from '@core/account' - export let activity: Partial = {} + export let activity: Activity enum Tab { Transaction = 'general.transaction', @@ -21,7 +21,10 @@ let hasMetadata = false $: { - const storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) + const storedNft = + activity.type === ActivityType.Nft + ? getNftByIdFromAllAccountNfts($selectedAccountIndex, activity.nftId) + : undefined hasMetadata = !!storedNft?.metadata } @@ -49,11 +52,11 @@ {/if} {#if activeTab === Tab.Transaction} - {:else if activeTab === Tab.Alias} + {:else if activeTab === Tab.Alias && activity.type === ActivityType.Alias} - {:else if activeTab === Tab.Nft} + {:else if activeTab === Tab.Nft && activity.type === ActivityType.Nft} - {:else if activeTab === Tab.Metadata} + {:else if activeTab === Tab.Metadata && activity.type === ActivityType.Nft} {/if} diff --git a/packages/shared/components/molecules/NftActivityDetails.svelte b/packages/shared/components/molecules/NftActivityDetails.svelte index 4183994801..0bf3c2cd52 100644 --- a/packages/shared/components/molecules/NftActivityDetails.svelte +++ b/packages/shared/components/molecules/NftActivityDetails.svelte @@ -3,11 +3,11 @@ import { time } from '@core/app' import { localize } from '@core/i18n' - import { Activity } from '@core/wallet' + import { NftActivity } from '@core/wallet' import { Icon as IconEnum } from '@lib/auxiliary/icon' - export let activity: Partial + export let activity: NftActivity $: isTimelocked = activity?.asyncData?.timelockDate > $time diff --git a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte index 3d186b06b0..2f5b1bac59 100644 --- a/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte +++ b/packages/shared/components/molecules/activity-info/NftMetadataInformation.svelte @@ -3,11 +3,11 @@ import { localize } from '@core/i18n' import { getNftByIdFromAllAccountNfts, IIrc27Metadata } from '@core/nfts' - import { Activity, NftActivity } from '@core/wallet' + import { NftActivity } from '@core/wallet' import { selectedAccountIndex } from '@core/account' - export let activity: Partial = {} - export let nftMetadata: Partial = {} + export let activity: NftActivity + export let nftMetadata: IIrc27Metadata | string = undefined type NftMetadataDetailsList = { [key in keyof IIrc27Metadata]: { @@ -16,16 +16,23 @@ } } - $: storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, (activity as NftActivity)?.nftId) + $: storedNft = getNftByIdFromAllAccountNfts($selectedAccountIndex, activity?.nftId) $: nftMetadataDetailsList = createNftMetadataDetailsList( - storedNft?.parsedMetadata ?? storedNft?.metadata ?? (nftMetadata as IIrc27Metadata) + storedNft?.parsedMetadata ?? storedNft?.metadata ?? nftMetadata ) function createNftMetadataDetailsList( metadata: IIrc27Metadata | string ): NftMetadataDetailsList | { metadata: { data: string } } { if (typeof metadata === 'string') { - return { metadata: { data: metadata } } + let formattedMetadata: string + try { + formattedMetadata = JSON.stringify(JSON.parse(metadata), null, '\t') + } catch (e) { + formattedMetadata = metadata + } + + return { metadata: { data: formattedMetadata } } } return createIrc27NftMetadataDetailsList(metadata) } diff --git a/packages/shared/components/popups/MintNftConfirmationPopup.svelte b/packages/shared/components/popups/MintNftConfirmationPopup.svelte index 55fb32c73c..84b9326f31 100644 --- a/packages/shared/components/popups/MintNftConfirmationPopup.svelte +++ b/packages/shared/components/popups/MintNftConfirmationPopup.svelte @@ -1,6 +1,6 @@