NFT-Minter Tutorial
Eine der größten Herausforderungen für Entwickler mit einem Web2-Hintergrund ist herauszufinden, wie sie ihren Smart Contract mit einem Frontend Projekt verbinden und mit ihm interagieren können.
Durch den Bau eines NFT-Minters - eine einfache Benutzeroberfläche, auf welcher ein Link den Nutzer zu seinen digitalen Vermögenswerten führt, ein Titel und eine Beschreibung - werden Sie Folgendes lernen:
- Verbinden von MetaMask mit Ihrem Frontend-Projekt
- Rufen von Smart-Contract Methoden von Ihrem Frontend
- Transaktionen mit MetaMask signieren
In diesem Tutorial werden wir Reactopens in a new tab als unser Frontend-Framework verwenden. Da sich dieses Tutorial in erster Linie auf die Web3-Entwicklung konzentriert, werden wir nicht viel Zeit darauf verwenden, die React Grundlagen zu behandeln. Stattdessen konzentrieren wir uns darauf, Funktionalität in unser Projekt zu bringen.
Als Voraussetzung solltest du ein grundlegendes Verständnis von React haben – du solltest wissen, wie Komponenten, Props, useState/useEffect und grundlegende Funktionsaufrufe funktionieren. Wenn du noch nie von diesen Begriffen gehört hast, solltest du dir dieses Einführungstutorial zu Reactopens in a new tab ansehen. Für diejenigen, die eher visuell lernen, empfehlen wir diese ausgezeichnete Videoreihe Full Modern React Tutorialopens in a new tab von Net Ninja.
Und wenn Sie sich noch nicht angemeldet haben, dann benötigen Sie auf jeden Fall einen Alchemy Account, um dieses Tutorial zu beenden und um etwas auf der Blockchain bauen zu können. Registriere dich hieropens in a new tab für ein kostenloses Konto.
Lass uns ohne weiteres starten!
NFTs erstellen 101
Bevor wir uns überhaupt einen Code anschauen, ist es wichtig zu verstehen, wie das erstellen von NFTs überhaupt funktioniert. Es benötigt dafür zwei Schritte:
Einen NFT-Smart-Contract auf der Ethereum-Blockchain veröffentlichen
Der größte Unterschied zwischen den beiden NFT smart Kontrakt Standards ist, dass der ERC-1155 ein Multi-Token Standard ist und eine Handvoll Funktionalitäten beinhaltet, wobei man mit dem ERC-721, welcher ein Single-Token Standard ist, nur eine Token-Transaktion gleichzeitig ausführen kann.
Die Minting-Funktion aufrufen
Normalerweise verlangt diese Minting-Funktion, dass du zwei Variablen als Parameter übergibst: erstens den recipient (Empfänger), der die Adresse angibt, die deinen frisch geminteten NFT erhält, und zweitens die tokenURI des NFTs, eine Zeichenfolge, die zu einem JSON-Dokument aufgelöst wird, das die Metadaten des NFTs beschreibt.
Die NFT Metadaten sind das, was Leben hineinbringt, welches Ihnen erlaubt Eigenschaften zu haben, wie zum Beispiel: Namen, eine Beschreibung, ein Bild (oder andere digitale Vermögenswerte), und andere Attribute. Hier ist ein Beispiel für eine tokenURIopens in a new tab, die die Metadaten eines NFT enthält.
In diesem Tutorial werden wir uns auf den 2 Teil fokussieren, das Aufrufen von einer bereits existierenden NFT smart Kontrakt Prägungs Funktion, indem wir unsere React UI benutzen.
Hier ist ein Linkopens in a new tab zu dem ERC-721-NFT-Smart-Contract, den wir in diesem Tutorial aufrufen werden. Wenn du lernen möchtest, wie wir ihn erstellt haben, empfehlen wir dir dringend unser anderes Tutorial „Wie man einen NFT erstellt“opens in a new tab.
Cool, nun verstehen wir wie die Erstellung von NFTS funktioniert, lass uns nun unsere Startdateien klonen!
Die Starter-Dateien klonen
Gehe zuerst zum nft-minter-tutorial GitHub-Repositoryopens in a new tab, um die Starter-Dateien für dieses Projekt zu erhalten. Klone dieses Repository in deine lokale Umgebung.
Wenn du dieses geklonte nft-minter-tutorial-Repository öffnest, wirst du feststellen, dass es zwei Ordner enthält: minter-starter-files und nft-minter.
minter-starter-filesenthält die Starter-Dateien (im Wesentlichen die React-UI) für dieses Projekt. In diesem Tutorial werden wir in diesem Verzeichnis arbeiten, während du lernst, wie du diese Benutzeroberfläche zum Leben erweckst, indem du sie mit deiner Ethereum-Wallet und einem NFT-Smart-Contract verbindest.nft-minterenthält das gesamte, vollständige Tutorial und dient dir als Referenz, falls du nicht weiterkommst.
Öffne als Nächstes deine Kopie von minter-starter-files in deinem Code-Editor und navigiere dann in deinen src-Ordner.
Der gesamte Code, den wir schreiben werden, befindet sich im Ordner src. Wir werden die Minter.js-Komponente bearbeiten und zusätzliche JavaScript-Dateien schreiben, um unserem Projekt Web3-Funktionalität zu verleihen.
Schritt 2: Unsere Starter-Dateien ansehen
Bevor wir mit dem Programmieren beginnen, ist es wichtig, sich anzusehen, was uns in den Starter-Dateien bereits zur Verfügung gestellt wird.
Dein React-Projekt zum Laufen bringen
Beginnen wir damit, das React-Projekt in unserem Browser auszuführen. Das Schöne an React ist, dass alle Änderungen, die wir speichern, live in unserem Browser aktualisiert werden, sobald unser Projekt im Browser läuft.
Um das Projekt zum Laufen zu bringen, navigiere zum Stammverzeichnis des Ordners minter-starter-files und führe npm install in deinem Terminal aus, um die Abhängigkeiten des Projekts zu installieren:
cd minter-starter-filesnpm installSobald die Installation abgeschlossen ist, führe npm start in deinem Terminal aus:
npm startDadurch sollte sich http://localhost:3000/opens in a new tab in deinem Browser öffnen, wo du das Frontend für unser Projekt siehst. Es sollte aus 3 Feldern bestehen: einem Feld zur Eingabe eines Links zum Asset deines NFTs, einem Feld zur Eingabe des Namens deines NFTs und einem Feld zur Angabe einer Beschreibung.
Wenn du versuchst, auf die Schaltflächen „Wallet verbinden“ oder „NFT minten“ zu klicken, wirst du feststellen, dass sie nicht funktionieren – das liegt daran, dass wir ihre Funktionalität noch programmieren müssen! :)
Die Minter.js-Komponente
HINWEIS: Stelle sicher, dass du dich im Ordner minter-starter-files und nicht im Ordner nft-minter befindest!
Gehen wir zurück in den src-Ordner in unserem Editor und öffnen die Datei Minter.js. Es ist sehr wichtig, dass wir alles in dieser Datei verstehen, da es sich um die primäre React-Komponente handelt, an der wir arbeiten werden.
Oben in dieser Datei befinden sich unsere Zustandsvariablen, die wir nach bestimmten Ereignissen aktualisieren werden.
1//Zustandsvariablen2const [walletAddress, setWallet] = useState("")3const [status, setStatus] = useState("")4const [name, setName] = useState("")5const [description, setDescription] = useState("")6const [url, setURL] = useState("")Noch nie von React-Zustandsvariablen oder State-Hooks gehört? Sieh dir dieseopens in a new tab Dokumentation an.
Hier ist, was die einzelnen Variablen darstellen:
walletAddress- eine Zeichenfolge, die die Wallet-Adresse des Benutzers speichertstatus- eine Zeichenfolge, die eine Nachricht enthält, die am unteren Rand der Benutzeroberfläche angezeigt wirdname- eine Zeichenfolge, die den Namen des NFT speichertdescription- eine Zeichenfolge, die die Beschreibung des NFT speicherturl- eine Zeichenfolge, die ein Link zum digitalen Asset des NFT ist
Nach den Zustandsvariablen siehst du drei nicht implementierte Funktionen: useEffect, connectWalletPressed und onMintPressed. Du wirst feststellen, dass alle diese Funktionen async sind, weil wir in ihnen asynchrone API-Aufrufe tätigen werden! Ihre Namen sind gleichbedeutend mit ihren Funktionalitäten:
1useEffect(async () => {2 //TODO: implementieren3}, [])45const connectWalletPressed = async () => {6 //TODO: implementieren7}89const onMintPressed = async () => {10 //TODO: implementieren11}Alles anzeigenuseEffectopens in a new tab – dies ist ein React-Hook, der aufgerufen wird, nachdem deine Komponente gerendert wurde. Da ihm ein leeres Array[]als Prop übergeben wird (siehe Zeile 3), wird er nur beim ersten Rendern der Komponente aufgerufen. Hier rufen wir unseren Wallet-Listener und eine weitere Wallet-Funktion auf, um unsere Benutzeroberfläche zu aktualisieren und anzuzeigen, ob eine Wallet bereits verbunden ist.connectWalletPressed– diese Funktion wird aufgerufen, um die MetaMask-Wallet des Benutzers mit unserer Dapp zu verbinden.onMintPressed– diese Funktion wird aufgerufen, um den NFT des Benutzers zu minten.
Gegen Ende dieser Datei haben wir die Benutzeroberfläche unserer Komponente. Wenn du diesen Code sorgfältig durchgehst, wirst du feststellen, dass wir unsere url-, name- und description-Zustandsvariablen aktualisieren, wenn sich die Eingabe in den entsprechenden Textfeldern ändert.
Du wirst auch sehen, dass connectWalletPressed und onMintPressed aufgerufen werden, wenn die Schaltflächen mit den IDs mintButton bzw. walletButton angeklickt werden.
1//die Benutzeroberfläche unserer Komponente2return (3 <div className="Minter">4 <button id="walletButton" onClick={connectWalletPressed}>5 {walletAddress.length > 0 ? (6 "Verbunden: " +7 String(walletAddress).substring(0, 6) +8 "..." +9 String(walletAddress).substring(38)10 ) : (11 <span>Wallet verbinden</span>12 )}13 </button>1415 <br></br>16 <h1 id="title">🧙♂️ Alchemy NFT Minter</h1>17 <p>18 Füge einfach den Link, den Namen und die Beschreibung deines Assets hinzu und drücke dann auf „Minten“.19 </p>20 <form>21 <h2>🖼 Link zum Asset: </h2>22 <input23 type="text"24 placeholder="z. B. https://gateway.pinata.cloud/ipfs/<hash>"25 onChange={(event) => setURL(event.target.value)}26 />27 <h2>🤔 Name: </h2>28 <input29 type="text"30 placeholder="z. B. Mein erster NFT!"31 onChange={(event) => setName(event.target.value)}32 />33 <h2>✍️ Beschreibung: </h2>34 <input35 type="text"36 placeholder="z. B. Noch cooler als CryptoKitties ;)"37 onChange={(event) => setDescription(event.target.value)}38 />39 </form>40 <button id="mintButton" onClick={onMintPressed}>41 NFT minten42 </button>43 <p id="status">{status}</p>44</div>45)Alles anzeigenSchließlich wollen wir uns ansehen, wo diese Minter-Komponente hinzugefügt wird.
Wenn du zur Datei App.js gehst, der Hauptkomponente in React, die als Container für alle anderen Komponenten fungiert, siehst du, dass unsere Minter-Komponente in Zeile 7 eingefügt wird.
In diesem Tutorial werden wir nur die Minter.js-Datei bearbeiten und Dateien in unserem src-Ordner hinzufügen.
Nachdem wir nun verstanden haben, womit wir arbeiten, richten wir unsere Ethereum-Wallet ein!
Richte deine Ethereum-Wallet ein
Damit Benutzer mit deinem Smart Contract interagieren können, müssen sie ihre Ethereum-Wallet mit deiner Dapp verbinden.
MetaMask herunterladen
In diesem Tutorial verwenden wir MetaMask, eine virtuelle Wallet im Browser, mit der Sie Ihre Ethereum-Kontoadresse verwalten können. Wenn du mehr darüber erfahren möchtest, wie Transaktionen auf Ethereum funktionieren, sieh dir diese Seite an.
Sie können MetaMask hieropens in a new tab kostenlos herunterladen und ein Konto erstellen. Wenn du ein Konto erstellst oder bereits eines hast, wechsle unbedingt zum „Ropsten Test Network“ oben rechts (damit wir nicht mit echtem Geld hantieren).
Ether von einem Faucet hinzufügen
Um unsere NFTs zu minten (oder Transaktionen auf der Ethereum-Blockchain zu signieren), benötigen wir einige gefälschte ETH. Um ETH zu erhalten, kannst du zum Ropsten-Faucetopens in a new tab gehen und deine Ropsten-Kontoadresse eingeben und dann auf „Send Ropsten ETH“ klicken. Kurz darauf solltest du ETH in deinem MetaMask-Konto sehen!
Deinen Kontostand überprüfen
Um zu überprüfen, ob unser Guthaben vorhanden ist, machen wir eine eth_getBalanceopens in a new tab-Anfrage mit dem Composer-Tool von Alchemyopens in a new tab. Dies gibt den Betrag an ETH in unserer Wallet zurück. Nachdem Sie die Adresse Ihres MetaMask-Kontos eingegeben und auf “Send Request” (Anforderung senden) geklickt haben, sollten Sie eine Antwort ähnlich der Folgenden erhalten:
1{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}HINWEIS: Dieses Ergebnis ist in Wei, nicht in ETH. Wei ist die kleinste Einheit von Ether. Die Umrechnung von Wei in ETH ist: 1 ETH = 10¹⁸ Wei. Wenn wir also 0xde0b6b3a7640000 in eine Dezimalzahl umwandeln, erhalten wir 1*10¹⁸, was 1 ETH entspricht.
Puh! Unser Falschgeld ist da!
MetaMask mit deiner Benutzeroberfläche verbinden
Nachdem unsere MetaMask-Wallet nun eingerichtet ist, verbinden wir unsere Dapp damit!
Da wir uns an das MVCopens in a new tab-Paradigma halten wollen, werden wir eine separate Datei erstellen, die unsere Funktionen zur Verwaltung der Logik, der Daten und der Regeln unserer Dapp enthält, und diese Funktionen dann an unser Frontend (unsere Minter.js-Komponente) übergeben.
Die connectWallet-Funktion
Dazu erstellen wir einen neuen Ordner namens utils in deinem src-Verzeichnis und fügen eine Datei namens interact.js hinzu, die alle unsere Interaktionsfunktionen für Wallets und Smart Contracts enthalten wird.
In unserer interact.js-Datei schreiben wir eine connectWallet-Funktion, die wir dann in unsere Minter.js-Komponente importieren und aufrufen.
Füge in deine interact.js-Datei Folgendes ein
1export const connectWallet = async () => {2 if (window.ethereum) {3 try {4 const addressArray = await window.ethereum.request({5 method: "eth_requestAccounts",6 })7 const obj = {8 status: "👆🏽 Schreibe eine Nachricht in das Textfeld oben.",9 address: addressArray[0],10 }11 return obj12 } catch (err) {13 return {14 address: "",15 status: "😥 " + err.message,16 }17 }18 } else {19 return {20 address: "",21 status: (22 <span>23 <p>24 {" "}25 🦊 <a target="_blank" href={`https://metamask.io/download`}>26 Du musst MetaMask, eine virtuelle Ethereum-Wallet, in deinem27 Browser installieren.28 </a>29 </p>30 </span>31 ),32 }33 }34}Alles anzeigenSchauen wir uns an, was dieser Code bewirkt:
Zuerst prüft unsere Funktion, ob window.ethereum in deinem Browser aktiviert ist.
window.ethereum ist eine globale API, die von MetaMask und anderen Wallet-Anbietern eingeschleust wird und es Websites ermöglicht, die Ethereum-Konten von Benutzern anzufordern. Wenn dies genehmigt wird, kann sie Daten aus den Blockchains lesen, mit denen der Benutzer verbunden ist, und dem Benutzer vorschlagen, Nachrichten und Transaktionen zu signieren. Weitere Informationen findest du in der MetaMask-Dokumentationopens in a new tab!
Wenn window.ethereum nicht vorhanden ist, bedeutet das, dass MetaMask nicht installiert ist. Dies führt dazu, dass ein JSON-Objekt zurückgegeben wird, bei dem die zurückgegebene address eine leere Zeichenfolge ist und das status-JSX-Objekt meldet, dass der Benutzer MetaMask installieren muss.
Die meisten Funktionen, die wir schreiben, geben JSON-Objekte zurück, mit denen wir unsere Zustandsvariablen und die Benutzeroberfläche aktualisieren können.
Wenn window.ethereum jedoch vorhanden ist, dann wird es interessant.
Mithilfe einer try/catch-Schleife versuchen wir, eine Verbindung zu MetaMask herzustellen, indem wir window.ethereum.request({ method: "eth_requestAccounts" });opens in a new tab aufrufen. Der Aufruf dieser Funktion öffnet MetaMask im Browser, woraufhin der Benutzer aufgefordert wird, seine Wallet mit deiner Dapp zu verbinden.
- Wenn der Benutzer die Verbindung herstellt, gibt
method: "eth_requestAccounts"ein Array zurück, das alle Adressen der Benutzerkonten enthält, die mit der Dapp verbunden sind. Insgesamt gibt unsereconnectWallet-Funktion ein JSON-Objekt zurück, das die ersteaddressin diesem Array (siehe Zeile 9) und einestatus-Nachricht enthält, die den Benutzer auffordert, eine Nachricht an den Smart Contract zu schreiben. - Wenn der Benutzer die Verbindung ablehnt, enthält das JSON-Objekt eine leere Zeichenfolge für die zurückgegebene
addressund einestatus-Nachricht, die widerspiegelt, dass der Benutzer die Verbindung abgelehnt hat.
Hinzufügen der connectWallet-Funktion zur Minter.js-UI-Komponente
Nachdem wir diese connectWallet-Funktion geschrieben haben, verbinden wir sie mit unserer Minter.js.-Komponente.
Zuerst müssen wir unsere Funktion in unsere Minter.js-Datei importieren, indem wir import { connectWallet } from "./utils/interact.js"; am Anfang der Minter.js-Datei hinzufügen. Deine ersten 11 Zeilen von Minter.js sollten nun so aussehen:
1import { useEffect, useState } from "react";2import { connectWallet } from "./utils/interact.js";34const Minter = (props) => {56 //Zustandsvariablen7 const [walletAddress, setWallet] = useState("");8 const [status, setStatus] = useState("");9 const [name, setName] = useState("");10 const [description, setDescription] = useState("");11 const [url, setURL] = useState("");Alles anzeigenDann rufen wir in unserer connectWalletPressed-Funktion unsere importierte connectWallet-Funktion auf, wie folgt:
1const connectWalletPressed = async () => {2 const walletResponse = await connectWallet()3 setStatus(walletResponse.status)4 setWallet(walletResponse.address)5}Fällt dir auf, wie der größte Teil unserer Funktionalität von unserer Minter.js-Komponente in die interact.js-Datei abstrahiert wird? Dies geschieht, damit wir dem M-V-C-Paradigma entsprechen!
In connectWalletPressed machen wir einfach einen Await-Aufruf an unsere importierte connectWallet-Funktion, und mit ihrer Antwort aktualisieren wir unsere status- und walletAddress-Variablen über ihre State-Hooks.
Speichern wir nun beide Dateien, Minter.js und interact.js, und testen unsere Benutzeroberfläche.
Öffne deinen Browser unter localhost:3000 und drücke die Schaltfläche „Wallet verbinden“ oben rechts auf der Seite.
Wenn du MetaMask installiert hast, solltest du aufgefordert werden, deine Wallet mit deiner Dapp zu verbinden. Akzeptiere die Aufforderung, eine Verbindung herzustellen.
Du solltest sehen, dass die Wallet-Schaltfläche nun anzeigt, dass deine Adresse verbunden ist.
Als Nächstes versuche, die Seite neu zu laden ... Das ist seltsam. Unsere Wallet-Schaltfläche fordert uns auf, MetaMask zu verbinden, obwohl es bereits verbunden ist ...
Aber keine Sorge! Das können wir leicht beheben, indem wir eine Funktion namens getCurrentWalletConnected implementieren, die prüft, ob eine Adresse bereits mit unserer Dapp verbunden ist, und unsere Benutzeroberfläche entsprechend aktualisiert!
Die getCurrentWalletConnected-Funktion
Füge in deine interact.js-Datei die folgende getCurrentWalletConnected-Funktion ein:
1export const getCurrentWalletConnected = async () => {2 if (window.ethereum) {3 try {4 const addressArray = await window.ethereum.request({5 method: "eth_accounts",6 })7 if (addressArray.length > 0) {8 return {9 address: addressArray[0],10 status: "👆🏽 Schreibe eine Nachricht in das Textfeld oben.",11 }12 } else {13 return {14 address: "",15 status: "🦊 Verbinde dich mit MetaMask über die Schaltfläche oben rechts.",16 }17 }18 } catch (err) {19 return {20 address: "",21 status: "😥 " + err.message,22 }23 }24 } else {25 return {26 address: "",27 status: (28 <span>29 <p>30 {" "}31 🦊 <a target="_blank" href={`https://metamask.io/download`}>32 Du musst MetaMask, eine virtuelle Ethereum-Wallet, in deinem33 Browser installieren.34 </a>35 </p>36 </span>37 ),38 }39 }40}Alles anzeigenDieser Code ist der connectWallet-Funktion, die wir gerade geschrieben haben, sehr ähnlich.
Der Hauptunterschied besteht darin, dass wir anstelle der Methode eth_requestAccounts, die MetaMask für den Benutzer öffnet, um seine Wallet zu verbinden, hier die Methode eth_accounts aufrufen, die einfach ein Array zurückgibt, das die MetaMask-Adressen enthält, die derzeit mit unserer Dapp verbunden sind.
Um diese Funktion in Aktion zu sehen, rufen wir sie in der useEffect-Funktion unserer Minter.js-Komponente auf.
Wie bei connectWallet müssen wir diese Funktion aus unserer interact.js-Datei in unsere Minter.js-Datei importieren, und zwar so:
1import { useEffect, useState } from "react"2import {3 connectWallet,4 getCurrentWalletConnected, //hier importieren5} from "./utils/interact.js"Jetzt rufen wir sie einfach in unserer useEffect-Funktion auf:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)5}, [])Beachte, dass wir die Antwort unseres Aufrufs an getCurrentWalletConnected verwenden, um unsere walletAddress- und status-Zustandsvariablen zu aktualisieren.
Nachdem du diesen Code hinzugefügt hast, versuche, unser Browserfenster zu aktualisieren. Die Schaltfläche sollte anzeigen, dass du verbunden bist, und eine Vorschau der Adresse deiner verbundenen Wallet anzeigen – auch nach dem Aktualisieren!
addWalletListener implementieren
Der letzte Schritt in der Einrichtung unserer Dapp-Wallet ist die Implementierung des Wallet-Listeners, damit unsere Benutzeroberfläche aktualisiert wird, wenn sich der Zustand unserer Wallet ändert, z. B. wenn der Benutzer die Verbindung trennt oder das Konto wechselt.
Füge in deine Minter.js-Datei eine Funktion addWalletListener hinzu, die wie folgt aussieht:
1function addWalletListener() {2 if (window.ethereum) {3 window.ethereum.on("accountsChanged", (accounts) => {4 if (accounts.length > 0) {5 setWallet(accounts[0])6 setStatus("👆🏽 Schreibe eine Nachricht in das Textfeld oben.")7 } else {8 setWallet("")9 setStatus("🦊 Verbinde dich mit MetaMask über die Schaltfläche oben rechts.")10 }11 })12 } else {13 setStatus(14 <p>15 {" "}16 🦊 <a target="_blank" href={`https://metamask.io/download`}>17 Du musst MetaMask, eine virtuelle Ethereum-Wallet, in deinem Browser installieren.18 </a>19 </p>20 )21 }22}Alles anzeigenLass uns kurz aufschlüsseln, was hier passiert:
- Zuerst prüft unsere Funktion, ob
window.ethereumaktiviert ist (d. h. MetaMask ist installiert).- Wenn nicht, setzen wir einfach unsere
status-Zustandsvariable auf eine JSX-Zeichenfolge, die den Benutzer auffordert, MetaMask zu installieren. - Wenn es aktiviert ist, richten wir den Listener
window.ethereum.on("accountsChanged")in Zeile 3 ein, der auf Zustandsänderungen in der MetaMask-Wallet lauscht. Dazu gehören, wenn der Benutzer ein zusätzliches Konto mit der Dapp verbindet, Konten wechselt oder ein Konto trennt. Wenn mindestens ein Konto verbunden ist, wird die ZustandsvariablewalletAddressals das erste Konto imaccounts-Array aktualisiert, das vom Listener zurückgegeben wird. Andernfalls wirdwalletAddressals leere Zeichenfolge festgelegt.
- Wenn nicht, setzen wir einfach unsere
Schließlich müssen wir sie in unserer useEffect-Funktion aufrufen:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)56 addWalletListener()7}, [])Und voilà! Wir haben die Programmierung all unserer Wallet-Funktionalitäten abgeschlossen! Nachdem unsere Wallet nun eingerichtet ist, finden wir heraus, wie wir unser NFT minten können!
NFT-Metadaten 101
Erinnerst du dich an die NFT-Metadaten, über die wir in Schritt 0 dieses Tutorials gesprochen haben? Sie erwecken einen NFT zum Leben und ermöglichen es ihm, Eigenschaften wie ein digitales Asset, einen Namen, eine Beschreibung und andere Attribute zu haben.
Wir müssen diese Metadaten als JSON-Objekt konfigurieren und speichern, damit wir sie als tokenURI-Parameter übergeben können, wenn wir die mintNFT-Funktion unseres Smart Contracts aufrufen.
Der Text in den Feldern „Link zum Asset“, „Name“, „Beschreibung“ wird die verschiedenen Eigenschaften der Metadaten unseres NFTs umfassen. Wir werden diese Metadaten als JSON-Objekt formatieren, aber es gibt ein paar Optionen, wo wir dieses JSON-Objekt speichern können:
- Wir könnten sie auf der Ethereum-Blockchain speichern, was jedoch sehr teuer wäre.
- Wir könnten sie auf einem zentralisierten Server wie AWS oder Firebase speichern. Aber das würde unserem Dezentralisierungs-Ethos widersprechen.
- Wir könnten IPFS verwenden, ein dezentralisiertes Protokoll und Peer-to-Peer-Netzwerk zum Speichern und Teilen von Daten in einem verteilten Dateisystem. Da dieses Protokoll dezentralisiert und kostenlos ist, ist es unsere beste Option!
Um unsere Metadaten auf IPFS zu speichern, verwenden wir Pinataopens in a new tab, eine praktische IPFS-API und ein Toolkit. Im nächsten Schritt erklären wir genau, wie das geht!
Pinata verwenden, um deine Metadaten auf IPFS zu pinnen
Wenn du noch kein Pinataopens in a new tab-Konto hast, registriere dich hieropens in a new tab für ein kostenloses Konto und führe die Schritte zur Verifizierung deiner E-Mail und deines Kontos durch.
Erstelle deinen Pinata-API-Schlüssel
Navigiere zur Seite https://pinata.cloud/keysopens in a new tab, wähle dann oben die Schaltfläche „New Key“ (Neuer Schlüssel), setze das Admin-Widget auf „Enabled“ (Aktiviert) und benenne deinen Schlüssel.
Dir wird dann ein Popup mit deinen API-Informationen angezeigt. Bewahre diese an einem sicheren Ort auf.
Nachdem unser Schlüssel nun eingerichtet ist, fügen wir ihn zu unserem Projekt hinzu, damit wir ihn verwenden können.
Eine .env-Datei erstellen
Wir können unseren Pinata-Schlüssel und das Geheimnis sicher in einer Umgebungsdatei speichern. Installieren wir das dotenv-Paketopens in a new tab in deinem Projektverzeichnis.
Öffne einen neuen Tab in deinem Terminal (getrennt von dem, auf dem der Localhost läuft) und stelle sicher, dass du dich im Ordner minter-starter-files befindest. Führe dann den folgenden Befehl in deinem Terminal aus:
1npm install dotenv --saveAls Nächstes erstelle eine .env-Datei im Stammverzeichnis deiner minter-starter-files, indem du Folgendes in deiner Befehlszeile eingibst:
1vim.envDadurch wird deine .env-Datei in vim (einem Texteditor) geöffnet. Um sie zu speichern, drücke „esc“ + „:“ + „q“ in dieser Reihenfolge auf deiner Tastatur.
Navigiere als Nächstes in VSCode zu deiner .env-Datei und füge deinen Pinata-API-Schlüssel und dein API-Geheimnis hinzu, und zwar so:
1REACT_APP_PINATA_KEY = <pinata-api-schlüssel>2REACT_APP_PINATA_SECRET = <pinata-api-geheimnis>Speichere die Datei, und dann kannst du damit beginnen, die Funktion zum Hochladen deiner JSON-Metadaten auf IPFS zu schreiben!
opens in a new tabpinJSONToIPFS implementieren
Glücklicherweise hat Pinata eine API speziell für das Hochladen von JSON-Daten auf IPFSopens in a new tab und ein praktisches JavaScript-Beispiel mit Axios, das wir mit leichten Änderungen verwenden können.
Erstellen wir in deinem utils-Ordner eine weitere Datei namens pinata.js und importieren dann unser Pinata-Geheimnis und den Schlüssel aus der .env-Datei wie folgt:
1require("dotenv").config()2const key = process.env.REACT_APP_PINATA_KEY3const secret = process.env.REACT_APP_PINATA_SECRETFüge als Nächstes den zusätzlichen Code von unten in deine pinata.js-Datei ein. Keine Sorge, wir werden aufschlüsseln, was alles bedeutet!
1require("dotenv").config()2const key = process.env.REACT_APP_PINATA_KEY3const secret = process.env.REACT_APP_PINATA_SECRET45const axios = require("axios")67export const pinJSONToIPFS = async (JSONBody) => {8 const url = `https://api.pinata.cloud/pinning/pinJSONToIPFS`9 //axios-POST-Anfrage an Pinata stellen ⬇️10 return axios11 .post(url, JSONBody, {12 headers: {13 pinata_api_key: key,14 pinata_secret_api_key: secret,15 },16 })17 .then(function (response) {18 return {19 success: true,20 pinataUrl:21 "https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash,22 }23 })24 .catch(function (error) {25 console.log(error)26 return {27 success: false,28 message: error.message,29 }30 })31}Alles anzeigenWas genau macht dieser Code also?
Zuerst importiert er axiosopens in a new tab, einen Promise-basierten HTTP-Client für den Browser und node.js, den wir verwenden werden, um eine Anfrage an Pinata zu stellen.
Dann haben wir unsere asynchrone Funktion pinJSONToIPFS, die einen JSONBody als Eingabe und den Pinata-API-Schlüssel und das Geheimnis in ihrem Header entgegennimmt, um eine POST-Anfrage an ihre pinJSONToIPFS-API zu stellen.
- Wenn diese POST-Anfrage erfolgreich ist, gibt unsere Funktion ein JSON-Objekt zurück, bei dem der
success-Boole’sche Wert auf „true“ gesetzt ist und diepinataUrlangibt, wo unsere Metadaten angeheftet wurden. Wir werden diese zurückgegebenepinataUrlalstokenURI-Eingabe für die Mint-Funktion unseres Smart Contracts verwenden. - Wenn diese Post-Anfrage fehlschlägt, gibt unsere Funktion ein JSON-Objekt zurück, bei dem der
success-Boole’sche Wert auf „false“ gesetzt ist und einemessage-Zeichenfolge unseren Fehler weitergibt.
Wie bei unseren connectWallet-Funktionsrückgabetypen geben wir JSON-Objekte zurück, damit wir ihre Parameter zur Aktualisierung unserer Zustandsvariablen und der Benutzeroberfläche verwenden können.
Lade deinen Smart Contract
Nachdem wir nun eine Möglichkeit haben, unsere NFT-Metadaten über unsere pinJSONToIPFS-Funktion auf IPFS hochzuladen, benötigen wir eine Möglichkeit, eine Instanz unseres Smart Contracts zu laden, damit wir seine mintNFT-Funktion aufrufen können.
Wie bereits erwähnt, werden wir in diesem Tutorial diesen bestehenden NFT-Smart-Contractopens in a new tab verwenden. Wenn du jedoch lernen möchtest, wie wir ihn erstellt haben oder selbst einen erstellen möchtest, empfehlen wir dir dringend, unser anderes Tutorial „Wie man einen NFT erstellt“opens in a new tab anzusehen.
Das Contract-ABI
Wenn du unsere Dateien genau untersucht hast, wirst du bemerkt haben, dass es in unserem src-Verzeichnis eine contract-abi.json-Datei gibt. Ein ABI ist notwendig, um anzugeben, welche Funktion ein Vertrag aufrufen wird, und um sicherzustellen, dass die Funktion Daten in dem von dir erwarteten Format zurückgibt.
Wir werden auch einen Alchemy-API-Schlüssel und die Alchemy-Web3-API benötigen, um uns mit der Ethereum-Blockchain zu verbinden und unseren Smart Contract zu laden.
Erstelle deinen Alchemy-API-Schlüssel
Wenn du noch kein Alchemy-Konto hast, registriere dich hier kostenlosopens in a new tab.
Sobald Sie ein Alchemy-Konto erstellt haben, können Sie einen API-Schlüssel generieren. Erstellen Sie dafür eine App. Dadurch können wir Anfragen an das Ropsten-Testnet stellen.
Navigiere zur Seite „App erstellen“ in deinem Alchemy-Dashboard, indem du in der Navigationsleiste über „Apps“ fährst und auf „App erstellen“ klickst.
Benenne deine App – wir haben „Mein erster NFT!“ gewählt –, gib eine kurze Beschreibung, wähle „Staging“ für die Umgebung, die für die Buchführung deiner App verwendet wird, und wähle „Ropsten“ als dein Netzwerk.
Klicken Sie auf “Create app” (App erstellen) und schon sind Sie fertig. Die App sollte in der untenstehenden Tabelle erscheinen.
Super, jetzt, da wir unsere HTTP-Alchemy-API-URL erstellt haben, kopiere sie in deine Zwischenablage ...
… und fügen wir sie zu unserer .env-Datei hinzu. Insgesamt sollte deine .env-Datei so aussehen:
1REACT_APP_PINATA_KEY = <pinata-key>2REACT_APP_PINATA_SECRET = <pinata-secret>3REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/<alchemy-key>Jetzt, da wir unser Contract-ABI und unseren Alchemy-API-Schlüssel haben, sind wir bereit, unseren Smart Contract mit Alchemy Web3opens in a new tab zu laden.
Richte deinen Alchemy-Web3-Endpunkt und deinen Vertrag ein
Wenn du es noch nicht hast, musst du zuerst Alchemy Web3opens in a new tab installieren, indem du im Terminal zum Stammverzeichnis navigierst: nft-minter-tutorial:
1cd ..2npm install @alch/alchemy-web3Als Nächstes kehren wir zu unserer interact.js-Datei zurück. Füge am Anfang der Datei den folgenden Code hinzu, um deinen Alchemy-Schlüssel aus deiner .env-Datei zu importieren und deinen Alchemy-Web3-Endpunkt einzurichten:
1require("dotenv").config()2const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY3const { createAlchemyWeb3 } = require("@alch/alchemy-web3")4const web3 = createAlchemyWeb3(alchemyKey)Alchemy Web3opens in a new tab ist ein Wrapper um Web3.jsopens in a new tab und bietet erweiterte API-Methoden und andere entscheidende Vorteile, um dir das Leben als Web3-Entwickler zu erleichtern. Es ist so konzipiert, dass es eine minimale Konfiguration erfordert, sodass du es sofort in deiner App verwenden kannst!
Als Nächstes fügen wir unser Contract-ABI und unsere Contract-Adresse zu unserer Datei hinzu.
1require("dotenv").config()2const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY3const { createAlchemyWeb3 } = require("@alch/alchemy-web3")4const web3 = createAlchemyWeb3(alchemyKey)56const contractABI = require("../contract-abi.json")7const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE"Sobald wir beides haben, sind wir bereit, unsere Mint-Funktion zu programmieren!
Die mintNFT-Funktion implementieren
Definieren wir in deiner interact.js-Datei unsere Funktion mintNFT, die gleichnamig unseren NFT minten wird.
Da wir zahlreiche asynchrone Aufrufe machen werden (an Pinata, um unsere Metadaten auf IPFS zu pinnen, an Alchemy Web3, um unseren Smart Contract zu laden, und an MetaMask, um unsere Transaktionen zu signieren), wird unsere Funktion ebenfalls asynchron sein.
Die drei Eingaben für unsere Funktion sind die url unseres digitalen Assets, der name und die description. Füge die folgende Funktionssignatur unter der connectWallet-Funktion hinzu:
1export const mintNFT = async (url, name, description) => {}Fehlerbehandlung bei der Eingabe
Natürlich ist es sinnvoll, am Anfang der Funktion eine Art Fehlerbehandlung für die Eingabe zu haben, damit wir diese Funktion beenden, wenn unsere Eingabeparameter nicht korrekt sind. Fügen wir in unserer Funktion den folgenden Code hinzu:
1export const mintNFT = async (url, name, description) => {2 //Fehlerbehandlung3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Bitte stelle sicher, dass alle Felder vor dem Minten ausgefüllt sind.",7 }8 }9}Alles anzeigenIm Wesentlichen, wenn einer der Eingabeparameter eine leere Zeichenfolge ist, geben wir ein JSON-Objekt zurück, bei dem der success-Boole'sche Wert auf „false“ gesetzt ist und die status-Zeichenfolge meldet, dass alle Felder in unserer Benutzeroberfläche vollständig sein müssen.
opens in a new tabHochladen der Metadaten auf IPFS
Sobald wir wissen, dass unsere Metadaten korrekt formatiert sind, besteht der nächste Schritt darin, sie in ein JSON-Objekt zu verpacken und über die von uns geschriebene pinJSONToIPFS-Funktion auf IPFS hochzuladen!
Dazu müssen wir zuerst die pinJSONToIPFS-Funktion in unsere interact.js-Datei importieren. Ganz oben in der interact.js fügen wir hinzu:
1import { pinJSONToIPFS } from "./pinata.js"Erinnere dich daran, dass pinJSONToIPFS einen JSON-Körper entgegennimmt. Bevor wir sie aufrufen, müssen wir also unsere url-, name- und description-Parameter in ein JSON-Objekt formatieren.
Aktualisieren wir unseren Code, um ein JSON-Objekt namens metadata zu erstellen und dann einen Aufruf an pinJSONToIPFS mit diesem metadata-Parameter zu machen:
1export const mintNFT = async (url, name, description) => {2 //Fehlerbehandlung3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Bitte stelle sicher, dass alle Felder vor dem Minten ausgefüllt sind.",7 }8 }910 //Metadaten erstellen11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //Pinata-Aufruf durchführen17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 Etwas ist beim Hochladen deiner tokenURI schiefgelaufen.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl25}Alles anzeigenBeachte, dass wir die Antwort unseres Aufrufs an pinJSONToIPFS(metadata) im pinataResponse-Objekt speichern. Dann analysieren wir dieses Objekt auf Fehler.
Wenn ein Fehler auftritt, geben wir ein JSON-Objekt zurück, bei dem der success-Boole’sche Wert auf „false“ gesetzt ist und unsere status-Zeichenfolge meldet, dass unser Aufruf fehlgeschlagen ist. Andernfalls extrahieren wir die pinataURL aus der pinataResponse und speichern sie als unsere tokenURI-Variable.
Jetzt ist es an der Zeit, unseren Smart Contract mit der Alchemy Web3-API zu laden, die wir am Anfang unserer Datei initialisiert haben. Füge die folgende Codezeile am Ende der mintNFT-Funktion hinzu, um den Vertrag auf die globale Variable window.contract zu setzen:
1window.contract = await new web3.eth.Contract(contractABI, contractAddress)Das Letzte, was wir in unserer mintNFT-Funktion hinzufügen müssen, ist unsere Ethereum-Transaktion:
1//Deine Ethereum-Transaktion einrichten2const transactionParameters = {3 to: contractAddress, // Erforderlich, außer bei Vertragsveröffentlichungen.4 from: window.ethereum.selectedAddress, // muss mit der aktiven Adresse des Benutzers übereinstimmen.5 data: window.contract.methods6 .mintNFT(window.ethereum.selectedAddress, tokenURI)7 .encodeABI(), //Aufruf des NFT-Smart-Contracts durchführen8}910//die Transaktion über MetaMask signieren11try {12 const txHash = await window.ethereum.request({13 method: "eth_sendTransaction",14 params: [transactionParameters],15 })16 return {17 success: true,18 status:19 "✅ Sieh dir deine Transaktion auf Etherscan an: https://ropsten.etherscan.io/tx/" +20 txHash,21 }22} catch (error) {23 return {24 success: false,25 status: "😥 Etwas ist schiefgelaufen: " + error.message,26 }27}Alles anzeigenWenn du bereits mit Ethereum-Transaktionen vertraut bist, wirst du feststellen, dass die Struktur ziemlich ähnlich zu dem ist, was du bereits gesehen hast.
- Zuerst richten wir unsere Transaktionsparameter ein.
togibt die Empfängeradresse an (unser Smart Contract)fromgibt den Unterzeichner der Transaktion an (die mit MetaMask verbundene Adresse des Benutzers:window.ethereum.selectedAddress)dataenthält den Aufruf unserer Smart-Contract-mintNFT-Methode, die unseretokenURIund die Wallet-Adresse des Benutzers,window.ethereum.selectedAddress, als Eingaben erhält
- Dann machen wir einen Await-Aufruf,
window.ethereum.request,, bei dem wir MetaMask bitten, die Transaktion zu signieren. Beachte, dass wir in dieser Anfrage unsere eth-Methode (eth_SentTransaction) angeben und unseretransactionParametersübergeben. An diesem Punkt öffnet sich MetaMask im Browser und fordert den Benutzer auf, die Transaktion zu signieren oder abzulehnen.- Wenn die Transaktion erfolgreich ist, gibt die Funktion ein JSON-Objekt zurück, bei dem der Boole’sche Wert
successauf „true“ gesetzt ist und diestatus-Zeichenfolge den Benutzer auffordert, Etherscan für weitere Informationen zu seiner Transaktion zu besuchen. - Wenn die Transaktion fehlschlägt, gibt die Funktion ein JSON-Objekt zurück, bei dem der
success-Boole’sche Wert auf „false“ gesetzt ist und diestatus-Zeichenfolge die Fehlermeldung weitergibt.
- Wenn die Transaktion erfolgreich ist, gibt die Funktion ein JSON-Objekt zurück, bei dem der Boole’sche Wert
Insgesamt sollte unsere mintNFT-Funktion so aussehen:
1export const mintNFT = async (url, name, description) => {2 //Fehlerbehandlung3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Bitte stelle sicher, dass alle Felder vor dem Minten ausgefüllt sind.",7 }8 }910 //Metadaten erstellen11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //Pinata-Pin-Anfrage17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 Etwas ist beim Hochladen deiner tokenURI schiefgelaufen.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl2526 //Smart Contract laden27 window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract();2829 //Deine Ethereum-Transaktion einrichten30 const transactionParameters = {31 to: contractAddress, // Erforderlich, außer bei Vertragsveröffentlichungen.32 from: window.ethereum.selectedAddress, // muss mit der aktiven Adresse des Benutzers übereinstimmen.33 data: window.contract.methods34 .mintNFT(window.ethereum.selectedAddress, tokenURI)35 .encodeABI(), //Aufruf des NFT-Smart-Contracts durchführen36 }3738 //Transaktion über MetaMask signieren39 try {40 const txHash = await window.ethereum.request({41 method: "eth_sendTransaction",42 params: [transactionParameters],43 })44 return {45 success: true,46 status:47 "✅ Sieh dir deine Transaktion auf Etherscan an: https://ropsten.etherscan.io/tx/" +48 txHash,49 }50 } catch (error) {51 return {52 success: false,53 status: "😥 Etwas ist schiefgelaufen: " + error.message,54 }55 }56}Alles anzeigenDas ist eine riesige Funktion! Jetzt müssen wir nur noch unsere mintNFT-Funktion mit unserer Minter.js-Komponente verbinden ...
Verbinde mintNFT mit unserem Minter.js-Frontend
Öffne deine Minter.js-Datei und aktualisiere die Zeile import { connectWallet, getCurrentWalletConnected } from "./utils/interact.js"; am Anfang zu:
1import {2 connectWallet,3 getCurrentWalletConnected,4 mintNFT,5} from "./utils/interact.js"Implementiere schließlich die onMintPressed-Funktion, um einen Await-Aufruf an deine importierte mintNFT-Funktion zu machen und die status-Zustandsvariable zu aktualisieren, um widerzuspiegeln, ob unsere Transaktion erfolgreich war oder fehlgeschlagen ist:
1const onMintPressed = async () => {2 const { status } = await mintNFT(url, name, description)3 setStatus(status)4}Stelle deinen NFT auf einer Live-Website bereit
Bereit, dein Projekt live zu schalten, damit Benutzer damit interagieren können? Sieh dir dieses Tutorialopens in a new tab an, um deinen Minter auf einer Live-Website bereitzustellen.
Ein letzter Schritt ...
Erobere die Blockchain-Welt im Sturm
Nur ein Scherz, du hast es bis zum Ende des Tutorials geschafft!
Zusammenfassend lässt sich sagen, dass du durch den Bau eines NFT-Minters erfolgreich gelernt hast, wie man:
- Verbinden von MetaMask mit Ihrem Frontend-Projekt
- Rufen von Smart-Contract Methoden von Ihrem Frontend
- Transaktionen mit MetaMask signieren
Vermutlich möchtest du die über deine Dapp geminteten NFTs in deiner Wallet präsentieren können – sieh dir also unbedingt unser kurzes Tutorial So zeigst du dein NFT in deiner Wallet anopens in a new tab an!
Und wie immer, wenn du Fragen hast, sind wir hier, um im Alchemy Discordopens in a new tab zu helfen. Wir können es kaum erwarten zu sehen, wie du die Konzepte aus diesem Tutorial auf deine zukünftigen Projekte anwendest!
Seite zuletzt aktualisiert: 22. Oktober 2025