NFTPort: Create an NFT Collection with NFTPort

Learn how to mint an NFT collection with NFTPort.

What is NFTPort?

NFTPort is a simple and developer-friendly NFT API and infrastructure that allows developers to create and deploy their NFT applications or collections in just a few hours instead of requiring months of development. NFTPort manages the backend NFT infrastructure and provides a versatile API for interacting with the infrastructure.

Read below to learn how to mint an NFT collection with NFTPort.

Prerequisites:

1. First, we need to upload some NFT image files to IPFS through Filebase.

We’ll start by uploading 3 images to Filebase for us to use. To do this, navigate to console.filebase.com. If you don’t have an account already, sign up, then log in.

2. Select ‘Buckets’ from the left side bar menu, or navigate to console.filebase.com/buckets.

Select ‘Create Bucket’ in the top right corner to create a new bucket for your NFTs.

3. Enter a bucket name and choose the IPFS storage network to create the bucket.

Bucket names must be unique across all Filebase users, be between 3 and 63 characters long, and can contain only lowercase characters, numbers, and dashes.

4. Next, select the bucket from your list of buckets, then select ‘Upload’ in the top right corner to upload your image files.

5. Select your images to be uploaded.

Once uploaded, they will be listed in the bucket.

6. You can view the object’s IPFS CID in the CID column, or you can click on your uploaded object to display the metadata for the object, which includes the IPFS CID.

Choose the method you prefer, and take note of the IPFS CID.

7. Next, create a new project folder for our project files. We’ll call it nft-collection. Then navigate inside this new folder.

mkdir nft-collection

cd nft-collection

8. Inside this folder, create another folder for your NFTs’ metadata files.

Call this ‘metadata’, then navigate inside of it as well.

mkdir metadata

cd metadata

9. Next, create a .JSON file for each NFT you plan to create in your collection. The format for this JSON file is as follows:

{
  "name": "NFT #1",
  "description": "The first NFT in my collection",
  "image": "https://ipfs.filebase.io/ipfs/IPFS_FILEBASE_CID",
  "attributes": [
    {
      "trait_type": "Rarity",
      "value": "Average"
    }
  ]
}

Replace IPFS_FILEBASE_CID with the CID for each NFT image you uploaded to Filebase.

To simplify things, name each .JSON file in the same manner you named your NFT image files. For example, if you followed a numerical naming scheme such as 1.png, 2.png, name your .JSON files as 1.JSON, 2.JSON, etc. Save all of these files in the ‘metadata’ directory.

10. Sign up for a free NFTPort API key here. We’ll need this in the next step.

11. Navigate back to the root directory of the project. Create a new file called upload.py.

Enter the following code into this file:

import requests
import os
from os import listdir
from os.path import join

metadata_directory_path =./metadata" 

files = [f for f in listdir(metadata_directory_path) if str(join(metadata_directory_path, f)).endswith('.json')]
metadata_files = []

for metadata in files:
    metadata_files.append(
        ("metadata_files", open(os.path.join(metadata_directory_path, metadata), "rb")))

response = requests.post(
        "https://api.nftport.xyz/v0/metadata/directory",
        headers={"Authorization": "NFTPORT_API_KEY"},
        files=metadata_files
    )
print(response.json())

Replace the following values:

  • NFTPORT_API_KEY: Your NFTPort API key from step 10.

12. Deploy the contract with the following curl command:

curl --request POST \\
  --url https://api.nftport.xyz/v0/contracts/collections \\
  --header 'Authorization: NFTPORT_API_KEY' \\
  --header 'Content-Type: application/json' \\
  --data '{
  "chain": "polygon",
  "name": "COLLECTION_NAME",
  "symbol": "SYMBOL",
  "max_supply": 100,
  "mint_price": 0.1,
  "tokens_per_mint": 10,
  "owner_address": "YOUR_WALLET_ADDRESS",
  "treasury_address": "YOUR_WALLET_ADDRESS",
  "public_mint_start_date": "2022-02-08T11:30:48+00:00",
  "metadata_updatable": true,
  "base_uri": "ipfs://",
  "prereveal_token_uri": "ipfs://",
  "presale_mint_start_date": "2022-04-28T11:30:48+00:00",
  "presale_whitelisted_addresses": [
    "WALLET_ADDRESS"
  ]
}'

Update the arguments in this command to reflect your desired configuration, such as your NFTPort API key and your crypto wallet address.

Take note of the contract hash returned from this command.

This will bring up detailed information on the transaction, including the Contract Address.

Copy this Contract Address.

14. Then, run your upload.py script:

python upload.py

15. Next, download the latest web3.min.js. Save this file in your project’s root directory.

16. Make a new file called index.html. Enter the following content into this file:

<html>
  <head>
    <script src="web3.min.js"></script>

    <script>
      const abi = [
        {
          inputs: [],
          stateMutability: "nonpayable",
          type: "constructor",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "owner",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "approved",
              type: "address",
            },
            {
              indexed: true,
              internalType: "uint256",
              name: "tokenId",
              type: "uint256",
            },
          ],
          name: "Approval",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "owner",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "operator",
              type: "address",
            },
            {
              indexed: false,
              internalType: "bool",
              name: "approved",
              type: "bool",
            },
          ],
          name: "ApprovalForAll",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "previousOwner",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "newOwner",
              type: "address",
            },
          ],
          name: "OwnershipTransferred",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
            {
              indexed: true,
              internalType: "bytes32",
              name: "previousAdminRole",
              type: "bytes32",
            },
            {
              indexed: true,
              internalType: "bytes32",
              name: "newAdminRole",
              type: "bytes32",
            },
          ],
          name: "RoleAdminChanged",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
            {
              indexed: true,
              internalType: "address",
              name: "account",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "sender",
              type: "address",
            },
          ],
          name: "RoleGranted",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
            {
              indexed: true,
              internalType: "address",
              name: "account",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "sender",
              type: "address",
            },
          ],
          name: "RoleRevoked",
          type: "event",
        },
        {
          anonymous: false,
          inputs: [
            {
              indexed: true,
              internalType: "address",
              name: "from",
              type: "address",
            },
            {
              indexed: true,
              internalType: "address",
              name: "to",
              type: "address",
            },
            {
              indexed: true,
              internalType: "uint256",
              name: "tokenId",
              type: "uint256",
            },
          ],
          name: "Transfer",
          type: "event",
        },
        {
          inputs: [],
          name: "ADMIN_ROLE",
          outputs: [
            {
              internalType: "bytes32",
              name: "",
              type: "bytes32",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "DEFAULT_ADMIN_ROLE",
          outputs: [
            {
              internalType: "bytes32",
              name: "",
              type: "bytes32",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "VERSION",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "to",
              type: "address",
            },
            {
              internalType: "uint256",
              name: "tokenId",
              type: "uint256",
            },
          ],
          name: "approve",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "owner",
              type: "address",
            },
          ],
          name: "balanceOf",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "baseURI",
          outputs: [
            {
              internalType: "string",
              name: "",
              type: "string",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "uint256",
              name: "tokenId",
              type: "uint256",
            },
          ],
          name: "getApproved",
          outputs: [
            {
              internalType: "address",
              name: "",
              type: "address",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "getInfo",
          outputs: [
            {
              components: [
                {
                  internalType: "uint256",
                  name: "version",
                  type: "uint256",
                },
                {
                  components: [
                    {
                      internalType: "string",
                      name: "name",
                      type: "string",
                    },
                    {
                      internalType: "string",
                      name: "symbol",
                      type: "string",
                    },
                    {
                      internalType: "address",
                      name: "owner",
                      type: "address",
                    },
                    {
                      internalType: "uint256",
                      name: "maxSupply",
                      type: "uint256",
                    },
                    {
                      internalType: "uint256",
                      name: "mintPrice",
                      type: "uint256",
                    },
                    {
                      internalType: "uint256",
                      name: "tokensPerMint",
                      type: "uint256",
                    },
                    {
                      internalType: "address payable",
                      name: "treasuryAddress",
                      type: "address",
                    },
                  ],
                  internalType: "struct NFTCollection.DeploymentConfig",
                  name: "deploymentConfig",
                  type: "tuple",
                },
                {
                  components: [
                    {
                      internalType: "string",
                      name: "baseURI",
                      type: "string",
                    },
                    {
                      internalType: "bool",
                      name: "metadataUpdatable",
                      type: "bool",
                    },
                    {
                      internalType: "uint256",
                      name: "publicMintStart",
                      type: "uint256",
                    },
                    {
                      internalType: "uint256",
                      name: "presaleMintStart",
                      type: "uint256",
                    },
                    {
                      internalType: "string",
                      name: "prerevealTokenURI",
                      type: "string",
                    },
                    {
                      internalType: "bytes32",
                      name: "presaleMerkleRoot",
                      type: "bytes32",
                    },
                  ],
                  internalType: "struct NFTCollection.RuntimeConfig",
                  name: "runtimeConfig",
                  type: "tuple",
                },
              ],
              internalType: "struct NFTCollection.ContractInfo",
              name: "info",
              type: "tuple",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
          ],
          name: "getRoleAdmin",
          outputs: [
            {
              internalType: "bytes32",
              name: "",
              type: "bytes32",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
            {
              internalType: "address",
              name: "account",
              type: "address",
            },
          ],
          name: "grantRole",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "bytes32",
              name: "role",
              type: "bytes32",
            },
            {
              internalType: "address",
              name: "account",
              type: "address",
            },
          ],
          name: "hasRole",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              components: [
                {
                  internalType: "string",
                  name: "name",
                  type: "string",
                },
                {
                  internalType: "string",
                  name: "symbol",
                  type: "string",
                },
                {
                  internalType: "address",
                  name: "owner",
                  type: "address",
                },
                {
                  internalType: "uint256",
                  name: "maxSupply",
                  type: "uint256",
                },
                {
                  internalType: "uint256",
                  name: "mintPrice",
                  type: "uint256",
                },
                {
                  internalType: "uint256",
                  name: "tokensPerMint",
                  type: "uint256",
                },
                {
                  internalType: "address payable",
                  name: "treasuryAddress",
                  type: "address",
                },
              ],
              internalType: "struct NFTCollection.DeploymentConfig",
              name: "deploymentConfig",
              type: "tuple",
            },
            {
              components: [
                {
                  internalType: "string",
                  name: "baseURI",
                  type: "string",
                },
                {
                  internalType: "bool",
                  name: "metadataUpdatable",
                  type: "bool",
                },
                {
                  internalType: "uint256",
                  name: "publicMintStart",
                  type: "uint256",
                },
                {
                  internalType: "uint256",
                  name: "presaleMintStart",
                  type: "uint256",
                },
                {
                  internalType: "string",
                  name: "prerevealTokenURI",
                  type: "string",
                },
                {
                  internalType: "bytes32",
                  name: "presaleMerkleRoot",
                  type: "bytes32",
                },
              ],
              internalType: "struct NFTCollection.RuntimeConfig",
              name: "runtimeConfig",
              type: "tuple",
            },
          ],
          name: "initialize",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "owner",
              type: "address",
            },
            {
              internalType: "address",
              name: "operator",
              type: "address",
            },
          ],
          name: "isApprovedForAll",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "address",
              name: "wallet",
              type: "address",
            },
            {
              internalType: "bytes32[]",
              name: "proof",
              type: "bytes32[]",
            },
          ],
          name: "isWhitelisted",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "maxSupply",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "metadataUpdatable",
          outputs: [
            {
              internalType: "bool",
              name: "",
              type: "bool",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "uint256",
              name: "amount",
              type: "uint256",
            },
          ],
          name: "mint",
          outputs: [],
          stateMutability: "payable",
          type: "function",
        },
        {
          inputs: [],
          name: "mintPrice",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "mintingActive",
          outputs: [
            {