From fe60bf3b49eb0f48487503bdab41819cb8ae51d6 Mon Sep 17 00:00:00 2001 From: Mark Paul Date: Fri, 13 Sep 2024 10:29:30 +1000 Subject: [PATCH] feature: logic and error handling improvements to CNftSolMinter --- package.json | 2 +- src/cnft-sol-minter.ts | 211 ++++++++++++++++++++++------------------- src/errors.ts | 1 + src/interfaces.ts | 10 ++ 4 files changed, 123 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index 4965b6b..c0def82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@itheum/sdk-mx-data-nft", - "version": "3.7.0-alpha.1", + "version": "3.7.0-alpha.2", "description": "SDK for Itheum's Data NFT Technology on MultiversX and Solana", "main": "out/index.js", "types": "out/index.d.js", diff --git a/src/cnft-sol-minter.ts b/src/cnft-sol-minter.ts index 8adde96..28b85a1 100644 --- a/src/cnft-sol-minter.ts +++ b/src/cnft-sol-minter.ts @@ -8,6 +8,7 @@ import { checkTraitsUrl, checkUrlIsUp } from './common/utils'; import { ErrArgumentNotSet } from './errors'; import { MinterSol } from './minter-sol'; import { StringValidator, validateResults } from './common/validator'; +import { CNftSolPostMintMetaType } from './interfaces'; export class CNftSolMinter extends MinterSol { /** @@ -25,8 +26,6 @@ export class CNftSolMinter extends MinterSol { * * NOTE: The `options.nftStorageToken` is required when not using custom image and traits, when using custom image and traits the traits should be compliant with the `traits` structure * - * For more information, see the [README documentation](https://github.com/Itheum/sdk-mx-data-nft#create-a-mint-transaction). - * * @param creatorAddress the address of the creator who we mint a CNft for * @param tokenName the name of the DataNFT-FT. Between 3 and 20 alphanumeric characters, no spaces. * @param dataMarshalUrl the url of the data marshal. A live HTTPS URL that returns a 200 OK HTTP code. @@ -59,7 +58,11 @@ export class CNftSolMinter extends MinterSol { imgGenBg?: string; imgGenSet?: string; } - ): Promise<{ imageUrl: string; metadataUrl: string; mintMeta: object }> { + ): Promise<{ + imageUrl: string; + metadataUrl: string; + mintMeta: CNftSolPostMintMetaType; + }> { const { imageUrl, traitsUrl, @@ -105,117 +108,125 @@ export class CNftSolMinter extends MinterSol { let imageOnIpfsUrl: string; let metadataOnIpfsUrl: string; - const { dataNftHash, dataNftStreamUrlEncrypted } = - await dataNFTDataStreamAdvertise( - dataStreamUrl, - dataMarshalUrl, - creatorAddress // the caller is the Creator - ); - - if (!imageUrl) { - if (!nftStorageToken) { - throw new ErrArgumentNotSet( - 'nftStorageToken', - 'NFT Storage token is required when not using custom image and traits' + // handle all logic related to data stream and ipfs gen of img,traits etc + let allDataStreamAndIPFSLogicDone = false; + + try { + const { dataNftHash, dataNftStreamUrlEncrypted } = + await dataNFTDataStreamAdvertise( + dataStreamUrl, + dataMarshalUrl, + creatorAddress // the caller is the Creator ); - } - // create the img generative service API based on user options - let imgGenServiceApi = `${this.imageServiceUrl}/v1/generateNFTArt?hash=${dataNftHash}`; + if (!imageUrl) { + if (!nftStorageToken) { + throw new ErrArgumentNotSet( + 'nftStorageToken', + 'NFT Storage token is required when not using custom image and traits' + ); + } - if (imgGenBg && imgGenBg.trim() !== '') { - imgGenServiceApi += `&bg=${imgGenBg.trim()}`; - } + // create the img generative service API based on user options + let imgGenServiceApi = `${this.imageServiceUrl}/v1/generateNFTArt?hash=${dataNftHash}`; - if (imgGenSet && imgGenSet.trim() !== '') { - imgGenServiceApi += `&set=${imgGenSet.trim()}`; - } + if (imgGenBg && imgGenBg.trim() !== '') { + imgGenServiceApi += `&bg=${imgGenBg.trim()}`; + } - let resImgCall: any = ''; - let dataImgCall: any = ''; - let _imageFile: Blob = new Blob(); - - resImgCall = await fetch(imgGenServiceApi); - dataImgCall = await resImgCall.blob(); - _imageFile = dataImgCall; - - const traitsFromImgHeader = resImgCall.headers.get('x-nft-traits') || ''; - - const { imageOnIpfsUrl: imgOnIpfsUrl } = await storeToIpfsOnlyImg( - nftStorageToken, - _imageFile - ); - - const cNftMetadataContent = createIpfsMetadataSolCNft( - tokenName, - datasetTitle, - datasetDescription, - imgOnIpfsUrl, - creatorAddress, - dataNftStreamUrlEncrypted, - dataPreviewUrl, - dataMarshalUrl, - traitsFromImgHeader, - extraAssets ?? [] - ); - - const { metadataIpfsUrl } = await storeToIpfsFullSolCNftMetadata( - nftStorageToken, - cNftMetadataContent - ); - - imageOnIpfsUrl = imgOnIpfsUrl; - metadataOnIpfsUrl = metadataIpfsUrl; - } else { - if (!traitsUrl) { - throw new ErrArgumentNotSet( - 'traitsUrl', - 'Traits URL is required when using custom image' + if (imgGenSet && imgGenSet.trim() !== '') { + imgGenServiceApi += `&set=${imgGenSet.trim()}`; + } + + let resImgCall: any = ''; + let dataImgCall: any = ''; + let _imageFile: Blob = new Blob(); + + resImgCall = await fetch(imgGenServiceApi); + dataImgCall = await resImgCall.blob(); + _imageFile = dataImgCall; + + const traitsFromImgHeader = + resImgCall.headers.get('x-nft-traits') || ''; + + const { imageOnIpfsUrl: imgOnIpfsUrl } = await storeToIpfsOnlyImg( + nftStorageToken, + _imageFile ); - } - await checkTraitsUrl(traitsUrl); + const cNftMetadataContent = createIpfsMetadataSolCNft( + tokenName, + datasetTitle, + datasetDescription, + imgOnIpfsUrl, + creatorAddress, + dataNftStreamUrlEncrypted, + dataPreviewUrl, + dataMarshalUrl, + traitsFromImgHeader, + extraAssets ?? [] + ); - imageOnIpfsUrl = imageUrl; - metadataOnIpfsUrl = traitsUrl; - } + const { metadataIpfsUrl } = await storeToIpfsFullSolCNftMetadata( + nftStorageToken, + cNftMetadataContent + ); - // we not make a call to our private cNFt minter API - let mintMeta: any = {}; + imageOnIpfsUrl = imgOnIpfsUrl; + metadataOnIpfsUrl = metadataIpfsUrl; + } else { + if (!traitsUrl) { + throw new ErrArgumentNotSet( + 'traitsUrl', + 'Traits URL is required when using custom image' + ); + } - try { - const postHeaders = new Headers(); - postHeaders.append('Content-Type', 'application/json'); - - const raw = JSON.stringify({ - metadataOnIpfsUrl, - tokenName, - mintForSolAddr: creatorAddress, - solSignature: 'solSignature', - signatureNonce: 'signatureNonce' - }); - - const requestOptions = { - method: 'POST', - headers: postHeaders, - body: raw - }; - - let resMintCall: any = ''; - let dataMintCall: any = ''; - - resMintCall = await fetch(this.solCNftMinterServiceUrl, requestOptions); - dataMintCall = await resMintCall.text(); - mintMeta = dataMintCall; - - // .then((response) => response.text()) - // .then((result) => console.log(result)) - // .catch((error) => console.error(error)); + await checkTraitsUrl(traitsUrl); + + imageOnIpfsUrl = imageUrl; + metadataOnIpfsUrl = traitsUrl; + } + + allDataStreamAndIPFSLogicDone = true; } catch (e: any) { - mintMeta = { error: true, errMsg: e.toString() }; throw e; } + // we not make a call to our private cNFt minter API + let mintMeta: CNftSolPostMintMetaType = {}; + + if (allDataStreamAndIPFSLogicDone) { + try { + const postHeaders = new Headers(); + postHeaders.append('Content-Type', 'application/json'); + + const raw = JSON.stringify({ + metadataOnIpfsUrl, + tokenName, + mintForSolAddr: creatorAddress, + solSignature: 'solSignature', + signatureNonce: 'signatureNonce' + }); + + const requestOptions = { + method: 'POST', + headers: postHeaders, + body: raw + }; + + let resMintCall: any = ''; + let dataMintCall: any = ''; + + resMintCall = await fetch(this.solCNftMinterServiceUrl, requestOptions); + dataMintCall = await resMintCall.text(); + mintMeta = dataMintCall; + } catch (e: any) { + mintMeta = { error: true, errMsg: e.toString() }; + throw e; + } + } + return { imageUrl: imageOnIpfsUrl, metadataUrl: metadataOnIpfsUrl, diff --git a/src/errors.ts b/src/errors.ts index 9e3642b..a6a63c5 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -20,6 +20,7 @@ export class ErrArgumentNotSet extends Error { super(`Argument "${argument}" is not set. ${message}`); } } + export class ErrInvalidArgument extends Error { public constructor(message: string) { super(`Invalid argument: ${message}`); diff --git a/src/interfaces.ts b/src/interfaces.ts index 7d41348..4a370ee 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -86,6 +86,7 @@ export enum NftEnumType { SemiFungibleESDT = 'SemiFungibleESDT', MetaESDT = 'MetaESDT' } + export interface MarketplaceRequirements { acceptedTokens: string[]; acceptedPayments: string[]; @@ -234,3 +235,12 @@ export interface UserData { accumulatedRewardsBypass: BigNumber.Value; vaultNonce: number; } + +export type CNftSolPostMintMetaType = { + error?: boolean; + errMsg?: string; + assetId?: string; + leafSchema?: any; + index?: number; + root?: any; +};