0'dan Ethereum DApp Oluşturma Rehberi

Murat Celiktepe
BlockchainIST Center
9 min readMay 31, 2021
ethereum

Herkese merhabalar, twitter’dan da paylaştığım Nader Dabit adlı kullanıcı tarafından yazılan şu makalenin içeriği oldukça kaliteli ve zengin olduğu için bunun türkçe versiyonunu kendi yorumlarımı katarak sizler için yazmak istedim.

Bu makale de ethereum üzerinde bir DApp(Decentralized Application) geliştirmek için ihtiyacınız olan hemen hemen her şeyi kullanıyor olacaksınız. Makelenin içerisinde temek olarak göreceğiniz konseptler şunlardır;

  • Solidity (Akıllı kontrat dili)
  • Ethers (Ethereum web sunucu kütüphanesi)
  • Hardhat (Ethereum geliştirme ortamı)
  • Metamask (Ethereum wallet)
  • Infura veya Alchemy
  • React

Bu rehberde aslında dikkat etmenizi ve öğrenmenizi istediğim şey bir DApp’i compile etme, hem local hemde ethereum testnet ağına deploy etme, frontend ile haberleştirebilme gibi uygulamalar. Yapacağımız DApp’i önce hardhat yardımı ile localimizdeki ethereum ağına, sonra ethereum’un kendi testnet ağlarından birine deploy edeceğiz ve etkileşime geçeceğiz. Ben react bilmiyorum gibi bir endişeye kapıldıysanız, yapacağımız işlerde react öğrenmek bizim ana amacımız değil. Bu yüzden temel anlamda kodun ne yaptığını anlasak yeterli olacaktır.

Bu makalede her yerde görülen token oluşturma, göndermek yerine bir kontrata nasıl veri yazılır ve nasıl veri okunur gibi konseptler üzerine yoğunlaşacağız. Bunu kontrat yazmaya yeni başlayanların ilk karşısına çıkan Greeting kontratı ile yapacağız. Burda kontrat çok basit vs. gibi düşünebilirsiniz ama amacımız bu kontratı nasıl deploy edeceğimiz, nasıl frontend aracılığıyla etkileşime gireceğimizdir.

Hazırsanız hadi başlayalım…

Öncelikle npx ile basit bir react app oluşturalım. (Eğer npx bilgisayarınızda yoksa şuradan edinebilirsiniz.)

npx create-react-app ethereum-dapp
cd ethereum-dapp

Oluşturduğumuz dApp klasörüne girdikten sonra aşağıdaki komut ile ihtiyacımız olan kütüphaneleri yükleyelim.

npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers

Bu kütüphanelerin ne işe yaradıklarını kullandığımız zaman detaylı anlayacağız. Şimdi hardhat ile ethereum geliştirme ortamı kuralım.

npx hardhat
hardhat

böyle bir ekran gelecek ve 2–3 seçenekli soru soracak. Benim seçtiklerimin aynısını seçip devam edin.

Hardhat komutundan sonra klasörümüze bir takım ek dosya ve klasörlerin eklenmiş olması lazım. Contract klasörü ve içinde bir kontrat dosyası gibi. Bunlardan önemli olarak;

  • hardhat.config.js → hardhat konfigürasyon ve pluginleri bu dosya içerisinde bulunuyor.
  • scripts → İçerisinde sample-script.js adından bir dosya bulunuyor ve kontratımızı deploy edecek kod parçacığını içeriyor.
  • contracts → Adından da anlaşılacağı üzere kontratlarımızın içerisinde bulunduğu klasörümüz.

Ben VS Code editörünü kullanıyorum size de tavsiye ederim. İstemezseniz farklı bir kod editörü de kullanabilirsiniz. Projeyi vs code üzerinde açalım ve devam edelim.

Şimdi hardhat.config.js dosyasını açıp içindeki kodlarla aşağıdaki kodları değiştirelim.

require("@nomiclabs/hardhat-waffle");module.exports = {
solidity: "0.8.3",
paths: {
artifacts: './src/artifacts',
},
networks: {
hardhat: {
chainId: 1337
}
}
};

Burda sadece chainId olarak metamask uyumlu olması için 1337 girdik.

hardhat.config.js

Dosyanın son hali yandaki gibi olmalıdır.

Şimdi ise kontrat dosyamızı inceleyelim.

smart contract

Bu oldukça basit bir akıllı kontrat örneğidir. Yaptığı tek şey deploy edildiğinde bir değişken tutmak ve bu değişkeni okuma-yazma imkanı sunmaktır. Constructor , diğer dillerden de hakim olduğumuz gibi, kontrat deploy edildiğinde bir defaya mahsus çalışan bir fonksiyondur.

Burada deploy edilirken bir stringalıyor ve bunu değişkene yazıyor. Aslında teknik olarak bunu ethereuma yazıyor gibi düşünebilirsiniz. Ardından set-get fonksiyonları tanımlanmış.

Kısaca greet fonksiyonu değişkeni döndüren bir işlevi yerine getirirken, setGreetingise aldığı string parametresini değişkene yazma görevi gerçekleştiriyor.

Konudan bağımsız olarak kontrattan veri okumak ücretsiz iken veri yazmak ücretli bir işlemdir.

Son olarak pragma solidity ^0.8.3; bizim solidity versiyonumuzu belirtiyor. Bu versiyonun hardhat.config.js içerisine yazdığımız versiyon ile aynısını olduğuna dikkat edin.

Kontrat ile frontend üzerinde ethers aracılığıyla haberleşeceğiz. Bunun için bize kontrat ABI ve kontrat adresi gerekiyor. Bu bilgileri bize hardhat sağlayacak. Şimdi kontratımızı compile edelim. Terminalde şu komut satırını çalıştıralım.

npx hardhat compile
hardhat

Komutu çalıştırdan sonra böyle bir sonuç ekranı almanız gerekiyor. Bu başarılı bir şekilde kodumuzun derlendiğini gösteriyor.

Şimdi src klasöründe artifacts adında klasör oluşturulduğunu göreceksiniz. artifacts/contracts/Greeter.json dosyası ihtiyacımız olan ABI‘yi içeriyor. Her ihtiyacımız olduğunda javascript dosyasının içinde şu şekilde erişebiliriz.

import Greeter from './artifacts/contracts/Greeter.sol/Greeter.json'

Evet şimdi ise öncelikle kontratı local’imize nasıl deploy edeceğimizi görelim. Farklı bir terminal açalım, yine aynı klasöre (bende “ethereum-dApp”) gidelim ve aşağıdaki komutu çalıştıralım.

npx hardhat node
hardhat

Burda göreceğiniz üzere kendi bilgisayarınızda bir blockchain node’u oluşturdu ve bize kullanabileceğimiz 20 tane hesap verdi. Bu hesapların her birinde 10000 fake ether bulunuyor. Oluşan blockchain ağı http://127.0.0.1:8545 adresini dinliyor ve bu adres-port aracalığıyla etkileşime gireceğiz. Ayrıca bu blockchaine metamask ile nasıl bağlacağımızı da birazdan göreceğiz.

Kontratımızı compile ettikten sonra şimdi de bu ağa deploy edelim. Bunun için öncelikle scripts klasöründe bulunan sample-script.js dosyasının adını deploy.js olarak değiştirelim. Bu tamamen dosyanın ne olduğu belli olsun diye yaptığımız bir şey ve yapmak zorunda da değilsiniz tabiki.

Şimdi node çalıştırdığımız terminali köşeye çekelim (kapatmayın sakın, çalışmaya devam etsin) ve bir önceki terminalimize geri dönelim. Aşağıdaki komutu çalıştıralım.

npx hardhat run scripts/deploy.js --network localhost

Uyarı olarak dosyanın ismini değiştirmediyseniz veya farklı bir şey yaptıysanız deploy.js ‘i onunla değiştirmeyi unutmayın.

hardhat

Eğer her şeyi eksiksiz yaptıysanız şöyle bir sonuç ile karşılaşmanız gerekiyor. Kontratımız başarılı bir şekilde deploy edildi. Kontrat adresimizi de bir yere yapıştıralım. Bu adres bizim client tarafında kontrat ile haberleşmek için kullacağımız adres olacaktır.

Şimdi metamask’i local blockchain’imize bağlayalım. Bunun için node çalıştırdığımız terminaldeki 20 hesaptan herhangi birini almamız gerekecek. Ben direk ilk hesabı alacağım. Öncelikle metamask’i açıp ağımıza bağlanalım.

metamask

Metamask’te yukarıda ağlar kısmına tıklayıp localhost 8545 olana tıklayalım. Bu bizi local ağa bağlayacaktır. Şimdide hardhat tarafından bize verilen 20 hesaptan birinin “private keyi” ile hesabımızı bağlayalım.

metamask

Sağ üstteki hesaplar ikonuna tıklayarak Import Wallet seçeneğine tıklayın. Çıkan sayfada Private Key tıklayıp, seçtiğiniz hesabın private key’ini buraya yapıştırın ve tamam deyin. Eğer 1. hesabın private key’ini seçtiyseniz 9999 küsürlü bir ether bakiyesi görmeniz gerekiyor. Bunun sebebi az önce kontrat deploy ederken fee ödemiş olmamız.

Buraya kadar başarılı gelebildiysek şimdi basit bir UI ile kontratla haberleşelim. Makalemizin amacı UI olmadığı için burda CSS ile vs. uğraşmayacağız. Tek ihtiyacımız olan şey kontrattaki değişkeni okuyabilmek ve kullanıcının bu değişkeni değiştirebilmesini sağlamak. Bunun için değişkeni okutmak için bir button ve değişkeni değiştirmek için bir input yeterli olacaktır.

Şimdi src/App.js ‘i açalım ve içindekileri temizleyelim. İçindekileri sildikten sonra aşağıdaki kodları olduğu gibi yapıştıralım.

import './App.css';
import { useState } from 'react';
import { ethers } from 'ethers'
import Greeter from './artifacts/contracts/Greeter.sol/Greeter.json'

// Update with the contract address logged out to the CLI when it was deployed
const greeterAddress = "Kontrat adresini buraya yapıştırınız."

function App() {
// store greeting in local state
const [greeting, setGreetingValue] = useState()

// request access to the user's MetaMask account
async function requestAccount() {
await window.ethereum.request({ method: 'eth_requestAccounts' });
}

// call the smart contract, read the current greeting value
async function fetchGreeting() {
if (typeof window.ethereum !== 'undefined') {
const provider = new ethers.providers.Web3Provider(window.ethereum)
const contract = new ethers.Contract(greeterAddress, Greeter.abi, provider)
try {
const data = await contract.greet()
console.log('data: ', data)
} catch (err) {
console.log("Error: ", err)
}
}
}

// call the smart contract, send an update
async function setGreeting() {
if (!greeting) return
if (typeof window.ethereum !== 'undefined') {
await requestAccount()
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner("Buraya seçtiğiniz accountun adresini yapıştırın")
const contract = new ethers.Contract(greeterAddress, Greeter.abi, signer)
const transaction = await contract.setGreeting(greeting)
await transaction.wait()
fetchGreeting()
}
}

return (
<div className="App">
<header className="App-header">
<button onClick={fetchGreeting}>Değişkeni Çek</button>
<button onClick={setGreeting}>Değişkeni Güncelle</button>
<input onChange={e => setGreetingValue(e.target.value)} placeholder="Set greeting" />
</header>
</div>
);
}

export default App;

Kod biraz javascript ile ilgili olduğu için tümünü detaylı anlatmaya gerek olduğunu düşünmüyorum. Sadece içerisinde önemli yerleri inceleyelim.

Öncelikle greeterAdress değişkenine deploy ettiğiniz kontrat adresimizi yapıştıralım. Aşağıda fetchGreeting() fonksiyonu temel olarak bizim değişkenimizi return ettiğimiz bir fonksiyondur. Fonksiyon içerisinde provider ve kontratımızı tanımlıyoruz. Kontrat tanımlamak için daha önceden de söylediğimiz gibi ABI ve kontrat adresi olmazsa olmaz şartımızdı. Ek olarak ethereum provider’ını verip kontratımızı contract değişkeninde tutuyoruz. Ardından da contract.greet() diyerek kontratta ki değişkenimizi çekiyoruz. Kontrattan veri okumak aslında bu kadar basit. Herhangi bir gas ücreti vs. ödemeniz gerekmiyor.

setGreeting() fonksiyonun da ise frontend tarafında state de tutulan değişkeni (kullanıcı tarafından girilen ve state’e kaydedilen) alıyoruz. Aynı şekilde ethereum provider tanımlıyoruz. Bu arada kafası karışanlar için belirtmekte fayda var. window.ethereum , metamask gibi bir cüzdanı provider olarak almamızı sağlıyor. Zaten kodda da göreceğiniz üzere önce undefined mı değil mi diye kontrol ediyoruz. Ardından signer kısmına kodda da belirttiğim üzere seçtiğiniz ethereum hesabının adresini yapıştıralım. Kontratı aynı şekilde tanımlıyoruz. Son olarak kontrat üzerindeki setGreeting() fonksiyonunu bizim değişkenimizi parametre olarak verecek şekilde çağırıyoruz. Bu kadar. Son olarak tekrar fetchGreeting() diyerek değişkenimiz güncellenmiş mi kontrol ediyoruz.

Şimdi bunu test etmek için terminalde şu komutu çalıştırarak projeyi başlatalım.

npm start

Projenin sizin metamask hesabını import ettiğiniz tarayıcıda başladığından emin olun. Ekranda sağ tık yapıp öğeyi denetle yapalım ve Console ekranını açalım. Şimdi “Değişkeni Çek” butonuna tıkladığımızda kontrattaki “Hello, Hardhat” değişkenini Console ekranında görebiliyor olmamız lazım. Text kısmına bir şeyler yazıp “Değişkeni Güncelle” butonuna tıkladığımızda bir metamask pop-up’ı görmemiz gerekiyor. Bu normalde de işlem yaparken onaylamak için çıkan pencere ile aynı pencere. Burda onayla dedikten sonra Console ekranında yeni değişkeni görmemiz gerekiyor.

Evet kısaca söylemek gerekirse bir akıllı kontrat ile bu şekilde haberleşebiliyoruz. Kontrattan veri okumak, veri yazmak vs. her şeyi ethers veya web3.js gibi kütüphaneler, hardhat gibi geliştirme ortamları sayesinde yapabiliyoruz.

Kontratı localimizdeki blockchain’e deploy etmeyi gördüğümüze göre şimdi de ethereum testnet’lerinden birine deploy edelim. Aslında ne kadar kolay ve benzer olduğunu kendiniz görünce şaşıracaksınız. Bu rehber için ethereum’un Ropsten Testnet ağını kullanacağız.

metamask

Öncelikle metamask’i Ropsten Testnet’ine bağlayalım.

Şimdi hesabımı hardhat’ten aldığımız hesap değilde normal metamask hesabımız olarak değiştirelim. Sonra şu faucet adresinden kendi adresimize fake ether gönderelim. hardhat.config.js dosyasında bazı değişiklikler yapmamız gerekiyor. Bunun için bizim bu metamask hesabımızın private key’ini export edip hardhat.config.js dosyasına yerleştirmemiz gerekiyor.

metamask

Export Private Key diyoruz ve bunu kopyalıyoruz. hardhat.config.js dosyasının module.exports kısmı aşağıdaki gibi olmalıdır. Burada Private Key buraya...yazan kısma bu kopyaladığınız private key’i yapıştırıyoruz.

Bunun dışında bizim bir ethereum node servisine ihtiyacımız var. Bunu da Infura veya Alchemy gibi servisler işimizi görecektir. Bu yazıda ben infura kullanacağım. Infura sitesine gidip bir hesap oluşturun.

infura

Hesap oluşturduktan sonra “Create a Project” diyelim. Projemize isim verdikten sonra projeyi oluşturacaktır.

infura

Ardından şöyle bir ekran bizi karşılıyor. Burda ENDPOINTS kısmından Ropsten seçelim. Aşağısında bize https ve wss ile başlayan iki link verecektir. Bunlardan https olanı kopyalayalım ve hardhat.config.js dosyasındaki URL kısmına yapıştıralım. Dosyamızın son hali aşağıdakine benzer bir şey olmalıdır.

require("@nomiclabs/hardhat-waffle");module.exports = {
defaultNetwork: "hardhat",
paths: {
artifacts: './src/artifacts',
},
networks: {
hardhat: {},
ropsten: {
url: "https://ropsten.infura.io/v3/your-project-id",
accounts: [`Private Key buraya...`]
}
},
solidity: "0.8.3",
};

Evet şimdi deploy aşamasına geçelim. Aşağıdaki komutu çalıştıralım ve deploy işlemini gerçekleştirelim.

npx hardhat run scripts/deploy.js --network ropsten

Bu diğerine göre ~17 saniye kadar sürecektir.

hardhat-ropsten

Ve görüldüğü üzere başarılı bir şekilde deploy edildi. Şimdi Etherscan Ropsten Network üzerinden kontrat adresinizle arama yaptığınızda kontratınızı görebileceksiniz.

Son olarak frontend de kontrat ile etkileşime geçmek için yukarıda hazırladığımız App.js dosyasının içinde sadece kontrat adresi ve signer adresini değiştirmelisiniz. Signer olarak ropsten ağında fake ether gönderdiğimiz hesabınızın adresini girmelisiniz, kontrat adresi olarak da ropsten ağına deploy ettiğimiz kontratın adresini girmelisiniz. Ardından tekrar “Değişkeni Çek” ve “Değişkeni Güncelle” komutlarını çalıştırabilirsiniz, bu sefer ropsten ağı üzerindeki kontrat ile haberleşmiş oluyorsunuz.

Evet biraz uzun bir makale oldu ama her şeyi elimden geldiğince detaylı anlatmak istedim. Bu makalede hem ethers’i frontend tarafından nasıl kullanabileceğimizi, hardhat ile ethereum ortamı oluşturmayı, ortamın ayarlarını istediğimiz şekilde değiştirmeyi, kontratı compile etmeyi, farklı ağlara deploy etmeyi, kontrat üzerindeki değeri okumayı ve yazmayı, infura servisine bağlanmayı ve onu kullanmayı gibi şeyler öğrenmiş olduk.

Bundan sonra tavsiyem yukarıdaki adımları farklı kontratlar ile denemeniz, farklı şekillerde, farklı ağlarda denemenizdir. Bu size ethereum ile çalışabilme deneyimi kazandıracaktır.

Bir sonraki yazıda görüşmek üzere…

Murat ÇELİKTEPE

LinkedIn → celiktepemurat

Twitter → muratctp

--

--