The "ERC721" Non-Fungible Tokens (NFTs)

The world of blockchain technology has birthed various innovations, one of the most captivating being non-fungible tokens (NFTs). Among the various NFT standards, ERC721 stands out as a foundational protocol for creating unique digital assets on the Ethereum blockchain. In this article, we'll explore ERC721 through the lens of a Solidity smart contract, and OpenZeppelin (an open-source framework to build secure smart contracts)

Dissecting the code, let's dive into solidity code to understand how ERC721 is implemented.

Line-by-Line Explanation:

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

ERC721.sol file is imported from the OpenZeppelin library, which provides the implementation of the ERC721 standard.

"@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

This line imports the ERC721Enumerable.sol file from the OpenZeppelin library. ERC721Enumerable.sol is an extension of ERC721 that adds enumerable functionalities to the token.

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";

This line imports the ERC721Pausable.sol file from the OpenZeppelin library. ERC721Pausable.sol is an extension of ERC721 that adds pausable functionalities to the token.

import "@openzeppelin/contracts/access/Ownable.sol";

This line imports the Ownable.sol file from the OpenZeppelin library. Ownable.sol provides basic authorization control functions, simplifying the implementation of user permissions.

contract MyToken is ERC721, ERC721Enumerable, ERC721Pausable, Ownable {
    code here;
}

Here begins the declaration of the MyToken contract. It inherits functionalities from ERC721, ERC721Enumerable, ERC721Pausable, and Ownable contracts.

uint256 private _nextTokenId;
uint maxSupply = 10;
bool public publicMintOpen = true;
bool public allowListMintOpen = true;

uint256 private _nextTokenIdThis line declares a private unsigned integer variable _nextTokenId, which is used to track the ID of the next token to be minted.

uint maxSupply = 10This line declares an unsigned integer variable maxSupply, which represents the maximum supply of tokens that can be minted.

bool public publicMintOpen = trueThis line declares a public boolean variable publicMintOpen, indicating whether public minting is open or closed by default. It's initialized as true.

bool public allowListMintOpen = trueThis line declares a public boolean variable allowListMintOpen, indicating whether minting from an allowlist is open or closed by default. It's initialized as true.

constructor() ERC721("MyToken", "MTK") Ownable(msg.sender) {}

This is the constructor function of the MyToken contract. It initializes the contract by calling the constructors of ERC721, Ownable, and passing "MyToken" as the token name and "MTK" as the token symbol

function _baseURI() internal pure override returns (string memory) { return "ipfs://QmY5rPqGTN1rZxMQg2ApiSZc7JiBNs1ryDzXPZpQhC1ibm/"; }

This function _baseURI is internal, pure, and overridden from the ERC721 contract. It returns the base URI for token metadata. This can be made dynamic. And called to be passed while trying to mint. The "ipfs://QmY5rPqGTN1rZxMQg2ApiSZc7JiBNs1ryDzXPZpQhC1ibm/"; } is a decentralized storage address for our token metadata.

function pause() public onlyOwner { _pause(); }

This function pause is public and can only be called by the owner. It pauses the token contract.

function unpause() public onlyOwner { _unpause(); }

This function unpause is public and can only be called by the owner. It unpauses the token contract.

function allowListMint() public payable  {
        require(allowListMintOpen, "minting closed");
        require(msg.value == 0.001 ether, "No enough fund");
        require(totalSupply() < maxSupply, "Sold Out!!!");
        uint256 tokenId = _nextTokenId++;
        _safeMint(msg.sender, tokenId);
    }

This function allowListMint is public and payable. It allows minting tokens from an allowlist under certain conditions.

// make mint payable
// Add limiting of supply
    function publicMint() public payable {
        require(publicMintOpen, "minting closed");
        require(msg.value == 0.01 ether, "No enough fund");
        require(totalSupply() < maxSupply, "Sold Out!!!");
        uint256 tokenId = _nextTokenId++;
        _safeMint(msg.sender, tokenId);
    }

This function publicMint is public and payable. It allows public minting of tokens under certain conditions.

The remaining lines contain overrides and implementations of internal functions required by ERC721 and its extensions. These functions ensure the proper functionality of the ERC721 token contract.

Conclusion: Understanding ERC721 smart contracts is crucial for developers and enthusiasts entering the NFT space. By dissecting and explaining each line of a sample ERC721 contract, we've gained insight into its structure, functionality, and purpose.

0
Subscribe to my newsletter

Read articles from Adekunle Stephen Omorotimi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Adekunle Stephen Omorotimi
Adekunle Stephen Omorotimi