Posted on Jan 30, 2022Read on Mirror.xyz

How to create an NFT collection with Solidity and JavaScript

Everyone is talking about Bored Apes, CryptoPunks, and Azuki, but have you ever wondered how they were created? This article might help answer that question.

Below is an overview of what we will do:

  • Create algorithmically generated images using JavaScript. Let’s use Azuki #1 as an example; by inspecting the NFT metadata here, we can see that the character has many attributes such as hair, clothing, eyes, etc. The artists will design and create different assets for each attribute, e.g. the hair can be short and pink, long and black, etc. The developer will run a program that generates the final image where each attribute is randomly selected.


  • Upload the images and the metadata to IPFS, we will use Pinata to do this. Those data will live on IPFS, a decentralised network, forever.
  • Write and deploy a smart contract in Solidity. We will use the smart contract to mint our NFTs. Minting means creating the NFT on the Ethereum blockchain. After we have minted the NFTs, we can view them on OpenSea.

Generate images with JavaScript

  • Clone the art engine repository from Hashlips: git clone[git@github.com](mailto:git@github.com):HashLips/hashlips_art_engine.git
  • Install the packages: npm install
  • The index.js script selects a random image for each attribute, e.g. background, eye color etc found in the layers folder and merges them into a single asset. Run npm run generate to output the art in the build/images directory.

Randomly Generate Art

Upload assets to Pinata

  • Sign in or create an account for Pinata Cloud.
  • Click upload and select the build/images folder we created above. Copy the CID value.
  • Go back to config.js in the art engine project, update the following values:
    • namePrefix, the prefix of the NFT name, e.g. for Azuki #1, Azuki is the namePrefix.
    • description, the description of the NFT collection.
    • baseUri, the base IPFS uri which references to the material you have uploaded using Pinata, and it will look something like ipfs://<IMAGES_FOLDER_CID>, e.g. ipfs://QmeoAsjESagveRXyZYENYZHMAskWSWqwqVWfNuAp42yKrS
  • Update the JSON metadata: npm run update_info. This updates the JSON files in build/json.

Update JSON Metadata

  • On Pinata, upload the JSON folder like you did for the images folder.

Deploy the smart contract

  • You will need MetaMask for this step. Install it from the official website if you haven’t already.
  • Change to the Ropsten Tests Network from the MetaMask extension.
  • (Optional) if you don’t have any test ether, get some from the ropsten faucet.
  • Go to the Remix IDE and create a MyNFT.sol file in the contracts folder.
  • Copy and paste the content of NFTLowerGas.sol from my repo. This file is adapted from SimpleNftLowerGas.sol from Hashlips. The main difference is I removed the hidden functionality, e.g. a placeholder is shown instead of the original NFT image until the collection owner chooses to reveal the images. Removing the functionality reduces the friction during the development and deployment process.
  • In MyNFT.sol, rename the contract name from NFTLowerGas to MyNFT. Matching the file name against the contract name is a best practice.
  • Compile MyNFT.sol.

Compile MyNFT

  • In the Deploy & Run Transactions tab, choose the Injected Web3 environment and select the MyNFT contract.
  • Click the arrow next to “Deploy” to expand a list of input arguments.
    • _NAME is the name of the ERC721 token.
    • _SYMBOL usually abbreviates the _NAME, e.g. the symbol for Bored Ape Yacht Club is BAYC.
    • _URIPREFIX is the IPFS uri that points to the JSON folder we uploaded, e.g. mine is ipfs://QmbUT1yg2BNhwV1r7h9vgDusjXh7mpvjfyX7JBPjUMpJ7H/, it’s the CID points to the JSON folder, and it’s important to include the / at the end.

Deploy MyNFT

Mint the NFTs

  • Once the MyNFT contract is deployed, we should see the it in the “Deployed Contracts” section.
  • Call the setPaused function with the input value of false.
  • Call the mint function, remember to specify the _mintAmount, e.g. 2.

Note: the MetaMask dialog will show every time we make a transaction. Make sure we are on the test network so we don’t spend any real ether.

View NFTs on OpenSea

  • Go to OpenSea Testnets.
  • Connect with your MetaMask account you used to mint the NFTs.
  • You should see a few purple eyes under your collection.


We could customise some important values in the JavaScript files and the smart contract. Here I will briefly mention that we could set the rarity of each attribute of the NFT, e.g. if we look at the layers/Eyeball folder, we have two files, Red#50.png and White#50.png, an equal chance of the image having either a red or white eyeball. You can see more in README.md of the art engine project. Some examples for the values we can customise in the smart contract are cost (the price of minting one NFT), maxSupply (the total number of NFT available) etc.

To recap, we have generated some art images with JavaScript by combining the assets that someone has already designed and made for us. We uploaded the generated artwork and the JSON metadata to Pinata Cloud. Finally, we deployed a Solidity smart contract on the Ropsten testnet to mint our NFTs. We can view those NFTs easily on OpenSea. I hope this tutorial was helpful, and I’d love it if you could share it with others so more people can benefit from it.