1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5986],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>m});var a=n(7294);function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function i(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?r(Object(n),!0).forEach((function(e){o(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function s(t,e){if(null==t)return{};var n,a,o=function(t,e){if(null==t)return{};var n,a,o={},r=Object.keys(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||(o[n]=t[n]);return o}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a<r.length;a++)n=r[a],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}var l=a.createContext({}),c=function(t){var e=a.useContext(l),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},p=function(t){var e=c(t.components);return a.createElement(l.Provider,{value:e},t.children)},d="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},h=a.forwardRef((function(t,e){var n=t.components,o=t.mdxType,r=t.originalType,l=t.parentName,p=s(t,["components","mdxType","originalType","parentName"]),d=c(n),h=o,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(m,i(i({ref:e},p),{},{components:n})):a.createElement(m,i({ref:e},p))}));function m(t,e){var n=arguments,o=e&&e.mdxType;if("string"==typeof t||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var l in e)hasOwnProperty.call(e,l)&&(s[l]=e[l]);s.originalType=t,s[d]="string"==typeof t?t:o,i[1]=s;for(var c=2;c<r;c++)i[c]=n[c];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},5334:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>p,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>d});var a=n(7462),o=n(3366),r=(n(7294),n(3905)),i=["components"],s={title:"How to Mint an NFT"},l=void 0,c={unversionedId:"tutorials/nfts/mint-nft",id:"tutorials/nfts/mint-nft",title:"How to Mint an NFT",description:"This tutorial describes how to mint an NFT using the ethers library and the smart contract from the previous section.",source:"@site/../docs/4.tutorials/nfts/mint-nft.md",sourceDirName:"4.tutorials/nfts",slug:"/tutorials/nfts/mint-nft",permalink:"/tutorials/nfts/mint-nft",draft:!1,editUrl:"https://github.com/elastos/Elastos.Wiki/edit/master/website/../docs/4.tutorials/nfts/mint-nft.md",tags:[],version:"current",lastUpdatedBy:"racollette",lastUpdatedAt:1677304687,formattedLastUpdatedAt:"Feb 25, 2023",frontMatter:{title:"How to Mint an NFT"},sidebar:"tutorialSidebar",previous:{title:"Deploying an NFT Contract on ESC",permalink:"/tutorials/nfts/create-nft"},next:{title:"Create a Web Frontend",permalink:"/tutorials/ui/frontend"}},p={},d=[{value:"Creating the Mint NFT Script",id:"creating-the-mint-nft-script",level:2},{value:"Step 1: Create an Alchemy Provider using ethers",id:"step-1-create-an-alchemy-provider-using-ethers",level:3},{value:"Step 2: Load the Contract ABI",id:"step-2-load-the-contract-abi",level:3},{value:"Step 3: Configure the Metadata of your NFT using IPFS",id:"step-3-configure-the-metadata-of-your-nft-using-ipfs",level:3},{value:"Step 4: Create a Signer and an Instance of the Contract",id:"step-4-create-a-signer-and-an-instance-of-the-contract",level:3},{value:"Step 5: Call mintNFT Function of the Contract",id:"step-5-call-mintnft-function-of-the-contract",level:3}],u={toc:d},h="wrapper";function m(t){var e=t.components,s=(0,o.Z)(t,i);return(0,r.kt)(h,(0,a.Z)({},u,s,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This tutorial describes how to mint an NFT using the ethers library and the smart contract from the ",(0,r.kt)("a",{parentName:"p",href:"/tutorials/nfts/create-nft"},"previous section"),"."),(0,r.kt)("p",null,"Minting an NFT is the act of publishing a unique instance of an ERC721 token on the blockchain. Now that we have successfully deployed a smart contract to the Elastos Smart Chain (ESC) testnet, let's mint an NFT!"),(0,r.kt)("h2",{id:"creating-the-mint-nft-script"},"Creating the Mint NFT Script"),(0,r.kt)("h3",{id:"step-1-create-an-alchemy-provider-using-ethers"},"Step 1: Create an Alchemy Provider using ethers"),(0,r.kt)("p",null,"Open the repository from the ",(0,r.kt)("a",{parentName:"p",href:"/tutorials/nfts/create-nft"},"previous tutorial")," in your favorite code editor (e.g. ",(0,r.kt)("a",{parentName:"p",href:"https://code.visualstudio.com/"},"VSCode"),"), and create a new file in the scripts folder called ",(0,r.kt)("inlineCode",{parentName:"p"},"mint-nft.js"),"."),(0,r.kt)("p",null,"We will be using the same ethers library to connect to the ESC testnet public RPC URL. Add the following code to the file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="mint-nft.js"',title:'"mint-nft.js"'},'require("dotenv").config();\nconst ethers = require("ethers");\n\n// Define the provider\nconst provider = new ethers.providers.JsonRpcProvider(RPC_URL);\n')),(0,r.kt)("p",null,"Note that we are using RPC_URL. Make sure you add this to your .env file so that it looks something like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title=".env"',title:'".env"'},'RPC_URL = "https://api-testnet.elastos.io/esc";\nPRIVATE_KEY = "your-metamask-private-key";\n')),(0,r.kt)("h3",{id:"step-2-load-the-contract-abi"}
1,"Step 2: Load the Contract ABI"),(0,r.kt)("p",null,"The contract ABI (Application Binary Interface) is an interface to interact with our smart contract. You can learn more about Contract ABIs ",(0,r.kt)("a",{parentName:"p",href:"https://docs.alchemyapi.io/alchemy/guides/eth_getlogs#what-are-ab-is"},"here"),". Hardhat automatically generates an ABI for us and saves it in the ",(0,r.kt)("inlineCode",{parentName:"p"},"MyNFT.json")," file. In order to use this we'll need to parse out the contents by adding the following code to the ",(0,r.kt)("inlineCode",{parentName:"p"},"mint-nft.js")," file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="mint-nft.js"',title:'"mint-nft.js"'},'const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");\n')),(0,r.kt)("p",null,"If you want to see the ABI you can print it to your console:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"console.log(JSON.stringify(contract.abi));\n")),(0,r.kt)("p",null,"To run and see your ABI printed to the console navigate to your terminal and run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"node scripts/mint-nft.js\n")),(0,r.kt)("h3",{id:"step-3-configure-the-metadata-of-your-nft-using-ipfs"},"Step 3: Configure the Metadata of your NFT using IPFS"),(0,r.kt)("p",null,"Our mintNFT smart contract function takes in a tokenURI parameter that should resolve to a JSON document describing the NFT's metadata\u2014 which is really what brings the NFT to life, allowing it to have configurable properties, such as a name, description, image, and other attributes."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Interplanetary File System (IPFS) is a decentralized protocol and peer-to-peer network for storing and sharing data in a distributed file system.")),(0,r.kt)("p",null,"We will use ",(0,r.kt)("a",{parentName:"p",href:"https://pinata.cloud/"},"Pinata"),", a convenient IPFS API and toolkit, to store our NFT asset and metadata and ensure that our NFT is truly decentralized. If you don't have a Pinata account, sign up for a free account ",(0,r.kt)("a",{parentName:"p",href:"https://pinata.cloud/signup"},"here"),"."),(0,r.kt)("p",null,"Once you've created an account:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Navigate to the Pinata Upload button on the top right"),(0,r.kt)("li",{parentName:"ul"},"Upload an image to pinata - this will be the image asset for your NFT. Feel free to name the asset whatever you wish"),(0,r.kt)("li",{parentName:"ul"},"After you upload, at the top of the page, there should be a green popup that allows you to view the hash of your upload \u2014> Copy that hashcode. You can view your upload at: ",(0,r.kt)("a",{parentName:"li",href:"https://gateway.pinata.cloud/ipfs/your-hash-code"},"https://gateway.pinata.cloud/ipfs/your-hash-code"),"\nFor the more visual learners, the steps above are summarized here: Now, we're going to want to upload one more document to Pinata. But before we do that, we need to create it!")),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"image",src:n(2207).Z,width:"844",height:"480"})),(0,r.kt)("p",null,"In your root directory, make a new file called ",(0,r.kt)("inlineCode",{parentName:"p"},"nft-metadata.json")," and add the following JSON code:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="nft-metadata.json"',title:'"nft-metadata.json"'},'{\n "attributes": [\n {\n "trait_type": "Breed",\n "value": "Maltipoo"\n },\n {\n "trait_type": "Eye color",\n "value": "Mocha"\n }\n ],\n "description": "The world\'s most adorable and sensitive pup.",\n "image": "https://gateway.pinata.cloud/ipfs/QmWmvTJmJU3pozR9ZHFmQC2DNDwi2XJtf3QGyYiiagFSWb",\n "name": "Ramses"\n}\n')),(0,r.kt)("p",null,"Feel free to change the data in the JSON. You can add or remove attributes. Most importantly, make sure the image field points to the location of your IPFS image\u2014 otherwise, your NFT will not include a photo of a dog."),(0,r.kt)("p",null,"Once you're done editing the JSON file, save it and upload it to Pinata, following the same steps we did for uploading the image."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"image",src:n(6130).Z,width:"844",height:"480"})),(0,r.kt)("h3",{id:"step-4-create-a-signer-and-an-instance-of-the-contract"},"Step 4: Create a Signer and an Instance of the Contract"),(0,r.kt)("p",null,"In order to be able to call the functions on our deployed contract, we need to define an ethers Signer using our wallet's private key. Next, we need to use the contract's deployed address, the contract ABI, and the aforementioned signer to define a contract instance."),(0,r.kt)("p",null,"In the ",(0,r.kt)("inlineCode",{parentName:"p"},"mint-nft.js")," file, add the following code:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="mint-nft.js"',title:'"mint-nft.js"'},'// Create a signer\nconst privateKey = process.env.PRIVATE_KEY;\nconst signer = new ethers.Wallet(privateKey, provider);\n\n// Get contract ABI and address\nconst abi = contract.abi;\nconst contractAddress = "0xA4766Ceb9E84a71D282A4CED9fB8Fe93C49b2Ff7";\n\n// Create a contract instance\nconst myNftContract = new ethers.Contract(contractAddress, abi, signer);\n')),(0,r.kt)("p",null,"In the snippet above, you can see that our contract's deployed address is ",(0,r.kt)("inlineCode",{parentName:"p"},"0xA4766Ceb9E84a71D282A4CED9fB8Fe93C49b2Ff7"),". If you don't remember your contract address or can't find it on the ",(0,r.kt)("a",{parentName:"p",href:"https://esc-testnet.elastos.io/"},"Elastos block explorer"),", simply re-deploy the contract from the ",(0,r.kt)("a",{parentName:"p",href:"/tutorials/nfts/create-nft"},"previous tutorial"),") again and note down the new address."),(0,r.kt)("h3",{id:"step-5-call-mintnft-function-of-the-contract"},"Step 5: Call mintNFT Function of the Contract"),(0,r.kt)("p",null,"Remember the metadata.json you uploaded to Pinata? Get its hashcode from Pinata and pass the following into a call to ",(0,r.kt)("inlineCode",{parentName:"p"},"mintNFT")," ",(0,r.kt)("a",{parentName:"p",href:"https://gateway.pinata.cloud/ipfs/your-metadata-hash-code"},"https://gateway.pinata.cloud/ipfs/your-metadata-hash-code")),(0,r.kt)("p",null,"Here's how to get the hashcode:"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"image",src:n(2340).Z,width:"844",height:"480"})),(0,r.kt)("admonition",{title:"Hashcode",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Double check that the hashcode you copied links to your metadata.json by loading ",(0,r.kt)("a",{parentName:"p",href:"https://gateway.pinata.cloud/ipfs/your-metadata-hash-code"},"https://gateway.pinata.cloud/ipfs/your-metadata-hash-code")," into a separate window. The page should look similar to the screenshot below:"),(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("img",{alt:"image",src:n(1611).Z,width:"1213",height:"359"}))),(0,r.kt)("p",null,"Now add the following piece of code to mint-nft.js to call the mintNFT function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="mint-nft.js"',title:'"mint-nft.js"'},'// Get the NFT Metadata IPFS URL\nconst tokenUri =\n "https://gateway.pinata.cloud/ipfs/QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP";\n\n// Call mintNFT function\nconst mintNFT = async () => {\n let nftTxn = await myNftContract.mintNFT(signer.address, tokenUri);\n await nftTxn.wait();\n console.log(\n `NFT Minted! Check it out at: https://esc-testnet.elastos.io/tx/${nftTxn.hash}`\n );\n};\n\nmintNFT()\n .then(() => process.exit(0))\n .catch((error) => {\n console.error(error);\n process.exit(1);\n });\n')),(0,r.kt)("p",null,"The final ",(0,r.kt)("inlineCode",{parentName:"p"},"mint-nft.js")," file should look something like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="mint-nft.js"',title:'"mint-nft.js"'},'require("dotenv").config();\nconst ethers = require("ethers");\n\n// Define an Alchemy Provider\nconst provider = new ethers.providers.AlchemyProvi
1der(RPC_URL);\n\n// Get contract ABI file\nconst contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");\n\n// Create a signer\nconst privateKey = process.env.PRIVATE_KEY;\nconst signer = new ethers.Wallet(privateKey, provider);\n\n// Get contract ABI and address\nconst abi = contract.abi;\nconst contractAddress = "0xA4766Ceb9E84a71D282A4CED9fB8Fe93C49b2Ff7";\n\n// Create a contract instance\nconst myNftContract = new ethers.Contract(contractAddress, abi, signer);\n\n// Get the NFT Metadata IPFS URL\nconst tokenUri =\n "https://gateway.pinata.cloud/ipfs/QmYueiuRNmL4MiA2GwtVMm6ZagknXnSpQnB3z2gWbz36hP";\n\n// Call mintNFT function\nconst mintNFT = async () => {\n let nftTxn = await myNftContract.mintNFT(signer.address, tokenUri);\n await nftTxn.wait();\n console.log(\n `NFT Minted! Check it out at: https://esc-testnet.elastos.io/tx/${nftTxn.hash}`\n );\n};\n\nmintNFT()\n .then(() => process.exit(0))\n .catch((error) => {\n console.error(error);\n process.exit(1);\n });\n')),(0,r.kt)("p",null,"Now, Let's mint our NFT by running the following command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"node scripts/mint-nft.js\n")),(0,r.kt)("p",null,"You should get an output that looks something like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NFT Minted! Check it out at:\nhttps://esc-testnet.elastos.io/tx/0x06a7a06aea5d55eb6e7a0f0f17bfeaad2fb4e310de55f5a884e1b623a3fab239\n")),(0,r.kt)("p",null,"You can check out your NFT mint on the explorer by following the URL above."),(0,r.kt)("p",null,"Use ",(0,r.kt)("inlineCode",{parentName:"p"},"mint-nft.js")," to mint as many NFTs as you want! Just be sure to pass in a new tokenURI describing the NFT metadata, otherwise, you'll just end up making a bunch of identical ones with different IDs."))}m.isMDXComponent=!0},1611:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/metadata-hash-code-84fd8df75430fccc09497ac7502b8caa.png"},2340:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/pinata-hash-code-0aa4a8ef239e3eb26b8c4db26f5c2d8f.gif"},6130:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/pinata-upload-json-3a29b091abf13ece379ba05bf0907618.gif"},2207:(t,e,n)=>{n.d(e,{Z:()=>a});const a=n.p+"assets/images/pinata-upload-png-043bddc878969dddf3c083386fa441de.gif"}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.