Кнопка «Mint NFT» на вашем сайте

Проекты коллекционных NFT, которые привлекают больше покупателей, имеют веб-сайт для монетного двора. В этом видео мы запускаем смарт-контракт по сбору NFT на Goerli, а затем необходимый пользовательский интерфейс, содержащий кнопку монетного двора.

Зависимости

Для этого урока вам понадобится NodeJs, я рекомендую загрузить его из Linux через NVM, URL RPC, я рекомендую использовать INFURA или Alchemy, Metamask с фондами Goerli Testnet, которые вы можете получить из Faucet.

1. Начальная конфигурация

mkdir MyNFT
cd MyNFT
npm install --save-dev truffle dotenv @truffle/hdwallet-provider @openzeppelin/contracts
npx truffle init
Вход в полноэкранный режим Выход из полноэкранного режима

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
  }
};
Войти в полноэкранный режим Выход из полноэкранного режима

2. Запуск договора

Создавайте и редактируйте договор в удобное для вас время.

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.");
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

migrations/1_my_deploy.js

const MyNFT = artifacts.require("MyNFT")

module.exports = async function (deployer) {
  await deployer.deploy(MyNFT)
}
Войти в полноэкранный режим Выход из полноэкранного режима

.env

GOERLI_RPC_URL=YOURRPCKEY
PRIVATE_KEY=YOURPRIVATEKEY
Войти в полноэкранный режим Выход из полноэкранного режима
npx truffle migrate --network goerli
Войти в полноэкранный режим Выйти из полноэкранного режима

3. Фронтенд

Создайте каталог client/contracts и скопируйте в него build/MyNFT.json. Также добавьте необходимые html и js и отредактируйте их по своему усмотрению.

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>
Войдите в полноэкранный режим Выход из полноэкранного режима

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)
  });
}
Войдите в полноэкранный режим Выйдите из полноэкранного режима

4. Взаимодействие через Интернет

npm install -g lite-server
cd client
lite-server
Войти в полноэкранный режим Выйти из полноэкранного режима

Результат находится на сайте http://localhost:3000.

Теперь вы можете внести изменения в контракт, а затем адаптировать веб-интерфейс. Я рекомендую Netlify в качестве платформы для развертывания, она бесплатная и простая.
Не стесняйтесь использовать [Github public template]https://github.com/FilosofiaCodigo/NFTCollectionTemplate) в качестве ссылки.

Спасибо за просмотр этого руководства!

Оцените статью
devanswers.ru
Добавить комментарий