From d44d2721e8cfdfdc2aa3758b3e7b5fdfdf8f8070 Mon Sep 17 00:00:00 2001 From: codeSTACKr Date: Mon, 28 Feb 2022 20:18:13 -0600 Subject: [PATCH] add rarity calculator --- .gitignore | 2 + README.md | 8 +++- package-lock.json | 10 ++--- package.json | 4 +- utils/getRarity_fromMetadata.js | 65 +++++++++++++++++++++++++++++++++ utils/rarity_rank.js | 59 ++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 utils/getRarity_fromMetadata.js create mode 100644 utils/rarity_rank.js diff --git a/.gitignore b/.gitignore index 09c28a63..49d8589c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,8 @@ build/ dist/ node_modules/ jspm_packages/ +package-lock.json +yarn.lock # TypeScript v1 declaration files diff --git a/README.md b/README.md index 8bea0a91..d2cd7751 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Join the Discord server for more help from the community: [codeSTACKr Discord](h The macro script from the second video: [macro1.mmmacro](macro1.mmmacro) +UPDATE: Added rarity calculator. See this [video](https://youtu.be/Uz1y4j9gvP8) for the walkthrough. + ## UPDATES & FIXES ### npm not recognized @@ -45,9 +47,11 @@ Ensure that your layer names in the `config.js` file match exactly to your layer ### "Quota Limit Reached" or "Too many requests" errors -There have been some changes made to the code from the original video resulting from some errors when uploading files, metadata, and minting using NFTPort. Depending on your plan, Free vs Community, there are rate limits. +There have been some changes made to the code from the original video resulting from some errors when uploading files, metadata, and minting using NFTPort. Depending on your plan, Free vs Community, there are rate limits. + +To fix these issues, I've updated the code to include a timeout that will allow the files to be uploaded at a slower rate, instead of all at once, eliminating these errors. -To fix these issues, I've updated the code to include a timeout that will allow the files to be uploaded at a slower rate, instead of all at once, eliminating these errors. +If you've reached your quota limit, contact NFTPort to upgrade your plan to get more. **To use this code:** diff --git a/package-lock.json b/package-lock.json index e862c0d2..6f851c82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "hashlips_art_engine", - "version": "1.1.1", + "name": "10k-collection-video", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "hashlips_art_engine", - "version": "1.1.1", + "name": "10k-collection-video", + "version": "1.1.0", "license": "MIT", "dependencies": { "canvas": "^2.8.0", @@ -16,7 +16,7 @@ "sha1": "^1.1.1" }, "bin": { - "hashlips_art_engine": "index.js" + "10k-collection-video": "index.js" } }, "node_modules/@mapbox/node-pre-gyp": { diff --git a/package.json b/package.json index e4dd988b..5b6312ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "10k-collection-video", - "version": "1.1.0", + "version": "1.2.0", "description": "Source code from \"How To Create An ENTIRE NFT Collection (10,000+) & MINT In Under 1 Hour Without Coding Knowledge\" video.", "main": "index.js", "bin": "index.js", @@ -15,6 +15,8 @@ "build": "node index.js", "generate": "node index.js", "rarity": "node utils/rarity.js", + "rarity_md": "node utils/getRarity_fromMetadata.js", + "rarity_rank": "node utils/rarity_rank.js", "preview": "node utils/preview.js", "pixelate": "node utils/pixelate.js", "update_info": "node utils/update_info.js", diff --git a/utils/getRarity_fromMetadata.js b/utils/getRarity_fromMetadata.js new file mode 100644 index 00000000..d375c866 --- /dev/null +++ b/utils/getRarity_fromMetadata.js @@ -0,0 +1,65 @@ +const basePath = process.cwd(); +const fs = require("fs"); + +const getRarity = () => { + // read json data + const rawdata = fs.readFileSync(`${basePath}/build/json/_metadata.json`); + const nfts = JSON.parse(rawdata); + + processRarity(nfts) +} + +function processRarity(nfts) { + const rarity = {} + + // loop through all nfts + for(const nft of nfts) { + // check if attributes exist + if(nft?.attributes?.length > 0) { + // loop through all attributes + for(attribute of nft.attributes) { + // add trait type to rarity object if it doesn't exist + if(!rarity[attribute.trait_type]) { + rarity[attribute.trait_type] = {} + } + // add attribute value to rarity object if it doesn't exist and set count to 0 + if(!rarity[attribute.trait_type][attribute.value]) { + rarity[attribute.trait_type][attribute.value] = { + count: 0 + } + } + // increment count of trait type + rarity[attribute.trait_type][attribute.value].count++ + // add rarity score to rarity object for each trait type + rarity[attribute.trait_type][attribute.value].rarityScore = (1 / (rarity[attribute.trait_type][attribute.value].count / nfts.length)).toFixed(2) + } + } + } + + // create a total rarity score for each nft by adding up all the rarity scores for each trait type + nfts.map(nft => { + if(nft?.attributes?.length > 0) { + let totalScore = 0; + for(attribute of nft.attributes) { + attribute.rarity_score = rarity[attribute.trait_type][attribute.value].rarityScore + totalScore += parseFloat(attribute.rarity_score) + } + nft.total_rarity_score = +parseFloat(totalScore).toFixed(2) + } + }) + + // sort nfts by total rarity score + nfts.sort((a, b) => b.total_rarity_score - a.total_rarity_score) + + // add rank to nfts + nfts.map((nft, index) => { + nft.rank = index + 1 + }) + + // sort nfts by edition again + nfts.sort((a, b) => a.custom_fields.edition - b.custom_fields.edition) + + fs.writeFileSync(`${basePath}/build/json/_metadata_with_rarity.json`, JSON.stringify(nfts, null, 2)); +} + +getRarity(); diff --git a/utils/rarity_rank.js b/utils/rarity_rank.js new file mode 100644 index 00000000..a3a9b268 --- /dev/null +++ b/utils/rarity_rank.js @@ -0,0 +1,59 @@ +const basePath = process.cwd(); +const fs = require("fs"); + +// initialize readline to prompt user for input +const readline = require("readline"); +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); +const prompt = (query) => new Promise((resolve) => rl.question(query, resolve)); + +(async () => { + try { + // read json data + const rawdata = fs.readFileSync( + `${basePath}/build/json/_metadata_with_rarity.json` + ); + const nfts = JSON.parse(rawdata); + + // prompt user to choose how to list nfts + // 1. get top ## nfts + // 2. get a specific nft by edition + const choice = await prompt( + "Enter 1 to get top ## NFTs by rarity or 2 to get a specific NFTs rarity: " + ); + + if (choice === "1") { + const top = await prompt("Enter the number of NFTs you want to get: "); + const sortedNfts = nfts.sort( + (a, b) => b.total_rarity_score - a.total_rarity_score + ); + const topNfts = sortedNfts.slice(0, top); + console.log( + topNfts.map(({ rank, total_rarity_score, name }) => { + return { + name, + rank, + total_rarity_score, + }; + }) + ); + } else if (choice === "2") { + const nftEdition = await prompt("Enter the NFT Edition: "); + const nft = nfts.find((nft) => nft.custom_fields.edition === +nftEdition); + console.log({ + name: nft.name, + rank: nft.rank, + total_rarity_score: nft.total_rarity_score, + }); + } else { + console.log("Invalid choice. Enter either 1 or 2."); + } + + // close readline + rl.close(); + } catch (e) { + console.error("unable to prompt", e); + } +})();