Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index.js only has 96 lines of code #9

Open
mkhitman90 opened this issue Jan 6, 2022 · 9 comments
Open

Index.js only has 96 lines of code #9

mkhitman90 opened this issue Jan 6, 2022 · 9 comments

Comments

@mkhitman90
Copy link

In the video when he is done with config.js and opens index.js i only have 96 lines of code and he scrolls down to 260 to make a vital code change. When i look at the index.js on Github i also only see 96 lines of code... where am i going wrong to not generate the rest of the code?

@RobJay67
Copy link

I am also running into the same issue

@barnabyjones220
Copy link

look closely at the lines hes added.

the guide actually shows that the first part of the generator, only generates pictures.

you have to choose to dump them to ipfs, and then if you want, contract them, or put them on opensea with lazyminting.

The guide isnt wrong, hes just modified his for everything he wants.

In the youtube videos, it posts the github, AND the ipfs configuration. what your looking at, is the IPFS config, along with the contract signing he has built in.

if your having issues with the code, verify your running these things on a mac or linux terminal, as windows has no git commands.

pay close attention to installing pre reqs and verify they exist before moving forward.

Outside of that, you would need to be more specific other than "its missing code". I get it, i felt the same way until i did some investigation.

@mkhitman90
Copy link
Author

Sorry for my first comment i have detailed my issue more thoroughly this time i really appreciate your time and help!

So i have made some progress i have all of my generated art uploaded to moralis shown in photo. But I notice some discrepancies....

First off my photos do not have the 64 0's after them when looking at image on IPFS, but i think that may be issue with my index.js code i have shown below.

Second i noticed my columns are labeled differently than the video, this is also connected to the first issue i think.

But my big issue now is when i execute my contract i am only seeing one photo for all nft's. i will leave the code for my contract below.

Screen Shot 2022-02-02 at 7 58 35 PM

Screen Shot 2022-02-02 at 8 10 27 PM

Screen Shot 2022-02-02 at 8 10 14 PM

Here is working code for Config.js

/*******************************************************************

  • UTILITY FUNCTIONS
    • scroll to BEGIN COLLECTION CONFIG to provide the config values
      ******************************************************************/
      const fs = require("fs");
      const dir = __dirname;

// adds a rarity to the configuration. This is expected to correspond with a directory containing the rarity for each defined layer
// @param _id - id of the rarity
// @param _from - number in the edition to start this rarity from
// @param _to - number in the edition to generate this rarity to
// @return a rarity object used to dynamically generate the NFTs
const addRarity = (_id, _from, _to) => {
const _rarityWeight = {
value: _id,
from: _from,
to: _to,
layerPercent: {},
};
return _rarityWeight;
};

// get the name without last 4 characters -> slice .png from the name
const cleanName = (_str) => {
let name = _str.slice(0, -4);
return name;
};

// reads the filenames of a given folder and returns it with its name and path
const getElements = (_path, _elementCount) => {
return fs
.readdirSync(_path)
.filter((item) => !/(^|/).[^\/\.]/g.test(item))
.map((i) => {
return {
id: _elementCount,
name: cleanName(i),
path: ${_path}/${i},
};
});
};

// adds a layer to the configuration. The layer will hold information on all the defined parts and
// where they should be rendered in the image
// @param _id - id of the layer
// @param _position - on which x/y value to render this part
// @param _size - of the image
// @return a layer object used to dynamically generate the NFTs
const addLayer = (_id, _position, _size) => {
if (!_id) {
console.log("error adding layer, parameters id required");
return null;
}
if (!_position) {
_position = { x: 0, y: 0 };
}
if (!_size) {
_size = { width: width, height: height };
}
// add two different dimension for elements:
// - all elements with their path information
// - only the ids mapped to their rarity
let elements = [];
let elementCount = 0;
let elementIdsForRarity = {};
rarityWeights.forEach((rarityWeight) => {
let elementsForRarity = getElements(${dir}/${_id}/${rarityWeight.value});

elementIdsForRarity[rarityWeight.value] = [];
elementsForRarity.forEach((_elementForRarity) => {
  _elementForRarity.id = `${editionDnaPrefix}${elementCount}`;
  elements.push(_elementForRarity);
  elementIdsForRarity[rarityWeight.value].push(_elementForRarity.id);
  elementCount++;
});
elements[rarityWeight.value] = elementsForRarity;

});

let elementsForLayer = {
id: _id,
position: _position,
size: _size,
elements,
elementIdsForRarity,
};
return elementsForLayer;
};

// adds layer-specific percentages to use one vs another rarity
// @param _rarityId - the id of the rarity to specifiy
// @param _layerId - the id of the layer to specifiy
// @param _percentages - an object defining the rarities and the percentage with which a given rarity for this layer should be used
const addRarityPercentForLayer = (_rarityId, _layerId, _percentages) => {
let _rarityFound = false;
rarityWeights.forEach((_rarityWeight) => {
if (_rarityWeight.value === _rarityId) {
let _percentArray = [];
for (let percentType in _percentages) {
_percentArray.push({
id: percentType,
percent: _percentages[percentType],
});
}
_rarityWeight.layerPercent[_layerId] = _percentArray;
_rarityFound = true;
}
});
if (!_rarityFound) {
console.log(
rarity ${_rarityId} not found, failed to add percentage information
);
}
};

/**************************************************************

  • BEGIN COLLECTION CONFIG
    *************************************************************/

// image width in pixels
const width = 1000;
// image height in pixels
const height = 1000;
// description for NFT in metadata file
const description = "ZombieBottom NFT's ";
// base url in case no unique metadata file i.e IPFS
const baseImageUri = "https://rmyakitghxta.usemoralis.com:2053/server";
// id for edition to start from
const startEditionFrom = 1;
// amount of NFTs to generate in edition
const editionSize = 10;
// prefix to add to edition dna ids (to distinguish dna counts from different generation processes for the same collection)
const editionDnaPrefix = 0;

// create required weights
// for each weight, call 'addRarity' with the id and from which to which element this rarity should be applied
let rarityWeights = [
/*
addRarity("super_rare", 1, 1),
addRarity("rare", 1, 1),
*/
addRarity("original", 1, editionSize),
];

// create required layers
// for each layer, call 'addLayer' with the id and optionally the positioning and size
// the id would be the name of the folder in your input directory, e.g. 'ball' for ./input/ball
const layers = [
addLayer("Background", { x: 0, y: 0 }, { width: width, height: height }),
addLayer("Base Body"),
addLayer("Eye"),
addLayer("Eyebrow"),
addLayer("Mouth"),
addLayer("Tattoo"),

];

// provide any specific percentages that are required for a given layer and rarity level
// all provided options are used based on their percentage values to decide which layer to select from
addRarityPercentForLayer("original", "Eyes", {
super_rare: 0,
rare: 0,
original: 100,
});

module.exports = {
layers,
width,
height,
description,
baseImageUri,
editionSize,
startEditionFrom,
rarityWeights,
};

Here is working code for index.js

const fs = require("fs");
// utilise Moralis
const Moralis = require("moralis/node");

// canvas for image compile
const { createCanvas, loadImage } = require("canvas");
// import config
const {
layers,
width,
height,
description,
baseImageUri,
editionSize,
startEditionFrom,
rarityWeights,
} = require("./input/config.js");
const console = require("console");
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");

// Moralis creds
const appId = "ltslQpoP0LPEGe2KAkQgYcv9pK3KfOQlAhrIpy3O";
const serverUrl = "https://rmyakitghxta.usemoralis.com:2053/server";
const masterKey = ""; // DO NOT DISPLAY IN PUBLIC DIR
const xAPIKey = "V"; // DO NOT DISPLAY IN PUBLIC DIR
const api_url = "https://deep-index.moralis.io/api-docs/#/storage/uploadFolder";

Moralis.start({ serverUrl, appId, masterKey });

// adds a signature to the top left corner of the canvas
const signImage = (_sig) => {
ctx.fillStyle = "#000000";
ctx.font = "bold 30pt Courier";
ctx.textBaseline = "top";
ctx.textAlign = "left";
ctx.fillText(_sig, 40, 40);
};

// generate a random color hue
const genColor = () => {
let hue = Math.floor(Math.random() * 360);
let pastel = hsl(${hue}, 100%, 85%);
return pastel;
};

const drawBackground = () => {
ctx.fillStyle = genColor();
ctx.fillRect(0, 0, width, height);
};

// add metadata for individual nft edition
const generateMetadata = (_dna, _edition, _attributesList, _path) => {
let dateTime = Date.now();
let tempMetadata = {
dna: _dna.join(""),
name: #${_edition},
description: description,
image: _path || baseImageUri,
edition: _edition,
date: dateTime,
attributes: _attributesList,
};
return tempMetadata;
};

// prepare attributes for the given element to be used as metadata
const getAttributeForElement = (_element) => {
let selectedElement = _element.layer.selectedElement;
let attribute = {
name: selectedElement.name,
rarity: selectedElement.rarity,
};
return attribute;
};

// loads an image from the layer path
// returns the image in a format usable by canvas
const loadLayerImg = async (_layer) => {
return new Promise(async (resolve) => {
const image = await loadImage(${_layer.selectedElement.path});
resolve({ layer: _layer, loadedImage: image });
});
};

const drawElement = (_element) => {
ctx.drawImage(
_element.loadedImage,
_element.layer.position.x,
_element.layer.position.y,
_element.layer.size.width,
_element.layer.size.height
);
};

// check the configured layer to find information required for rendering the layer
// this maps the layer information to the generated dna and prepares it for
// drawing on a canvas
const constructLayerToDna = (_dna = [], _layers = [], _rarity) => {
let mappedDnaToLayers = _layers.map((layer, index) => {
let selectedElement = layer.elements.find(
(element) => element.id === _dna[index]
);
return {
location: layer.location,
position: layer.position,
size: layer.size,
selectedElement: { ...selectedElement, rarity: _rarity },
};
});
return mappedDnaToLayers;
};

// check if the given dna is contained within the given dnaList
// return true if it is, indicating that this dna is already in use and should be recalculated
const isDnaUnique = (_DnaList = [], _dna = []) => {
let foundDna = _DnaList.find((i) => i.join("") === _dna.join(""));
return foundDna == undefined ? true : false;
};

const getRandomRarity = (_rarityOptions) => {
let randomPercent = Math.random() * 100;
let percentCount = 0;

for (let i = 0; i <= _rarityOptions.length; i++) {
percentCount += _rarityOptions[i].percent;
if (percentCount >= randomPercent) {
console.log(use random rarity ${_rarityOptions[i].id});
return _rarityOptions[i].id;
}
}
return _rarityOptions[0].id;
};

// create a dna based on the available layers for the given rarity
// use a random part for each layer
const createDna = (_layers, _rarity) => {
let randNum = [];
let _rarityWeight = rarityWeights.find((rw) => rw.value === _rarity);
_layers.forEach((layer) => {
let num = Math.floor(
Math.random() * layer.elementIdsForRarity[_rarity].length
);
if (_rarityWeight && _rarityWeight.layerPercent[layer.id]) {
// if there is a layerPercent defined, we want to identify which dna to actually use here (instead of only picking from the same rarity)
let _rarityForLayer = getRandomRarity(
_rarityWeight.layerPercent[layer.id]
);
num = Math.floor(
Math.random() * layer.elementIdsForRarity[_rarityForLayer].length
);
randNum.push(layer.elementIdsForRarity[_rarityForLayer][num]);
} else {
randNum.push(layer.elementIdsForRarity[_rarity][num]);
}
});
return randNum;
};

// holds which rarity should be used for which image in edition
let rarityForEdition;
let filePath = null;
// get the rarity for the image by edition number that should be generated
const getRarity = (_editionCount) => {
if (!rarityForEdition) {
// prepare array to iterate over
rarityForEdition = [];
rarityWeights.forEach((rarityWeight) => {
for (let i = rarityWeight.from; i <= rarityWeight.to; i++) {
rarityForEdition.push(rarityWeight.value);
}
});
}
return rarityForEdition[editionSize - _editionCount];
};

const writeMetaData = (_data) => {
fs.writeFileSync("./output/_metadata.json", _data);
};

// holds which dna has already been used during generation
let dnaListByRarity = {};
// holds metadata for all NFTs
let metadataList = [];
// Create generative art by using the canvas api
const startCreating = async () => {
console.log("##################");
console.log("# Generative Art #");
console.log("# - Generating your NFT collection");
console.log("##################");
console.log();

// clear meta data from previous run
writeMetaData("");

// prepare dnaList object
rarityWeights.forEach((rarityWeight) => {
dnaListByRarity[rarityWeight.value] = [];
});

// create NFTs from startEditionFrom to editionSize
let editionCount = startEditionFrom;

while (editionCount <= editionSize) {
console.log("-----------------");
console.log("Mutating %d of %d", editionCount, editionSize);

// upload to ipfs
const saveFileIPFS = async () => {
  // get rarity from to config to create NFT as
  let rarity = getRarity(editionCount);
  console.log("- rarity: " + rarity);

  // calculate the NFT dna by getting a random part for each layer/feature
  // based on the ones available for the given rarity to use during generation
  let newDna = createDna(layers, rarity);
  while (!isDnaUnique(dnaListByRarity[rarity], newDna)) {
    // recalculate dna as this has been used before.
    console.log(
      "found duplicate DNA " + newDna.join("-") + ", recalculate..."
    );
    newDna = createDna(layers, rarity);
  }
  console.log("- dna: " + newDna.join("-"));

  // propagate information about required layer contained within config into a mapping object
  // = prepare for drawing
  let results = constructLayerToDna(newDna, layers, rarity);
  let loadedElements = [];

  // load all images to be used by canvas
  results.forEach((layer) => {
    loadedElements.push(loadLayerImg(layer));
  });

  let attributesList = [];

  await Promise.all(loadedElements).then((elementArray) => {
    // create empty image
    ctx.clearRect(0, 0, width, height);
    // draw a random background color
    drawBackground();
    // store information about each layer to add it as meta information
    attributesList = [];
    // draw each layer
    elementArray.forEach((element) => {
      drawElement(element);
      attributesList.push(getAttributeForElement(element));
    });
    // add an image signature as the edition count to the top left of the image
    signImage(`#${editionCount}`);
    // write the image to the output directory
  });
  dnaListByRarity[rarity].push(newDna);

  const base64ImgData = canvas.toBuffer();
  const base64 = base64ImgData.toString("base64");

  let filename = editionCount.toString() + ".png";
  let filetype = "image/png";

  // save locally as file
  fs.writeFileSync(`./output/${filename}`, canvas.toBuffer(filetype));

  // save to hosted IPFS file
  const file = new Moralis.File(filename, { base64: base64 });
  const fileIpfs = await file.saveIPFS({ useMasterKey: true });

  const filePath = file.ipfs();
  const fileHash = file.hash();

  const metadata = {
    name: filename,
    nftFilePath: filePath,
    nftFileHash: fileHash,
  };

  console.log("Metadata: ", metadata);
  console.log("File Path: ", filePath);
  console.log(
    "Mutant " + editionCount.toString() + " a resident of Moralis"
  );

  const data = {
    editionCount: editionCount,
    filePath: filePath,
    fileHash: fileHash,
    newDna: newDna,
    attributesList: attributesList,
    file: file,
  };

  return data;
};

// upload metadata
const uploadMetadata = async (_params) => {
  // do something else here after firstFunction completes
  let nftMetadata = generateMetadata(
    _params.newDna,
    _params.editionCount,
    _params.attributesList,
    _params.filePath
  );
  metadataList.push(nftMetadata);

  const metaFile = new Moralis.File(editionCount.toString() + ".json", {
    base64: Buffer.from(
      JSON.stringify(
        metadataList.find((meta) => meta.edition == _params.editionCount)
      )
    ).toString("base64"),
  });

  // save locally as file
  fs.writeFileSync(
    `./output/${editionCount}.json`,
    JSON.stringify(
      metadataList.find((meta) => meta.edition == editionCount)
    )
  );
  // save to hosted IPFS file
  let _metaFile = await metaFile.saveIPFS({ useMasterKey: true });

  // Save file reference to Moralis
  const FileDatabase = new Moralis.Object("Files");
  FileDatabase.set("name", _params.editionCount.toString());
  FileDatabase.set("path", _params.filePath);
  FileDatabase.set("hash", _params.filePath);
  FileDatabase.set("imagefile", _params.file);
  FileDatabase.set("metafile", metaFile);
  await FileDatabase.save();
};

const handleFinal = async () => {
  const image = await saveFileIPFS();
  await uploadMetadata(image);
};

await handleFinal();
// iterate
editionCount++;

}
writeMetaData(JSON.stringify(metadataList));
console.log("#########################################");
console.log("Welcome to Zombie-Bottom - Meet the Squad");
console.log("#########################################");
console.log();
};

// Initiate code
startCreating();

Contract code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

//import 1155 token contract from Openzeppelin
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

// Example contract to be deployed via https://remix.ethereum.org/ for testing purposes.

contract OZ is ERC1155, Ownable {
using SafeMath for uint256;

constructor()
    ERC1155(
        "ipfs://QmS6w7Lip6N3CVKTGNaZv7gCv3mPn2L9kDSG3rdDQBkudJ" // You can get this saved in dasboard of your Moralis server instance.
    )
{
    // account, token_id, number
    _mint(msg.sender, 1, 1, "");
    _mint(msg.sender, 2, 1, "");
    _mint(msg.sender, 3, 1, "");
}

/*
// More to come here.
function mint(address account, uint256 id, uint256 amount) public onlyOwner {
    _mint(account, id, amount, "");
}
function burn(address account, uint256 id, uint256 amount) public {
    require(msg.sender == account);
    _burn(account, id, amount);
}
*/

}

@mkhitman90
Copy link
Author

i removed my sensitive data from the index.js in the code above

@mkhitman90
Copy link
Author

one last pic of working code for generating.

Screen Shot 2022-02-02 at 8 28 18 PM

.

@lucasredway
Copy link

Sorry for my first comment i have detailed my issue more thoroughly this time i really appreciate your time and help!

So i have made some progress i have all of my generated art uploaded to moralis shown in photo. But I notice some discrepancies....

First off my photos do not have the 64 0's after them when looking at image on IPFS, but i think that may be issue with my index.js code i have shown below.

Second i noticed my columns are labeled differently than the video, this is also connected to the first issue i think.

But my big issue now is when i execute my contract i am only seeing one photo for all nft's. i will leave the code for my contract below.

Screen Shot 2022-02-02 at 7 58 35 PM Screen Shot 2022-02-02 at 8 10 27 PM Screen Shot 2022-02-02 at 8 10 14 PM

Here is working code for Config.js

/*******************************************************************

  • UTILITY FUNCTIONS
    • scroll to BEGIN COLLECTION CONFIG to provide the config values
      ******************************************************************/
      const fs = require("fs");
      const dir = __dirname;

// adds a rarity to the configuration. This is expected to correspond with a directory containing the rarity for each defined layer // @param _id - id of the rarity // @param _from - number in the edition to start this rarity from // @param _to - number in the edition to generate this rarity to // @return a rarity object used to dynamically generate the NFTs const addRarity = (_id, _from, _to) => { const _rarityWeight = { value: _id, from: _from, to: _to, layerPercent: {}, }; return _rarityWeight; };

// get the name without last 4 characters -> slice .png from the name const cleanName = (_str) => { let name = _str.slice(0, -4); return name; };

// reads the filenames of a given folder and returns it with its name and path const getElements = (_path, _elementCount) => { return fs .readdirSync(_path) .filter((item) => !/(^|/).[^\/\.]/g.test(item)) .map((i) => { return { id: _elementCount, name: cleanName(i), path: ${_path}/${i}, }; }); };

// adds a layer to the configuration. The layer will hold information on all the defined parts and // where they should be rendered in the image // @param _id - id of the layer // @param _position - on which x/y value to render this part // @param _size - of the image // @return a layer object used to dynamically generate the NFTs const addLayer = (_id, _position, _size) => { if (!_id) { console.log("error adding layer, parameters id required"); return null; } if (!_position) { _position = { x: 0, y: 0 }; } if (!_size) { _size = { width: width, height: height }; } // add two different dimension for elements: // - all elements with their path information // - only the ids mapped to their rarity let elements = []; let elementCount = 0; let elementIdsForRarity = {}; rarityWeights.forEach((rarityWeight) => { let elementsForRarity = getElements(${dir}/${_id}/${rarityWeight.value});

elementIdsForRarity[rarityWeight.value] = [];
elementsForRarity.forEach((_elementForRarity) => {
  _elementForRarity.id = `${editionDnaPrefix}${elementCount}`;
  elements.push(_elementForRarity);
  elementIdsForRarity[rarityWeight.value].push(_elementForRarity.id);
  elementCount++;
});
elements[rarityWeight.value] = elementsForRarity;

});

let elementsForLayer = { id: _id, position: _position, size: _size, elements, elementIdsForRarity, }; return elementsForLayer; };

// adds layer-specific percentages to use one vs another rarity // @param _rarityId - the id of the rarity to specifiy // @param _layerId - the id of the layer to specifiy // @param _percentages - an object defining the rarities and the percentage with which a given rarity for this layer should be used const addRarityPercentForLayer = (_rarityId, _layerId, _percentages) => { let _rarityFound = false; rarityWeights.forEach((_rarityWeight) => { if (_rarityWeight.value === _rarityId) { let _percentArray = []; for (let percentType in _percentages) { _percentArray.push({ id: percentType, percent: _percentages[percentType], }); } _rarityWeight.layerPercent[_layerId] = _percentArray; _rarityFound = true; } }); if (!_rarityFound) { console.log( rarity ${_rarityId} not found, failed to add percentage information ); } };

/**************************************************************

  • BEGIN COLLECTION CONFIG
    *************************************************************/

// image width in pixels const width = 1000; // image height in pixels const height = 1000; // description for NFT in metadata file const description = "ZombieBottom NFT's "; // base url in case no unique metadata file i.e IPFS const baseImageUri = "https://rmyakitghxta.usemoralis.com:2053/server"; // id for edition to start from const startEditionFrom = 1; // amount of NFTs to generate in edition const editionSize = 10; // prefix to add to edition dna ids (to distinguish dna counts from different generation processes for the same collection) const editionDnaPrefix = 0;

// create required weights // for each weight, call 'addRarity' with the id and from which to which element this rarity should be applied let rarityWeights = [ /* addRarity("super_rare", 1, 1), addRarity("rare", 1, 1), */ addRarity("original", 1, editionSize), ];

// create required layers // for each layer, call 'addLayer' with the id and optionally the positioning and size // the id would be the name of the folder in your input directory, e.g. 'ball' for ./input/ball const layers = [ addLayer("Background", { x: 0, y: 0 }, { width: width, height: height }), addLayer("Base Body"), addLayer("Eye"), addLayer("Eyebrow"), addLayer("Mouth"), addLayer("Tattoo"),

];

// provide any specific percentages that are required for a given layer and rarity level // all provided options are used based on their percentage values to decide which layer to select from addRarityPercentForLayer("original", "Eyes", { super_rare: 0, rare: 0, original: 100, });

module.exports = { layers, width, height, description, baseImageUri, editionSize, startEditionFrom, rarityWeights, };

Here is working code for index.js

const fs = require("fs"); // utilise Moralis const Moralis = require("moralis/node");

// canvas for image compile const { createCanvas, loadImage } = require("canvas"); // import config const { layers, width, height, description, baseImageUri, editionSize, startEditionFrom, rarityWeights, } = require("./input/config.js"); const console = require("console"); const canvas = createCanvas(width, height); const ctx = canvas.getContext("2d");

// Moralis creds const appId = "ltslQpoP0LPEGe2KAkQgYcv9pK3KfOQlAhrIpy3O"; const serverUrl = "https://rmyakitghxta.usemoralis.com:2053/server"; const masterKey = ""; // DO NOT DISPLAY IN PUBLIC DIR const xAPIKey = "V"; // DO NOT DISPLAY IN PUBLIC DIR const api_url = "https://deep-index.moralis.io/api-docs/#/storage/uploadFolder";

Moralis.start({ serverUrl, appId, masterKey });

// adds a signature to the top left corner of the canvas const signImage = (_sig) => { ctx.fillStyle = "#000000"; ctx.font = "bold 30pt Courier"; ctx.textBaseline = "top"; ctx.textAlign = "left"; ctx.fillText(_sig, 40, 40); };

// generate a random color hue const genColor = () => { let hue = Math.floor(Math.random() * 360); let pastel = hsl(${hue}, 100%, 85%); return pastel; };

const drawBackground = () => { ctx.fillStyle = genColor(); ctx.fillRect(0, 0, width, height); };

// add metadata for individual nft edition const generateMetadata = (_dna, _edition, _attributesList, _path) => { let dateTime = Date.now(); let tempMetadata = { dna: _dna.join(""), name: #${_edition}, description: description, image: _path || baseImageUri, edition: _edition, date: dateTime, attributes: _attributesList, }; return tempMetadata; };

// prepare attributes for the given element to be used as metadata const getAttributeForElement = (_element) => { let selectedElement = _element.layer.selectedElement; let attribute = { name: selectedElement.name, rarity: selectedElement.rarity, }; return attribute; };

// loads an image from the layer path // returns the image in a format usable by canvas const loadLayerImg = async (_layer) => { return new Promise(async (resolve) => { const image = await loadImage(${_layer.selectedElement.path}); resolve({ layer: _layer, loadedImage: image }); }); };

const drawElement = (_element) => { ctx.drawImage( _element.loadedImage, _element.layer.position.x, _element.layer.position.y, _element.layer.size.width, _element.layer.size.height ); };

// check the configured layer to find information required for rendering the layer // this maps the layer information to the generated dna and prepares it for // drawing on a canvas const constructLayerToDna = (_dna = [], _layers = [], _rarity) => { let mappedDnaToLayers = _layers.map((layer, index) => { let selectedElement = layer.elements.find( (element) => element.id === _dna[index] ); return { location: layer.location, position: layer.position, size: layer.size, selectedElement: { ...selectedElement, rarity: _rarity }, }; }); return mappedDnaToLayers; };

// check if the given dna is contained within the given dnaList // return true if it is, indicating that this dna is already in use and should be recalculated const isDnaUnique = (_DnaList = [], _dna = []) => { let foundDna = _DnaList.find((i) => i.join("") === _dna.join("")); return foundDna == undefined ? true : false; };

const getRandomRarity = (_rarityOptions) => { let randomPercent = Math.random() * 100; let percentCount = 0;

for (let i = 0; i <= _rarityOptions.length; i++) { percentCount += _rarityOptions[i].percent; if (percentCount >= randomPercent) { console.log(use random rarity ${_rarityOptions[i].id}); return _rarityOptions[i].id; } } return _rarityOptions[0].id; };

// create a dna based on the available layers for the given rarity // use a random part for each layer const createDna = (_layers, _rarity) => { let randNum = []; let _rarityWeight = rarityWeights.find((rw) => rw.value === _rarity); _layers.forEach((layer) => { let num = Math.floor( Math.random() * layer.elementIdsForRarity[_rarity].length ); if (_rarityWeight && _rarityWeight.layerPercent[layer.id]) { // if there is a layerPercent defined, we want to identify which dna to actually use here (instead of only picking from the same rarity) let _rarityForLayer = getRandomRarity( _rarityWeight.layerPercent[layer.id] ); num = Math.floor( Math.random() * layer.elementIdsForRarity[_rarityForLayer].length ); randNum.push(layer.elementIdsForRarity[_rarityForLayer][num]); } else { randNum.push(layer.elementIdsForRarity[_rarity][num]); } }); return randNum; };

// holds which rarity should be used for which image in edition let rarityForEdition; let filePath = null; // get the rarity for the image by edition number that should be generated const getRarity = (_editionCount) => { if (!rarityForEdition) { // prepare array to iterate over rarityForEdition = []; rarityWeights.forEach((rarityWeight) => { for (let i = rarityWeight.from; i <= rarityWeight.to; i++) { rarityForEdition.push(rarityWeight.value); } }); } return rarityForEdition[editionSize - _editionCount]; };

const writeMetaData = (_data) => { fs.writeFileSync("./output/_metadata.json", _data); };

// holds which dna has already been used during generation let dnaListByRarity = {}; // holds metadata for all NFTs let metadataList = []; // Create generative art by using the canvas api const startCreating = async () => { console.log("##################"); console.log("# Generative Art #"); console.log("# - Generating your NFT collection"); console.log("##################"); console.log();

// clear meta data from previous run writeMetaData("");

// prepare dnaList object rarityWeights.forEach((rarityWeight) => { dnaListByRarity[rarityWeight.value] = []; });

// create NFTs from startEditionFrom to editionSize let editionCount = startEditionFrom;

while (editionCount <= editionSize) { console.log("-----------------"); console.log("Mutating %d of %d", editionCount, editionSize);

// upload to ipfs
const saveFileIPFS = async () => {
  // get rarity from to config to create NFT as
  let rarity = getRarity(editionCount);
  console.log("- rarity: " + rarity);

  // calculate the NFT dna by getting a random part for each layer/feature
  // based on the ones available for the given rarity to use during generation
  let newDna = createDna(layers, rarity);
  while (!isDnaUnique(dnaListByRarity[rarity], newDna)) {
    // recalculate dna as this has been used before.
    console.log(
      "found duplicate DNA " + newDna.join("-") + ", recalculate..."
    );
    newDna = createDna(layers, rarity);
  }
  console.log("- dna: " + newDna.join("-"));

  // propagate information about required layer contained within config into a mapping object
  // = prepare for drawing
  let results = constructLayerToDna(newDna, layers, rarity);
  let loadedElements = [];

  // load all images to be used by canvas
  results.forEach((layer) => {
    loadedElements.push(loadLayerImg(layer));
  });

  let attributesList = [];

  await Promise.all(loadedElements).then((elementArray) => {
    // create empty image
    ctx.clearRect(0, 0, width, height);
    // draw a random background color
    drawBackground();
    // store information about each layer to add it as meta information
    attributesList = [];
    // draw each layer
    elementArray.forEach((element) => {
      drawElement(element);
      attributesList.push(getAttributeForElement(element));
    });
    // add an image signature as the edition count to the top left of the image
    signImage(`#${editionCount}`);
    // write the image to the output directory
  });
  dnaListByRarity[rarity].push(newDna);

  const base64ImgData = canvas.toBuffer();
  const base64 = base64ImgData.toString("base64");

  let filename = editionCount.toString() + ".png";
  let filetype = "image/png";

  // save locally as file
  fs.writeFileSync(`./output/${filename}`, canvas.toBuffer(filetype));

  // save to hosted IPFS file
  const file = new Moralis.File(filename, { base64: base64 });
  const fileIpfs = await file.saveIPFS({ useMasterKey: true });

  const filePath = file.ipfs();
  const fileHash = file.hash();

  const metadata = {
    name: filename,
    nftFilePath: filePath,
    nftFileHash: fileHash,
  };

  console.log("Metadata: ", metadata);
  console.log("File Path: ", filePath);
  console.log(
    "Mutant " + editionCount.toString() + " a resident of Moralis"
  );

  const data = {
    editionCount: editionCount,
    filePath: filePath,
    fileHash: fileHash,
    newDna: newDna,
    attributesList: attributesList,
    file: file,
  };

  return data;
};

// upload metadata
const uploadMetadata = async (_params) => {
  // do something else here after firstFunction completes
  let nftMetadata = generateMetadata(
    _params.newDna,
    _params.editionCount,
    _params.attributesList,
    _params.filePath
  );
  metadataList.push(nftMetadata);

  const metaFile = new Moralis.File(editionCount.toString() + ".json", {
    base64: Buffer.from(
      JSON.stringify(
        metadataList.find((meta) => meta.edition == _params.editionCount)
      )
    ).toString("base64"),
  });

  // save locally as file
  fs.writeFileSync(
    `./output/${editionCount}.json`,
    JSON.stringify(
      metadataList.find((meta) => meta.edition == editionCount)
    )
  );
  // save to hosted IPFS file
  let _metaFile = await metaFile.saveIPFS({ useMasterKey: true });

  // Save file reference to Moralis
  const FileDatabase = new Moralis.Object("Files");
  FileDatabase.set("name", _params.editionCount.toString());
  FileDatabase.set("path", _params.filePath);
  FileDatabase.set("hash", _params.filePath);
  FileDatabase.set("imagefile", _params.file);
  FileDatabase.set("metafile", metaFile);
  await FileDatabase.save();
};

const handleFinal = async () => {
  const image = await saveFileIPFS();
  await uploadMetadata(image);
};

await handleFinal();
// iterate
editionCount++;

} writeMetaData(JSON.stringify(metadataList)); console.log("#########################################"); console.log("Welcome to Zombie-Bottom - Meet the Squad"); console.log("#########################################"); console.log(); };

// Initiate code startCreating();

Contract code

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

//import 1155 token contract from Openzeppelin import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol"; import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol"; import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

// Example contract to be deployed via https://remix.ethereum.org/ for testing purposes.

contract OZ is ERC1155, Ownable { using SafeMath for uint256;

constructor()
    ERC1155(
        "ipfs://QmS6w7Lip6N3CVKTGNaZv7gCv3mPn2L9kDSG3rdDQBkudJ" // You can get this saved in dasboard of your Moralis server instance.
    )
{
    // account, token_id, number
    _mint(msg.sender, 1, 1, "");
    _mint(msg.sender, 2, 1, "");
    _mint(msg.sender, 3, 1, "");
}

/*
// More to come here.
function mint(address account, uint256 id, uint256 amount) public onlyOwner {
    _mint(account, id, amount, "");
}
function burn(address account, uint256 id, uint256 amount) public {
    require(msg.sender == account);
    _burn(account, id, amount);
}
*/

}

Please send full code in this file

@roop37
Copy link

roop37 commented Feb 18, 2022

got the codes bro?

@roop37
Copy link

roop37 commented Feb 18, 2022

need the codes asap
image

@mkhitman90
Copy link
Author

mkhitman90 commented Feb 18, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants