paint-brush
How to Create On-Chain and Off-Chain NFT Collection Smart Contractsby@pranaybathini
2,490 reads
2,490 reads

How to Create On-Chain and Off-Chain NFT Collection Smart Contracts

by Pranay BathiniMarch 3rd, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

The idea to create an NFT DApp is inspired from the loot project but I also want to add my own flavors of creativity to it and understand the working of smart contracts in the process. I am also going to show how to create your own DApp which I designed for fun last year and also to learn about NFTs and DApps. To develop our own NFT smart contract, we require [Ownable](https://://www.hackernoon.com/2021/07/how-to-create-your-own-cryptocurrency-on-ethereum.html)

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How to Create On-Chain and Off-Chain NFT Collection Smart Contracts
Pranay Bathini HackerNoon profile picture



Introduction

In this series of blogs, I am going to show how to create an on-chain and off-chain NFT collection smart contract and create a DApp to mint NFTs.


I am also going to show how to create your own DApp which I designed for fun last year and also to learn about NFTs and DApps.


Idea

The idea to create an NFT DApp is inspired by the loot project but I also want to add my own flavors of creativity to it and understand the working of smart contracts in the process.


Learning

Before this, I tried out different things like building my own token on the Ethereum test network back in July 2021 when I am new to cryptocurrency space and understanding little things like how merkle tree is used.


It is this time when I learned about remix IDE, MetaMask wallet, different test networks of Ethereum blockchain, deploying smart contracts through remix IDE. I also learned little things like we can deploy the same contract which deployed on Ethereum blockchain on other blockchains like Binance Smart Chain.


I have decided what to build but don’t know how. I began exploring some resources with little knowledge and found this solidity tutorial from a Reddit post.


I have gone through the solidity basics to understand code from verified smart contracts and to develop new ones.


Smart Contract Development

After getting a bit of knowledge on solidity, I began exploring the smart contract of the loot project. It didn’t make much sense but after spending some time with it, I understood the working.


I know ERC-721 standard is used to build NFTs and ERC-20 standard to build our own token on Ethereum blockchain but don’t know what functions exactly we need to define in those standards.

I referred to openzeppelin docs to understand more about the functions in the ERC-721. So, without any further journey lessons, I will jump into smart contract development.


To develop our own NFT smart contract, we require

  • Ownable Smart contract

    • It is used to manage the ownership of the contract. By default, the owner of a smart contract is the address from which it is deployed.
    • It has functions that lets transfer ownership of the contract to another address using[transferOwnership(newOwner)](https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable-transferOwnership-address-) method.
    • It lets you renounce your ownership of the contract with [renounceOwnership()](https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable-renounceOwnership--)
    • It provides [onlyOwner()](https://docs.openzeppelin.com/contracts/2.x/api/ownership#Ownable-onlyOwner--) modifier to let some functions get executed by the only owner like starting the sale, pausing the contract, Give away NFTs from the contract.
  • Enumerable721 Smart contract

    • It extends ERC721 standards, so we don’t need our contract to extend ERC721 contract explicitly.
    • This provides enumerability of all the token ids in the contract as well as all token ids owned by each account.
    • See the functions provided by the documentation.
  • ReentrancyGuard Smart Contract

    • This module helps prevent reentrant calls to a function meaning it makes [nonReentrant](https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard-nonReentrant--)modifier available, which can be applied to functions to make sure there are no nested (reentrant) calls to them.
    • Functions marked as nonReentrant may not call one another.
  • Pausable Smart Contract

    • It is also advisable to extend this one which allows child contracts to implement an emergency stop mechanism that can be triggered by an authorized account.
    • This used through inheritance and makes modifiers whenNotPaused  and whenPaused available which can be applied to the functions of your contract.


We can make our main smart contract extend these smart contracts directly by importing these in our code.


The code is found here for Loot Royale Onchain NFT Smart Contract - https://gist.github.com/pranaybathini/52f4ff2da4c3518855264febe7d95739


Let us discuss the functions inside the main smart contract - BattleRoyale.sol

Three functions are important.


  • Function to let the users mint NFT Tokens by paying the required amount of price for the NFTs they are minting
  • Function to get the token URI of the NFT. This takes in token Id and gives a JSON with the NFT. Here in our case, it is an SVG image generated from the code - On Chain. No external calls are required.
  • Function to get the amount from the contract address to your own address or any address you want to withdraw. I wrote the function to withdraw to owner's address of the smart contract.


NFT Design for on-chain smart contract

Here is what one of my NFTs looks like.


A simple HTML CSS Design inside svg tag with curved border and it also displays the token ID at the top. It took some time for me to realize that we can include html CSS inside svg tag. Initially, I took the HTML CSS code and used this site to convert to SVG but the output svg size is very heavy.


Another problem I faced while storing this data for design was that the max size of a smart contract cannot be more than 24576 bytes. So, I moved the code to another smart contract then to library, just so to reuse it in another contract. This is just one line but took some time since I tried optimizing it first before realizing I can do move this to another contract. Learning++.


Here is the link to SVG Code for the above NFT.

Also, you can see my data in the code which is different from loot project. You should have guessed by now where I gotmy data from. Now let’s see what are on-chain vs off-chain NFTs.



On-chain vs Off-chain NFTs

The difference between on-chain and off-chain NFTs as the name suggests we will be storing all the data related to NFTs on the blockchain itself for on-chain NFTs.

In the case of off-chain, I need to provide some external URLs like https://somedomain.com , ipfs://sha256hash/1.png.


In both cases, I need to return the JSON output file following the NFT metadata standard.

A sample IPFS image URL looks like this -


ipfs://QmV3yGkzx2Uw3NHPZV9SAMLA58j7LvCFLFYtyfCMBAvstF/2.jpg


You can open this in brave browser directly - a pin I have drawn on the art flow mobile app a long time back.


If we were to create off-chain NFTs, what would the code look like?

Refer to this github gist link for offchain smart contract.


I will set the IPFS or HTTPS BASE URI in the contract when the sale starts or nowadays, the developers are revealing the NFTs after all NFTs are minted.


It is simple to write a function to set URI variable and call it once all NFTs are minted.


There are two variables

  • Base URI - actual URI for NFTs
  • Blind URI - Till we reveal the NFTs, this image or video will be the same for all the minted NFTs.


The URI we should set will be like ipfs://QmV3yGkzx2Uw3NHPZV9SAMLA58j7LvCFLFYtyfCMBAvstF/

When we query, our token Id gets appended to it and Open Sea or any other marketplace can find and display it.


Starting steps are to set the contract active, then set the blind URI. Once all NFTs are minted, you can reveal the NFTs minted.


The tokenURI method output will look like


{
    "image": "ipfs://QmV3yGkzx2Uw3NHPZV9SAMLA58j7LvCFLFYtyfCMBAvstF/1.png",
    "name": "Loot Royale 1",
    "description" : "Some description"
}




Compiling and Deploying to blockchain

Now we have our contracts, how do we deploy them to the blockchain network. Many blockchains forked Ethereum with added changes to bring DApp development features. You can deploy to any network that supports solidity.

Let us deploy this on-chain NFT smart contract to Ethereum’s Ropsten test network. But before that, we need




Next steps

  • Copy the contract to your remix IDE. It should look like below.


  • You can select the compiler version to any version above 8.0 But remember this version which you used to compile. This is needed while verifying the contract on the block explorer.
  • In case you don’t know what is a block explorer, refer to this blog to understand in detail.
  • Go to the compiler tab and click on compile. You should see a green tick mark like below.



  • Go to the deploy tab. You should select the contract as BattleRoyale.sol
  • By default, the environment will be Javascript VM. All the transactions will be executed in a sandbox blockchain in the browser. This means nothing will be persisted when you reload the page. The Javascript VM is its own blockchain and on each reload it will start a new blockchain, the old one will not be saved.


  • You need to select Injected Web3 as an environment, which will allow us to inject metamask and deploy to the network selected on metamask. You should be able to see your metamask account and balance in the accounts section.

  • When you click on deploy, you will be prompted twice. First, the CardDesign Library is deployed and then our smart contract.

  • You will receive two metamask notifications once the contracts are deployed. Click on them, you will be redirected to Ropsten block explorer. You can also view the transactions from the activity tab in metamask.

  • Congrats, now the On-chain NFT smart contract - loot royale has been deployed.


But how do we interact with it? I will explain in detail how to interact with it from our custom react frontend later. Let’s see how to interact with the contract from the block explorer.


FYI, block explorer is also a DApp.



Verifying the contract on blockchain Explorer

Now, let us verify the contract on the blockchain explorer and interact with it from the explorer itself.

  • Open contract addresses of Card Design Library in one tab (We require this address), Open the contract address of the Loot Royale contract in another tab like below.



  • Click on verify and Publish and fill in the details below. I used 8.7 as a compiler version while deploying from remix, so I am using the same here. Click on continue.


  • Copy the code from remix IDE and paste in the code part. Remove the string from constructor part like below.



  • Enter the library address as below and verify you are not a robot and click on Verify and publish.



Now, our contract is verified. It looks like the below image. You should see the functions to read and write to the blockchain.


Navigate to the write contract section and click on connect to web3, you will be prompted to connect to a provider like below.


Click on Metamask, it will prompt you to connect. Click on connect to web3 again and you should be able to connect explorer with Metamask like below.


Now click on mintSingle function, it will an NFT. Enter 0.01 as NFT Price like below.


Congratulations. You have successfully minted an NFT. Now, let’s view the token URI.


You can go to testnets.opensea.io, connect your wallet and you should be able to see your Loot Royale NFTs.



Loot Royale NFTs on Open sea Testnet



In the next blog, I will show how to design the frontend for lootroyale.xyz to mint the loot royale NFTs since this blog has become lengthy already.


Any feedback is appreciated. In case of any doubts or issues or any new ideas, DM me on Twitter - @pranay_bathini. Let us learn together.



Thanks for reading!!


This article was also published here