Skip to content

Commit

Permalink
feature: logic and error handling improvements to CNftSolMinter
Browse files Browse the repository at this point in the history
  • Loading branch information
newbreedofgeek committed Sep 13, 2024
1 parent fe60bf3 commit 507e028
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 156 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@itheum/sdk-mx-data-nft",
"version": "3.7.0-alpha.2",
"version": "3.7.0-alpha.3",
"description": "SDK for Itheum's Data NFT Technology on MultiversX and Solana",
"main": "out/index.js",
"types": "out/index.d.js",
Expand Down
304 changes: 159 additions & 145 deletions src/cnft-sol-minter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,168 +63,182 @@ export class CNftSolMinter extends MinterSol {
metadataUrl: string;
mintMeta: CNftSolPostMintMetaType;
}> {
const {
imageUrl,
traitsUrl,
nftStorageToken,
extraAssets,
imgGenBg,
imgGenSet
} = options ?? {};

const tokenNameValidator = new StringValidator()
.notEmpty()
.alphanumeric()
.minLength(3)
.maxLength(20)
.validate(tokenName);

const datasetTitleValidator = new StringValidator()
.notEmpty()
.minLength(10)
.maxLength(60)
.validate(datasetTitle.trim());

const datasetDescriptionValidator = new StringValidator()
.notEmpty()
.minLength(10)
.maxLength(400)
.validate(datasetDescription);

validateResults([
tokenNameValidator,
datasetTitleValidator,
datasetDescriptionValidator
]);

// deep validate all mandatory URLs
try {
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);
} catch (error) {
throw error;
}
let imageOnIpfsUrl: string = '';
let metadataOnIpfsUrl: string = '';
let mintMeta: CNftSolPostMintMetaType = {};

let imageOnIpfsUrl: string;
let metadataOnIpfsUrl: string;
try {
const {
imageUrl,
traitsUrl,
nftStorageToken,
extraAssets,
imgGenBg,
imgGenSet
} = options ?? {};

const tokenNameValidator = new StringValidator()
.notEmpty()
.alphanumeric()
.minLength(3)
.maxLength(20)
.validate(tokenName);

const datasetTitleValidator = new StringValidator()
.notEmpty()
.minLength(10)
.maxLength(60)
.validate(datasetTitle.trim());

const datasetDescriptionValidator = new StringValidator()
.notEmpty()
.minLength(10)
.maxLength(400)
.validate(datasetDescription);

validateResults([
tokenNameValidator,
datasetTitleValidator,
datasetDescriptionValidator
]);

// deep validate all mandatory URLs
try {
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);
} catch (error) {
throw error;
}

// handle all logic related to data stream and ipfs gen of img,traits etc
let allDataStreamAndIPFSLogicDone = false;
// 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
);

if (!imageUrl) {
if (!nftStorageToken) {
throw new ErrArgumentNotSet(
'nftStorageToken',
'NFT Storage token is required when not using custom image and traits'
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()}`;
}

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') || '';

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'
const { imageOnIpfsUrl: imgOnIpfsUrl } = await storeToIpfsOnlyImg(
nftStorageToken,
_imageFile
);
}

await checkTraitsUrl(traitsUrl);
if (!imgOnIpfsUrl || imgOnIpfsUrl === '') {
throw new Error('Saving Image to IPFS failed');
}

const cNftMetadataContent = createIpfsMetadataSolCNft(
tokenName,
datasetTitle,
datasetDescription,
imgOnIpfsUrl,
creatorAddress,
dataNftStreamUrlEncrypted,
dataPreviewUrl,
dataMarshalUrl,
traitsFromImgHeader,
extraAssets ?? []
);

imageOnIpfsUrl = imageUrl;
metadataOnIpfsUrl = traitsUrl;
}
const { metadataIpfsUrl } = await storeToIpfsFullSolCNftMetadata(
nftStorageToken,
cNftMetadataContent
);

allDataStreamAndIPFSLogicDone = true;
} catch (e: any) {
throw e;
}
if (!metadataIpfsUrl || metadataIpfsUrl === '') {
throw new Error('Saving cNFT Metadata to IPFS failed');
}

// we not make a call to our private cNFt minter API
let mintMeta: CNftSolPostMintMetaType = {};
imageOnIpfsUrl = imgOnIpfsUrl;
metadataOnIpfsUrl = metadataIpfsUrl;
} else {
if (!traitsUrl) {
throw new ErrArgumentNotSet(
'traitsUrl',
'Traits URL is required when using custom image'
);
}

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;
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
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;
}
}
} catch (e) {
console.error(e);
}

return {
Expand Down
42 changes: 32 additions & 10 deletions src/common/mint-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ export async function storeToIpfs(
try {
const imageHash = await storeImageToIpfs(image, storageToken);
const traitsHash = await storeTraitsToIpfs(traits, storageToken);
return {
imageOnIpfsUrl: `https://ipfs.io/ipfs/${imageHash}`,
metadataOnIpfsUrl: `https://ipfs.io/ipfs/${traitsHash}`
};

if (imageHash && traitsHash) {
return {
imageOnIpfsUrl: `https://ipfs.io/ipfs/${imageHash}`,
metadataOnIpfsUrl: `https://ipfs.io/ipfs/${traitsHash}`
};
} else {
return {
imageOnIpfsUrl: '',
metadataOnIpfsUrl: ''
};
}
} catch (error) {
throw error;
}
Expand All @@ -61,9 +69,16 @@ export async function storeToIpfsFullSolCNftMetadata(
metadataStructureSolCNft,
storageToken
);
return {
metadataIpfsUrl: `https://ipfs.io/ipfs/${metadataIpfsHash}`
};

if (metadataIpfsHash) {
return {
metadataIpfsUrl: `https://ipfs.io/ipfs/${metadataIpfsHash}`
};
} else {
return {
metadataIpfsUrl: ''
};
}
} catch (error) {
throw error;
}
Expand All @@ -75,9 +90,16 @@ export async function storeToIpfsOnlyImg(
): Promise<{ imageOnIpfsUrl: string }> {
try {
const imageHash = await storeImageToIpfs(image, storageToken);
return {
imageOnIpfsUrl: `https://ipfs.io/ipfs/${imageHash}`
};

if (imageHash) {
return {
imageOnIpfsUrl: `https://ipfs.io/ipfs/${imageHash}`
};
} else {
return {
imageOnIpfsUrl: ''
};
}
} catch (error) {
throw error;
}
Expand Down

0 comments on commit 507e028

Please sign in to comment.