DEV Community

Cover image for "Mint NFT" button on your website
Ahmed Castro for Filosofía Código EN

Posted on

"Mint NFT" button on your website

Collectibles NFTs proyects that attract more buyers have a website for mint. In this video we launch a NFT collection smart contract on Goerli and then the required UI containing the mint button.

https://www.youtube.com/watch?v=6m17YQWHq-M

Dependencies

For this tutorial you will need NodeJs, I recommend downloading it from Linux via NVM, a RPC URL, I recommend using INFURA or Alchemy, Metamask with Goerli Testnet funds that you can get from the Faucet.

1. Initial configuration

mkdir MyNFT
cd MyNFT
npm install --save-dev truffle dotenv @truffle/hdwallet-provider @openzeppelin/contracts
npx truffle init
Enter fullscreen mode Exit fullscreen mode

truffle-config.js

require('dotenv').config()
const HDWalletProvider = require('@truffle/hdwallet-provider');

const fs = require('fs');

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*",
    },
    goerli: {
      provider: function () {
        return new HDWalletProvider(process.env.PRIVATE_KEY, process.env.GOERLI_RPC_URL);
      },
      network_id: 5,
      gas: 4000000,
      networkCheckTimeout: 10000
    }
  },
  mocha: {
  },
  compilers: {
    solc: {
      version: "0.8.16",
    }
  },
  db: {
    enabled: false
  }
};
Enter fullscreen mode Exit fullscreen mode

2. Contract launch

Create and edit the contract at your convenience.

contracts/MyNFT.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyNFT is ERC721Enumerable {
    uint256 public MAX_ELEMENTS = 5;
    uint256 public PRICE = 0.01 ether;
    address public CREATOR = 0x0000000000000000000000000000000000000000;
    uint256 public token_count;
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdTracker;

    constructor() ERC721("My NFT", "MNFT") {}

    function _baseURI() internal view virtual override returns (string memory) {
        return "MIURL";
    }

    function _totalSupply() internal view returns (uint) {
        return _tokenIdTracker.current();
    }

    function totalMint() public view returns (uint256) {
        return _totalSupply();
    }

    function mint(address _to, uint256 _count) public payable {
        uint256 total = _totalSupply();
        require(total + _count <= MAX_ELEMENTS, "Max limit");
        require(total <= MAX_ELEMENTS, "Sale end");
        require(msg.value >= PRICE*_count, "Value below price");

        for (uint256 i = 0; i < _count; i++) {
            _mintAnElement(_to);
        }
    }

    function _mintAnElement(address _to) private {
        uint id = _totalSupply();
        _tokenIdTracker.increment();
        _safeMint(_to, id);
    }

    function withdrawAll() public {
        (bool success, ) = CREATOR.call{value:address(this).balance}("");
        require(success, "Transfer failed.");
    }
}
Enter fullscreen mode Exit fullscreen mode

migrations/1_my_deploy.js

const MyNFT = artifacts.require("MyNFT")

module.exports = async function (deployer) {
  await deployer.deploy(MyNFT)
}
Enter fullscreen mode Exit fullscreen mode

.env

GOERLI_RPC_URL=YOURRPCKEY
PRIVATE_KEY=YOURPRIVATEKEY
Enter fullscreen mode Exit fullscreen mode
npx truffle migrate --network goerli
Enter fullscreen mode Exit fullscreen mode

3. Frontend

Create the client/contracts directory and copypaste build/MyNFT.json on it. Also, add the necessary html and js and edit them at your convenience.

client/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
</head>
<body>
  <input id="connect_button" type="button" value="Connect" onclick="connectWallet()" style="display: none"></input>
  <p id="account_address" style="display: none"></p>
  <p id="web3_message"></p>
  <p id="contract_state"></p>
  <select id="mint_amount">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
  </select>
  <input type="button" value="mint!" onclick="_mint()">
  <p id="nft_price"></p>
  <p id="nft_balance"></p>
  <br>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js"></script>
  <script type="text/javascript" src="blockchain_stuff.js"></script>
</body>
</html>

<script>
  function _mint()
  {
    mint_amount = document.getElementById("mint_amount").value
    mint(mint_amount)
  }
</script>
Enter fullscreen mode Exit fullscreen mode

client/src/contract_interaction.js

const NETWORK_ID = 5

const MY_NFT_CONTRACT_ADDRESS = "0xc7c463b90B393b4A0d3650Aa70a08211a6D5fB79"
const MY_NFT_CONTRACT_ABI_PATH = "./MyNFTABI.json"
var my_nft_contract
var price

var accounts
var web3

function metamaskReloadCallback() {
  window.ethereum.on('accountsChanged', (accounts) => {
    document.getElementById("web3_message").textContent="Network changed, refreshing...";
    window.location.reload()
  })
  window.ethereum.on('networkChanged', (accounts) => {
    document.getElementById("web3_message").textContent="Network chainged, refreshing...";
    window.location.reload()
  })
}

const getWeb3 = async () => {
  return new Promise((resolve, reject) => {
    if(document.readyState=="complete")
    {
      if (window.ethereum) {
        const web3 = new Web3(window.ethereum)
        window.location.reload()
        resolve(web3)
      } else {
        reject("must install MetaMask")
        document.getElementById("web3_message").textContent="Error: Connect to Metamask";
      }
    }else
    {
      window.addEventListener("load", async () => {
        if (window.ethereum) {
          const web3 = new Web3(window.ethereum)
          resolve(web3)
        } else {
          reject("must install MetaMask")
          document.getElementById("web3_message").textContent="Error: Please install Metamask";
        }
      });
    }
  });
};

const getContract = async (web3, address, abi_path) => {
  const response = await fetch(abi_path);
  const data = await response.json();

  const netId = await web3.eth.net.getId();
  contract = new web3.eth.Contract(
    data,
    address
    );
  return contract
}

async function loadDapp() {
  metamaskReloadCallback()
  document.getElementById("web3_message").textContent="Please connect to Metamask"
  var awaitWeb3 = async function () {
    web3 = await getWeb3()
    web3.eth.net.getId((err, netId) => {
      if (netId == NETWORK_ID) {
        var awaitContract = async function () {
          my_nft_contract = await getContract(web3, MY_NFT_CONTRACT_ADDRESS, MY_NFT_CONTRACT_ABI_PATH)
          document.getElementById("web3_message").textContent="You are connected to Metamask"
          onContractInitCallback()
          web3.eth.getAccounts(function(err, _accounts){
            accounts = _accounts
            if (err != null)
            {
              console.error("An error occurred: "+err)
            } else if (accounts.length > 0)
            {
              onWalletConnectedCallback()
              document.getElementById("account_address").style.display = "block"
            } else
            {
              document.getElementById("connect_button").style.display = "block"
            }
          });
        };
        awaitContract();
      } else {
        document.getElementById("web3_message").textContent="Please connect to Goerli";
      }
    });
  };
  awaitWeb3();
}

async function connectWallet() {
  await window.ethereum.request({ method: "eth_requestAccounts" })
  accounts = await web3.eth.getAccounts()
  onWalletConnectedCallback()
}

loadDapp()

const onContractInitCallback = async () => {
  price = await my_nft_contract.methods.PRICE().call()
  document.getElementById("nft_price").textContent = "NFT Price: " + web3.utils.fromWei(price) + " ETH";
}

const onWalletConnectedCallback = async () => {
  balance = await my_nft_contract.methods.balanceOf(accounts[0]).call()
  document.getElementById("nft_balance").textContent= "Your balance: " + balance;
}


//// Functions ////

const mint = async (amount) => {
  const result = await my_nft_contract.methods.mint(accounts[0], amount)
  .send({ from: accounts[0], gas: 0, value: price * amount })
  .on('transactionHash', function(hash){
    document.getElementById("web3_message").textContent="Executing...";
  })
  .on('receipt', function(receipt){
    document.getElementById("web3_message").textContent="Success.";    })
  .catch((revertReason) => {
    console.log("ERROR! Transaction reverted: " + revertReason.receipt.transactionHash)
  });
}
Enter fullscreen mode Exit fullscreen mode

4. Interact via web

npm install -g lite-server
cd client
lite-server
Enter fullscreen mode Exit fullscreen mode

The result is in http://localhost:3000.

Now you can do changes to the contract and then adapt the web UI. I recommend Netlify as a deploying plataform, is free and simple.
Feel free to use the [Github public template]https://github.com/FilosofiaCodigo/NFTCollectionTemplate) as a reference.

Thanks for watching this tutorial!

Top comments (0)