NFTPort: Create an NFT Collection with NFTPort
Learn how to mint an NFT collection with NFTPort.
Last updated
Learn how to mint an NFT collection with NFTPort.
Last updated
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.
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.
Select ‘Create Bucket’ in the top right corner to create a new bucket for your NFTs.
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.
Once uploaded, they will be listed in the bucket.
Choose the method you prefer, and take note of the IPFS CID.
nft-collection
. Then navigate inside this new folder.mkdir nft-collection
cd nft-collection
Call this ‘metadata’, then navigate inside of it as well.
mkdir metadata
cd metadata
{
"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.
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.
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.
upload.py
script:python upload.py
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: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "ownerOf",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "prerevealTokenURI",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "presaleActive",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "presaleMerkleRoot",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
{
internalType: "bytes32[]",
name: "proof",
type: "bytes32[]",
},
],
name: "presaleMint",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [],
name: "presaleMintStart",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "publicMintStart",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "renounceRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "role",
type: "bytes32",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "revokeRole",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "safeTransferFrom",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
{
internalType: "bytes",
name: "_data",
type: "bytes",
},
],
name: "safeTransferFrom",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "operator",
type: "address",
},
{
internalType: "bool",
name: "approved",
type: "bool",
},
],
name: "setApprovalForAll",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "bytes4",
name: "interfaceId",
type: "bytes4",
},
],
name: "supportsInterface",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "tokenURI",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "tokensPerMint",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address",
},
],
name: "transferAdminRights",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address",
},
{
internalType: "address",
name: "to",
type: "address",
},
{
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "transferFrom",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "treasuryAddress",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
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: "newConfig",
type: "tuple",
},
],
name: "updateConfig",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "withdrawFees",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
];
const address = "COTRACT_ADDRESS"; //Replace with your own contract address
</script>
<script>
async function connect() {
//Allows the user to connect to a wallet like MetaMask
if (window.ethereum) {
const accounts = await window.ethereum.request({
method: "eth_requestAccounts",
});
window.address = accounts[0];
document.getElementById("address").textContent = accounts[0];
window.web3 = new Web3(window.ethereum);
window.contract = new web3.eth.Contract(abi, address);
loadInfo();
return true;
}
return false;
}
async function loadInfo() {
//Fetches information about the contract like mint price
window.info = await window.contract.methods.getInfo().call();
document.getElementById("price").innerText =
info.deploymentConfig.mintPrice + " wei";
document.getElementById("price").href =
"<https://etherscan.io/unitconverter?wei=>" +
info.deploymentConfig.mintPrice;
document.getElementById("maxAmount").innerText =
info.deploymentConfig.tokensPerMint;
}
async function mint() {
const amount = parseInt(document.getElementById("amount").value);
const value = BigInt(info.deploymentConfig.mintPrice) * BigInt(amount);
// Calls the contract ABI to mint NFTs
await contract.methods
.mint(amount)
.send({ from: window.address, value: value.toString() });
}
connect();
</script>
</head>
<body>
<div>
<div id="address">Wallet not connected</div>
<div>
<button id="connect" onclick="connect()">Connect your wallet</button>
</div>
<div>
<div>Minting price per token: <a id="price" target="_blank"></a></div>
<div>Maximum tokens per mint: <span id="maxAmount"></span></div>
<div>
<input
id="amount"
type="number"
step="1"
min="1"
max="10"
value="1"
/>
<button id="mint" onclick="mint()">Mint</button>
</div>
</div>
</div>
</body>
</html>
Replace CONTRACT_ADDRESS with the contract address you took note of from Polygonscan.
index.html
page to be hosted on:npm install
npm install http-server
npx http-server
localhost:80
, where you should see your minting webpage. It will resemble the following:To change the cosmetics of the website, edit the index.html file to include different CSS styling.
From here, you can connect your wallet and mint your NFTs!