├── .gitignore ├── README.md ├── package.json ├── scripts ├── deploy-script.js ├── get-token-script.js └── mint-script.js ├── test └── test.js ├── hardhat.config.js └── contracts └── NFT.sol /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | #Hardhat files 4 | cache 5 | artifacts 6 | .env 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NFT Contract Deployment On Polygon + Pinata 2 | 3 | This is the companion repository for the tutorial ["How To Build Layer 2 NFTs With Polygon and IPFS"](https://medium.com/pinata/how-to-create-layer-2-nfts-with-polygon-and-ipfs-aef998ff8ef2). -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "chai": "^4.3.4", 7 | "ethereum-waffle": "^3.3.0", 8 | "ethers": "^5.1.4", 9 | "hardhat": "^2.3.0" 10 | }, 11 | "dependencies": { 12 | "@openzeppelin/contracts": "^4.1.0", 13 | "dotenv": "^9.0.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /scripts/deploy-script.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const NFT = await hre.ethers.getContractFactory("MyNFT"); 5 | const nft = await NFT.deploy(); 6 | 7 | await nft.deployed(); 8 | 9 | console.log("NFT deployed to:", nft.address); 10 | } 11 | 12 | main() 13 | .then(() => process.exit(0)) 14 | .catch(error => { 15 | console.error(error); 16 | process.exit(1); 17 | }); 18 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | 3 | describe("NFT", function() { 4 | it("It should deploy the contract, mint a token, and resolve to the right URI", async function() { 5 | const NFT = await ethers.getContractFactory("MyNFT"); 6 | const nft = await NFT.deploy(); 7 | const URI = "ipfs://QmWJBNeQAm9Rh4YaW8GFRnSgwa4dN889VKm9poc2DQPBkv"; 8 | await nft.deployed(); 9 | await nft.mint("0xd72203b26D887a60Af3a11178eF4A48BE8DecbA6", URI) 10 | expect(await nft.tokenURI(1)).to.equal(URI) 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /scripts/get-token-script.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const NFT = await hre.ethers.getContractFactory("MyNFT"); 5 | const CONTRACT_ADDRESS = "YOUR CONTRACT ADDRESS" 6 | const contract = NFT.attach(CONTRACT_ADDRESS); 7 | 8 | const owner = await contract.ownerOf(1); 9 | console.log("Owner:", owner); 10 | const uri = await contract.tokenURI(1); 11 | console.log("URI: ", uri); 12 | } 13 | 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch(error => { 18 | console.error(error); 19 | process.exit(1); 20 | }); -------------------------------------------------------------------------------- /scripts/mint-script.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const NFT = await hre.ethers.getContractFactory("MyNFT"); 5 | const URI = "ipfs://QmZu6UUBHo2bHLiRMZCoQf6hiSmnFVVzWqyEAyF9SJwxhx" 6 | const WALLET_ADDRESS = "YOUR WALLET ADDRESS" 7 | const CONTRACT_ADDRESS = "YOUR CONTRACT ADDRESS" 8 | const contract = NFT.attach(CONTRACT_ADDRESS); 9 | 10 | await contract.mint(WALLET_ADDRESS, URI); 11 | console.log("NFT minted:", contract); 12 | } 13 | 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch(error => { 18 | console.error(error); 19 | process.exit(1); 20 | }); 21 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const PRIVATE_KEY = process.env.PRIVATE_KEY; 3 | require("@nomiclabs/hardhat-waffle"); 4 | 5 | // This is a sample Hardhat task. To learn how to create your own go to 6 | // https://hardhat.org/guides/create-task.html 7 | task("accounts", "Prints the list of accounts", async () => { 8 | const accounts = await ethers.getSigners(); 9 | 10 | for (const account of accounts) { 11 | console.log(account.address); 12 | } 13 | }); 14 | 15 | // You need to export an object to set up your config 16 | // Go to https://hardhat.org/config/ to learn more 17 | 18 | /** 19 | * @type import('hardhat/config').HardhatUserConfig 20 | */ 21 | module.exports = { 22 | defaultNetwork: "matic", 23 | networks: { 24 | hardhat: { 25 | }, 26 | matic: { 27 | url: "https://rpc-mumbai.maticvigil.com", 28 | accounts: [PRIVATE_KEY] 29 | } 30 | }, 31 | solidity: { 32 | version: "0.8.0", 33 | settings: { 34 | optimizer: { 35 | enabled: true, 36 | runs: 200 37 | } 38 | } 39 | }, 40 | paths: { 41 | sources: "./contracts", 42 | tests: "./test", 43 | cache: "./cache", 44 | artifacts: "./artifacts" 45 | }, 46 | mocha: { 47 | timeout: 20000 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /contracts/NFT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 4 | import "@openzeppelin/contracts/utils/Counters.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract MyNFT is ERC721, Ownable { 8 | using Counters for Counters.Counter; 9 | using Strings for uint256; 10 | Counters.Counter private _tokenIds; 11 | mapping (uint256 => string) private _tokenURIs; 12 | string private _baseURIextended; 13 | 14 | constructor() ERC721("MyNFT", "MNFT") {} 15 | 16 | function _setTokenURI(uint256 tokenId, string memory _tokenURI) 17 | internal 18 | virtual 19 | { 20 | _tokenURIs[tokenId] = _tokenURI; 21 | } 22 | 23 | function tokenURI(uint256 tokenId) 24 | public 25 | view 26 | virtual 27 | override 28 | returns (string memory) 29 | { 30 | require( 31 | _exists(tokenId), 32 | "ERC721Metadata: URI query for nonexistent token" 33 | ); 34 | 35 | string memory _tokenURI = _tokenURIs[tokenId]; 36 | return _tokenURI; 37 | } 38 | 39 | function mint(address recipient, string memory uri) 40 | public 41 | returns (uint256) 42 | { 43 | _tokenIds.increment(); 44 | 45 | uint256 newItemId = _tokenIds.current(); 46 | _mint(recipient, newItemId); 47 | _setTokenURI(newItemId, uri); 48 | return newItemId; 49 | } 50 | } 51 | --------------------------------------------------------------------------------