Les projets de NFTs de collections plus célèbres ont commencé avec une website pour minter. On ce vidéo on va créer un smart contract en Goerli déployer une UI avec un bouton de mint.
Dépendances
Pour ce tutoriel tu vas avoir besoin de NodeJs, je vous conseille de le télécharger avec NVM, aussi on aura besoin d'une RPC URL, je vous conseille d'utiliser INFURA, et puis Metamask avec du GoerliETH que to peux trouver dans un Faucet.
1. Configuration initiale
mkdir MyNFTCollection
cd MyNFTCollection
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: 4,
gas: 4000000,
networkCheckTimeout: 10000
}
},
mocha: {
},
compilers: {
solc: {
version: "0.8.16",
}
},
db: {
enabled: false
}
};
2. Déployer le contrat
Créez et éditez le contrat suivant a votre convenance.
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. Le frontend
Créez le dossier client/contracts
, créez dedans le fichier MyNFTABI.json
et copypastez dedans l'atribut abi
dans le fichier build/contracts/MyNFT.json
. De plus, modifiez le HTML et le JS a votre convenance.
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>
Rapelez vous copypaster l'address du contract en MY_NFT_CONTRACT_ADDRESS
.
client/blockchain_stuff.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. Essayons le site web
npm install -g lite-server
cd client
lite-server
On peut voir le résultat sur http://localhost:3000.
Maintenant on peut changer le smart contract et adapter l'UI du site web. Je vous conseille d'utiliser Netlify pour déployer, c'est gratuit et simple. De plus, utilisez le répo sur Github si vous avez besoin.
¡Merci pour regarder ce tutoriel!
Top comments (0)