Skip to content

Commit

Permalink
Merge pull request #21 from thepeanutgalleryandco/v1-5-0
Browse files Browse the repository at this point in the history
V1 5 0
  • Loading branch information
thepeanutgalleryandco committed Feb 4, 2022
2 parents bc7f3ea + 8d0842f commit c819e31
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 23 deletions.
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Base code is from the below repos - Massive thank you to the teams behind these
- [hashlips_art_engine](https://github.com/HashLips/hashlips_art_engine)
- [codeSTACKr](https://github.com/codeSTACKr/video-source-code-create-nft-collection/)
- [Gerhard Molin - Provenance Addition](https://github.com/avocadohooman)
- [Arnau González - Exclusions Addition](https://github.com/arnaugm)

File Uploads can be done via [Pinata](https://app.pinata.cloud/) or a similar service that gives you a single CID for images and another one for meta files or [NFTPort](https://nftport.xyz) can be used.

Expand All @@ -40,12 +41,25 @@ If you would like to support my NFT collection, please take a look at the below.
## Dependencies for scripts to run
- `npm install`

**Please note that if you have a Mac with a M1 chip and you run into issues with npm install, then please try to install Node.js version 14 instead of the latest Node version and try the npm install again **


## UPDATES & FIXES


### Added metadata exclusions functionality
Users have new metadata exclusion configuration options
- Maximum Repeatability - Set the maximum number of times that a layer be generated per layer configuration set. This is not on a layer item level, but instead of a layer level.
- Incompatible Traits - Set the combination of traits that may not be generated together to remove / enforce certain combinations.

Please see the [Layer Configuration](./README.md#b-update-your-layer-configurations) section.

### Randomise generic metadata image URLs
Uses can now generate generic metadata where each NFT contains a different / randomised image URL instead of a static image URL. Users manually upload their generic images and retrieve the IPFS URLs and then simply add them into the list for genericURLs. Please see the [Generic Metadata](./README.md#9-update-nfts-for-reveal---generic-image-until-purchased-then-only-reveal-nft) section.


### Added provenance generation capability (Experimental)
Users can now generate provenance hashes for each image and for their whole collection. Please see the [Provenance Section](./README.md#d-provenance-information) section.
Users can now generate provenance hashes for each image and for their whole collection. Please see the [Provenance](./README.md#d-provenance-information) section.


### Added Support For ERC1155 Batch Minting And Total Token Count
Expand Down Expand Up @@ -87,9 +101,14 @@ Modify the following parts at the very least, below are just sample values that
#### a. If you are planning on using Solana, then update this section.
<img width="1134" alt="Screenshot 2022-01-13 at 12 47 25" src="https://user-images.githubusercontent.com/52892685/149316077-8479678d-57fc-418f-9a91-4d74c26e8b59.png">

#### b. Update your layer folder names, order in which they need to be processed and the number of images to create
#### b. Update your layer configurations
- Update your folder names, order in which they need to be processed and the number of images to create
- Optionally add maximum repeatability rule in for the layers - Please see [Maximum Repeatability Feature](https://github.com/thepeanutgalleryandco/create-and-mint-nft-collection/issues/16)
- Optionally add layer combination exclusion rules in for the layers - Please see [Layer Combination Exclusion Feature](https://github.com/thepeanutgalleryandco/create-and-mint-nft-collection/issues/15)

*Example of default configuration along with maximum repeatability and layer compatibility*

<img width="420" alt="Screenshot 2022-01-13 at 12 47 53" src="https://user-images.githubusercontent.com/52892685/149316165-e1b92db3-ce8d-428e-9b30-76f2b606f960.png">
![Screenshot 2022-02-04 at 15 12 32](https://user-images.githubusercontent.com/52892685/152534935-739acf27-238f-4cc2-b654-e819b481892d.png)


#### c. Update the width and height of your canvas
Expand All @@ -110,11 +129,11 @@ Update the `constants/nft_details.js` file with the details that you want to be
- `ignoreExactBlankName` - This value is a boolean with a value of false or true. If true, then any layer that contains only the name "blank" with a rarity character and value in the metadata will be skipped and not added to the properties of the NFT. When set to false, then the information will be added to the metadata and added to the properties of the NFT.
- `genericTitle` - Replace with what you want the generic titles to say. Only change if you are planning on using NFT reveal and want a different name for your NFTs.
- `genericDescription` - Replace with what you want the generic descriptions to say. Only change if you are planning on using NFT reveal and want a different name for your NFTs.
- `genericURL` - Replace with the image URL that your generic NFTs should show. Only change if you are planning on using NFT reveal and want a different name for your NFTs.
- `genericURLs` - Replace with the image URLs that your generic NFTs should show. Only change if you are planning on using NFT reveal and want a different name for your NFTs.
- `ignoreAllNamesWithBlank` - This value is a boolean with a value of false or true. If true, then any layer item that contains the word blank within the filename will be skipped from being added to the metadata information. When set to false, then the information will be added to the metadata. E.x white_eyes_blank #100.png will be added to metadata if set to false, while being skipped if true.

Modify only the parts that you will be using and keep the rest as set by default.
For example, if you are planning on using NFTPort for your file and metadata uploads, then do not modify the `imageFilesBase` and `metaDataJSONFilesBase` fields. If you are planning on not doing a reveal NFT collection and simply have everything revealed, then do not modify the `genericTitle`, `genericDescription` and `genericURL` fields. If you want your NFT properties on Opensea to show, for example "Blank #15.png", then set the `ignoreExactBlankName` value to false. If you want to remove all "blank" layer items from your NFT properties on Opensea, for example "white_eyes_blank #10.png", then set the `ignoreAllNamesWithBlank` value to true.
For example, if you are planning on using NFTPort for your file and metadata uploads, then do not modify the `imageFilesBase` and `metaDataJSONFilesBase` fields. If you are planning on not doing a reveal NFT collection and simply have everything revealed, then do not modify the `genericTitle`, `genericDescription` and `genericURLs` fields. If you want your NFT properties on Opensea to show, for example "Blank #15.png", then set the `ignoreExactBlankName` value to false. If you want to remove all "blank" layer items from your NFT properties on Opensea, for example "white_eyes_blank #10.png", then set the `ignoreAllNamesWithBlank` value to true.

Example configuration:
<img width="1100" alt="Screenshot 2022-01-24 at 11 13 59" src="https://user-images.githubusercontent.com/52892685/150754309-05cbd195-3249-490a-a5a2-529f968d8f28.png">
Expand Down Expand Up @@ -200,13 +219,13 @@ Use this only if you want to use a different name and description for your NFTs


### 9. Update NFTs For Reveal - Generic Image Until Purchased, Then Only Reveal NFT
Use the `Custom - Update_Json_To_Generic_Meta Command` below to update all NFT files with the `genericTitle`, `genericDescription` and `genericURL` values set in the `constants/account_details.js` files. This will be shown as your NFTs details and picture before a purchase.
Use the `Custom - Update_Json_To_Generic_Meta Command` below to update all NFT files with the `genericTitle`, `genericDescription` and `genericURLs` values set in the `constants/nft_details.js` file. This will be shown as your NFT's details and picture before a purchase.

This process will create a new `genericJSON` directory where the `_metadata.json` file will be located along with each file's generic JSON object file. Remember to change your `uploadGenericMeta` key's value to `true` in the `constants/account_details.js` file before making use of the UploadMetas script so that it will upload the files in this directory instead of the normal `json` directory if you are making use of reveals.

**Please remember that your contract needs to be updateable to use this, otherwise this image will stay the image of your NFT, before and after purchase.**

**Please remember to update the genericURL field with the URL where the generic image is located. If you need to upload a single file to IPFS, simply use the NFTPort API via the frontend to upload a file and receive an IPFS URL that you can use for the genericURL field.**
**Please remember to update the genericURLs field with the URLs where the generic images are located. You can upload your generic image files to IPFS by simply using the NFTPort API via the frontend to upload a file and receive an IPFS URL that you can use within the genericURLs field.**


### 10. Uploading Files (Images and Metadata)
Expand Down
2 changes: 1 addition & 1 deletion constants/account_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const ACCOUNT_DETAILS = {
contract_address: 'YOUR_CONTRACT_ADDRESS_HERE', // Set your contract address here, not your transaction hash. After creating a contract on NFTPort, retrieve the contract address via the APIs. Ex. 0xfe81cm1l28b21753ebe117c84als2d6588e150ff
mint_to_address: 'YOUR_WALLET_ADDRESS_HERE', // Set your wallet address here that will be the owner of the minted NFTs. Ex. 0x5cE5D823f4bD8Ec610293fBa65832B479152C7E1
chain: 'CHAIN_TO_MINT_TO', // Set the chain where the NFTs will be minted to here. At the time of writing, "polygon" and "rinkeby" are possible values.
max_rate_limit: '1', // Update your ratelimit linked to your APIKey / account from NFTPort. Ex. '1'
max_rate_limit: '2', // Update your ratelimit linked to your APIKey / account from NFTPort. Ex. '1'
numberOfRetries: '2', // Update your API retry count here so that your NFTPort APIs can attempt a retry if unsuccessful at first. Ex. '3'
timeout: '1000', // Milliseconds. Set the timeout for API errors. If there is an error, it will wait then try again. 5000 = 5 seconds.
mint_range: ['1','2'], // Set your min and max values in here and all NFT editions in this range will be minted and these values are inclusive. Ex. '5','10' will mint NFTs 5, 6, 7, 8, 9 and 10.
Expand Down
2 changes: 1 addition & 1 deletion constants/nft_details.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-and-mint-nft-collection",
"version": "1.4.2",
"version": "1.5.0",
"description": "Source code to create and mint generative art via NFTPort API. Special thanks to codeSTACKr and Hashlips for their source codebase.",
"main": "index.js",
"bin": "index.js",
Expand Down
13 changes: 13 additions & 0 deletions src/exclusions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Load modules and constants
const { combinationOfTraitsAlreadyExists } = require('./exclusions/combination_traits');
const { incompatibleTraitsUsed } = require('./exclusions/incompatible_traits');

// Checks the different exclusions and return true if any of them are true
const needsExclusion = (selectedTraitsList, newTraits, maxRepeatedTraits, incompatibleTraits) => {

return combinationOfTraitsAlreadyExists(selectedTraitsList, newTraits, maxRepeatedTraits) || incompatibleTraitsUsed(newTraits, incompatibleTraits);
};

module.exports = {
needsExclusion,
};
40 changes: 40 additions & 0 deletions src/exclusions/combination_traits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Check if the maximum repeatability have been reached
const combinationOfTraitsAlreadyExists = (selectedTraitsList, newTraits, maxRepeatedTraits) => {
//console.log(newTraits);
// Check if maximum repeatability check needs to be done and if not, return false and exit this check
if (!maxRepeatedTraits) {
return false;
}

// Loops through each trait within the selected traits list
for (let existingTraits of selectedTraitsList) {

// Set a starting value of 0 for the selected traits
let commonTraits = 0;

// Loops through each new trait and only keep on looping if maximum repeatability have not been reached
for (let i = 0; (i < newTraits.length) && (commonTraits <= maxRepeatedTraits); i++) {

// Checks if the new trait is already in the selected traits list
if (newTraits[i].id === existingTraits[i].id) {

// Increment the selected traits value as it has been found before
commonTraits++;
}
}

// Check if the selected trait has breached the maximum repeatability limit and return true if that is the case
if (commonTraits > maxRepeatedTraits) {
console.log("Combination of traits excluded because of maximum repeatability exclusion rule!");
return true;
}

}

// Return false if the traits have been looped through and the maximum repeatability have not been breached
return false;
};

module.exports = {
combinationOfTraitsAlreadyExists,
};
57 changes: 57 additions & 0 deletions src/exclusions/incompatible_traits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Take in a list of layers and then build a simple json object that contains the layer name with the layer item next to it.
const simplifyTraits = (traits) => {
const simpleTraits = {};
traits.forEach((trait) => {
simpleTraits[trait.layer] = trait.name;
});
return simpleTraits;
};

// Set true / false if the layer has defined incompatibilities
const traitHasDefinedIncompatibilities = (newTrait, incompatibleTraits) => {
const traitKey = `${newTrait.layer}/${newTrait.name}`;
return incompatibleTraits[traitKey];
};

// Set true / false if incompatabale layers are used and return true if it is the case
const incompatibleTraitsUsed = (newTraits, incompatibleTraits) => {

// Check if incompatible traits check needs to be done and if not, return false and exit this check
if (!incompatibleTraits) {
return false;
}

// Generate a layer_name: layer_item json object from the traits list
const simpleNewTraits = simplifyTraits(newTraits);

// Loop through each layer in the list
for (let i = 0; (i < newTraits.length); i++) {

// Set true / false if the layer has a defined incompatibility
const definedIncompatibilities = traitHasDefinedIncompatibilities(newTraits[i], incompatibleTraits);

// Check if incompatibilities were found for the layer
if (definedIncompatibilities !== undefined) {

// Loop through each of the incompatibility layer items
for (let n = 0; (n < definedIncompatibilities.length); n++) {

// Split each of the incompatibility layers into a layer name and a layer item
const [layer, trait] = definedIncompatibilities[n].split('/');

// Check if the layer name and layer item combination can be found in the layer_name and layer_item json object and if it can be found, return true and stop processing further
if (simpleNewTraits[layer] === trait) {
console.log("Combination of traits excluded because of incompatible layers exclusion rule!");
return true;
}
}
}
}

// If all layers and layer items were checked and no incompatibilities found, then return false
return false;
};

module.exports = {
incompatibleTraitsUsed,
};
Loading

0 comments on commit c819e31

Please sign in to comment.