Bir DeFi uygulaması oluşturun ve dağıtın
Bu öğreticide, kullanıcıların akıllı sözleşmeye bir ERC20 token'ı yatırabilecekleri ve Farm Token'larını basıp onlara aktarabilecekleri, Solidity ile bir DeFi Uygulaması oluşturacağız. Kullanıcılar daha sonra Farm Token'larını akıllı sözleşmede yakarak ERC20 token'larını geri çekebilirler ve ERC20 token'ları kendilerine geri aktarılır.
Truffle ve Ganache kurun
İlk kez bir akıllı sözleşme yazıyorsanız, ortamınızı ayarlamanız gerekecektir. İki araç kullanacağız: Truffle(opens in a new tab) ve Ganache(opens in a new tab).
Truffle, Ethereum için akıllı sözleşmeler geliştirmek için bir geliştirme ortamı ve test çerçevesidir. Truffle ile akıllı sözleşmeler oluşturmak ve blok zincirine yerleştirmek kolaydır. Ganache, akıllı sözleşmeleri test etmek için yerel bir Ethereum blok zinciri oluşturmamıza izin veriyor. Gerçek ağın özelliklerini simüle eder ve ilk 10 hesap 100 test ether'ı ile finanse edilir, böylece akıllı sözleşme dağıtımını ve testini ücretsiz ve kolay hâle getirir. Ganache, bir masaüstü uygulaması ve bir komut satırı aracı olarak mevcuttur. Bu makale için UI masaüstü uygulamasını kullanacağız.
(opens in a new tab)Ganache UI masaüstü uygulaması
Projeyi oluşturmak için aşağıdaki komutları çalıştırın
mkdir your-project-namecd your-project-nametruffle init
Bu, akıllı sözleşmelerimizin geliştirilmesi ve uygulanması için boş bir proje oluşturacaktır. Oluşturulan proje yapısı aşağıdaki gibidir:
contracts
: Solidity akıllı sözleşmeleri için klasörmigrations
: Dağıtım komut dosyaları için klasörtest
: Akıllı sözleşmelerimizin testi için klasörtruffle-config.js
: Truffle yapılandırma dosyası
ERC20 Token'ını Oluşturun
Öncelikle akıllı sözleşmede stake etmek için kullanacağımız ERC20 token'ımızı oluşturmamız gerekiyor. Değiştirilebilir simgemizi oluşturmak için önce OpenZeppelin kütüphanesini kurmamız gerekecek. Bu kütüphane, ERC20 ve ERC721 gibi standartların uygulamalarını içerir. Onu kurmak için, şu komutu çalıştırın:
npm install @openzeppelin/contracts
OpenZeppelin kütüphanesini kullanarak, aşağıdaki solidity koduyla contracts/MyToken.sol
'a yazarak ERC20 token'ımızı oluşturabiliriz:
1pragma solidity ^0.8.0;23import "@openzeppelin/contracts/token/ERC20/ERC20.sol";45contract MyToken is ERC20 {6 constructor() public ERC20("MyToken", "MTKN"){7 _mint(msg.sender, 1000000000000000000000000);8 }9}Tümünü gösterKopyala
Yukarıdaki kodda:
- Satır: openzeppelin'den bu token standardının uygulamasını içeren ERC20.sol sözleşmesini içe aktarıyoruz.
- Satır: ERC20.sol sözleşmesinden kalıtıma uğruyoruz.
Satır 6: ERC20.sol yapıcısını çağırıp ad ve sembol parametrelerini sırasıyla
"MyToken"
ve"MTKN"
olarak geçiyoruz.- Satır: Akıllı sözleşmeyi dağıtan hesap için 1 milyon token basıyor ve aktarıyoruz (ERC20 token'ı için varsayılan 18 ondalık basamağı kullanıyoruz. Bu, 1 token basmak istiyorsak, onu 10000000000000000000, 1'den sonra 18 sıfır, olarak temsil edeceğiniz anlamına gelir).
_decimals
alanının 18 olarak ayarlandığı ERC20.sol yapıcı uygulamasını aşağıda görebiliriz:
1string private _name;2string private _symbol;3uint8 private _decimals;45constructor (string memory name_, string memory symbol_) public {6 _name = name_;7 _symbol = symbol_;8 _decimals = 18;9}Tümünü gösterKopyala
ERC20 Token'ını Derleyin
Akıllı sözleşmemizi derlemek için önce solidity derleyici versiyonumuzu kontrol etmeliyiz. Bunu şu komutu çalıştırarak kontrol edebilirsiniz:
truffle version
Varsayılan versiyon Solidity v0.5.16
'dır. Token'ımız 0.6.2
solidity versiyonu kullanılarak yazıldığından, sözleşmelerimizi derlemek için komutu çalıştırırsak bir derleyici hatası alırız. Hangi solidity derleyici sürümünün kullanılacağını belirlemek için truffle-config.js
dosyasına gidin ve aşağıda görüldüğü gibi istediğiniz derleyici sürümüne ayarlayın:
1// Configure your compilers2compilers: {3 solc: {4 version: "^0.8.0", // Fetch exact version from solc-bin (default: truffle's version)5 // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)6 // settings: { // See the solidity docs for advice about optimization and evmVersion7 // optimizer: {8 // enabled: false,9 // runs: 20010 // },11 // evmVersion: "byzantium"12 // }13 }14}Tümünü göster
Şimdi aşağıdaki komutu çalıştırarak akıllı sözleşmemizi derleyebiliriz:
truffle compile
ERC20 Token'ını Dağıtın
Derlemeden sonra artık token'ımızı dağıtabiliriz.
migrations
klasöründe, 2_deploy_Tokens.js
isimli bir dosya oluşturun. Bu dosya, hem ERC20 Token'ımızı hem de FarmToken akıllı sözleşmemizi dağıtacağımız yerdir. Aşağıdaki kod, MyToken.sol sözleşmemizi dağıtmak için kullanılır:
1const MyToken = artifacts.require("MyToken")23module.exports = async function (deployer, network, accounts) {4 // Deploy MyToken5 await deployer.deploy(MyToken)6 const myToken = await MyToken.deployed()7}
Ganache'yi açın ve yerel bir Ethereum blok zinciri başlatmak için "Quickstart" (Hızlı Başlangıç) seçeneğini seçin. Sözleşmemizi dağıtmak için, şunu çalıştırın:
truffle migrate
Sözleşmelerimizi dağıtmak için kullanılan adres, Ganache'nin bize gösterdiği adresler listesinden ilkidir. Bunu doğrulamak için Ganache masaüstü uygulamasını açabiliriz ve akıllı sözleşmelerimizi dağıtmak için ether maliyeti nedeniyle ilk hesap için ether bakiyesinin düştüğünü doğrulayabiliriz:
(opens in a new tab)Ganache masaüstü uygulaması
Dağıtıcı adresine 1 milyon MyToken token'ının gönderildiğini doğrulamak amacıyla, dağıtılan akıllı sözleşmemizle etkileşim kurmak için Truffle Konsolunu kullanabiliriz.
Akıllı sözleşmemizle etkileşim kurmak için aşağıdaki komutu çalıştırın:
truffle console
Artık sıradaki komutları terminale yazabiliriz:
Akıllı sözleşmeyi alın:
myToken = await MyToken.deployed()
Ganache'dan hesap dizisini alın:
accounts = await web3.eth.getAccounts()
İlk hesabın bakiyesini alın:
balance = await myToken.balanceOf(accounts[0])
Bakiyeyi 18 ondalık basamak olarak biçimlendirin:
web3.utils.fromWei(balance.toString())
Yukarıdaki komutları çalıştırarak, ilk adreste gerçekten de 1 milyon MyTokens olduğunu göreceğiz:
İlk adreste 1000000 MyToken var
FarmToken Akıllı Sözleşmesini Oluşturun
FarmToken akıllı sözleşmesinin 3 fonksiyonu olacaktır:
balance()
: FarmToken akıllı sözleşmesindeki MyToken bakiyesini alın.deposit(uint256 _amount)
: MyToken'ı kullanıcı adına FarmToken akıllı sözleşmesine aktarın ve ardından FarmToken'ı kullanıcıya aktarın.withdraw(uint256 _amount)
: Kullanıcının FarmToken token'larını yakın ve MyToken token'larını kullanıcının adresine aktarın.
FarmToken yapıcısına bakalım:
1pragma solidity ^0.6.2;23import "@openzeppelin/contracts/token/ERC20/IERC20.sol";4import "@openzeppelin/contracts/utils/Address.sol";5import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";6import "@openzeppelin/contracts/token/ERC20/ERC20.sol";78contract FarmToken is ERC20 {9 using Address for address;10 using SafeMath for uint256; // As of Solidity v0.8.0, mathematical operations can be done safely without the need for SafeMath11 using SafeERC20 for IERC20;1213 IERC20 public token;1415 constructor(address _token)16 public17 ERC20("FarmToken", "FRM")18 {19 token = IERC20(_token);20 }Tümünü gösterKopyala
3.-6. Satır: Openzeppelin'den şu sözleşmeleri içe aktarıyoruz: IERC20.sol, Address.sol, SafeERC20.sol ve ERC20.sol.
Satır 8: FarmToken, ERC20 sözleşmesinden kalıtıma uğrar.
14.-19. Satır: FarmToken yapıcısı parametre olarak MyToken sözleşmesinin adresini alacak ve onun sözleşmesini
token
adlı genel değişkenimize atayacağız.
Hadi balance()
fonksiyonunu uygulayalım. Hiçbir parametre almayacak ve bu akıllı sözleşmedeki MyToken bakiyesini iade edecek. Aşağıda gösterildiği gibi uygulanır:
1function balance() public view returns (uint256) {2 return token.balanceOf(address(this));3}Kopyala
deposit(uint256 _amount)
fonksiyonu için, kullanıcının yatırmak istediği miktarı parametre olarak alacak ve FarmToken token'larını basıp kullanıcıya aktaracak:
1function deposit(uint256 _amount) public {2 // Amount must be greater than zero3 require(_amount > 0, "amount cannot be 0");45 // Transfer MyToken to smart contract6 token.safeTransferFrom(msg.sender, address(this), _amount);78 // Mint FarmToken to msg sender9 _mint(msg.sender, _amount);10}Tümünü gösterKopyala
withdraw(uint256 _amount)
fonksiyonu için, kullanıcının yakmak istediği FarmToken miktarını parametre olarak alacağız ve ardından aynı miktarda MyToken'ı kullanıcıya geri aktaracağız:
1function withdraw(uint256 _amount) public {2 // Burn FarmTokens from msg sender3 _burn(msg.sender, _amount);45 // Transfer MyTokens from this smart contract to msg sender6 token.safeTransfer(msg.sender, _amount);7}Kopyala
Şimdi akıllı sözleşmemizi dağıtacağız. Bunu yapmak için 2_deploy_Tokens.js
dosyasına geri döneceğiz ve dağıtılacak yeni sözleşmeyi ekleyeceğiz:
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (deployer, network, accounts) {5 // Deploy MyToken6 await deployer.deploy(MyToken)7 const myToken = await MyToken.deployed()89 // Deploy Farm Token10 await deployer.deploy(FarmToken, myToken.address)11 const farmToken = await FarmToken.deployed()12}Tümünü göster
FarmToken'ı dağıtırken, dağıtılmış MyToken sözleşmesinin adresini parametre olarak ilettiğimizi unutmayın.
Şimdi, sözleşmelerimizi dağıtmak için, truffle compile
ve truffle migrate
komutlarını çalıştırın.
Akıllı sözleşmemizi test edelim. Akıllı sözleşmemizle etkileşim kurmak için truffle console
kullanmak yerine, bu işlemi otomatikleştirmek için bir komut dosyası oluşturacağız. scripts
isimli bir klasör oluşturun ve aşağıdaki getMyTokenBalance.js
dosyasını ekleyin. FarmToken akıllı sözleşmesindeki MyToken bakiyesini kontrol edecek:
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 myToken = await MyToken.deployed()6 farmToken = await FarmToken.deployed()7 balance = await myToken.balanceOf(farmToken.address)8 console.log(web3.utils.fromWei(balance.toString()))9 callback()10}Tümünü göster
Bu komut dosyasını çalıştırmak için aşağıdaki cli komutunu çalıştırın:
truffle exec .\scripts\getMyTokenBalance.js
0 olan beklenen sonucu alacağız. FarmToken'ın henüz dağıtılmadığına dair bir hata alırsanız truffle ağı, sözleşme kodunuzun en son sürümünü almamıştır. Ganache'yi kapatın, yeniden hızlı bir şekilde başlatın ve truffle migrate
'i çalıştırdığınızdan emin olun.
Şimdi, akıllı sözleşmeye MyToken stake edelim. deposit(uint256 _amount)
fonksiyonu ERC20'den safeTransferFrom
fonksiyonunu çağırdığından, kullanıcının MyToken'ı kullanıcı adına aktarmak için önce akıllı sözleşmeyi onaylaması gerekir. Yani aşağıdaki komut dosyasında önce bu adımı onaylayacağız, sonra fonksiyonu çağıracağız:
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 const accounts = await new web3.eth.getAccounts()6 const myToken = await MyToken.deployed()7 const farmToken = await FarmToken.deployed()89 // Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner through transferFrom.10 // This is zero by default.11 const allowanceBefore = await myToken.allowance(12 accounts[0],13 farmToken.address14 )15 console.log(16 "Amount of MyToken FarmToken is allowed to transfer on our behalf Before: " +17 allowanceBefore.toString()18 )1920 // In order to allow the Smart Contract to transfer to MyToken (ERC-20) on the accounts[0] behalf,21 // we must explicitly allow it.22 // We allow farmToken to transfer x amount of MyToken on our behalf23 await myToken.approve(farmToken.address, web3.utils.toWei("100", "ether"))2425 // Validate that the farmToken can now move x amount of MyToken on our behalf26 const allowanceAfter = await myToken.allowance(accounts[0], farmToken.address)27 console.log(28 "Amount of MyToken FarmToken is allowed to transfer on our behalf After: " +29 allowanceAfter.toString()30 )3132 // Verify accounts[0] and farmToken balance of MyToken before and after the transfer33 balanceMyTokenBeforeAccounts0 = await myToken.balanceOf(accounts[0])34 balanceMyTokenBeforeFarmToken = await myToken.balanceOf(farmToken.address)35 console.log("*** My Token ***")36 console.log(37 "Balance MyToken Before accounts[0] " +38 web3.utils.fromWei(balanceMyTokenBeforeAccounts0.toString())39 )40 console.log(41 "Balance MyToken Before TokenFarm " +42 web3.utils.fromWei(balanceMyTokenBeforeFarmToken.toString())43 )4445 console.log("*** Farm Token ***")46 balanceFarmTokenBeforeAccounts0 = await farmToken.balanceOf(accounts[0])47 balanceFarmTokenBeforeFarmToken = await farmToken.balanceOf(farmToken.address)48 console.log(49 "Balance FarmToken Before accounts[0] " +50 web3.utils.fromWei(balanceFarmTokenBeforeAccounts0.toString())51 )52 console.log(53 "Balance FarmToken Before TokenFarm " +54 web3.utils.fromWei(balanceFarmTokenBeforeFarmToken.toString())55 )56 // Call Deposit function from FarmToken57 console.log("Call Deposit Function")58 await farmToken.deposit(web3.utils.toWei("100", "ether"))59 console.log("*** My Token ***")60 balanceMyTokenAfterAccounts0 = await myToken.balanceOf(accounts[0])61 balanceMyTokenAfterFarmToken = await myToken.balanceOf(farmToken.address)62 console.log(63 "Balance MyToken After accounts[0] " +64 web3.utils.fromWei(balanceMyTokenAfterAccounts0.toString())65 )66 console.log(67 "Balance MyToken After TokenFarm " +68 web3.utils.fromWei(balanceMyTokenAfterFarmToken.toString())69 )7071 console.log("*** Farm Token ***")72 balanceFarmTokenAfterAccounts0 = await farmToken.balanceOf(accounts[0])73 balanceFarmTokenAfterFarmToken = await farmToken.balanceOf(farmToken.address)74 console.log(75 "Balance FarmToken After accounts[0] " +76 web3.utils.fromWei(balanceFarmTokenAfterAccounts0.toString())77 )78 console.log(79 "Balance FarmToken After TokenFarm " +80 web3.utils.fromWei(balanceFarmTokenAfterFarmToken.toString())81 )8283 // End function84 callback()85}Tümünü göster
Bu komut dosyasını çalıştırmak için: truffle exec .\scripts\transferMyTokenToFarmToken.js
. Konsolunuzda şunu görmelisiniz:
transferMyTokenToFarmToken.js çıktısı
Gördüğümüz gibi, ilk hesapta FarmToken'ları olduğu için MyToken'ları akıllı sözleşmeye başarıyla yatırdık.
Çekmek için:
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 const accounts = await new web3.eth.getAccounts()6 const myToken = await MyToken.deployed()7 const farmToken = await FarmToken.deployed()89 // Verify accounts[0] and farmToken balance of MyToken before and after the transfer10 balanceMyTokenBeforeAccounts0 = await myToken.balanceOf(accounts[0])11 balanceMyTokenBeforeFarmToken = await myToken.balanceOf(farmToken.address)12 console.log("*** My Token ***")13 console.log(14 "Balance MyToken Before accounts[0] " +15 web3.utils.fromWei(balanceMyTokenBeforeAccounts0.toString())16 )17 console.log(18 "Balance MyToken Before TokenFarm " +19 web3.utils.fromWei(balanceMyTokenBeforeFarmToken.toString())20 )2122 console.log("*** Farm Token ***")23 balanceFarmTokenBeforeAccounts0 = await farmToken.balanceOf(accounts[0])24 balanceFarmTokenBeforeFarmToken = await farmToken.balanceOf(farmToken.address)25 console.log(26 "Balance FarmToken Before accounts[0] " +27 web3.utils.fromWei(balanceFarmTokenBeforeAccounts0.toString())28 )29 console.log(30 "Balance FarmToken Before TokenFarm " +31 web3.utils.fromWei(balanceFarmTokenBeforeFarmToken.toString())32 )3334 // Call Deposit function from FarmToken35 console.log("Call Withdraw Function")36 await farmToken.withdraw(web3.utils.toWei("100", "ether"))3738 console.log("*** My Token ***")39 balanceMyTokenAfterAccounts0 = await myToken.balanceOf(accounts[0])40 balanceMyTokenAfterFarmToken = await myToken.balanceOf(farmToken.address)41 console.log(42 "Balance MyToken After accounts[0] " +43 web3.utils.fromWei(balanceMyTokenAfterAccounts0.toString())44 )45 console.log(46 "Balance MyToken After TokenFarm " +47 web3.utils.fromWei(balanceMyTokenAfterFarmToken.toString())48 )4950 console.log("*** Farm Token ***")51 balanceFarmTokenAfterAccounts0 = await farmToken.balanceOf(accounts[0])52 balanceFarmTokenAfterFarmToken = await farmToken.balanceOf(farmToken.address)53 console.log(54 "Balance FarmToken After accounts[0] " +55 web3.utils.fromWei(balanceFarmTokenAfterAccounts0.toString())56 )57 console.log(58 "Balance FarmToken After TokenFarm " +59 web3.utils.fromWei(balanceFarmTokenAfterFarmToken.toString())60 )6162 // End function63 callback()64}Tümünü göster
Bu komut dosyasını çalıştırmak için: truffle exec .\scripts\withdrawMyTokenFromTokenFarm.js
. Aşağıdaki çıktıda görebileceğimiz gibi, MyTokens'i başarıyla geri aldık ve FarmTokens'i yaktık:
withdrawMyTokenFromTokenFarm.js çıktısı
Referanslar
Sözleşmeler - OpenZeppelin Belgeleri(opens in a new tab)
Akıllı Sözleşmeler için Güzel Araçlar | Truffle Suite(opens in a new tab)
Ganache | Truffle Suite(opens in a new tab)
DeFi nedir? Başlangıç Rehberi (2021 Güncellendi) (99bitcoins.com)(opens in a new tab)
DeFi - DeFi Llama'da Merkeziyetsiz Finans Lider Tablosu(opens in a new tab)
Son düzenleme: @nhsz(opens in a new tab), 15 Ağustos 2023