How to Write a Basic NFT Smart Contract & Deploy to the Polygon Network
We will be able to mint our NFT to a different wallet address
Overview
NFT is rapidly changing the crypto world, and since they give total control to the owner of the asset. These digital assets could be photos, videos, music, or an in-game item. This guide will cover a simple way of creating a basic NFT smart contract, we would also be deploying it to the polygon network. This guide will also cover some fundamental concepts about ERC-721.
What is a Non-Fungible Token?
NFTs or Non Fungible Tokens basically means that it's a one-kind-of-a-kind digital asset that belongs to you and you only. The most popular NFTs right now include music, artwork, and even include tweets and videos.
Token: Tokens are basically assets with value, that can be transferred, traded, bought, and sold.
Non-fungible: means that they are not interchangeable and each of them represents a unique asset owned by a specific person.
NFTs represent digital proof of ownership that can be bought and sold online. They are also securely recorded on the decentralized blockchain making them impossible to change. NFTs have been around for years now, the most famous being CryptoKitties which was a game for buying, selling cats on the Ethereum blockchain.
What is ERC-721?
ERC-721 (Ethereum Request for Comment) is an open standard that provides technical guidance to developers for construct on the EVM, it generally makes NFTs simple to work with. Within a smart contract, the ERC-721 standard allows Ethereum API for NFTs. The standard for instance, ensures that NFTs can be exchanged and monitored, ensuring that the ownership of the token is accurately recorded in the blockchain.
ERC-721 is a more complex standard than ERC-20 and unlike ERC-20, ERC-721 also lacks adecimals
field, because each token is unique and cannot be partitioned. NFTs are not limited to ERC-721 there are other token standards such as the ERC-1155 which is another standard for NFTs that gives semi-fungibility to them.
What are the functions of ERC-721
It is worth noting that ERC-721 has similar functions to ERC-20. Some of the functions include:
- A
name
is used to indicate the token's name, so it can be easily identified. - The
symbol
of the token is the symbol by which the contract would be known. It provides an outside program with the token's shorthand name. - The
totalSupply
returns the total number of tokens on the blockchain; the supply doesn't have to be constant. - The
balanceOf
function is used to find the number of tokens that a particular address owns.
Ownership Functions
These functions define the ownership of the token and how it can be transferred and they are essential for letting users perform token transactions between each other.
- The
ownerOf
function basically returns the address of the owner of the token. hence, we can determine the owner of a token using its token ID. approve
function also basically approves another party to transfer a token on the owner's behalf.The
takeOwnership
function allows a user who possesses a certain number of tokens to withdraw them from another user's balance.transfer
lets the owner of the token send it to another user, it is a method of transferring tokens.
Metadata Function This contains all data that basically distinguish one token from all the others
The tokenMetadata
feature that lets us discover a token’s metadata or a link to the information associated with a token.
Events They are triggered whenever a contract calls them. The ERC-721 standard defines two events and they are:
- The
Transfer
which is fired whenever the ownership of a token changes. - The
approve
function is fired whenever a user approves another user to take ownership of a token.
Getting Started
For building this smart contract we would be making use of the following tools.
- Remix IDE - a powerful tool that would help us write Solidity code for our smart contract.
Solidity - is a programming language used for writing smart contracts.
Smart Contracts - is simply an agreement between buyers and sellers written in form of computer code.
Pinata - is an IPFS pinning service that stores our NFT tokens on the IPFS ( Interplanetary File System).
OpenZeppelin - Trusted and used by Defi and NFT projects to build secure smart contracts in Solidity.
Metamask - a crypto wallet that holds our NFT. (We would be using its browser extension).
Our NFT
Setting up Pinata
Firstly, You would need to create an account with Pinata, it is quite easy and also free to set up. Then you can upload your NFT image and json file.
This is how you create a json file by copying the code below to a notepad and then saving it with .json
{
"attributes":[
{
trait_type":"Color",
"value":"Black"},
{
trait_type":"Creature",
"value":"Rare"},
],
"name": "",
"description": "",
"image": "",
}
I have filled some of the fields according to the project name. Pinata is much easier than pinning files on your local IPFS node. This is also because my local node isn't always online, and I need the NFT item to be consistently available.
Creating our own token
For ease and security, we’ll use Openzeppelin contract wizard. With Openzeppelin, we don’t need to write the whole ERC-721 interface. Instead, we can import the library contract and use its functions.
Be sure to tick where necessary as well as typing the name
and symbol
of the project, which in this case is Rare and BLK respectively. be sure to copy the code to the clipboard.
Head over to the Remix IDE and make a new Solidity file, in our case - Rare.sol
Paste the following code into your Rare.sol file:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract Rare is ERC721, ERC721Enumerable, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("Rare", "BLK") {}
function _baseURI() internal pure override returns (string memory) {
return "link to pinata upload";
}
function safeMint(address to) public onlyOwner {
_tokenIdCounter.increment();
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721,ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Let's break down what this code above does:
Line 1: This basically Specifies the SPDX license type. Solidity ^0.6.8 introduces SPDX license identifiers so developers can specify the exact license the contract uses. (for instance, OpenZeppelin Contracts use MIT license).
Line 2: This declared the Solidity version.
Line 4-7: This Imports the OpenZepplin contracts according to the features we would be needing for the smart contract.
Line 9: This tells us the name of our new contract which is Rare and also mentions that it is based on ERC-721, enumerable and ownable.
Line 10&12: Means that assign all the functions inside Counters
library like current()
or increment()
to the counter struct.
Line 14: Initializing the constructor and defining the name
, and symbol
of our token.
Line 15-17: this returns our Base URI
which is basically the link to our NFT image.
Line 19-23: Declaring the function SafeMint
with an arguments, variable address to store the address of the receiver of NFT token, which is currently set to onlyOwner
.Then we need to make sure that indexing starts from value 1 and not 0. Hence, the counter function.
Line 27-42: This contains functions to be over-ridden by solidity, defining the transfer function such that transfer can only be from one address to another based on the tokenId.
Line 34-42: The Enumerable function implements an optional extension of ERC721, this adds enumerability of all the token ids in the contract together with those from each account.
We would then move to Compile
the smart contract
A green tick indicating that our project was successfully compiled would be visible in the left corner of the menu tab. Then we would deploy
the project by firstly selecting Injected Web3
from the drop-down menu.
A pop-up from Metamask will appear and we would have to connect our project to the wallet. We would also be getting some test Matic from the Polygon faucet. After successful connection, the Custom(80001) network
would be visible below the Injected Web
drop-down indicating we are on the right network (Polygon Testnet).
Next, we would be hitting the deploy
button, to push our project into production.
Now that our project is live, we can perform simple transactions such as safeMint
to another address or checking the balanceOf
the tokens we have left.
We can scan for transactions on our newly written smart contract by copying the wallet address to the polygon testnet.
Conclusion
Great!
Congratulations on making it to the end of this article we have gone through a basic way of building a smart contract as well as deploying our project to the Polygon Testnet.
I hope you enjoyed this tutorial and learned something new, your feedback is more than welcome!. I would like to connect with you on Twitter and Linkedln.