NFT Basım Aracı Eğitimi
Web2 geçmişinden gelen geliştiriciler için en büyük zorluklardan biri, akıllı sözleşmenizi bir ön yüz projesine nasıl bağlayacağınızı ve onunla nasıl etkileşime gireceğinizi bulmaktı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 basım aracı oluşturarak şunları öğreneceksiniz:
- Ön yüz projeniz aracılığıyla MetaMask'a bağlanmak
- Ön yüzünüzden akıllı sözleşme yöntemlerini çağırmak
- MetaMask kullanarak işlemleri imzalamak
Bu eğitimde, ön yüz çerçevemiz olarak React (opens in a new tab) kullanacağız. Bu eğitim öncelikle Web3 geliştirmeye odaklandığından, React temellerini parçalara ayırmak için fazla zaman harcamayacağız. Bunun yerine, projemize işlevsellik kazandırmaya odaklanacağız.
Ön koşul olarak, başlangıç seviyesinde bir React anlayışına sahip olmalısınız; bileşenlerin, propların, useState/useEffect'in ve temel işlev çağırmanın nasıl çalıştığını bilmelisiniz. Bu terimlerden herhangi birini daha önce hiç duymadıysanız, bu React'e Giriş eğitimine (opens in a new tab) göz atmak isteyebilirsiniz. Daha görsel öğrenenler için, Net Ninja'nın bu mükemmel Tam Modern React Eğitimi (opens in a new tab) video serisini şiddetle tavsiye ediyoruz.
Ve eğer henüz yapmadıysanız, bu eğitimi tamamlamak ve Blokzincir üzerinde 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.
Daha fazla uzatmadan başlayalım!
NFT Yapımı 101
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ınlamak
İki NFT akıllı sözleşme standardı arasındaki en büyük fark, ERC-1155'in çoklu token standardı olması ve toplu işlem işlevselliği içermesi, ERC-721'in ise tek token standardı olması ve bu nedenle aynı anda yalnızca bir token transferini desteklemesidir.
Basım işlevini çağırın
Genellikle, bu basım işlevi parametre olarak iki değişken geçirmenizi gerektirir; ilki, 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 değeridir.
Bir NFT'nin meta verisi, ona bir isim, açıklama, resim (veya farklı bir dijital varlık) ve diğer nitelikler gibi özelliklere sahip olmasını sağlayarak onu gerçekten hayata geçiren şeydir. İşte bir NFT'nin meta verilerini içeren bir tokenURI örneği (opens in a new tab).
Bu eğitimde, 2. bölüme, yani React kullanıcı arayüzümüzü kullanarak bir NFT akıllı sözleşmesi basım işlevini çağırmaya odaklanacağız.
Sepolia gibi desteklenen bir test ağına dağıtılmış bir ERC-721 NFT akıllı sözleşmesine ihtiyacınız olacak. Kendiniz bir tane dağıtmak isterseniz, Alchemy'nin Sepolia'ya bir akıllı sözleşme dağıtma (opens in a new tab) kılavuzunu öneririz.
Harika, artık 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
İlk olarak, bu proje için başlangıç dosyalarını almak üzere 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-files, bu proje için başlangıç dosyalarını (temelde React kullanıcı arayüzü) içerir. Bu eğitimde, 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ış eğitimin tamamını içerir ve takılırsanız bir referans olarak sizin için oradadır.
Ardından, kod düzenleyicinizde minter-starter-files kopyanızı açın ve ardından src klasörünüze gidin.
Yazacağımız tüm kodlar src klasörü 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.
2. Adım: Başlangıç dosyalarımızı inceleyin
Kodlamaya başlamadan önce, başlangıç dosyalarında bizim için nelerin sağlandığını kontrol etmek önemlidir.
React projenizi çalıştırın
React projesini tarayıcımızda ç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-files
npm install
Bunların yüklenmesi bittiğinde, terminalinizde npm start komutunu çalıştırın:
npm start
Bunu yapmak, tarayıcınızda projemizin ön yüzünü 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ı girmek için bir yer, NFT'nizin adını girmek ve bir açıklama sağlamak.
"Connect Wallet" (Cüzdanı Bağla) veya "Mint NFT" (NFT Bas) düğmelerine tıklamayı denerseniz, çalışmadıklarını fark edeceksiniz; bunun nedeni hala işlevlerini programlamamız gerekmesidir! :)
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.
//Durum değişkenleri
const [walletAddress, setWallet] = useState("")
const [status, setStatus] = useState("")
const [name, setName] = useState("")
const [description, setDescription] = useState("")
const [url, setURL] = useState("")
React durum değişkenlerini veya durum kancalarını (state hooks) hiç duymadınız mı? Bu (opens in a new tab) belgelere göz atın.
İşte değişkenlerin her birinin temsil ettiği şeyler:
walletAddress- kullanıcının cüzdan adresini saklayan bir dizestatus- kullanıcı arayüzünün altında görüntülenecek bir mesaj içeren bir dizename- NFT'nin adını saklayan bir dizedescription- NFT'nin açıklamasını saklayan bir dizeurl- NFT'nin dijital varlığına giden bir bağlantı olan bir dize
Durum değişkenlerinden sonra, uygulanmamış üç işlev göreceksiniz: useEffect, connectWalletPressed ve onMintPressed. Bu işlevlerin hepsinin async olduğunu fark edeceksiniz, bunun nedeni içlerinde asenkron API çağrıları yapacak olmamızdır! İsimleri işlevleriyle aynıdır:
useEffect(async () => {
//TODO: uygula
}, [])
const connectWalletPressed = async () => {
//TODO: uygula
}
const onMintPressed = async () => {
//TODO: uygula
}
useEffect(opens in a new tab) - bu, bileşeniniz oluşturulduktan sonra çağrılan bir React kancasıdır. İçine boş bir dizi[]prop'u geçirildiği için (bkz. satır 3), yalnızca bileşenin ilk oluşturulmasında çağrılacaktır. Burada, bir cüzdanın zaten bağlı olup olmadığını yansıtacak şekilde kullanıcı arayüzümüzü güncellemek için cüzdan dinleyicimizi ve başka bir cüzdan işlevini çağıracağız.connectWalletPressed- bu işlev, kullanıcının MetaMask cüzdanını dapp'imize bağlamak için çağrılacaktır.onMintPressed- bu işlev, 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ü var. 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 kimliklerine sahip düğmelere tıklandığında connectWalletPressed ve onMintPressed işlevlerinin çağrıldığını göreceksiniz.
//bileşenimizin kullanıcı arayüzü
return (
<div className="Minter">
<button id="walletButton" onClick={connectWalletPressed}>
{walletAddress.length > 0 ? (
"Connected: " +
String(walletAddress).substring(0, 6) +
"..." +
String(walletAddress).substring(38)
) : (
<span>Connect Wallet</span>
)}
</button>
<br></br>
<h1 id="title">🧙♂️ Alchemy NFT Minter</h1>
<p>
Simply add your asset's link, name, and description, then press "Mint."
</p>
<form>
<h2>🖼 Link to asset: </h2>
<input
type="text"
placeholder="e.g., https://gateway.pinata.cloud/ipfs/<hash>"
onChange={(event) => setURL(event.target.value)}
/>
<h2>🤔 Name: </h2>
<input
type="text"
placeholder="e.g., My first NFT!"
onChange={(event) => setName(event.target.value)}
/>
<h2>✍️ Description: </h2>
<input
type="text"
placeholder="e.g., Even cooler than cryptokitties ;)"
onChange={(event) => setDescription(event.target.value)}
/>
</form>
<button id="mintButton" onClick={onMintPressed}>
Mint NFT
</button>
<p id="status">{status}</p>
</div>
)
Son olarak, bu Minter bileşeninin nereye eklendiğini ele alalım.
React'te diğer tüm bileşenler için bir kapsayıcı görevi gören ana bileşen olan App.js dosyasına giderseniz, Minter bileşenimizin 7. satırda enjekte edildiğini göreceksiniz.
Bu eğitimde, yalnızca Minter.js file dosyasını düzenleyecek ve src klasörümüze dosyalar ekleyeceğiz.
Artık neyle çalıştığımızı anladığımıza göre, Ethereum cüzdanımızı kuralım!
Ethereum cüzdanınızı kurun
Kullanıcıların akıllı sözleşmenizle etkileşime girebilmesi için Ethereum cüzdanlarını dapp'inize bağlamaları gerekecektir.
MetaMask'ı İndirin
Bu eğitim için, Ethereum hesap adresinizi yönetmek için kullanılan tarayıcıdaki sanal bir cüzdan olan MetaMask'ı kullanacağız. Ethereum'daki işlemlerin nasıl çalıştığı hakkında daha fazla bilgi edinmek istiyorsanız, bu sayfaya göz atın.
Buradan (opens in a new tab) ücretsiz olarak MetaMask'ı indirebilir ve bir hesap oluşturabilirsiniz. Bir hesap oluştururken veya zaten bir hesabınız varsa, Sepolia gibi desteklenen bir test ağına geçtiğinizden emin olun (böylece gerçek parayla işlem yapmamış oluruz).
Bir Musluktan Ether ekleyin
NFT'lerimizi basmak (veya Ethereum Blokzincirinde herhangi bir işlemi imzalamak) için biraz sahte ETH'ye ihtiyacımız olacak. Test ağı ETH'si almak için Alchemy Sepolia musluğu (opens in a new tab) gibi aktif olarak bakımı yapılan bir musluk kullanın ve Sepolia hesap adresinizi girin. Kısa bir süre sonra MetaMask hesabınızda ETH görmelisiniz!
Bakiyenizi kontrol edin
Bakiyemizin orada olduğundan emin olmak için, Alchemy'nin korumalı alan 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ürecektir. MetaMask hesap adresinizi girip "Send Request" (İsteği Gönder) düğmesine tıkladıktan sonra, şuna benzer bir yanıt görmelisiniz:
{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}
NOT: Bu sonuç ETH değil, Wei cinsindendir. Wei, Ether'in en küçük birimi olarak kullanılır. Wei'den ETH'ye dönüşüm şöyledir: 1 ETH = 10¹⁸ Wei. Yani 0xde0b6b3a7640000 değerini ondalık sayıya dönüştürürsek, 1 ETH'ye eşit olan 1*10¹⁸ elde ederiz.
Oh be! Sahte paramızın hepsi orada!
MetaMask'ı Kullanıcı Arayüzünüze Bağlayın
Artık MetaMask cüzdanımız kurulduğuna göre, dapp'imizi ona bağlayalım!
MVC (opens in a new tab) paradigmasına uymak istediğimizden, dapp'imizin mantığını, verilerini ve kurallarını yönetecek işlevlerimizi içeren ayrı bir dosya oluşturacağız ve ardından bu işlevleri ön yüzümüze (Minter.js bileşenimize) aktaracağız.
connectWallet işlevi
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 işlevlerimizi içerecek olan interact.js adında bir dosya ekleyelim.
interact.js dosyamızda, daha sonra Minter.js bileşenimize içe aktarıp çağıracağımız bir connectWallet işlevi yazacağız.
interact.js dosyanıza aşağıdakileri ekleyin
export const connectWallet = async () => {
if (window.ethereum) {
try {
const addressArray = await window.ethereum.request({
method: "eth_requestAccounts",
})
const obj = {
status: "👆🏽 Write a message in the text-field above.",
address: addressArray[0],
}
return obj
} catch (err) {
return {
address: "",
status: "😥 " + err.message,
}
}
} else {
return {
address: "",
status: (
<span>
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your
browser.
</a>
</p>
</span>
),
}
}
}
Bu kodun ne yaptığını inceleyelim:
İlk olarak, işlevimiz tarayıcınızda window.ethereum nesnesinin etkin olup olmadığını kontrol eder.
window.ethereum, MetaMask ve diğer cüzdan sağlayıcıları tarafından enjekte edilen 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 blokzincirlerden veri 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'ın yüklü olmadığı anlamına gelir. Bu, döndürülen address değerinin boş bir dize olduğu ve status JSX nesnesinin kullanıcının MetaMask'ı yüklemesi gerektiğini ilettiği bir JSON nesnesinin döndürülmesiyle sonuçlanır.
Yazdığımız işlevlerin çoğu, durum değişkenlerimizi ve kullanıcı arayüzümüzü güncellemek için kullanabileceğimiz JSON nesneleri döndürecektir.
Şimdi eğer window.ethereum mevcut ise, işte 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'a bağlanmaya çalışacağız. Bu işlevi çağırmak, tarayıcıda MetaMask'ı açacak ve kullanıcıdan cüzdanını dapp'inize bağlaması istenecektir.
- Kullanıcı bağlanmayı seçerse,
method: "eth_requestAccounts", kullanıcının dapp'e bağlı olan tüm hesap adreslerini içeren bir dizi döndürecektir. Sonuç olarak,connectWalletişlevimiz, bu dizideki ilkaddressadresini (bkz. satır 9) ve kullanıcıdan akıllı sözleşmeye bir mesaj yazmasını isteyen birstatusmesajı 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çerecektir.
Minter.js Kullanıcı Arayüzü Bileşeninize connectWallet işlevini ekleyin
Artık bu connectWallet işlevini yazdığımıza göre, onu Minter.js. bileşenimize bağlayalım.
İlk olarak, Minter.js dosyasının en üstüne import { connectWallet } from "./utils/interact.js"; ekleyerek işlevimizi Minter.js dosyamıza içe aktarmamız gerekecek. Minter.js dosyanızın ilk 11 satırı artık şöyle görünmelidir:
import { useEffect, useState } from "react";
import { connectWallet } from "./utils/interact.js";
const Minter = (props) => {
//Durum değişkenleri
const [walletAddress, setWallet] = useState("");
const [status, setStatus] = useState("");
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [url, setURL] = useState("");
Ardından, connectWalletPressed işlevimizin içinde, içe aktarılan connectWallet işlevimizi şu şekilde çağıracağız:
const connectWalletPressed = async () => {
const walletResponse = await connectWallet()
setStatus(walletResponse.status)
setWallet(walletResponse.address)
}
İşlevselliğimizin çoğunun interact.js dosyasından Minter.js bileşenimizden nasıl soyutlandığına dikkat ettiniz mi? Bu, M-V-C paradigmasına uymamız içindir!
connectWalletPressed içinde, içe aktarılan connectWallet işlevimize basitçe 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, hem Minter.js hem de interact.js dosyalarını kaydedelim ve şimdiye kadarki kullanıcı arayüzümüzü test edelim.
Tarayıcınızı localhost:3000 adresinde açın ve sayfanın sağ üst köşesindeki "Connect Wallet" (Cüzdanı Bağla) düğmesine basın.
MetaMask yüklüyse, cüzdanınızı dapp'inize bağlamanız istenecektir. Bağlanma davetini kabul edin.
Cüzdan düğmesinin artık adresinizin bağlı olduğunu yansıttığını görmelisiniz.
Ardından, sayfayı yenilemeyi deneyin... bu garip. Cüzdan düğmemiz, zaten bağlı olmasına rağmen bizden MetaMask'ı bağlamamızı istiyor...
Yine de endişelenmeyin! Bir adresin dapp'imize zaten bağlı olup olmadığını kontrol edecek ve kullanıcı arayüzümüzü buna göre güncelleyecek olan getCurrentWalletConnected adlı bir işlevi uygulayarak bunu kolayca düzeltebiliriz!
getCurrentWalletConnected işlevi
interact.js dosyanıza aşağıdaki getCurrentWalletConnected işlevini ekleyin:
export const getCurrentWalletConnected = async () => {
if (window.ethereum) {
try {
const addressArray = await window.ethereum.request({
method: "eth_accounts",
})
if (addressArray.length > 0) {
return {
address: addressArray[0],
status: "👆🏽 Write a message in the text-field above.",
}
} else {
return {
address: "",
status: "🦊 Connect to MetaMask using the top right button.",
}
}
} catch (err) {
return {
address: "",
status: "😥 " + err.message,
}
}
} else {
return {
address: "",
status: (
<span>
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your
browser.
</a>
</p>
</span>
),
}
}
}
Bu kod, az önce yazdığımız connectWallet işlevine çok benzer.
Temel fark, kullanıcının cüzdanını bağlaması için MetaMask'ı açan eth_requestAccounts yöntemini çağırmak yerine, burada basitçe şu anda dapp'imize bağlı olan MetaMask adreslerini içeren bir dizi döndüren eth_accounts yöntemini çağırmamızdır.
Bu işlevi çalışırken görmek için, onu Minter.js bileşenimizin useEffect işlevinde çağıralım.
connectWallet için yaptığımız gibi, bu işlevi interact.js dosyamızdan Minter.js dosyamıza şu şekilde içe aktarmalıyız:
import { useEffect, useState } from "react"
import {
connectWallet,
getCurrentWalletConnected, //buraya içe aktar
} from "./utils/interact.js"
Şimdi, onu basitçe useEffect işlevimizde çağırıyoruz:
useEffect(async () => {
const { address, status } = await getCurrentWalletConnected()
setWallet(address)
setStatus(status)
}, [])
Dikkat edin, walletAddress ve status durum değişkenlerimizi güncellemek için getCurrentWalletConnected çağrımızın yanıtını 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'ı uygulayın
Dapp cüzdan kurulumumuzdaki son adım, kullanıcı bağlantıyı kestiğinde veya hesap değiştirdiğinde olduğu gibi cüzdanımızın durumu değiştiğ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 işlevi ekleyin:
function addWalletListener() {
if (window.ethereum) {
window.ethereum.on("accountsChanged", (accounts) => {
if (accounts.length > 0) {
setWallet(accounts[0])
setStatus("👆🏽 Write a message in the text-field above.")
} else {
setWallet("")
setStatus("🦊 Connect to MetaMask using the top right button.")
}
})
} else {
setStatus(
<p>
{" "}
🦊 <a target="_blank" href={`https://metamask.io/download`}>
You must install MetaMask, a virtual Ethereum wallet, in your browser.
</a>
</p>
)
}
}
Burada neler olduğunu hızlıca inceleyelim:
- İlk olarak, işlevimiz
window.ethereumnesnesinin etkin olup olmadığını (yani MetaMask'ın yüklü olup olmadığını) kontrol eder.- Değilse,
statusdurum değişkenimizi kullanıcıdan MetaMask'ı yüklemesini isteyen bir JSX dizesine ayarlarız. - Etkinse, 3. satırda MetaMask cüzdanındaki durum değişikliklerini dinleyen
window.ethereum.on("accountsChanged")dinleyicisini kurarız; bu değişiklikler kullanıcının dapp'e ek bir hesap bağlamasını, hesap değiştirmesini veya bir hesabın bağlantısını kesmesini içerir. En az bir hesap bağlıysa,walletAddressdurum değişkeni, dinleyici tarafından döndürülenaccountsdizisindeki ilk hesap olarak güncellenir. Aksi takdirde,walletAddressboş bir dize olarak ayarlanır.
- Değilse,
Son olarak, onu useEffect işlevimizde çağırmalıyız:
useEffect(async () => {
const { address, status } = await getCurrentWalletConnected()
setWallet(address)
setStatus(status)
addWalletListener()
}, [])
Ve işte oldu! Tüm cüzdan işlevselliğimizi programlamayı tamamladık! Artık cüzdanımız kurulduğuna göre, NFT'mizi nasıl basacağımızı bulalım!
NFT Meta Verisi 101
Bu eğitimin 0. Adımında bahsettiğimiz NFT meta verilerini hatırlayın; bir NFT'yi hayata geçirerek dijital varlık, isim, açıklama ve diğer nitelikler gibi özelliklere sahip olmasını sağlar.
Bu meta veriyi bir JSON nesnesi olarak yapılandırmamız ve saklamamız gerekecek, böylece akıllı sözleşmemizin mintNFT işlevini çağırırken onu tokenURI parametresi olarak geçirebiliriz.
"Link to Asset" (Varlığa Bağlantı), "Name" (İsim), "Description" (Açıklama) alanlarındaki metinler, NFT'mizin meta verilerinin farklı özelliklerini oluşturacaktır. Bu meta veriyi bir JSON nesnesi olarak biçimlendireceğiz, ancak bu JSON nesnesini nerede saklayabileceğimiz konusunda birkaç seçenek var:
- Onu Ethereum blokzincirinde saklayabiliriz; ancak bunu yapmak çok pahalı olacaktır.
- Onu AWS veya Firebase gibi merkezi bir sunucuda saklayabiliriz. Ancak bu, merkeziyetsizlik anlayışımıza ters düşer.
- 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 saklamak için kullanışlı bir IPFS API'si ve araç seti olan Pinata (opens in a new tab)'yı kullanacağız. Bir sonraki adımda, bunu tam olarak nasıl yapacağımızı açıklayacağız!
Meta verilerinizi IPFS'ye 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, Admin (Yönetici) aracını etkin olarak ayarlayın ve anahtarınızı adlandırın.
Daha sonra 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, kullanabilmemiz için onu projemize ekleyelim.
Bir .env dosyası oluşturun
Pinata anahtarımızı ve gizli anahtarımızı bir ortam dosyasında güvenle saklayabiliriz. Proje dizininize dotenv paketini (opens in a new tab) kuralım.
Terminalinizde (yerel ana bilgisayarı çalıştıran sekmeden ayrı olarak) yeni bir sekme açın ve minter-starter-files klasöründe olduğunuzdan emin olun, ardından terminalinizde aşağıdaki komutu çalıştırın:
npm install dotenv --save
Ardından, komut satırınıza aşağıdakileri girerek minter-starter-files klasörünüzün kök dizininde bir .env dosyası oluşturun:
vim.env
Bu, .env dosyanızı vim'de (bir metin düzenleyici) açacaktır. Kaydetmek için klavyenizde sırasıyla "esc" + ":" + "q" tuşlarına basın.
Ardından, VSCode'da .env dosyanıza gidin ve Pinata API anahtarınızı ve API gizli anahtarınızı şu şekilde ekleyin:
REACT_APP_PINATA_KEY = <pinata-api-key>
REACT_APP_PINATA_SECRET = <pinata-api-secret>
Dosyayı kaydedin ve ardından JSON meta verilerinizi IPFS'ye yüklemek için işlevi yazmaya başlamaya hazırsınız!
pinJSONToIPFS'yi uygulayın
Neyse ki bizim için 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 gizli anahtarımızı ve anahtarımızı .env dosyasından şu şekilde içe aktaralım:
require("dotenv").config()
const key = process.env.REACT_APP_PINATA_KEY
const secret = process.env.REACT_APP_PINATA_SECRET
Ardından, aşağıdaki ek kodu pinata.js dosyanıza yapıştırın. Endişelenmeyin, her şeyin ne anlama geldiğini açıklayacağız!
require("dotenv").config()
const key = process.env.REACT_APP_PINATA_KEY
const secret = process.env.REACT_APP_PINATA_SECRET
const axios = require("axios")
export const pinJSONToIPFS = async (JSONBody) => {
const url = `https://api.pinata.cloud/pinning/pinJSONToIPFS`
//Pinata'ya axios POST isteği yapılıyor ⬇️
return axios
.post(url, JSONBody, {
headers: {
pinata_api_key: key,
pinata_secret_api_key: secret,
},
})
.then(function (response) {
return {
success: true,
pinataUrl:
"https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash,
}
})
.catch(function (error) {
console.log(error)
return {
success: false,
message: error.message,
}
})
}
Peki 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)'u içe aktarır.
Ardından, pinJSONToIPFS API'lerine bir POST isteği yapmak için girdi olarak bir JSONBody ve başlığında Pinata api anahtarı ile gizli anahtarını alan asenkron pinJSONToIPFS işlevimiz var.
- Bu POST isteği başarılı olursa, işlevimiz
successboolean değeri true olan ve meta verilerimizin sabitlendiğipinataUrldeğerini içeren bir JSON nesnesi döndürür. Döndürülen bupinataUrldeğerini akıllı sözleşmemizin basım işlevinetokenURIgirdisi olarak kullanacağız. - Bu post isteği başarısız olursa, işlevimiz
successboolean değeri false olan ve hatamızı ileten birmessagedizesi içeren bir JSON nesnesi döndürür.
connectWallet işlevi dönüş türlerimizde olduğu gibi, parametrelerini durum değişkenlerimizi ve kullanıcı arayüzümüzü güncellemek için kullanabilmemiz amacıyla JSON nesneleri döndürüyoruz.
Akıllı sözleşmenizi yükleyin
Artık pinJSONToIPFS işlevimiz aracılığıyla NFT meta verilerimizi IPFS'ye yüklemenin bir yoluna sahip olduğumuza göre, mintNFT işlevini ç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 eğitimde bu mevcut NFT akıllı sözleşmesini (opens in a new tab) kullanacağız; ancak, onu nasıl yaptığımızı öğrenmek veya kendiniz bir tane yapmak isterseniz, diğer eğitimimiz olan "Nasıl NFT Oluşturulur" (opens in a new tab) eğitimine 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 ABI, bir sözleşmenin hangi işlevi çağıracağını belirlemenin yanı sıra işlevin verileri beklediğiniz biçimde döndürmesini sağlamak için gereklidir.
Ayrıca Ethereum blokzincirine 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 oluşturarak bir API anahtarı üretebilirsiniz. Bu, Sepolia test ağına istekte bulunmamızı sağlayacaktır.
Gezinme çubuğunda "Apps" (Uygulamalar) üzerine gelip "Create App" (Uygulama Oluştur) seçeneğine tıklayarak Alchemy Kontrol Panelinizdeki "Create App" sayfasına gidin.
Uygulamanızı adlandırın (biz "My First NFT!" seçtik), kısa bir açıklama sunun, uygulamanızın defter tutma işlemleri için kullanılan Ortam (Environment) için "Staging"i seçin ve ağınız için "Sepolia"yı seçin.
"Create app"e tıklayın ve işte bu kadar! Uygulamanız aşağıdaki tabloda görünmelidir.
Harika, artık HTTP Alchemy API URL'mizi oluşturduğumuza göre, onu panonuza kopyalayın...
…ve ardından onu .env dosyamıza ekleyelim. Genel olarak, .env dosyanız şöyle görünmelidir:
REACT_APP_PINATA_KEY = <pinata-key>
REACT_APP_PINATA_SECRET = <pinata-secret>
REACT_APP_ALCHEMY_KEY = https://eth-sepolia.g.alchemy.com/v2/<alchemy-key>
Artık sözleşme ABI'mize ve Alchemy API anahtarımıza sahip olduğumuza 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 kurun
İlk olarak, eğer henüz sahip değilseniz, terminalde ana dizine: nft-minter-tutorial giderek Alchemy Web3 (opens in a new tab)'ü kurmanız gerekecektir:
cd ..
npm install @alch/alchemy-web3
Ardından interact.js dosyamıza geri dönelim. Dosyanın en üstüne, Alchemy anahtarınızı .env dosyanızdan içe aktarmak ve Alchemy Web3 uç noktanızı kurmak için aşağıdaki kodu ekleyin:
require("dotenv").config()
const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(alchemyKey)
Alchemy Web3 (opens in a new tab), bir web3 geliştiricisi olarak hayatınızı kolaylaştırmak için gelişmiş API yöntemleri ve diğer önemli avantajlar sağlayan Web3.js (opens in a new tab) etrafında bir sarmalayıcıdır. Uygulamanızda hemen kullanmaya başlayabilmeniz için minimum yapılandırma gerektirecek şekilde tasarlanmıştır!
Ardından, sözleşme ABI'mizi ve sözleşme adresimizi dosyamıza ekleyelim.
require("dotenv").config()
const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(alchemyKey)
const contractABI = require("../contract-abi.json")
const contractAddress = "0x4C4a07F737Bf57F6632B6CAB089B78f62385aCaE"
Bunların her ikisine de sahip olduğumuzda, basım işlevimizi kodlamaya başlamaya hazırız!
mintNFT işlevini uygulayın
interact.js dosyanızın içinde, adından da anlaşılacağı gibi NFT'mizi basacak olan mintNFT işlevimizi tanımlayalım.
Çok sayıda asenkron ç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'a), işlevimiz de asenkron olacaktır.
İşlevimize üç girdi, dijital varlığımızın url değeri, name ve description olacaktır. connectWallet işlevinin altına aşağıdaki işlev imzasını ekleyin:
export const mintNFT = async (url, name, description) => {}
Girdi hatası işleme
Doğal olarak, işlevin başlangıcında bir tür girdi hatası işlemeye sahip olmak mantıklıdır, böylece girdi parametrelerimiz doğru değilse bu işlevden çıkarız. İşlevimizin içine aşağıdaki kodu ekleyelim:
export const mintNFT = async (url, name, description) => {
//hata yönetimi
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
}
Temel olarak, girdi parametrelerinden herhangi biri boş bir dizeyse, success boolean değerinin false olduğu ve status dizesinin kullanıcı arayüzümüzdeki tüm alanların eksiksiz olması gerektiğini ilettiği bir JSON nesnesi döndürürüz.
Meta verileri IPFS'ye yükleyin
Meta verilerimizin düzgün biçimlendirildiğini bildiğimizde, bir sonraki adım onu bir JSON nesnesine sarmak ve yazdığımız pinJSONToIPFS aracılığıyla IPFS'ye yüklemektir!
Bunu yapmak için, önce pinJSONToIPFS işlevini interact.js dosyamıza içe aktarmamız gerekir. interact.js dosyasının en üstüne şunu ekleyelim:
import { pinJSONToIPFS } from "./pinata.js"
pinJSONToIPFS işlevinin bir JSON gövdesi aldığını hatırlayın. Bu yüzden ona bir çağrı yapmadan önce, url, name ve description parametrelerimizi bir JSON nesnesi olarak biçimlendirmemiz gerekecek.
metadata adında bir JSON nesnesi oluşturmak için kodumuzu güncelleyelim ve ardından bu metadata parametresiyle pinJSONToIPFS işlevine bir çağrı yapalım:
export const mintNFT = async (url, name, description) => {
//hata yönetimi
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
//meta veri oluştur
const metadata = new Object()
metadata.name = name
metadata.image = url
metadata.description = description
//Pinata çağrısı yap
const pinataResponse = await pinJSONToIPFS(metadata)
if (!pinataResponse.success) {
return {
success: false,
status: "😢 Something went wrong while uploading your tokenURI.",
}
}
const tokenURI = pinataResponse.pinataUrl
}
Dikkat 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ıyoruz.
Bir hata varsa, success boolean değerinin false olduğu ve status dizemizin çağrımızın başarısız olduğunu ilettiği bir JSON nesnesi döndürürüz. Aksi takdirde, pinataURL değerini pinataResponse nesnesinden çıkarır ve tokenURI değişkenimiz olarak saklarız.
Şimdi dosyamızın en üstünde başlattığımız Alchemy Web3 API'sini kullanarak akıllı sözleşmemizi yükleme zamanı. Sözleşmeyi window.contract küresel değişkeninde ayarlamak için mintNFT işlevinin altına aşağıdaki kod satırını ekleyin:
window.contract = await new web3.eth.Contract(contractABI, contractAddress)
mintNFT işlevimize eklenecek son şey Ethereum işlemimizdir:
//Ethereum işleminizi ayarlayın
const transactionParameters = {
to: contractAddress, // Sözleşme yayınları dışında gereklidir.
from: window.ethereum.selectedAddress, // kullanıcının aktif adresiyle eşleşmelidir.
data: window.contract.methods
.mintNFT(window.ethereum.selectedAddress, tokenURI)
.encodeABI(), //NFT akıllı sözleşmesine çağrı yap
}
//işlemi MetaMask aracılığıyla imzala
try {
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
})
return {
success: true,
status:
"✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +
txHash,
}
} catch (error) {
return {
success: false,
status: "😥 Something went wrong: " + error.message,
}
}
Ethereum işlemlerine zaten aşinaysanız, yapının gördüklerinize oldukça benzer olduğunu fark edeceksiniz.
- İlk olarak, işlem parametrelerimizi ayarlıyoruz.
toalıcı adresini (akıllı sözleşmemizi) belirtirfromişlemin imzalayıcısını (kullanıcının MetaMask'a bağlı adresi:window.ethereum.selectedAddress) belirtirdata,tokenURIdeğerimizi ve kullanıcının cüzdan adresi olanwindow.ethereum.selectedAddressdeğerini girdi olarak alan akıllı sözleşmemintNFTyöntemimize yapılan çağrıyı içerir
- Ardından, MetaMask'tan işlemi imzalamasını istediğimiz bir await çağrısı olan
window.ethereum.request,yaparız. Dikkat edin, bu istekte eth yöntemimizi (eth_SentTransaction) belirtiyor vetransactionParametersparametremizi geçiriyoruz. Bu noktada, MetaMask tarayıcıda açılacak ve kullanıcıdan işlemi imzalamasını veya reddetmesini isteyecektir.- İşlem başarılı olursa, işlev
successboolean değerinin true olarak ayarlandığı vestatusdizesinin kullanıcıdan işlemi hakkında daha fazla bilgi için Etherscan'i kontrol etmesini istediği bir JSON nesnesi döndürecektir. - İşlem başarısız olursa, işlev
successboolean değerinin false olarak ayarlandığı vestatusdizesinin hata mesajını ilettiği bir JSON nesnesi döndürecektir.
- İşlem başarılı olursa, işlev
Sonuç olarak, mintNFT işlevimiz şöyle görünmelidir:
export const mintNFT = async (url, name, description) => {
//hata yönetimi
if (url.trim() == "" || name.trim() == "" || description.trim() == "") {
return {
success: false,
status: "❗Please make sure all fields are completed before minting.",
}
}
//meta veri oluştur
const metadata = new Object()
metadata.name = name
metadata.image = url
metadata.description = description
//Pinata sabitleme isteği
const pinataResponse = await pinJSONToIPFS(metadata)
if (!pinataResponse.success) {
return {
success: false,
status: "😢 Something went wrong while uploading your tokenURI.",
}
}
const tokenURI = pinataResponse.pinataUrl
//akıllı sözleşmeyi yükle
window.contract = await new web3.eth.Contract(contractABI, contractAddress) //loadContract();
//Ethereum işleminizi ayarlayın
const transactionParameters = {
to: contractAddress, // Sözleşme yayınları dışında gereklidir.
from: window.ethereum.selectedAddress, // kullanıcının aktif adresiyle eşleşmelidir.
data: window.contract.methods
.mintNFT(window.ethereum.selectedAddress, tokenURI)
.encodeABI(), //NFT akıllı sözleşmesine çağrı yap
}
//işlemi MetaMask aracılığıyla imzala
try {
const txHash = await window.ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
})
return {
success: true,
status:
"✅ Check out your transaction on Etherscan: https://ropsten.etherscan.io/tx/" +
txHash,
}
} catch (error) {
return {
success: false,
status: "😥 Something went wrong: " + error.message,
}
}
}
Bu devasa bir işlev! Şimdi, sadece mintNFT işlevimizi Minter.js bileşenimize bağlamamız gerekiyor...
mintNFT'yi Minter.js ön yüzümüze 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:
import {
connectWallet,
getCurrentWalletConnected,
mintNFT,
} from "./utils/interact.js"
Son olarak, içe aktarılan mintNFT işlevinize await çağrısı yapmak için onMintPressed işlevini uygulayın ve işlemimizin başarılı olup olmadığını yansıtacak şekilde status durum değişkenini güncelleyin:
const onMintPressed = async () => {
const { status } = await mintNFT(url, name, description)
setStatus(status)
}
NFT'nizi canlı bir web sitesine dağıtın
Kullanıcıların etkileşime girmesi için projenizi canlıya almaya hazır mısınız? Minter'ınızı canlı bir web sitesine dağıtmak için React dağıtım belgelerine (opens in a new tab) göz atın.
Son bir adım...
Blokzincir dünyasını kasıp kavurun
Şaka yapıyorum, eğitimin sonuna geldiniz!
Özetlemek gerekirse, bir NFT basım aracı oluşturarak şunları başarıyla öğrendiniz:
- Ön yüz projeniz aracılığıyla MetaMask'a bağlanmak
- Ön yüzünüzden akıllı sözleşme yöntemlerini çağırmak
- MetaMask kullanarak işlemleri imzalamak
Muhtemelen, dapp'iniz aracılığıyla basılan NFT'leri cüzdanınızda sergilemek istersiniz; bu nedenle Cüzdanınızda NFT'nizi Nasıl Görüntülersiniz adlı hızlı eğitimimize göz atmayı unutmayın!
Ve her zaman olduğu gibi, herhangi bir sorunuz varsa, Alchemy Discord (opens in a new tab)'unda yardımcı olmak için buradayız. Bu eğitimdeki kavramları gelecekteki projelerinize nasıl uygulayacağınızı görmek için sabırsızlanıyoruz!