Tutorial Minter NFT
Salah satu tantangan terbesar bagi pengembang yang berasal dari latar belakang Web2 adalah mencari tahu cara menghubungkan kontrak pintar Anda ke proyek frontend dan berinteraksi dengannya.
Dengan membangun minter NFT — UI sederhana di mana Anda dapat memasukkan tautan ke aset digital Anda, judul, dan deskripsi — Anda akan belajar cara:
- Terhubung ke MetaMask melalui proyek frontend Anda
- Memanggil metode kontrak pintar dari frontend Anda
- Menandatangani transaksi menggunakan MetaMask
Dalam tutorial ini, kita akan menggunakan React (opens in a new tab) sebagai kerangka kerja frontend kita. Karena tutorial ini terutama difokuskan pada pengembangan Web3, kita tidak akan menghabiskan banyak waktu untuk menguraikan dasar-dasar React. Sebaliknya, kita akan fokus pada membawa fungsionalitas ke proyek kita.
Sebagai prasyarat, Anda harus memiliki pemahaman tingkat pemula tentang React—mengetahui cara kerja komponen, props, useState/useEffect, dan pemanggilan fungsi dasar. Jika Anda belum pernah mendengar istilah-istilah tersebut sebelumnya, Anda mungkin ingin memeriksa Tutorial Pengantar React (opens in a new tab) ini. Untuk pembelajar yang lebih visual, kami sangat merekomendasikan seri video Tutorial React Modern Lengkap (opens in a new tab) yang sangat bagus ini oleh Net Ninja.
Dan jika Anda belum melakukannya, Anda pasti akan membutuhkan akun Alchemy untuk menyelesaikan tutorial ini serta membangun apa pun di blockchain. Daftar untuk akun gratis di sini (opens in a new tab).
Tanpa basa-basi lagi, mari kita mulai!
Dasar-dasar Membuat NFT
Sebelum kita mulai melihat kode apa pun, penting untuk memahami cara kerja pembuatan NFT. Ini melibatkan dua langkah:
Menerbitkan kontrak pintar NFT di blockchain Ethereum
Perbedaan terbesar antara kedua standar kontrak pintar NFT adalah bahwa ERC-1155 merupakan standar multi-token dan mencakup fungsionalitas batch, sedangkan ERC-721 adalah standar token tunggal dan oleh karena itu hanya mendukung transfer satu token pada satu waktu.
Memanggil fungsi minting
Biasanya, fungsi minting ini mengharuskan Anda untuk meneruskan dua variabel sebagai parameter, pertama recipient, yang menentukan alamat yang akan menerima NFT yang baru saja Anda mint, dan kedua tokenURI NFT, sebuah string yang mengarah ke dokumen JSON yang mendeskripsikan metadata NFT.
Metadata NFT adalah hal yang benar-benar menghidupkannya, memungkinkannya memiliki properti, seperti nama, deskripsi, gambar (atau aset digital yang berbeda), dan atribut lainnya. Berikut adalah contoh tokenURI (opens in a new tab), yang berisi metadata NFT.
Dalam tutorial ini, kita akan fokus pada bagian 2, memanggil fungsi minting kontrak pintar NFT yang sudah ada menggunakan UI React kita.
Berikut adalah tautan (opens in a new tab) ke kontrak pintar NFT ERC-721 yang akan kita panggil dalam tutorial ini. Jika Anda ingin mempelajari cara kami membuatnya, kami sangat menyarankan Anda untuk memeriksa tutorial kami yang lain, "Cara Membuat NFT" (opens in a new tab).
Keren, sekarang setelah kita memahami cara kerja pembuatan NFT, mari kita kloning file awal kita!
Kloning file awal
Pertama, buka repositori GitHub nft-minter-tutorial (opens in a new tab) untuk mendapatkan file awal untuk proyek ini. Kloning repositori ini ke lingkungan lokal Anda.
Saat Anda membuka repositori nft-minter-tutorial yang dikloning ini, Anda akan melihat bahwa repositori ini berisi dua folder: minter-starter-files dan nft-minter.
minter-starter-filesberisi file awal (pada dasarnya UI React) untuk proyek ini. Dalam tutorial ini, kita akan bekerja di direktori ini, saat Anda belajar cara menghidupkan UI ini dengan menghubungkannya ke dompet Ethereum Anda dan kontrak pintar NFT.nft-minterberisi seluruh tutorial yang telah selesai dan ada untuk Anda sebagai referensi jika Anda mengalami kebuntuan.
Selanjutnya, buka salinan minter-starter-files Anda di editor kode Anda, lalu navigasikan ke folder src Anda.
Semua kode yang akan kita tulis akan berada di bawah folder src. Kita akan mengedit komponen Minter.js dan menulis file javascript tambahan untuk memberikan fungsionalitas Web3 pada proyek kita.
Langkah 2: Periksa file awal kita
Sebelum kita mulai membuat kode, penting untuk memeriksa apa yang sudah disediakan untuk kita di file awal.
Jalankan proyek react Anda
Mari kita mulai dengan menjalankan proyek React di browser kita. Keindahan React adalah setelah proyek kita berjalan di browser, setiap perubahan yang kita simpan akan diperbarui secara langsung di browser kita.
Untuk menjalankan proyek, navigasikan ke direktori root dari folder minter-starter-files, dan jalankan npm install di terminal Anda untuk menginstal dependensi proyek:
cd minter-starter-filesnpm installSetelah selesai menginstal, jalankan npm start di terminal Anda:
npm startMelakukan hal itu akan membuka http://localhost:3000/ (opens in a new tab) di browser Anda, di mana Anda akan melihat frontend untuk proyek kita. Ini harus terdiri dari 3 bidang: tempat untuk memasukkan tautan ke aset NFT Anda, memasukkan nama NFT Anda, dan memberikan deskripsi.
Jika Anda mencoba mengklik tombol "Connect Wallet" atau "Mint NFT", Anda akan melihat bahwa tombol tersebut tidak berfungsi—itu karena kita masih perlu memprogram fungsionalitasnya! :)
Komponen Minter.js
CATATAN: Pastikan Anda berada di folder minter-starter-files dan bukan di folder nft-minter!
Mari kembali ke folder src di editor kita dan buka file Minter.js. Sangat penting bagi kita untuk memahami semua yang ada di file ini, karena ini adalah komponen React utama yang akan kita kerjakan.
Di bagian atas file ini, kita memiliki variabel status yang akan kita perbarui setelah peristiwa tertentu.
1//State variables // Variabel state2const [walletAddress, setWallet] = useState("")3const [status, setStatus] = useState("")4const [name, setName] = useState("")5const [description, setDescription] = useState("")6const [url, setURL] = useState("")Belum pernah mendengar tentang variabel status React atau hook status? Periksa dokumentasi ini (opens in a new tab).
Berikut adalah apa yang diwakili oleh masing-masing variabel:
walletAddress- sebuah string yang menyimpan alamat dompet penggunastatus- sebuah string yang berisi pesan untuk ditampilkan di bagian bawah UIname- sebuah string yang menyimpan nama NFTdescription- sebuah string yang menyimpan deskripsi NFTurl- sebuah string yang merupakan tautan ke aset digital NFT
Setelah variabel status, Anda akan melihat tiga fungsi yang belum diimplementasikan: useEffect, connectWalletPressed, dan onMintPressed. Anda akan melihat bahwa semua fungsi ini adalah async, itu karena kita akan melakukan panggilan API asinkron di dalamnya! Nama-nama mereka sesuai dengan fungsionalitasnya:
1useEffect(async () => {2 //TODO: implement // TODO: implementasikan3}, [])45const connectWalletPressed = async () => {6 //TODO: implement // TODO: implementasikan7}89const onMintPressed = async () => {10 //TODO: implement // TODO: implementasikan11}Tampilkan semuauseEffect(opens in a new tab) - ini adalah hook React yang dipanggil setelah komponen Anda dirender. Karena ia memiliki prop array kosong[]yang diteruskan ke dalamnya (lihat baris 3), ia hanya akan dipanggil pada render pertama komponen. Di sini kita akan memanggil pendengar dompet kita dan fungsi dompet lainnya untuk memperbarui UI kita guna mencerminkan apakah dompet sudah terhubung.connectWalletPressed- fungsi ini akan dipanggil untuk menghubungkan dompet MetaMask pengguna ke dapp kita.onMintPressed- fungsi ini akan dipanggil untuk melakukan mint NFT pengguna.
Di dekat akhir file ini, kita memiliki UI dari komponen kita. Jika Anda memindai kode ini dengan cermat, Anda akan melihat bahwa kita memperbarui variabel status url, name, dan description kita ketika input di bidang teks yang sesuai berubah.
Anda juga akan melihat bahwa connectWalletPressed dan onMintPressed dipanggil ketika tombol dengan ID mintButton dan walletButton masing-masing diklik.
1//the UI of our component // UI dari komponen kita2return (3 <div className="Minter">4 <button id="walletButton" onClick={connectWalletPressed}>5 {walletAddress.length > 0 ? (6 "Connected: " +7 String(walletAddress).substring(0, 6) +8 "..." +9 String(walletAddress).substring(38)10 ) : (11 <span>Connect Wallet</span>12 )}13 </button>1415 <br></br>16 <h1 id="title">🧙♂️ Alchemy NFT Minter</h1>17 <p>18 Simply add your asset's link, name, and description, then press "Mint."19 </p>20 <form>21 <h2>🖼 Link to asset: </h2>22 <input23 type="text"24 placeholder="e.g., https://gateway.pinata.cloud/ipfs/<hash>"25 onChange={(event) => setURL(event.target.value)}26 />27 <h2>🤔 Name: </h2>28 <input29 type="text"30 placeholder="e.g., My first NFT!"31 onChange={(event) => setName(event.target.value)}32 />33 <h2>✍️ Description: </h2>34 <input35 type="text"36 placeholder="e.g., Even cooler than cryptokitties ;)"37 onChange={(event) => setDescription(event.target.value)}38 />39 </form>40 <button id="mintButton" onClick={onMintPressed}>41 Mint NFT42 </button>43 <p id="status">{status}</p>44</div>45)Tampilkan semuaTerakhir, mari kita bahas di mana komponen Minter ini ditambahkan.
Jika Anda pergi ke file App.js, yang merupakan komponen utama di React yang bertindak sebagai wadah untuk semua komponen lainnya, Anda akan melihat bahwa komponen Minter kita disuntikkan pada baris 7.
Dalam tutorial ini, kita hanya akan mengedit file Minter.js dan menambahkan file di folder src kita.
Sekarang setelah kita memahami apa yang sedang kita kerjakan, mari kita siapkan dompet Ethereum kita!
Siapkan dompet Ethereum Anda
Agar pengguna dapat berinteraksi dengan kontrak pintar Anda, mereka perlu menghubungkan dompet Ethereum mereka ke dapp Anda.
Unduh MetaMask
Untuk tutorial ini, kita akan menggunakan MetaMask, dompet virtual di browser yang digunakan untuk mengelola alamat akun Ethereum Anda. Jika Anda ingin memahami lebih lanjut tentang cara kerja transaksi di Ethereum, periksa halaman ini.
Anda dapat mengunduh dan membuat akun MetaMask secara gratis di sini (opens in a new tab). Saat Anda membuat akun, atau jika Anda sudah memiliki akun, pastikan untuk beralih ke “Ropsten Test Network” di kanan atas (sehingga kita tidak berurusan dengan uang sungguhan).
Tambahkan ether dari Faucet
Untuk melakukan mint NFT kita (atau menandatangani transaksi apa pun di blockchain Ethereum), kita akan membutuhkan beberapa Eth palsu. Untuk mendapatkan Eth, Anda dapat pergi ke faucet Ropsten (opens in a new tab) dan memasukkan alamat akun Ropsten Anda, lalu klik “Send Ropsten Eth.” Anda akan melihat Eth di akun MetaMask Anda segera setelahnya!
Periksa saldo Anda
Untuk memeriksa kembali apakah saldo kita ada di sana, mari kita buat permintaan eth_getBalance (opens in a new tab) menggunakan alat komposer Alchemy (opens in a new tab). Ini akan mengembalikan jumlah Eth di dompet kita. Setelah Anda memasukkan alamat akun MetaMask Anda dan mengklik “Send Request”, Anda akan melihat respons seperti ini:
1{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}CATATAN: Hasil ini dalam wei, bukan eth. Wei digunakan sebagai denominasi terkecil dari ether. Konversi dari wei ke eth adalah: 1 eth = 10¹⁸ wei. Jadi jika kita mengonversi 0xde0b6b3a7640000 ke desimal, kita mendapatkan 1*10¹⁸ yang sama dengan 1 eth.
Fiuh! Uang palsu kita semuanya ada di sana!
Hubungkan MetaMask ke UI Anda
Sekarang setelah dompet MetaMask kita disiapkan, mari kita hubungkan dapp kita ke sana!
Karena kita ingin mengikuti paradigma MVC (opens in a new tab), kita akan membuat file terpisah yang berisi fungsi kita untuk mengelola logika, data, dan aturan dapp kita, lalu meneruskan fungsi tersebut ke frontend kita (komponen Minter.js kita).
Fungsi connectWallet
Untuk melakukannya, mari kita buat folder baru bernama utils di direktori src Anda dan tambahkan file bernama interact.js di dalamnya, yang akan berisi semua fungsi interaksi dompet dan kontrak pintar kita.
Di file interact.js kita, kita akan menulis fungsi connectWallet, yang kemudian akan kita impor dan panggil di komponen Minter.js kita.
Di file interact.js Anda, tambahkan yang berikut ini
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: "👆🏽 Write a message in the text-field above.",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 You must install MetaMask, a virtual Ethereum wallet, in your27 browser.28 </a>29 </p>30 </span>31 ),32 }33 }34}Tampilkan semuaMari kita uraikan apa yang dilakukan kode ini:
Pertama, fungsi kita memeriksa apakah window.ethereum diaktifkan di browser Anda.
window.ethereum adalah API global yang disuntikkan oleh MetaMask dan penyedia dompet lainnya yang memungkinkan situs web untuk meminta akun Ethereum pengguna. Jika disetujui, ia dapat membaca data dari blockchain yang terhubung dengan pengguna, dan menyarankan agar pengguna menandatangani pesan dan transaksi. Periksa dokumentasi MetaMask (opens in a new tab) untuk info lebih lanjut!
Jika window.ethereum tidak ada, maka itu berarti MetaMask tidak diinstal. Ini menghasilkan objek JSON yang dikembalikan, di mana address yang dikembalikan adalah string kosong, dan objek JSX status menyampaikan bahwa pengguna harus menginstal MetaMask.
Sebagian besar fungsi yang kita tulis akan mengembalikan objek JSON yang dapat kita gunakan untuk memperbarui variabel status dan UI kita.
Sekarang jika window.ethereum ada, maka di situlah hal-hal menjadi menarik.
Menggunakan loop try/catch, kita akan mencoba terhubung ke MetaMask dengan memanggil window.ethereum.request({ method: "eth_requestAccounts" }); (opens in a new tab). Memanggil fungsi ini akan membuka MetaMask di browser, di mana pengguna akan diminta untuk menghubungkan dompet mereka ke dapp Anda.
- Jika pengguna memilih untuk terhubung,
method: "eth_requestAccounts"akan mengembalikan array yang berisi semua alamat akun pengguna yang terhubung ke dapp. Secara keseluruhan, fungsiconnectWalletkita akan mengembalikan objek JSON yang berisiaddresspertama dalam array ini (lihat baris 9) dan pesanstatusyang meminta pengguna untuk menulis pesan ke kontrak pintar. - Jika pengguna menolak koneksi, maka objek JSON akan berisi string kosong untuk
addressyang dikembalikan dan pesanstatusyang mencerminkan bahwa pengguna menolak koneksi.
Tambahkan fungsi connectWallet ke Komponen UI Minter.js Anda
Sekarang setelah kita menulis fungsi connectWallet ini, mari kita hubungkan ke komponen Minter.js. kita.
Pertama, kita harus mengimpor fungsi kita ke dalam file Minter.js kita dengan menambahkan import { connectWallet } from "./utils/interact.js"; ke bagian atas file Minter.js. 11 baris pertama Minter.js Anda sekarang akan terlihat seperti ini:
1import { useEffect, useState } from "react";2import { connectWallet } from "./utils/interact.js";34const Minter = (props) => {56 //State variables // Variabel state7 const [walletAddress, setWallet] = useState("");8 const [status, setStatus] = useState("");9 const [name, setName] = useState("");10 const [description, setDescription] = useState("");11 const [url, setURL] = useState("");Tampilkan semuaKemudian, di dalam fungsi connectWalletPressed kita, kita akan memanggil fungsi connectWallet yang diimpor, seperti ini:
1const connectWalletPressed = async () => {2 const walletResponse = await connectWallet()3 setStatus(walletResponse.status)4 setWallet(walletResponse.address)5}Perhatikan bagaimana sebagian besar fungsionalitas kita diabstraksikan dari komponen Minter.js kita dari file interact.js? Ini agar kita mematuhi paradigma M-V-C!
Di connectWalletPressed, kita cukup melakukan panggilan await ke fungsi connectWallet yang diimpor, dan menggunakan responsnya, kita memperbarui variabel status dan walletAddress kita melalui hook status mereka.
Sekarang, mari kita simpan kedua file Minter.js dan interact.js dan uji UI kita sejauh ini.
Buka browser Anda di localhost:3000, dan tekan tombol "Connect Wallet" di kanan atas halaman.
Jika Anda telah menginstal MetaMask, Anda akan diminta untuk menghubungkan dompet Anda ke dapp Anda. Terima undangan untuk terhubung.
Anda akan melihat bahwa tombol dompet sekarang mencerminkan bahwa alamat Anda terhubung.
Selanjutnya, coba segarkan halaman... ini aneh. Tombol dompet kita meminta kita untuk menghubungkan MetaMask, meskipun sudah terhubung...
Namun jangan khawatir! Kita dapat dengan mudah memperbaikinya dengan mengimplementasikan fungsi yang disebut getCurrentWalletConnected, yang akan memeriksa apakah sebuah alamat sudah terhubung ke dapp kita dan memperbarui UI kita sesuai dengan itu!
Fungsi getCurrentWalletConnected
Di file interact.js Anda, tambahkan fungsi getCurrentWalletConnected berikut:
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: "👆🏽 Write a message in the text-field above.",11 }12 } else {13 return {14 address: "",15 status: "🦊 Connect to MetaMask using the top right button.",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 You must install MetaMask, a virtual Ethereum wallet, in your33 browser.34 </a>35 </p>36 </span>37 ),38 }39 }40}Tampilkan semuaKode ini sangat mirip dengan fungsi connectWallet yang baru saja kita tulis sebelumnya.
Perbedaan utamanya adalah alih-alih memanggil metode eth_requestAccounts, yang membuka MetaMask bagi pengguna untuk menghubungkan dompet mereka, di sini kita memanggil metode eth_accounts, yang hanya mengembalikan array yang berisi alamat MetaMask yang saat ini terhubung ke dapp kita.
Untuk melihat fungsi ini beraksi, mari kita panggil di fungsi useEffect dari komponen Minter.js kita.
Seperti yang kita lakukan untuk connectWallet, kita harus mengimpor fungsi ini dari file interact.js kita ke dalam file Minter.js kita seperti ini:
1import { useEffect, useState } from "react"2import {3 connectWallet,4 getCurrentWalletConnected, //import here // impor di sini5} from "./utils/interact.js"Sekarang, kita cukup memanggilnya di fungsi useEffect kita:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)5}, [])Perhatikan, kita menggunakan respons dari panggilan kita ke getCurrentWalletConnected untuk memperbarui variabel status walletAddress dan status kita.
Setelah Anda menambahkan kode ini, coba segarkan jendela browser kita. Tombol tersebut harus mengatakan bahwa Anda terhubung, dan menampilkan pratinjau alamat dompet Anda yang terhubung - bahkan setelah Anda menyegarkan!
Implementasikan addWalletListener
Langkah terakhir dalam penyiapan dompet dapp kita adalah mengimplementasikan pendengar dompet sehingga UI kita diperbarui ketika status dompet kita berubah, seperti ketika pengguna memutuskan sambungan atau beralih akun.
Di file Minter.js Anda, tambahkan fungsi addWalletListener yang terlihat seperti berikut:
1function addWalletListener() {2 if (window.ethereum) {3 window.ethereum.on("accountsChanged", (accounts) => {4 if (accounts.length > 0) {5 setWallet(accounts[0])6 setStatus("👆🏽 Write a message in the text-field above.")7 } else {8 setWallet("")9 setStatus("🦊 Connect to MetaMask using the top right button.")10 }11 })12 } else {13 setStatus(14 <p>15 {" "}16 🦊 <a target="_blank" href={`https://metamask.io/download`}>17 You must install MetaMask, a virtual Ethereum wallet, in your browser.18 </a>19 </p>20 )21 }22}Tampilkan semuaMari kita uraikan dengan cepat apa yang terjadi di sini:
- Pertama, fungsi kita memeriksa apakah
window.ethereumdiaktifkan (yaitu, MetaMask diinstal).- Jika tidak, kita cukup mengatur variabel status
statuskita ke string JSX yang meminta pengguna untuk menginstal MetaMask. - Jika diaktifkan, kita menyiapkan pendengar
window.ethereum.on("accountsChanged")pada baris 3 yang mendengarkan perubahan status di dompet MetaMask, yang mencakup saat pengguna menghubungkan akun tambahan ke dapp, beralih akun, atau memutuskan sambungan akun. Jika ada setidaknya satu akun yang terhubung, variabel statuswalletAddressdiperbarui sebagai akun pertama dalam arrayaccountsyang dikembalikan oleh pendengar. Jika tidak,walletAddressdiatur sebagai string kosong.
- Jika tidak, kita cukup mengatur variabel status
Terakhir, kita harus memanggilnya di fungsi useEffect kita:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)56 addWalletListener()7}, [])Dan voila! Kita telah selesai memprogram semua fungsionalitas dompet kita! Sekarang setelah dompet kita disiapkan, mari kita cari tahu cara melakukan mint NFT kita!
Dasar-dasar Metadata NFT
Jadi ingat metadata NFT yang baru saja kita bicarakan di Langkah 0 dari tutorial ini—itu menghidupkan NFT, memungkinkannya memiliki properti, seperti aset digital, nama, deskripsi, dan atribut lainnya.
Kita perlu mengonfigurasi metadata ini sebagai objek JSON dan menyimpannya, sehingga kita dapat meneruskannya sebagai parameter tokenURI saat memanggil fungsi mintNFT kontrak pintar kita.
Teks di bidang "Link to Asset", "Name", "Description" akan terdiri dari berbagai properti metadata NFT kita. Kita akan memformat metadata ini sebagai objek JSON, tetapi ada beberapa opsi untuk tempat kita dapat menyimpan objek JSON ini:
- Kita bisa menyimpannya di blockchain Ethereum; namun, melakukan hal itu akan sangat mahal.
- Kita bisa menyimpannya di server terpusat, seperti AWS atau Firebase. Tapi itu akan mengalahkan etos desentralisasi kita.
- Kita bisa menggunakan IPFS, protokol desentralisasi dan jaringan peer-to-peer untuk menyimpan dan berbagi data dalam sistem file terdistribusi. Karena protokol ini terdesentralisasi dan gratis, ini adalah opsi terbaik kita!
Untuk menyimpan metadata kita di IPFS, kita akan menggunakan Pinata (opens in a new tab), API dan toolkit IPFS yang nyaman. Pada langkah berikutnya, kita akan menjelaskan dengan tepat cara melakukan ini!
Gunakan Pinata untuk menyematkan metadata Anda ke IPFS
Jika Anda tidak memiliki akun Pinata (opens in a new tab), daftar untuk akun gratis di sini (opens in a new tab) dan selesaikan langkah-langkah untuk memverifikasi email dan akun Anda.
Buat kunci API Pinata Anda
Navigasikan ke halaman https://pinata.cloud/keys (opens in a new tab), lalu pilih tombol "New Key" di bagian atas, atur widget Admin sebagai diaktifkan, dan beri nama kunci Anda.
Anda kemudian akan diperlihatkan popup dengan info API Anda. Pastikan untuk meletakkannya di tempat yang aman.
Sekarang setelah kunci kita disiapkan, mari kita tambahkan ke proyek kita sehingga kita dapat menggunakannya.
Buat file .env
Kita dapat dengan aman menyimpan kunci dan rahasia Pinata kita dalam file lingkungan. Mari kita instal paket dotenv (opens in a new tab) di direktori proyek Anda.
Buka tab baru di terminal Anda (terpisah dari yang menjalankan host lokal) dan pastikan Anda berada di folder minter-starter-files, lalu jalankan perintah berikut di terminal Anda:
1npm install dotenv --saveSelanjutnya, buat file .env di direktori root dari minter-starter-files Anda dengan memasukkan yang berikut ini di baris perintah Anda:
1vim.envIni akan membuka file .env Anda di vim (editor teks). Untuk menyimpannya tekan "esc" + ":" + "q" pada keyboard Anda dalam urutan itu.
Selanjutnya, di VSCode, navigasikan ke file .env Anda dan tambahkan kunci API Pinata dan rahasia API Anda ke dalamnya, seperti ini:
1REACT_APP_PINATA_KEY = <pinata-api-key>2REACT_APP_PINATA_SECRET = <pinata-api-secret>Simpan file, dan kemudian Anda siap untuk mulai menulis fungsi untuk mengunggah metadata JSON Anda ke IPFS!
Implementasikan pinJSONToIPFS
Untungnya bagi kita, Pinata memiliki API khusus untuk mengunggah data JSON ke IPFS (opens in a new tab) dan contoh JavaScript dengan axios yang nyaman yang dapat kita gunakan, dengan beberapa modifikasi kecil.
Di folder utils Anda, mari kita buat file lain bernama pinata.js dan kemudian impor rahasia dan kunci Pinata kita dari file .env seperti ini:
1require("dotenv").config()2const key = process.env.REACT_APP_PINATA_KEY3const secret = process.env.REACT_APP_PINATA_SECRETSelanjutnya, tempelkan kode tambahan dari bawah ke dalam file pinata.js Anda. Jangan khawatir, kita akan menguraikan apa arti semuanya!
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 //making axios POST request to Pinata ⬇️ // membuat permintaan POST axios ke Pinata ⬇️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}Tampilkan semuaJadi apa sebenarnya yang dilakukan kode ini?
Pertama, ia mengimpor axios (opens in a new tab), klien HTTP berbasis promise untuk browser dan node.js, yang akan kita gunakan untuk membuat permintaan ke Pinata.
Kemudian kita memiliki fungsi asinkron kita pinJSONToIPFS, yang mengambil JSONBody sebagai inputnya dan kunci api serta rahasia Pinata di headernya, semuanya untuk membuat permintaan POST ke API pinJSONToIPFS mereka.
- Jika permintaan POST ini berhasil, maka fungsi kita mengembalikan objek JSON dengan boolean
successsebagai true danpinataUrltempat metadata kita disematkan. Kita akan menggunakanpinataUrlyang dikembalikan ini sebagai inputtokenURIke fungsi mint kontrak pintar kita. - Jika permintaan post ini gagal, maka fungsi kita mengembalikan objek JSON dengan boolean
successsebagai false dan stringmessageyang menyampaikan kesalahan kita.
Sama seperti tipe pengembalian fungsi connectWallet kita, kita mengembalikan objek JSON sehingga kita dapat menggunakan parameternya untuk memperbarui variabel status dan UI kita.
Muat kontrak pintar Anda
Sekarang setelah kita memiliki cara untuk mengunggah metadata NFT kita ke IPFS melalui fungsi pinJSONToIPFS kita, kita akan membutuhkan cara untuk memuat instance kontrak pintar kita sehingga kita dapat memanggil fungsi mintNFT-nya.
Seperti yang kami sebutkan sebelumnya, dalam tutorial ini kita akan menggunakan kontrak pintar NFT yang sudah ada ini (opens in a new tab); namun, jika Anda ingin mempelajari cara kami membuatnya, atau membuatnya sendiri, kami sangat menyarankan Anda untuk memeriksa tutorial kami yang lain, "Cara Membuat NFT." (opens in a new tab).
ABI kontrak
Jika Anda memeriksa file kami dengan cermat, Anda akan melihat bahwa di direktori src kita, ada file contract-abi.json. ABI diperlukan untuk menentukan fungsi mana yang akan dipanggil oleh kontrak serta memastikan bahwa fungsi tersebut akan mengembalikan data dalam format yang Anda harapkan.
Kita juga akan membutuhkan kunci API Alchemy dan API Web3 Alchemy untuk terhubung ke blockchain Ethereum dan memuat kontrak pintar kita.
Buat kunci API Alchemy Anda
Jika Anda belum memiliki akun Alchemy, daftar gratis di sini. (opens in a new tab)
Setelah Anda membuat akun Alchemy, Anda dapat menghasilkan kunci API dengan membuat aplikasi. Ini akan memungkinkan kita untuk membuat permintaan ke testnet Ropsten.
Navigasikan ke halaman “Create App” di Dasbor Alchemy Anda dengan mengarahkan kursor ke “Apps” di bilah navigasi dan mengklik “Create App”.
Beri nama aplikasi Anda, kami memilih "My First NFT!", tawarkan deskripsi singkat, pilih “Staging” untuk Lingkungan yang digunakan untuk pembukuan aplikasi Anda, dan pilih “Ropsten” untuk jaringan Anda.
Klik “Create app” dan selesai! Aplikasi Anda akan muncul di tabel di bawah ini.
Luar biasa, jadi sekarang setelah kita membuat URL API Alchemy HTTP kita, salin ke papan klip Anda...
…dan kemudian mari kita tambahkan ke file .env kita. Secara keseluruhan, file .env Anda akan terlihat seperti ini:
1REACT_APP_PINATA_KEY = <pinata-key>2REACT_APP_PINATA_SECRET = <pinata-secret>3REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/<alchemy-key> // eth-ropsten.alchemyapi.io/v2/<alchemy-key>Sekarang setelah kita memiliki ABI kontrak kita dan kunci API Alchemy kita, kita siap untuk memuat kontrak pintar kita menggunakan Alchemy Web3 (opens in a new tab).
Siapkan titik akhir dan kontrak Alchemy Web3 Anda
Pertama, jika Anda belum memilikinya, Anda perlu menginstal Alchemy Web3 (opens in a new tab) dengan menavigasi ke direktori beranda: nft-minter-tutorial di terminal:
1cd ..2npm install @alch/alchemy-web3Selanjutnya mari kembali ke file interact.js kita. Di bagian atas file, tambahkan kode berikut untuk mengimpor kunci Alchemy Anda dari file .env Anda dan menyiapkan titik akhir Alchemy Web3 Anda:
1require("dotenv").config()2const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY3const { createAlchemyWeb3 } = require("@alch/alchemy-web3")4const web3 = createAlchemyWeb3(alchemyKey)Alchemy Web3 (opens in a new tab) adalah pembungkus di sekitar Web3.js (opens in a new tab), menyediakan metode API yang ditingkatkan dan manfaat penting lainnya untuk membuat hidup Anda sebagai pengembang web3 lebih mudah. Ini dirancang untuk membutuhkan konfigurasi minimal sehingga Anda dapat mulai menggunakannya di aplikasi Anda segera!
Selanjutnya, mari kita tambahkan ABI kontrak dan alamat kontrak kita ke file kita.
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"Setelah kita memiliki keduanya, kita siap untuk mulai membuat kode fungsi mint kita!
Implementasikan fungsi mintNFT
Di dalam file interact.js Anda, mari kita definisikan fungsi kita, mintNFT, yang sesuai namanya akan melakukan mint NFT kita.
Karena kita akan melakukan banyak panggilan asinkron (ke Pinata untuk menyematkan metadata kita ke IPFS, Alchemy Web3 untuk memuat kontrak pintar kita, dan MetaMask untuk menandatangani transaksi kita), fungsi kita juga akan asinkron.
Tiga input ke fungsi kita adalah url dari aset digital kita, name, dan description. Tambahkan tanda tangan fungsi berikut di bawah fungsi connectWallet:
1export const mintNFT = async (url, name, description) => {}Penanganan kesalahan input
Tentu saja, masuk akal untuk memiliki semacam penanganan kesalahan input di awal fungsi, jadi kita keluar dari fungsi ini jika parameter input kita tidak benar. Di dalam fungsi kita, mari kita tambahkan kode berikut:
1export const mintNFT = async (url, name, description) => {2 //error handling // penanganan kesalahan3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Please make sure all fields are completed before minting.",7 }8 }9}Tampilkan semuaPada dasarnya, jika salah satu parameter input adalah string kosong, maka kita mengembalikan objek JSON di mana boolean success adalah false, dan string status menyampaikan bahwa semua bidang di UI kita harus lengkap.
Unggah metadata ke IPFS
Setelah kita tahu metadata kita diformat dengan benar, langkah selanjutnya adalah membungkusnya ke dalam objek JSON dan mengunggahnya ke IPFS melalui pinJSONToIPFS yang kita tulis!
Untuk melakukannya, pertama-tama kita perlu mengimpor fungsi pinJSONToIPFS ke dalam file interact.js kita. Di bagian paling atas interact.js, mari kita tambahkan:
1import { pinJSONToIPFS } from "./pinata.js"Ingat bahwa pinJSONToIPFS mengambil badan JSON. Jadi sebelum kita memanggilnya, kita perlu memformat parameter url, name, dan description kita ke dalam objek JSON.
Mari kita perbarui kode kita untuk membuat objek JSON yang disebut metadata dan kemudian melakukan panggilan ke pinJSONToIPFS dengan parameter metadata ini:
1export const mintNFT = async (url, name, description) => {2 //error handling // penanganan kesalahan3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Please make sure all fields are completed before minting.",7 }8 }910 //make metadata // buat metadata11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //make pinata call // buat panggilan pinata17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 Something went wrong while uploading your tokenURI.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl25}Tampilkan semuaPerhatikan, kita menyimpan respons dari panggilan kita ke pinJSONToIPFS(metadata) di objek pinataResponse. Kemudian, kita mengurai objek ini untuk mencari kesalahan apa pun.
Jika ada kesalahan, kita mengembalikan objek JSON di mana boolean success adalah false dan string status kita menyampaikan bahwa panggilan kita gagal. Jika tidak, kita mengekstrak pinataURL dari pinataResponse dan menyimpannya sebagai variabel tokenURI kita.
Sekarang saatnya untuk memuat kontrak pintar kita menggunakan API Web3 Alchemy yang kita inisialisasi di bagian atas file kita. Tambahkan baris kode berikut ke bagian bawah fungsi mintNFT untuk mengatur kontrak pada variabel global window.contract:
1window.contract = await new web3.eth.Contract(contractABI, contractAddress)Hal terakhir yang ditambahkan dalam fungsi mintNFT kita adalah transaksi Ethereum kita:
1//set up your Ethereum transaction // siapkan transaksi Ethereum Anda2const transactionParameters = {3 to: contractAddress, // Required except during contract publications. // Diperlukan kecuali selama publikasi kontrak.4 from: window.ethereum.selectedAddress, // must match user's active address. // harus cocok dengan alamat aktif pengguna.5 data: window.contract.methods6 .mintNFT(window.ethereum.selectedAddress, tokenURI)7 .encodeABI(), //make call to NFT smart contract // buat panggilan ke smart contract NFT8}910//sign the transaction via MetaMask // tandatangani transaksi melalui MetaMask11try {12 const txHash = await window.ethereum.request({13 method: "eth_sendTransaction",14 params: [transactionParameters],15 })16 return {17 success: true,18 status:19 "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +20 txHash,21 }22} catch (error) {23 return {24 success: false,25 status: "😥 Something went wrong: " + error.message,26 }27}Tampilkan semuaJika Anda sudah terbiasa dengan transaksi Ethereum, Anda akan melihat bahwa strukturnya cukup mirip dengan apa yang pernah Anda lihat.
- Pertama, kita menyiapkan parameter transaksi kita.
tomenentukan alamat penerima (kontrak pintar kita)frommenentukan penandatangan transaksi (alamat pengguna yang terhubung ke MetaMask:window.ethereum.selectedAddress)databerisi panggilan ke metodemintNFTkontrak pintar kita, yang menerimatokenURIkita dan alamat dompet pengguna,window.ethereum.selectedAddress, sebagai input
- Kemudian, kita melakukan panggilan await,
window.ethereum.request,di mana kita meminta MetaMask untuk menandatangani transaksi. Perhatikan, dalam permintaan ini, kita menentukan metode eth kita (eth_SentTransaction) dan meneruskantransactionParameterskita. Pada titik ini, MetaMask akan terbuka di browser, dan meminta pengguna untuk menandatangani atau menolak transaksi.- Jika transaksi berhasil, fungsi akan mengembalikan objek JSON di mana boolean
successdiatur ke true dan stringstatusmeminta pengguna untuk memeriksa Etherscan untuk informasi lebih lanjut tentang transaksi mereka. - Jika transaksi gagal, fungsi akan mengembalikan objek JSON di mana boolean
successdiatur ke false, dan stringstatusmenyampaikan pesan kesalahan.
- Jika transaksi berhasil, fungsi akan mengembalikan objek JSON di mana boolean
Secara keseluruhan, fungsi mintNFT kita akan terlihat seperti ini:
1export const mintNFT = async (url, name, description) => {2 //error handling // penanganan kesalahan3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Please make sure all fields are completed before minting.",7 }8 }910 //make metadata // buat metadata11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //pinata pin request // permintaan pin pinata17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 Something went wrong while uploading your tokenURI.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl2526 //load smart contract // muat smart contract27 window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract(); // loadContract();2829 //set up your Ethereum transaction // siapkan transaksi Ethereum Anda30 const transactionParameters = {31 to: contractAddress, // Required except during contract publications. // Diperlukan kecuali selama publikasi kontrak.32 from: window.ethereum.selectedAddress, // must match user's active address. // harus cocok dengan alamat aktif pengguna.33 data: window.contract.methods34 .mintNFT(window.ethereum.selectedAddress, tokenURI)35 .encodeABI(), //make call to NFT smart contract // buat panggilan ke smart contract NFT36 }3738 //sign transaction via MetaMask // tandatangani transaksi melalui MetaMask39 try {40 const txHash = await window.ethereum.request({41 method: "eth_sendTransaction",42 params: [transactionParameters],43 })44 return {45 success: true,46 status:47 "✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +48 txHash,49 }50 } catch (error) {51 return {52 success: false,53 status: "😥 Something went wrong: " + error.message,54 }55 }56}Tampilkan semuaItu adalah satu fungsi raksasa! Sekarang, kita hanya perlu menghubungkan fungsi mintNFT kita ke komponen Minter.js kita...
Hubungkan mintNFT ke frontend Minter.js kita
Buka file Minter.js Anda dan perbarui baris import { connectWallet, getCurrentWalletConnected } from "./utils/interact.js"; di bagian atas menjadi:
1import {2 connectWallet,3 getCurrentWalletConnected,4 mintNFT,5} from "./utils/interact.js"Terakhir, implementasikan fungsi onMintPressed untuk melakukan panggilan await ke fungsi mintNFT yang Anda impor dan perbarui variabel status status untuk mencerminkan apakah transaksi kita berhasil atau gagal:
1const onMintPressed = async () => {2 const { status } = await mintNFT(url, name, description)3 setStatus(status)4}Terapkan NFT Anda ke situs web langsung
Siap untuk membuat proyek Anda langsung agar pengguna dapat berinteraksi dengannya? Periksa tutorial ini (opens in a new tab) untuk menerapkan Minter Anda ke situs web langsung.
Satu langkah terakhir...
Guncang dunia blockchain
Hanya bercanda, Anda berhasil mencapai akhir tutorial!
Sebagai rekap, dengan membangun minter NFT, Anda berhasil mempelajari cara:
- Terhubung ke MetaMask melalui proyek frontend Anda
- Memanggil metode kontrak pintar dari frontend Anda
- Menandatangani transaksi menggunakan MetaMask
Mungkin, Anda ingin dapat memamerkan NFT yang di-mint melalui dapp Anda di dompet Anda — jadi pastikan untuk memeriksa tutorial singkat kami Cara Melihat NFT Anda di Dompet Anda (opens in a new tab)!
Dan, seperti biasa, jika Anda memiliki pertanyaan, kami di sini untuk membantu di Discord Alchemy (opens in a new tab). Kami tidak sabar untuk melihat bagaimana Anda menerapkan konsep dari tutorial ini ke proyek masa depan Anda!
Pembaruan terakhir halaman: 25 Februari 2026