Skip to content

Instantly share code, notes, and snippets.

@yupeshekhonov
Last active March 31, 2024 00:16
Show Gist options
  • Save yupeshekhonov/4b087837363b43fa15f8d0ff9c66fcaa to your computer and use it in GitHub Desktop.
Save yupeshekhonov/4b087837363b43fa15f8d0ff9c66fcaa to your computer and use it in GitHub Desktop.
How to deploy a smart contract to an Ethereum testnet, then call it to mint an NFT.

How to mint an NFT on a Ethereum testnet

In this tutorial, we will walk through creating and deploying an ERC-721 smart contract on the Goerli test network using Hardhat and Solidity. Also, we will mint and NFT and add it to Metamask.

Prerequisites

You need to have the following installed and prepared to start this guide:

  • Node.js, version > 14.

  • npm or yarn.

  • Goerli, Mumbai or another testnet URL (watch this video)

    ⚠️ Don't forget to get the tokens for the testnet using its faucet.

  • Metamask account.

Initialize your project

Create a folder and initialize a project.

mkdir test-nft
cd test-nft
npm init - y
yarn init -y 

Add the Hardhat to your project and initialize it:

npm install --save-dev hardhat
yarn add -D hardhat

npx hardhat
yarn hardhat

You should see a welcome message and options on what you can do. We will use the TypeScript project type in this guide. Select this option and accept to install all suggested packages.

To check if everything works properly, please run:

npx hardhat test
yarn hardhat test

We now have our hardhat development environment successfully configured. Let us now install the OpenZeppelin contracts package.

npm install @openzeppelin/contracts 
yarn add @openzeppelin/contracts

Write the smart contract

Create a new file called MyNFT.sol in the /contracts folder. Add the following code to the file. This file will contain our smart contract.

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("MyNFT", "NFT") {}

    function mintNFT(address recipient, string memory tokenURI)
        public
        onlyOwner
        returns (uint256)
    {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

⚠️ Make sure that the version defined above (^0.8.17) is the same as the version defined in the hardhat.config.ts file.

⚠️ Also, compile your contract to make sure everything is good to deploy.

npx hardhat compile
yarn hardhat compile

Even despite you created a Typescript project using Hardhat, you may need to install TS separately:

npm install --save-dev typescript
npm install --save-dev ts-node
yarn add -D typescript
yarn add -D ts-node

In this contract, we have our function mintNFT() that allows us to mint an NFT! You will notice this function takes in two variables:

address - recipient specifies the address that will receive your freshly minted NFT.

string memory tokenURI - is a string that should resolve to a JSON document that describes the NFT metadata. An NFT metadata is really what brings it to life, allowing it to have additional properties, such as a name, description, image, and other attributes. Later on, we will describe how to configure this metadata.

mintNFT calls some methods from the inherited ERC721 library, and ultimately returns a number that represents the ID of the freshly minted NFT.

Connect the network and the Metamask account

Install the dotenv package in your project directory by running:

npm install dotenv --save
yarn add dotenv --save

Then, create a .env file in the root directory of our project, and add your Metamask private key and the network RPC to it.

Follow these instructions to export your private key from Metamask.

Your .env should look like this:

API_URL = "https://eth-goerli.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY = "your-metamask-private-key"

After this, update your hardhat.config.ts so that our project knows about all of these values.

import dotenv from "dotenv"
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

dotenv.config()
const { API_URL, PRIVATE_KEY } = process.env;

const config: HardhatUserConfig = {
    solidity: "0.8.17",
    defaultNetwork: "goerli",
    networks: {
        hardhat: {},
        goerli: {
            url: API_URL,
            accounts: [`0x${PRIVATE_KEY}`],
        },
    },
};

export default config;

Write a deployment script

Now that our contract is written and our configuration file is ready, it is time to write the contract deploy script.

Create the file deploy.ts with the following:

import {ethers} from "hardhat";

async function main() {
   // Grab the contract factory 
   const MyNFT = await ethers.getContractFactory("MyNFT");

   // Start deployment, returning a promise that resolves to a contract object
   const myNFT = await MyNFT.deploy(); // Instance of the contract 
   console.log("Contract deployed to address:", myNFT.address);
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

Deploy the contract

We are finally ready to deploy our smart contract! For this, run the following command line:

npx hardhat run scripts/deploy.ts --network goerli
yarn hardhat run scripts/deploy.ts --network goerli

You should then see something like:

Contract deployed to address: 0x30b2d9930587c0D235BDE869E79c0298e8160a3B

⚠️ Please do not forget that you need to have tokens for contract deployment.

If we go to Goerli Etherscan and search for our contract address we should be able to see that it has been deployed successfully.

Create a minting script

Add the API_KEY vakue to your .env file. So, now, it should look like this:

API_URL = "https://eth-goerli.g.alchemy.com/v2/your-api-key"
PRIVATE_KEY = "your-metamask-private-key"
API_KEY = "your-api-key"

We will use the ethers object from the hardhat library, so we need to install additional dependencies:

npm install --save-dev @nomiclabs/hardhat-ethers 'ethers@^5.0.0'
yarn add -D @nomiclabs/hardhat-ethers 'ethers@^5.0.0'

After this, we need to change imports in the hardhat.config.ts file:

import "@nomiclabs/hardhat-ethers"
// import "@nomicfoundation/hardhat-toolbox";

Now, we can create a new file in the /scripts folder called mint-nft.ts.

import dotenv from "dotenv"
import {ethers} from 'hardhat'

dotenv.config();

const TOKEN_IPFS_CIDS = {
    1: 'QmZ8Syn28bEhZJKYeZCxUTM5Ut74ccKKDbQCqk5AuYsEnp',
    2: 'QmZVpSsjvxev3C8Dv4E44fSp8gGMP6aoLMp56HmZi5Wkxh',
    3: 'QmZMo8JDB9isA7k7tr8sFLXYwNJNa51XjJinkLWcc9vnta',
    4: 'QmV7fqfJBozrc7VtaHSd64GvwNYqoQE1QptaysenTJrbpL',
    5: 'QmSK1Zr6u2f2b8VgaFgz9CY1NR3JEyygQPQjJZaAA496Bh',
    6: 'QmafTK2uFRuLyir2zJpLSBMercq2nDfxtSiMWXL1dbqTDn',
    7: 'QmXTMYJ3rKeTCaQ79QQPe2EYcpVFbHr3maqJCPGcUobS4B',
    8: 'QmQa97BYq9se73AztVF4xG52fGSBVB1kZKtAtuhYLHE1NA',
}
const TOKEN_URI = "https://ipfs.unique.network/ipfs/" + TOKEN_IPFS_CIDS["2"]
// This is the contract that we have deployed earlier 
const CONTRACT_ADDRESS = '0x3664F6c1178E19Bb775b597d6584CaA3B88a1C35'

// Get Alchemy App URL
const API_KEY = process.env.API_KEY;

// Define an Alchemy Provider
const provider = new ethers.providers.AlchemyProvider('goerli', API_KEY)

// Get contract ABI file
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");

// Create a signer
const privateKey = process.env.PRIVATE_KEY
// @ts-ignore
const signer = new ethers.Wallet(privateKey, provider)

// Get contract ABI and address
const abi = contract.abi

// Create a contract instance
const myNftContract = new ethers.Contract(CONTRACT_ADDRESS, abi, signer)

// Call mintNFT function
const mintNFT = async () => {
    let nftTxn = await myNftContract.mintNFT(signer.address, TOKEN_URI)
    await nftTxn.wait()
    console.log(`NFT Minted! Check it out at: https://goerli.etherscan.io/tx/${nftTxn.hash}`)
}

mintNFT()
.then(() => process.exit(0))
.catch((error) => {
    console.error(error);
    process.exit(1);
});

Great! We are ready to mint our NFT. Please note that we have the array of cids, so you can use any value, or you can mint NFTs for all values using a loop. Now, let's run the script to check the results:

npx hardhat run scripts/mint-nft.ts --network goerli
yarn hardhat run scripts/mint-nft.ts --network goerli

After exectung the script, you should receive this text in the console:

NFT Minted! Check it out at: https://goerli.etherscan.io/tx/0xa4ce7169c567376fee9e50e2caa64ade0aba5bfb32977ce734bb448d49093455

You can check out your NFT mint on Etherscan by following the URL. You can view your NFT on OpenSea by searching for your contract address. Check out our NFT here.

Add to Metamask

As a prerequisite, you should already have Metamask on mobile installed, and it should include the account to which you minted your NFT — you can get the app for free on iOS, or Android. This is, because only mobile version of Metamask can display images for NFTs. You will not be able to see images in a browser extension.

At the top of the app, press the Wallet button, after which you'll be prompted to select a network. As our NFT was minted on the Goerli network, you'll want to select Goerli as your network.

Once you're on the Goerli network, select the NFTs tab on the right and add the NFT smart contract address and the ID of your NFT—you can specify just 1, all NFTs minted by this smart contract will be added automatically.

photo_2022-11-21_10-21-30 (2)

Congrats! You can now view your NFT in your wallet!

photo_2022-11-21_10-21-30

@durdenx96
Copy link

At what point did you configure the metadata to contain the NFT image?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment