# Build Your Own NFT Collection with QuickNode and Optimism

Building and deploying your own NFT collection can be time and money-consuming, especially with the gas prices on Ethereum. With the rise of layer-2 solutions and cheap RPCs, this doesn't have to be the case! This tutorial will explain building an NFT Collection using the [ERC-721](https://ethereum.org/en/developers/docs/standards/tokens/erc-721/) token standard. You will store all NFT assets and metadata on IPFS with [QuickNode](https://dashboard.quicknode.com/storage) and deploy the smart contract on [Optimism](https://www.optimism.io/) Goerli Testnet.

[![D_D Newsletter CTA](https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png align="left")](https://devdao.to/blog-newsletter-1)

## Requirements

1. A basic understanding of [Solidity development](https://www.quicknode.com/guides/ethereum-development/smart-contracts/how-to-create-a-hello-world-smart-contract-with-solidity) will be helpful but is not required.
    
2. A basic understanding of the [ERC-721](https://ethereum.org/en/developers/docs/standards/tokens/erc-721/) token standard will be helpful but is not required.
    
3. A basic understanding of the [Remix](https://remix.ethereum.org/) IDE will be helpful but is not required.
    
4. Image assets and metadata of the NFT collections.
    
5. MetaMask or any other wallet and a small amount of Goerli test ETH.

6. A free [QuickNode](https://www.quicknode.com/) account.

## What is QuickNode IPFS?

The QuickNode IPFS service lets you store data decentralized using IPFS. Your files are automatically spread and replicated across global data centers, ensuring redundancy and distribution throughout the network. 

## What is Optimism?

Optimism is a layer-2 scaling solution that Ethereum developers choose for its speed and low transaction costs while maintaining full compatibility with the EVM.

## What are the Steps?

1. Store NFT assets and metadata on QuickNode IPFS.
    
2. Create and deploy an ERC-721 contract on the Optimism Goerli Testnet.
    
3. Interact with the Smart Contract to mint NFTs
    
4. View your NFTs on OpenSea.
    
## Storing Files on IPFS

First, you upload your images and metadata via [QuickNode](https://dashboard.quicknode.com/storage).

[Open the QuickNode website](https://www.quicknode.com/) and navigate to the "Storage" section. Click the **Add a file** button and select the file from your local machine.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692864842685/265225f1-fdff-4a0f-bf08-10df2ca1353c.png?auto=compress,format&format=webp align="left")

After you upload the file, it will appear like this, showing the file name, CID, status, and other information about the file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692865232027/369a9abb-568a-4e1d-ac3a-2c2e61eef173.png?auto=compress,format&format=webp align="left")

Upload images for each of the NFTs. [You'll find all the images on GitHub](https://github.com/AAYUSH-GUPTA-coder/NFT-COLLECTION-QUICKNODE-TUTORIAL/tree/main/images). The outcome will look similar to this.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692867518088/2ac00c65-2f3e-49b4-a368-baf62c1a4226.png?auto=compress,format&format=webp align="left")

Create three JSON metadata files to store information about our NFT collections.

* `0.json`: Agra collection
    
* `1.json`: Delhi collection
    
* `2.json`: Goa collection
    

The `0.json` file should look something like this:

```solidity
{
  "name": "Agra",
  "description": "Agra is a historic city in northern India, renowned for the iconic Taj Mahal, a marble mausoleum. It's a UNESCO World Heritage site and symbolizes love and architectural splendor. Agra also boasts Agra Fort and Fatehpur Sikri, both reflecting the city's Mughal heritage and attracting countless tourists for their cultural significance.",
  "image": "ipfs://Qmdr1zPumimEFKRkszo3nfFhGQ3UwofQXMbfDy1wd1gdLQ",
  "properties": {
    "rarity": "a bit rare",
    "fanciness": 8
  }
}
```

* **name**: Contains the name of the NFT.
    
* **description**: Contains the description of the NFT.
    
* **image**: Includes the link to the previously obtained image (IPFS URL).
    
* **properties**: Encompasses the various attributes of the NFT.
    

Create the remaining JSON files, `1.json` and `2.json`, for the Delhi and Goa collections. [You'll find the Metadata example on GitHub](https://github.com/AAYUSH-GUPTA-coder/NFT-COLLECTION-QUICKNODE-TUTORIAL/tree/main/metadata).

Similarly, upload your metadata folder to QuickNode IPFS. Once successfully uploaded, it will appear as shown:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692874812751/79aa6d1d-7d71-4df8-8257-6beac718ed0a.png?auto=compress,format&format=webp align="left")

You can view the JSON file by clicking on the filename in the QuickNode IPFS dashboard.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692875218884/4fda8d2e-8f92-4ae4-8944-268330d2c3c6.png?auto=compress,format&format=webp align="left")

Now, click "COPY IPFS URL" to copy the CID and the gateway link, allowing you to access the file. For example, this is the link to the `0.json` file.

[**https://quicknode.quicknode-ipfs.com/ipfs/QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb**](https://quicknode.quicknode-ipfs.com/ipfs/QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692875496119/12994666-7593-4e14-b459-95f67d3bc825.png?auto=compress,format&format=webp align="left")

## **Creating & Deploying the NFT Smart Contract**

Use the OpenZeppelin contracts library to create an [ERC-721 contract](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721) and [deploy it on the Optimism Goerli Testnet using the Remix IDE](https://remix.ethereum.org/). Ensure you have some Goerli Ether, which you can [get from the Quicknode Optimism Faucet](https://faucet.quicknode.com/optimism/goerli).

Create a new file named `QuickNft.sol` in Remix IDE and paste the following code:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

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

error NFT_NOT_EXIST();
error YOU_ALREADY_MINTED_NFT();
error ALL_NFTS_ARE_MINTED();

contract QuickNft is ERC721Enumerable, Ownable {
    uint256 public supplies = 500;
    uint256 public minted;
    string[] public cid = [
        "ipfs://QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb",
        "ipfs://Qmch5VaqXCc5ZbwKuL2awac1vrBXBBPiB5h7WxtYKDZ7DS",
        "ipfs://QmQg5wf1KHLDA1pEg51wK44UqPa6wJztTxppgb92VyPEbR"
    ];

    constructor() ERC721("QuickNft", "QNN") {}

    /**
     * @notice function to put NFT on Opensea
     * @param _cidId ID of the metadata of NFT we want to mint
     * @dev tokenURI overrides the Openzeppelin's ERC721 implementation for tokenURI function
     * This function returns the URI from where we can extract the metadata for a given tokenId
     */
    function tokenURI(
        uint256 _cidId
    ) public view virtual override returns (string memory) {
        if (_cidId >= cid.length) revert NFT_NOT_EXIST();
        return string(abi.encodePacked(cid[_cidId]));
    }

    /**
     * @notice function to mint the NFT
     * @param _cidId CID ID to select the metadata of your choice
     */
    function mint(uint256 _cidId) public {
        if (_cidId >= cid.length) revert NFT_NOT_EXIST();
        if (minted + 1 > supplies) revert ALL_NFTS_ARE_MINTED();
        _safeMint(msg.sender, minted);
        unchecked {
            ++minted;
        }
    }

    /**
     * @notice function to get total number of NFTs minted
     */
    function totalNftMinted() public view returns (uint256) {
        return minted;
    }
}
```

Let's break down the above Solidity smart contract code line by line:

```solidity
// SPDX-License-Identifier: MIT
```

This line specifies the license identifier for the contract. In this case, it's indicating that the contract is under the MIT License.

```solidity
pragma solidity 0.8.17;
```

This pragma sets the version of Solidity. In this case, the compiler will use version 0.8.17 of Solidity for the compilation.

```solidity
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
```

These lines are importing necessary contracts from the OpenZeppelin library. The the `ERC721Enumerable` contract helps to create an ERC-721 token that supports enumeration (listing tokens), the `Ownable` contract will provide basic ownership functionality and the `Strings` contract is used for manipulating strings.

```solidity
error NFT_NOT_EXIST();
error YOU_ALREADY_MINTED_NFT();
error ALL_NFTS_ARE_MINTED();
```

These lines define custom error messages that we used in the contract.

```solidity
contract QuickNft is ERC721Enumerable, Ownable {
```

This line defines the `QuickNft` contract, which inherits from `ERC721Enumerable` and `Ownable`,  so the contract will be both an ERC-721 token (with enumeration capabilities) and have ownership functionality.

```solidity
uint256 public supply = 500;
uint256 public minted;
```

These lines declare two state variables. `supply` represents the total number of NFTs available for minting, and `minted` keeps track of how many NFTs people minted so far.

```solidity
string[] public cid = [
    "ipfs://QmQQEjRjhUQPgJ51U2PKkwyRLgktzGWmX95vgUzWfBj5gb",
    "ipfs://Qmch5VaqXCc5ZbwKuL2awac1vrBXBBPiB5h7WxtYKDZ7DS",
    "ipfs://QmQg5wf1KHLDA1pEg51wK44UqPa6wJztTxppgb92VyPEbR"
];
```

An array `cid` is defined, containing three IPFS URLs that represent the metadata of the NFTs.

```solidity
constructor() ERC721("QuickNft", "QNN") {}
```

The contract's constructor initializes the ERC-721 token with "QuickNft" as the name and "QNN" as the symbol.

```solidity
function tokenURI(uint256 _cidId) public view virtual override returns (string memory) {
    if (_cidId >= cid.length) revert NFT_NOT_EXIST();
    return string(abi.encodePacked(cid[_cidId]));
}
```

This function, `tokenURI`, overrides the default ERC721 behavior and returns the IPFS URL (metadata URI) associated with the given `_cidId`.

```solidity
function mint(uint256 _cidId) public {
    if (_cidId >= cid.length) revert NFT_NOT_EXIST();
    if (minted + 1 > supplies) revert ALL_NFTS_ARE_MINTED();
    _safeMint(msg.sender, minted);
    unchecked {
        ++minted;
    }
}
```

The `mint` function allows users to mint NFTs. It checks if the `_cidId` is valid and the total number of minted NFTs is within the available supply. If this is the case, it mints a new NFT for the caller and increments the `minted` count.

```solidity
function totalNftMinted() public view returns (uint256) {
    return minted;
}
```

The `totalNftMinted` function returns the total count of minted NFTs.

In case you don't have the Optimism Goerli Testnet set up in your wallet, follow these steps:

[![D_D Newsletter CTA](https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png align="left")](https://devdao.to/blog-newsletter-1)

## Creating an Optimism Endpoint on QuickNode

To deploy a smart contract to Optimism's test blockchain, Goerli, you'll need an API endpoint to communicate with the network. [Go to the QuickNode Dashboard to configure it.](https://dashboard.quicknode.com/endpoints)

Once logged in, click the "Create an endpoint" button, then select the "Optimism" chain and "Goerli" network.

After creating your endpoint, copy the HTTP provider link and keep it handy, as you'll need it next.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692972974293/6532afd7-8c99-4fec-b026-76ddf2f3f989.png?auto=compress,format&format=webp align="left")

## Configuring Your Web3 Wallet with QuickNode

Configure your RPC settings if you're using MetaMask to deploy this contract. Some compatible wallets are [Coinbase Wallet](https://www.coinbase.com/es/wallet), [Rainbow Wallet](https://rainbow.me/) and [TrustWallet](https://trustwallet.com/es/).

Open up MetaMask and click the network dropdown at the top. After, click the "Add Network" button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692981270357/8cf1c8c2-1026-48e8-b20a-f594a2555de8.png?auto=compress,format&format=webp align="left")

At the bottom of the page, click "Add a network manually" and fill out the following details:

* Network name: Optimism Goerli Testnet
    
* New RPC URL: Enter the QuickNode HTTP URL you retrieved earlier
    
* Chain ID: 420
    
* Currency symbol: ETH
    
* Block Explorer URL: [**https://optimism-goerli.blockscout.com**](https://optimism-goerli.blockscout.com)
    

It should end up looking similar to this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692981515517/200fa9cf-1449-4b1e-8b2c-f6c49309ece1.png?auto=compress,format&format=webp align="left")

## Compiling the Smart Contract

Open Remix IDE, copy and paste the above code, and navigate to the Deploy section. Select 'Injected Web3' as the environment, and deploy it by choosing the correct contract name. You need to select the chain on your MetaMask wallet. In our case, we are deploying it on the Optimism Goerli Testnet with chain ID 420. Click the Deploy button

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692972641112/35e866c5-6d16-4580-9b37-870718c7b240.png?auto=compress,format&format=webp align="left")

Approve the transaction on MetaMask by clicking the Confirm button. Once the transaction is complete, your contract will be deployed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692982135567/08bd8aae-c524-4765-9397-60925a641940.png?auto=compress,format&format=webp align="left")

Now you can perform functions like mint NFT by entering CID ID. We can also retrieve the NFT URI by entering the CID ID.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692984714894/6918f5a7-9f13-4b2a-9d22-bb5e9f2e53c5.png?auto=compress,format&format=webp align="left")

## Minting an NFT

Enter the CID ID of the NFT you want to mint and click on the Confirm Button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692985097616/de40d378-da01-44f9-a5a9-cd2d348b4a8b.png?auto=compress,format&format=webp align="left")

After some time, you can see the NFT on [OpenSea](https://testnets.opensea.io/collection/quicknft-1).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692985680055/e4293a0d-8a57-4b6d-a5db-301137afd99e.png?auto=compress,format&format=webp align="left")

## 🎉BOOM 🎉

You've completed the entire tutorial. Give yourself a well-deserved pat on the back. You've learned how to:

* Create an NFT Collection using the ERC-721 Token standard.
    
* Store NFT Metadata in a decentralized manner using QuickNode IPFS.
    
* Compile and deploy a Smart Contract on the Optimism Goerli Testnet.
    
* Interact with the smart contract using Remix.
    

**🎉** Bonus for sticking till the end: use code **BUILD-AMB-15**. This coupon gives you 1 month of the QuickNode Build ($49) plan for free **🎉**

[![D_D Newsletter CTA](https://sitemedia.ams3.digitaloceanspaces.com/blog_banner_v1_d1653cce08.png align="left")](https://devdao.to/blog-newsletter-1)

###💥 Simply WOW 💥

If you found this tutorial helpful and enjoyable, consider sharing it with your friends. I hope you've gained new insights or even solved a challenge. Thank you for reading, and have a great time!

Feel free to connect with me on [Twitter](https://twitter.com/Aayush_gupta_ji), [GitHub](https://github.com/AAYUSH-GUPTA-coder), and [LinkedIn](https://www.linkedin.com/in/aayush-gupta-20023b183/). I welcome your suggestions and comments!

WAGMI 🚀🚀
