NFT Minter Öğreticisi
Web2 arka planından gelen geliştiriciler için en büyük zorluklardan biri, akıllı bağlantınızı bir ön uç projesine nasıl bağlayacağınızı ve onunla nasıl etkileşimde bulunacağınızı anlamaktır.
Dijital varlığınıza bir bağlantı, bir başlık ve bir açıklama girebileceğiniz basit bir kullanıcı arayüzü olan bir NFT minter oluşturarak şunları nasıl yapacağınızı öğreneceksiniz:
- Ön uç projeniz aracılığıyla MetaMask'a bağlanma
- Ön ucunuzdan akıllı sözleşme yöntemlerini arama
- MetaMask kullanarak işlemleri imzalama
Bu öğreticide, ön uç çerçevemiz olarak React (opens in a new tab) kullanacağız. Bu eğitim öncelikle Web3 geliştirmeye odaklandığından, React temellerini açıklamak için fazla zaman harcamayacağız. Bunun yerine, projemize işlevsellik getirmeye odaklanacağız.
Bir ön koşul olarak, başlangıç düzeyinde bir React anlayışına sahip olmalısınız; bileşenlerin, donanımların, useState/useEffect ve temel fonksiyon çağırmanın nasıl çalıştığını bilmeniz gerekir. Bu terimlerden herhangi birini daha önce hiç duymadıysanız, bu React'e Giriş öğreticisine (opens in a new tab) göz atmak isteyebilirsiniz. Daha çok görsel öğrenenler için Net Ninja'nın bu mükemmel Tam Modern React Öğreticisi (opens in a new tab) video serisini şiddetle tavsiye ederiz.
Ve henüz yapmadıysanız, bu öğreticiyi tamamlamak ve blok zincirinde herhangi bir şey oluşturmak için kesinlikle bir Alchemy hesabına ihtiyacınız olacak. Buradan (opens in a new tab) ücretsiz bir hesap için kaydolun.
Lafı fazla uzatmadan başlayalım!
NFT Yapımına Giriş
Herhangi bir koda bakmaya başlamadan önce, bir NFT yapmanın nasıl çalıştığını anlamak önemlidir. İki adım içerir:
Ethereum blokzincirinde bir NFT akıllı sözleşmesi yayımlayın
İki NFT akıllı iletişim standardı arasındaki en büyük fark, ERC-1155'in çok token'lı bir standart olması ve toplu işlevsellik içermesi; ERC-721'in ise tek token'lı bir standart olması ve bu nedenle bir seferde yalnızca bir token'ın aktarılmasını desteklemesidir.
Basım fonksiyonunu çağırın
Genellikle bu basım fonksiyonu, parametre olarak iki değişken iletmenizi gerektirir: birincisi, yeni basılmış NFT'nizi alacak adresi belirten recipient ve ikincisi, NFT'nin meta verilerini açıklayan bir JSON belgesine çözümlenen bir dize olan NFT'nin tokenURI'sidir.
Bir NFT'nin meta verileri gerçekten onu hayata geçiren şeydir ve bir isim, açıklama, görüntü (veya farklı dijital varlık) ve diğer nitelikler gibi özelliklere sahip olmasına izin verir. İşte bir NFT'nin meta verilerini içeren bir tokenURI örneği (opens in a new tab).
Bu öğreticide, React UI'ımızı kullanarak mevcut bir NFT'nin akıllı sözleşme basım fonksiyonunu çağırarak 2. bölüme odaklanacağız.
Bu öğreticide çağıracağımız ERC-721 NFT akıllı sözleşmesinin bağlantısı buradadır (opens in a new tab). Bunu nasıl yaptığımızı öğrenmek isterseniz, diğer öğreticimiz olan "Bir NFT Nasıl Oluşturulur" (opens in a new tab) belgesine göz atmanızı önemle tavsiye ederiz.
Harika, şimdi bir NFT yapmanın nasıl çalıştığını anladığımıza göre, başlangıç dosyalarımızı klonlayalım!
Başlangıç dosyalarını klonlayın
Öncelikle, bu projenin başlangıç dosyalarını almak için nft-minter-tutorial GitHub deposuna (opens in a new tab) gidin. Bu depoyu yerel ortamınıza klonlayın.
Bu klonlanmış nft-minter-tutorial deposunu açtığınızda, iki klasör içerdiğini fark edeceksiniz: minter-starter-files ve nft-minter.
minter-starter-filesbu proje için başlangıç dosyalarını (temel olarak React kullanıcı arayüzünü) içerir. Bu öğreticide, bu kullanıcı arayüzünü Ethereum cüzdanınıza ve bir NFT akıllı sözleşmesine bağlayarak nasıl hayata geçireceğinizi öğrenirken bu dizinde çalışacağız.nft-minter, tamamlanmış öğreticinin tamamını içerir ve takılırsanız referans olması için oradadır.
Ardından, minter-starter-files kopyanızı kod düzenleyicinizde açın ve src klasörünüze gidin.
Yazacağımız tüm kodlar src klasörünün altında yer alacaktır. Projemize Web3 işlevselliği kazandırmak için Minter.js bileşenini düzenleyecek ve ek javascript dosyaları yazacağız.
Adım 2: Başlangıç dosyalarımıza göz atın
Kodlamaya başlamadan önce, başlangıç dosyalarında bizim için nelerin sağlandığını kontrol etmek önemlidir.
React projenizi çalıştırın
Tarayıcımızda React projesini çalıştırarak başlayalım. React'in güzelliği, projemizi tarayıcımızda çalıştırdıktan sonra, kaydettiğimiz tüm değişikliklerin tarayıcımızda canlı olarak güncellenmesidir.
Projeyi çalıştırmak için minter-starter-files klasörünün kök dizinine gidin ve projenin bağımlılıklarını yüklemek için terminalinizde npm install komutunu çalıştırın:
cd minter-starter-filesnpm installBunların kurulumu tamamlandıktan sonra terminalinizde npm start komutunu çalıştırın:
npm startBunu yapmak, tarayıcınızda projemizin ön ucunu göreceğiniz http://localhost:3000/ (opens in a new tab) adresini açmalıdır. 3 alandan oluşmalıdır: NFT'nizin varlığına bir bağlantı yerleştireceğiniz, NFT'nizin adını gireceğiniz ve bir açıklama sağlayabileceğiniz bir yer.
"Connect Wallet" (Cüzdanı Bağla) veya "Mint NFT" (NFT Bas) düğmelerinE tıklamayı denerseniz, çalışmadıklarını fark edeceksiniz. Çünkü hâlâ işlevlerini kodlamamız gerekiyor! :)
Minter.js bileşeni
NOT: nft-minter klasöründe değil, minter-starter-files klasöründe olduğunuzdan emin olun!
Düzenleyicimizde src klasörüne geri dönelim ve Minter.js dosyasını açalım. Üzerinde çalışacağımız birincil React bileşeni olduğu için bu dosyadaki her şeyi anlamamız çok önemlidir.
Bu dosyamızın en üstünde, belirli olaylardan sonra güncelleyeceğimiz durum değişkenlerimiz var.
1//Durum değişkenleri2const [walletAddress, setWallet] = useState("")3const [status, setStatus] = useState("")4const [name, setName] = useState("")5const [description, setDescription] = useState("")6const [url, setURL] = useState("")React durum değişkenlerini veya durum kancalarını hiç duymadınız mı? Bu (opens in a new tab) belgelere göz atın.
Değişkenlerin her birinin temsil ettiği şey:
walletAddress- kullanıcının cüzdan adresini saklayan bir dizedirstatus- kullanıcı arayüzünün altında görüntülenecek bir mesaj içeren bir dizedirname- NFT'nin adını saklayan bir dizedirdescription- NFT'nin açıklamasını saklayan bir dizedirurl- NFT'nin dijital varlığına bir bağlantı olan bir dizedir
Durum değişkenlerinden sonra, uygulanmamış üç fonksiyon göreceksiniz: useEffect, connectWalletPressed ve onMintPressed. Tüm bu fonksiyonların async olduğunu fark edeceksiniz, çünkü içlerinde eşzamansız API çağrıları yapacağız! Adları, fonksiyonlarıyla aynıdır:
1useEffect(async () => {2 //TODO: uygula3}, [])45const connectWalletPressed = async () => {6 //TODO: uygula7}89const onMintPressed = async () => {10 //TODO: uygula11}Tümünü gösteruseEffect(opens in a new tab) - bu, bileşeniniz oluşturulduktan sonra çağrılan bir React kancasıdır. İçine boş bir[]dizisi prop'u aktarıldığı için (bkz. 3. satır), yalnızca bileşenin ilk render işleminde çağrılacaktır. Burada, bir cüzdanın zaten bağlı olup olmadığını yansıtacak şekilde kullanıcı arayüzünü güncellemek için cüzdan dinleyicimizi ve başka bir cüzdan fonksiyonunu çağıracağız.connectWalletPressed- bu fonksiyon, kullanıcının MetaMask cüzdanını merkeziyetsiz uygulamamıza bağlamak için çağrılacaktır.onMintPressed- bu fonksiyon, kullanıcının NFT'sini basmak için çağrılacaktır.
Bu dosyanın sonuna doğru, bileşenimizin kullanıcı arayüzü bulunuyor. Bu kodu dikkatlice incelerseniz, ilgili metin alanlarındaki girdi değiştiğinde url, name ve description durum değişkenlerimizi güncellediğimizi fark edeceksiniz.
Ayrıca, sırasıyla mintButton ve walletButton kimlikli düğmelere tıklandığında connectWalletPressed ve onMintPressed fonksiyonlarının çağrıldığını göreceksiniz.
1//bileşenimizin kullanıcı arayüzü2return (3 <div className="Minter">4 <button id="walletButton" onClick={connectWalletPressed}>5 {walletAddress.length > 0 ? (6 "Bağlandı: " +7 String(walletAddress).substring(0, 6) +8 "..." +9 String(walletAddress).substring(38)10 ) : (11 <span>Cüzdanı Bağla</span>12 )}13 </button>1415 <br></br>16 <h1 id="title">🧙♂️ Alchemy NFT Basıcısı</h1>17 <p>18 Varlığınızın bağlantısını, adını ve açıklamasını ekleyin, ardından "Bas" düğmesine basın.19 </p>20 <form>21 <h2>🖼 Varlık bağlantısı: </h2>22 <input23 type="text"24 placeholder="örn. https://gateway.pinata.cloud/ipfs/<hash>"25 onChange={(event) => setURL(event.target.value)}26 />27 <h2>🤔 Ad: </h2>28 <input29 type="text"30 placeholder="örn. İlk NFT'm!"31 onChange={(event) => setName(event.target.value)}32 />33 <h2>✍️ Açıklama: </h2>34 <input35 type="text"36 placeholder="örn. Cryptokitties'den bile daha havalı ;)"37 onChange={(event) => setDescription(event.target.value)}38 />39 </form>40 <button id="mintButton" onClick={onMintPressed}>41 NFT Bas42 </button>43 <p id="status">{status}</p>44</div>45)Tümünü gösterSon olarak bu Minter bileşeninin nereye eklendiğine değinelim.
App.js dosyasına giderseniz, ki bu dosya React'te diğer tüm bileşenler için bir kapsayıcı görevi gören ana bileşendir, Minter bileşenimizin 7. satıra eklendiğini görürsünüz.
Bu öğreticide, yalnızca Minter.js dosyasını düzenleyecek ve src klasörümüze dosyalar ekleyeceğiz.
Artık ne üzerinde çalıştığımızı anladığımıza göre, Ethereum cüzdanımızı oluşturalım!
Ethereum cüzdanınızı kurun
Kullanıcıların akıllı sözleşmenizle etkileşime girebilmeleri için Ethereum cüzdanlarını merkeziyetsiz uygulamanıza bağlamaları gerekir.
MetaMask'ı indirin
Bu öğretici için, Ethereum hesap adresinizi yönetmek için kullanılan tarayıcıda sanal bir cüzdan olan MetaMask'ı kullanacağız. Ethereum'daki işlemlerin nasıl çalıştığı hakkında daha fazla bilgi edinmek isterseniz, bu sayfaya göz atın.
MetaMask'ı buradan (opens in a new tab) ücretsiz indirip bir hesap oluşturabilirsiniz. Bir hesap oluşturuyorsanız veya zaten bir hesabınız varsa, sağ üstteki "Ropsten Test Ağı"na geçtiğinizden emin olun (böylece gerçek parayla uğraşmayız).
Musluktan ether ekleyin
NFT'lerimizi basmak (veya Ethereum blok zincirindeki herhangi bir işlemi imzalamak) için biraz sahte Eth'e ihtiyacımız olacak. Eth almak için Ropsten musluğuna (opens in a new tab) gidip Ropsten hesap adresinizi girebilir, ardından “Send Ropsten Eth” (Ropsten Eth Gönder) düğmesine tıklayabilirsiniz. Kısa bir süre sonra MetaMask hesabınızda Eth'i görmelisiniz!
Bakiyenizi kontrol edin
Bakiyemizin orada olup olmadığını iki kez kontrol etmek için Alchemy’nin composer aracını (opens in a new tab) kullanarak bir eth_getBalance (opens in a new tab) isteği yapalım. Bu, cüzdanımızdaki Eth miktarını döndürür. MetaMask hesap adresinizi girdikten ve "Send Request"e tıkladıktan sonra aşağıdaki gibi bir yanıt görmelisiniz:
1{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}NOT: Bu sonuç eth cinsinden değil wei cinsindendir. Wei, ether'ın en küçük birimi olarak kullanılır. Wei'den eth'e dönüşüm: 1 eth = 10¹⁸ wei. Yani 0xde0b6b3a7640000'ı ondalık sayıya dönüştürürsek 1*10¹⁸ elde ederiz, bu da 1 eth'e eşittir.
Vay be! Tüm sahte paramız yerinde!
MetaMask'ı kullanıcı arayüzünüze bağlayın
Artık MetaMask cüzdanımız kurulduğuna göre, merkeziyetsiz uygulamamızı ona bağlayalım!
MVC (opens in a new tab) paradigmasına uymak istediğimiz için, merkeziyetsiz uygulamamızın mantığını, verilerini ve kurallarını yöneten fonksiyonlarımızı içeren ayrı bir dosya oluşturacak ve ardından bu fonksiyonları ön uca (Minter.js bileşenimiz) aktaracağız.
connectWallet fonksiyonu
Bunu yapmak için src dizininizde utils adında yeni bir klasör oluşturalım ve içine tüm cüzdan ve akıllı sözleşme etkileşim fonksiyonlarımızı içerecek olan interact.js adlı bir dosya ekleyelim.
interact.js dosyamızda bir connectWallet fonksiyonu yazacağız, bunu daha sonra Minter.js bileşenimize aktarıp çağıracağız.
interact.js dosyanıza aşağıdakileri ekleyin
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: "👆🏽 Yukarıdaki metin alanına bir mesaj yazın.",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 Tarayıcınıza sanal bir Ethereum cüzdanı olan MetaMask'i yüklemeniz gerekir.27 </a>28 </p>29 </span>30 ),31 }32 }33}Tümünü gösterŞimdi bu kodun ne yaptığını inceleyelim:
İlk olarak, fonksiyonumuz tarayıcınızda window.ethereum'un etkin olup olmadığını kontrol eder.
window.ethereum, MetaMask ve diğer cüzdan sağlayıcıları tarafından eklenen ve web sitelerinin kullanıcıların Ethereum hesaplarını talep etmesine olanak tanıyan küresel bir API'dir. Onaylanırsa, kullanıcının bağlı olduğu blok zincirlerinden verileri okuyabilir ve kullanıcının mesajları ve işlemleri imzalamasını önerebilir. Daha fazla bilgi için MetaMask belgelerine (opens in a new tab) göz atın!
Eğer window.ethereum mevcut değilse, bu MetaMask'in kurulu olmadığı anlamına gelir. Bu, döndürülen address'in boş bir dize olduğu ve status JSX nesnesinin kullanıcının MetaMask'i yüklemesi gerektiğini ilettiği bir JSON nesnesinin döndürülmesiyle sonuçlanır.
Yazdığımız fonksiyonların çoğu, durum değişkenlerimizi ve kullanıcı arayüzümüzü güncellemek için kullanabileceğimiz JSON nesneleri döndürecektir.
Eğer window.ethereum mevcut ise, o zaman işler ilginçleşir.
Bir try/catch döngüsü kullanarak, window.ethereum.request({ method: \"eth_requestAccounts\" }); (opens in a new tab) çağrısı yaparak MetaMask'e bağlanmaya çalışacağız. Bu fonksiyonun çağrılması, tarayıcıda MetaMask'i açar ve bu sayede kullanıcıdan cüzdanını merkeziyetsiz uygulamanıza bağlaması istenir.
- Kullanıcı bağlanmayı seçerse
method: \"eth_requestAccounts\", kullanıcının merkeziyetsiz uygulamaya bağlı tüm hesap adreslerini içeren bir dizi döndürür. Sonuç olarak,connectWalletfonksiyonumuz bu dizideki ilkaddress'i (bkz. satır 9) ve kullanıcıyı akıllı sözleşmeye bir mesaj yazmaya yönlendiren birstatusmesajını içeren bir JSON nesnesi döndürecektir. - Kullanıcı bağlantıyı reddederse JSON nesnesi, döndürülen
addressiçin boş bir dize ve kullanıcının bağlantıyı reddettiğini yansıtan birstatusmesajı içerir.
connectWallet fonksiyonunu Minter.js kullanıcı arayüzü bileşeninize ekleyin
Bu connectWallet fonksiyonunu yazdığımıza göre, şimdi onu Minter.js. bileşenimize bağlayalım.
İlk olarak, Minter.js dosyasının en üstüne import { connectWallet } from \"./utils/interact.js\"; satırını ekleyerek fonksiyonumuzu Minter.js dosyamıza aktarmamız gerekecek. Minter.js dosyanızın ilk 11 satırı şimdi şöyle görünmelidir:
1import { useEffect, useState } from "react";2import { connectWallet } from "./utils/interact.js";34const Minter = (props) => {56 //Durum değişkenleri7 const [walletAddress, setWallet] = useState("");8 const [status, setStatus] = useState("");9 const [name, setName] = useState("");10 const [description, setDescription] = useState("");11 const [url, setURL] = useState("");Tümünü gösterArdından, connectWalletPressed fonksiyonumuzun içinde, içe aktardığımız connectWallet fonksiyonunu şu şekilde çağıracağız:
1const connectWalletPressed = async () => {2 const walletResponse = await connectWallet()3 setStatus(walletResponse.status)4 setWallet(walletResponse.address)5}İşlevselliğimizin çoğunun interact.js dosyasından Minter.js bileşenimizden nasıl soyutlandığına dikkat edin. Bu, M-V-C paradigmasına uymamız içindir!
connectWalletPressed içinde, içe aktarılan connectWallet fonksiyonumuza bir await çağrısı yaparız ve yanıtını kullanarak status ve walletAddress değişkenlerimizi durum kancaları aracılığıyla güncelleriz.
Şimdi, Minter.js ve interact.js dosyalarını kaydedelim ve şimdiye kadarki kullanıcı arayüzümüzü test edelim.
Tarayıcınızı localhost:3000 üzerinde açın ve sayfanın sağ üst köşesindeki "Connect Wallet" düğmesine basın.
MetaMask yüklüyse, cüzdanınızı merkeziyetsiz uygulamanıza bağlamanız istenecektir. Bağlanmak için daveti kabul edin.
Cüzdan düğmesinin artık adresinizin bağlı olduğunu yansıttığını görmelisiniz.
Şimdi, sayfayı yenilemeyi deneyin... bu garip. Cüzdan düğmemiz zaten bağlı olmasına rağmen MetaMask'i bağlamamızı istiyor...
Ama merak etmeyin! Bunu, bir adresin merkeziyetsiz uygulamamıza zaten bağlı olup olmadığını kontrol edecek ve kullanıcı arayüzümüzü buna göre güncelleyecek olan getCurrentWalletConnected adlı bir fonksiyonu uygulayarak kolayca düzeltebiliriz!
getCurrentWalletConnected fonksiyonu
interact.js dosyanıza aşağıdaki getCurrentWalletConnected fonksiyonunu ekleyin:
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: "👆🏽 Yukarıdaki metin alanına bir mesaj yazın.",11 }12 } else {13 return {14 address: "",15 status: "🦊 Sağ üstteki düğmeyi kullanarak MetaMask'e bağlanın.",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 Tarayıcınıza sanal bir Ethereum cüzdanı olan MetaMask'i yüklemeniz gerekir.33 </a>34 </p>35 </span>36 ),37 }38 }39}Tümünü gösterBu kod, az önce yazdığımız connectWallet fonksiyonuna çok benzer.
Temel fark, kullanıcının cüzdanını bağlaması için MetaMask'i açan eth_requestAccounts yöntemini çağırmak yerine, burada yalnızca merkeziyetsiz uygulamamıza bağlı olan MetaMask adreslerini içeren bir dizi döndüren eth_accounts yöntemini çağırıyoruz.
Bu fonksiyonu çalışırken görmek için Minter.js bileşenimizin useEffect fonksiyonunda çağıralım.
connectWallet için yaptığımız gibi, bu fonksiyonu interact.js dosyamızdan Minter.js dosyamıza şu şekilde aktarmalıyız:
1import { useEffect, useState } from "react"2import {3 connectWallet,4 getCurrentWalletConnected, //buraya aktar5} from "./utils/interact.js"Şimdi, onu sadece useEffect fonksiyonumuzda çağırıyoruz:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)5}, [])Dikkat edin, getCurrentWalletConnected çağrımızın yanıtını walletAddress ve status durum değişkenlerimizi güncellemek için kullanıyoruz.
Bu kodu ekledikten sonra tarayıcı penceremizi yenilemeyi deneyin. Düğme, bağlı olduğunuzu söylemeli ve yeniledikten sonra bile bağlı cüzdanınızın adresinin bir önizlemesini göstermelidir!
addWalletListener fonksiyonunu uygulayın
Merkeziyetsiz uygulama cüzdanı kurulumumuzun son adımı, örneğin kullanıcı bağlantısını keserek veya hesap değiştirerek cüzdanımızın durumunu değiştirdiğinde kullanıcı arayüzümüzün güncellenmesi için cüzdan dinleyicisini uygulamaktır.
Minter.js dosyanıza, aşağıdakine benzeyen bir addWalletListener fonksiyonu ekleyin:
1function addWalletListener() {2 if (window.ethereum) {3 window.ethereum.on("accountsChanged", (accounts) => {4 if (accounts.length > 0) {5 setWallet(accounts[0])6 setStatus("👆🏽 Yukarıdaki metin alanına bir mesaj yazın.")7 } else {8 setWallet("")9 setStatus("🦊 Sağ üstteki düğmeyi kullanarak MetaMask'e bağlanın.")10 }11 })12 } else {13 setStatus(14 <p>15 {" "}16 🦊 <a target="_blank" href={`https://metamask.io/download`}>17 Tarayıcınıza sanal bir Ethereum cüzdanı olan MetaMask'i yüklemeniz gerekir.18 </a>19 </p>20 )21 }22}Tümünü gösterBurada neler olduğunu hızlıca çözelim:
- İlk olarak fonksiyonumuz
window.ethereum'un etkin olup olmadığını kontrol eder (yani MetaMask'in kurulu olup olmadığını).- Etkin değilse,
statusdurum değişkenimizi, kullanıcıyı MetaMask'i yüklemeye yönlendiren bir JSX dizesine ayarlarız. - Etkinleştirilmişse, kullanıcının merkeziyetsiz uygulamaya ek bir hesap bağlaması, hesapları değiştirmesi veya bir hesabın bağlantısını kesmesi gibi MetaMask cüzdanındaki durum değişikliklerini dinleyen
window.ethereum.on(\"accountsChanged\")dinleyicisini 3. satırda kurarız. Bağlı en az bir hesap varsa,walletAddressdurum değişkeni, dinleyici tarafından döndürülenaccountsdizisindeki ilk hesap olarak güncellenir. Aksi takdirde,walletAddressboş bir dize olarak ayarlanır.
- Etkin değilse,
Son olarak, onu useEffect fonksiyonumuzda çağırmalıyız:
1useEffect(async () => {2 const { address, status } = await getCurrentWalletConnected()3 setWallet(address)4 setStatus(status)56 addWalletListener()7}, [])İşte oldu! Cüzdan fonksiyonlarımızın tümünü programlamayı tamamladık! Cüzdanımız kurulduğuna göre, şimdi NFT'mizi nasıl basacağımızı bulalım!
NFT Meta Verilerine Giriş
Bu öğreticinin 0. Adımında bahsettiğimiz NFT meta verilerini hatırlayın; dijital varlık, ad, açıklama ve diğer nitelikler gibi özelliklere sahip olmasını sağlayarak bir NFT'ye hayat verirler.
Bu meta verileri bir JSON nesnesi olarak yapılandırıp saklamamız gerekecek, böylece akıllı sözleşmemizin mintNFT fonksiyonunu çağırırken bunu tokenURI parametresi olarak geçirebiliriz.
"Link to Asset" (Varlığa Bağlantı), "Name" (Ad) ve "Description" (Açıklama) alanlarındaki metin, NFT'mizin meta verisinin farklı özelliklerini oluşturacaktır. Bu meta verileri bir JSON nesnesi olarak biçimlendireceğiz, ancak bu JSON nesnesini nerede depolayabileceğimiz konusunda birkaç seçenek var:
- Bunu Ethereum blok zincirinde saklayabiliriz ama bunu yapmak çok pahalı olacaktır.
- AWS veya Firebase gibi merkezi bir sunucuda depolayabiliriz. Ancak bu, merkeziyetsizlik anlayışımızı bozar.
- Dağıtılmış bir dosya sisteminde veri depolamak ve paylaşmak için merkeziyetsiz bir protokol ve eşler arası ağ olan IPFS'yi kullanabiliriz. Bu protokol merkeziyetsiz ve ücretsiz olduğu için en iyi seçeneğimizdir!
Meta verilerimizi IPFS'de depolamak için, kullanışlı bir IPFS API'si ve araç takımı olan Pinata (opens in a new tab)'yı kullanacağız. Bir sonraki adımda, bunun tam olarak nasıl yapılacağını açıklayacağız!
Meta verilerinizi IPFS'e sabitlemek için Pinata'yı kullanın
Bir Pinata (opens in a new tab) hesabınız yoksa, buradan (opens in a new tab) ücretsiz bir hesap için kaydolun ve e-postanızı ve hesabınızı doğrulamak için adımları tamamlayın.
Pinata API anahtarınızı oluşturun
https://pinata.cloud/keys (opens in a new tab) sayfasına gidin, ardından üstteki "New Key" (Yeni Anahtar) düğmesini seçin, Yönetici aracını etkinleştirin ve anahtarınızı adlandırın.
Ardından, API bilgilerinizi içeren bir açılır pencere gösterilecektir. Bunu güvenli bir yere koyduğunuzdan emin olun.
Artık anahtarımız ayarlandığına göre onu kullanabilmek için projemize ekleyelim.
Bir .env dosyası oluşturun
Pinata anahtarımızı ve sırrımızı bir ortam dosyasında güvenle saklayabiliriz. Proje dizininize dotenv paketini (opens in a new tab) yükleyelim.
Terminalinizde yeni bir sekme açın (yerel ana bilgisayarı çalıştırandan ayrı) ve minter-starter-files klasöründe olduğunuzdan emin olun, ardından terminalinizde aşağıdaki komutu çalıştırın:
1npm install dotenv --saveArdından, komut satırınıza aşağıdakileri girerek minter-starter-files kök dizininizde bir .env dosyası oluşturun:
1vim.envBu, .env dosyanızı vim (bir metin düzenleyici) içinde açacaktır. Kaydetmek için klavyenizdeki "esc" + ":" + "q" tuşlarına bu sırayla basın.
Ardından, VSCode'da .env dosyanıza gidin ve Pinata API anahtarınızı ve API sırrınızı şu şekilde ekleyin:
1REACT_APP_PINATA_KEY = <pinata-api-key>2REACT_APP_PINATA_SECRET = <pinata-api-secret>Dosyayı kaydettikten sonra JSON meta verilerinizi IPFS'ye yüklemek için fonksiyonu yazmaya başlamaya hazırsınız!
pinJSONToIPFS fonksiyonunu uygulayın
Neyse ki Pinata'nın, JSON verilerini IPFS'ye yüklemek için özel bir API'si (opens in a new tab) ve bazı küçük değişikliklerle kullanabileceğimiz, axios içeren kullanışlı bir JavaScript örneği var.
utils klasörünüzde pinata.js adında başka bir dosya oluşturalım ve ardından Pinata sırrımızı ve anahtarımızı .env dosyasından şu şekilde içe aktaralım:
1require("dotenv").config()2const key = process.env.REACT_APP_PINATA_KEY3const secret = process.env.REACT_APP_PINATA_SECRETArdından, aşağıdaki ek kodu pinata.js dosyanıza yapıştırın. Endişelenmeyin, her şeyin ne anlama geldiğini anlatacağız!
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 //Pinata'ya axios POST isteği yapılıyor ⬇️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}Tümünü gösterPeki bu kod tam olarak ne yapıyor?
İlk olarak, Pinata'ya bir istekte bulunmak için kullanacağımız, tarayıcı ve node.js için promise tabanlı bir HTTP istemcisi olan axios (opens in a new tab) içe aktarılır.
Ardından, pinJSONToIPFS API'lerine bir POST isteği yapmak için girişi olarak bir JSONBody ve başlığında Pinata api anahtarını ve sırrını alan eş zamansız pinJSONToIPFS fonksiyonumuz var.
- Bu POST isteği başarılı olursa, fonksiyonumuz
successboole değeritrueolan ve meta verilerimizin sabitlendiğipinataUrl'yi içeren bir JSON nesnesi döndürür. Akıllı sözleşmemizin mint fonksiyonunatokenURIgirdisi olarak döndürülen bupinataUrlöğesini kullanacağız. - Bu post isteği başarısız olursa, fonksiyonumuz
successboole değerifalseolan bir JSON nesnesi ve hatamızı ileten birmessagedizesi döndürür.
connectWalletfonksiyon dönüş türlerimizde olduğu gibi, durum değişkenlerimizi ve kullanıcı arayüzünü güncellemek amacıyla parametrelerini kullanabilmemiz için JSON nesneleri döndürüyoruz.
Akıllı sözleşmenizi yükleyin
Artık pinJSONToIPFS fonksiyonumuz aracılığıyla NFT meta verilerimizi IPFS'ye yüklemenin bir yolu olduğuna göre, mintNFT fonksiyonunu çağırabilmemiz için akıllı sözleşmemizin bir örneğini yüklemenin bir yoluna ihtiyacımız olacak.
Daha önce de belirttiğimiz gibi, bu öğreticide bu mevcut NFT akıllı sözleşmesini (opens in a new tab) kullanıyor olacağız; ancak, bunu nasıl yaptığımızı öğrenmek veya kendiniz yapmak isterseniz, diğer öğreticimiz olan "Bir NFT Nasıl Oluşturulur." (opens in a new tab) başlıklı yazımıza göz atmanızı şiddetle tavsiye ederiz.
Sözleşme ABI'si
Dosyalarımızı yakından incelediyseniz src dizinimizde bir contract-abi.json dosyası olduğunu fark etmişsinizdir. Bir sözleşmenin hangi fonksiyonu çağıracağını belirlemek ve fonksiyonun beklediğiniz biçimde veri döndürmesini sağlamak için bir ABI gereklidir.
Ayrıca Ethereum blok zincirine bağlanmak ve akıllı sözleşmemizi yüklemek için bir Alchemy API anahtarına ve Alchemy Web3 API'sine ihtiyacımız olacak.
Alchemy API anahtarınızı oluşturun
Henüz bir Alchemy hesabınız yoksa, buradan ücretsiz kaydolun. (opens in a new tab)
Bir Alchemy hesabı oluşturduktan sonra, bir uygulama yaratarak bir API anahtarı oluşturabilirsiniz. Bu, Ropsten test ağına istekte bulunmamıza izin verecektir.
İmlecinizi gezinme çubuğundaki "Apps"in (Uygulamalar) üzerine gelip "Create App"e (Uygulama Oluştur) tıklayarak Alchemy Gösterge Panelinizdeki "Create App" sayfasına gidin.
Uygulamanıza bir ad verin (biz, "İlk NFT'm!"i seçtik), kısa bir açıklama yazın, Environment (Ortam) için "Staging"i (Hazırlama) seçin (uygulamanızın muhasebesi için kullanılır) ve network (ağ) için "Ropsten"i seçin.
"Create app"e (Uygulama oluştur) tıklamanız yeterlidir! Uygulamanız aşağıdaki tabloda görünmelidir.
Harika, şimdi HTTP Alchemy API URL'mizi oluşturduğumuza göre, onu panonuza kopyalayın...
…ve sonra onu .env dosyamıza ekleyelim. Toplamda, .env dosyanız şöyle görünmelidir:
1REACT_APP_PINATA_KEY = <pinata-key>2REACT_APP_PINATA_SECRET = <pinata-secret>3REACT_APP_ALCHEMY_KEY = https://eth-ropsten.alchemyapi.io/v2/<alchemy-key>Artık sözleşme ABI'mız ve Alchemy API anahtarımız olduğuna göre Alchemy Web3 (opens in a new tab) kullanarak akıllı sözleşmemizi yüklemeye hazırız.
Alchemy Web3 uç noktanızı ve sözleşmenizi ayarlayın
Öncelikle, henüz sahip değilseniz terminalde ana dizine giderek Alchemy Web3 (opens in a new tab)'ü yüklemeniz gerekir: nft-minter-tutorial:
1cd ..2npm install @alch/alchemy-web3Şimdi interact.js dosyamıza geri dönelim. Alchemy anahtarınızı .env dosyanızdan içe aktarmak için dosyanın en üstüne aşağıdaki kodu ekleyin ve Alchemy Web3 uç noktanızı ayarlayın:
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), Web3.js (opens in a new tab) için bir sarmalayıcıdır ve bir web3 geliştiricisi olarak hayatınızı kolaylaştırmak için gelişmiş API yöntemleri ve diğer önemli avantajları sağlar. Uygulamanızda hemen kullanmaya başlayabilmeniz için minimum yapılandırma gerektirecek şekilde tasarlanmıştır!
Ardından sözleşme ABI'ımızı ve sözleşme adresimizi dosyamıza ekleyelim.
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"Her ikisine de sahip olduğumuzda, mint fonksiyonumuzu kodlamaya başlamaya hazırız!
mintNFT fonksiyonunu uygulayın
interact.js dosyanızın içinde, NFT'mizi aynı adla basacak olan mintNFT fonksiyonumuzu tanımlayalım.
Çok sayıda eş zamansız çağrı yapacağımız için (meta verilerimizi IPFS'ye sabitlemek için Pinata'ya, akıllı sözleşmemizi yüklemek için Alchemy Web3'e ve işlemlerimizi imzalamak için MetaMask'e), fonksiyonumuz da eş zamansız olacaktır.
Fonksiyonumuza üç girdi, dijital varlığımızın url'si, name ve description olacaktır. connectWallet fonksiyonunun altına aşağıdaki fonksiyon imzasını ekleyin:
1export const mintNFT = async (url, name, description) => {}Giriş hata yönetimi
Doğal olarak, girdi parametrelerimiz doğru değilse bu fonksiyondan çıkmak için fonksiyonun başlangıcında bir tür girdi hatası işlemeye sahip olmak mantıklıdır. Fonksiyonumuzun içine aşağıdaki kodu ekleyelim:
1export const mintNFT = async (url, name, description) => {2 //hata yönetimi3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Lütfen basım yapmadan önce tüm alanların doldurulduğundan emin olun.",7 }8 }9}Tümünü gösterEsasen, girdi parametrelerinden herhangi biri boş bir dizeyse, success boole değerinin false olduğu bir JSON nesnesi döndürürüz ve status dizesi, kullanıcı arayüzümüzdeki tüm alanların doldurulması gerektiğini belirtir.
Meta verileri IPFS'e yükleyin
Meta verilerimizin doğru şekilde biçimlendirildiğini öğrendikten sonraki adım, onu bir JSON nesnesi olarak paketlemek ve yazdığımız pinJSONToIPFS aracılığıyla IPFS'ye yüklemektir!
Bunu yapmak için önce pinJSONToIPFS fonksiyonunu interact.js dosyamıza aktarmamız gerekiyor. interact.js'nin en üstüne şunu ekleyelim:
1import { pinJSONToIPFS } from "./pinata.js"pinJSONToIPFS'in bir JSON gövdesi aldığını hatırlayın. Bu nedenle onu çağırmadan önce url, name ve description parametrelerimizi bir JSON nesnesi olarak biçimlendirmemiz gerekecek.
Şimdi metadata adında bir JSON nesnesi oluşturmak için kodumuzu güncelleyelim ve ardından bu metadata parametresiyle pinJSONToIPFS'a bir çağrı yapalım:
1export const mintNFT = async (url, name, description) => {2 //hata yönetimi3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Lütfen basım yapmadan önce tüm alanların doldurulduğundan emin olun.",7 }8 }910 //meta veri oluştur11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //pinata çağrısı yap17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 tokenURI'niz yüklenirken bir şeyler ters gitti.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl25}Tümünü gösterDikkat edin, pinJSONToIPFS(metadata) çağrımızın yanıtını pinataResponse nesnesinde saklıyoruz. Ardından, bu nesneyi herhangi bir hata için ayrıştırırız.
Bir hata varsa, success boole değerinin false olduğu bir JSON nesnesi döndürürüz ve status dizemiz çağrımızın başarısız olduğunu belirtir. Aksi takdirde, pinataURL'u pinataResponse'tan çıkarır ve onu tokenURI değişkenimiz olarak saklarız.
Şimdi dosyamızın başında başlattığımız Alchemy Web3 API'sini kullanarak akıllı sözleşmemizi yükleme zamanı. Sözleşmeyi window.contract global değişkeninde ayarlamak için mintNFT fonksiyonunun altına aşağıdaki kod satırını ekleyin:
1window.contract = await new web3.eth.Contract(contractABI, contractAddress)mintNFT fonksiyonumuza eklenecek son şey Ethereum işlemimizdir:
1//Ethereum işleminizi ayarlayın2const transactionParameters = {3 to: contractAddress, // Sözleşme yayınları dışında gereklidir.4 from: window.ethereum.selectedAddress, // kullanıcının aktif adresiyle eşleşmelidir.5 data: window.contract.methods6 .mintNFT(window.ethereum.selectedAddress, tokenURI)7 .encodeABI(), //NFT akıllı sözleşmesine çağrı yapın8}910//işlemi MetaMask aracılığıyla imzalayın11try {12 const txHash = await window.ethereum.request({13 method: "eth_sendTransaction",14 params: [transactionParameters],15 })16 return {17 success: true,18 status:19 "✅ İşleminizi Etherscan'de kontrol edin: https://ropsten.etherscan.io/tx/" +20 txHash,21 }22} catch (error) {23 return {24 success: false,25 status: "😥 Bir şeyler ters gitti: " + error.message,26 }27}Tümünü gösterEthereum işlemlerine zaten aşinaysanız, yapının gördüklerinize oldukça benzer olduğunu fark edeceksiniz.
- İlk olarak işlem parametrelerimizi oluşturuyoruz.
toalıcı adresini belirtir (akıllı sözleşmemiz)from, işlemi imzalayanı belirtir (kullanıcının MetaMask'a bağlı adresi:window.ethereum.selectedAddress)data, girdi olaraktokenURI'ımızı ve kullanıcının cüzdan adresi olanwindow.ethereum.selectedAddress'ı alan akıllı sözleşmemintNFTyöntemimize yapılan çağrıyı içerir
- Ardından, MetaMask'ten işlemi imzalamasını istediğimiz bir
window.ethereum.requestbekleme çağrısı yaparız. Dikkat edin, bu istekte eth yöntemimizi (eth_SentTransaction) belirtiyor vetransactionParameters'ımızı aktarıyoruz. Bu noktada, MetaMask tarayıcıda açılır ve kullanıcıdan işlemi imzalamasını veya reddetmesini ister.- İşlem başarılı olursa fonksiyon,
successboole değerinintrueolarak ayarlandığı bir JSON nesnesi döndürür vestatusdizesi kullanıcıdan işlemleri hakkında daha fazla bilgi için Etherscan'i kontrol etmesini ister. - İşlem başarısız olursa fonksiyon,
successboole değerininfalseolarak ayarlandığı bir JSON nesnesi döndürür vestatusdizesi hata mesajını aktarır.
- İşlem başarılı olursa fonksiyon,
Sonuç olarak, mintNFT fonksiyonumuz şöyle görünmelidir:
1export const mintNFT = async (url, name, description) => {2 //hata yönetimi3 if (url.trim() == "" || name.trim() == "" || description.trim() == "") {4 return {5 success: false,6 status: "❗Lütfen basım yapmadan önce tüm alanların doldurulduğundan emin olun.",7 }8 }910 //meta veri oluştur11 const metadata = new Object()12 metadata.name = name13 metadata.image = url14 metadata.description = description1516 //pinata pin isteği17 const pinataResponse = await pinJSONToIPFS(metadata)18 if (!pinataResponse.success) {19 return {20 success: false,21 status: "😢 tokenURI'niz yüklenirken bir şeyler ters gitti.",22 }23 }24 const tokenURI = pinataResponse.pinataUrl2526 //akıllı sözleşmeyi yükle27 window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract();2829 //Ethereum işleminizi ayarlayın30 const transactionParameters = {31 to: contractAddress, // Sözleşme yayınları dışında gereklidir.32 from: window.ethereum.selectedAddress, // kullanıcının aktif adresiyle eşleşmelidir.33 data: window.contract.methods34 .mintNFT(window.ethereum.selectedAddress, tokenURI)35 .encodeABI(), //NFT akıllı sözleşmesine çağrı yapın36 }3738 //işlemi MetaMask aracılığıyla imzala39 try {40 const txHash = await window.ethereum.request({41 method: "eth_sendTransaction",42 params: [transactionParameters],43 })44 return {45 success: true,46 status:47 "✅ İşleminizi Etherscan'de kontrol edin: https://ropsten.etherscan.io/tx/" +48 txHash,49 }50 } catch (error) {51 return {52 success: false,53 status: "😥 Bir şeyler ters gitti: " + error.message,54 }55 }56}Tümünü gösterBu dev bir fonksiyon! Şimdi, sadece mintNFT fonksiyonumuzu Minter.js bileşenimize bağlamamız gerekiyor...
mintNFT'yi Minter.js ön ucumuza bağlayın
Minter.js dosyanızı açın ve en üstteki import { connectWallet, getCurrentWalletConnected } from "./utils/interact.js"; satırını şu şekilde güncelleyin:
1import {2 connectWallet,3 getCurrentWalletConnected,4 mintNFT,5} from "./utils/interact.js"Son olarak, içe aktarılan mintNFTfonksiyonunuza bekleme çağrısı yapmak için onMintPressed fonksiyonunu uygulayın ve işlemimizin başarılı mı yoksa başarısız mı olduğunu yansıtmak için status durum değişkenini güncelleyin:
1const onMintPressed = async () => {2 const { status } = await mintNFT(url, name, description)3 setStatus(status)4}NFT'nizi yayındaki bir web sitesinde yayınlayın
Kullanıcıların etkileşim kurması için projenizi yayınlamaya hazır mısınız? Minter'ınızı canlı bir web sitesinde dağıtmak için bu öğreticiye (opens in a new tab) göz atın.
Son bir adım...
Blokzincir dünyasını kasıp kavurun
Şaka yapıyorum, öğreticiyi tamamladınız!
Özetlemek gerekirse, bir NFT minter oluşturarak şunları nasıl yapacağınızı başarıyla öğrendiniz:
- Ön uç projeniz aracılığıyla MetaMask'a bağlanma
- Ön ucunuzdan akıllı sözleşme yöntemlerini arama
- MetaMask kullanarak işlemleri imzalama
Muhtemelen, merkeziyetsiz uygulamanız aracılığıyla basılan NFT'leri cüzdanınızda sergilemek istersiniz — bu yüzden hızlı öğreticimiz olan NFT'nizi Cüzdanınızda Nasıl Görüntülersiniz (opens in a new tab) başlıklı yazımıza göz atmayı unutmayın!
Ve her zaman olduğu gibi, herhangi bir sorunuz olursa Alchemy Discord (opens in a new tab)'da size yardım etmeye hazırız. Bu öğreticideki kavramları gelecekteki projelerinize nasıl uygulayacağınızı görmek için sabırsızlanıyoruz!
Sayfanın son güncellenmesi: 25 Şubat 2026