Transfer dan persetujuan token ERC-20 dari kontrak pintar solidity
Pada tutorial sebelumnya kita telah mempelajari anatomi token ERC-20 di Solidity pada blockchain Ethereum. Dalam artikel ini kita akan melihat bagaimana kita dapat menggunakan kontrak pintar untuk berinteraksi dengan token menggunakan bahasa Solidity.
Untuk kontrak pintar ini, kita akan membuat pertukaran terdesentralisasi tiruan yang nyata di mana pengguna dapat menukar ether dengan token ERC-20 kita yang baru saja disebarkan.
Untuk tutorial ini kita akan menggunakan kode yang kita tulis pada tutorial sebelumnya sebagai dasar. DEX kita akan membuat instansiasi kontrak di konstruktornya dan melakukan operasi:
- menukar token menjadi ether
- menukar ether menjadi token
Kita akan memulai kode pertukaran terdesentralisasi kita dengan menambahkan basis kode ERC20 sederhana kita:
1pragma solidity ^0.8.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}171819contract ERC20Basic is IERC20 {2021 string public constant name = "ERC20Basic";22 string public constant symbol = "ERC";23 uint8 public constant decimals = 18;242526 mapping(address => uint256) balances;2728 mapping(address => mapping (address => uint256)) allowed;2930 uint256 totalSupply_ = 10 ether;313233 constructor() {34 balances[msg.sender] = totalSupply_;35 }3637 function totalSupply() public override view returns (uint256) {38 return totalSupply_;39 }4041 function balanceOf(address tokenOwner) public override view returns (uint256) {42 return balances[tokenOwner];43 }4445 function transfer(address receiver, uint256 numTokens) public override returns (bool) {46 require(numTokens <= balances[msg.sender]);47 balances[msg.sender] = balances[msg.sender]-numTokens;48 balances[receiver] = balances[receiver]+numTokens;49 emit Transfer(msg.sender, receiver, numTokens);50 return true;51 }5253 function approve(address delegate, uint256 numTokens) public override returns (bool) {54 allowed[msg.sender][delegate] = numTokens;55 emit Approval(msg.sender, delegate, numTokens);56 return true;57 }5859 function allowance(address owner, address delegate) public override view returns (uint) {60 return allowed[owner][delegate];61 }6263 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {64 require(numTokens <= balances[owner]);65 require(numTokens <= allowed[owner][msg.sender]);6667 balances[owner] = balances[owner]-numTokens;68 allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;69 balances[buyer] = balances[buyer]+numTokens;70 emit Transfer(owner, buyer, numTokens);71 return true;72 }73}7475Tampilkan semuaKontrak pintar DEX baru kita akan menyebarkan ERC-20 dan mendapatkan semua pasokan:
1contract DEX {23 IERC20 public token;45 event Bought(uint256 amount);6 event Sold(uint256 amount);78 constructor() {9 token = new ERC20Basic();10 }1112 function buy() payable public {13 // TODO // TODO14 }1516 function sell(uint256 amount) public {17 // TODO // TODO18 }1920}Tampilkan semuaJadi sekarang kita memiliki DEX kita dan ia memiliki semua cadangan token yang tersedia. Kontrak tersebut memiliki dua fungsi:
buy: Pengguna dapat mengirim ether dan mendapatkan token sebagai gantinyasell: Pengguna dapat memutuskan untuk mengirim token untuk mendapatkan ether kembali
Fungsi buy
Mari kita kodekan fungsi buy. Pertama-tama kita perlu memeriksa jumlah ether yang terkandung dalam pesan dan memverifikasi bahwa kontrak memiliki cukup token dan bahwa pesan tersebut memiliki sejumlah ether di dalamnya. Jika kontrak memiliki cukup token, ia akan mengirimkan sejumlah token kepada pengguna dan memancarkan event Bought.
Perhatikan bahwa jika kita memanggil fungsi require jika terjadi kesalahan, ether yang dikirim akan langsung dibatalkan (revert) dan diberikan kembali kepada pengguna.
Agar tetap sederhana, kita hanya menukar 1 token dengan 1 Wei.
1function buy() payable public {2 uint256 amountTobuy = msg.value;3 uint256 dexBalance = token.balanceOf(address(this));4 require(amountTobuy > 0, "You need to send some ether");5 require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");6 token.transfer(msg.sender, amountTobuy);7 emit Bought(amountTobuy);8}Jika pembelian berhasil, kita akan melihat dua event dalam transaksi: Transfer token dan event Bought.
Fungsi sell
Fungsi yang bertanggung jawab untuk penjualan pertama-tama akan mengharuskan pengguna untuk menyetujui jumlah tersebut dengan memanggil fungsi approve sebelumnya. Menyetujui transfer mengharuskan token ERC20Basic yang diinstansiasi oleh DEX dipanggil oleh pengguna. Hal ini dapat dicapai dengan terlebih dahulu memanggil fungsi token() dari kontrak DEX untuk mengambil alamat di mana DEX menyebarkan kontrak ERC20Basic yang disebut token. Kemudian kita membuat instansiasi dari kontrak tersebut di sesi kita dan memanggil fungsi approve-nya. Kemudian kita dapat memanggil fungsi sell dari DEX dan menukar token kita kembali menjadi ether. Sebagai contoh, seperti inilah tampilannya dalam sesi brownie interaktif:
1#### Python in interactive brownie console... # ### Python di konsol interaktif brownie...23# deploy the DEX # deploy DEX4dex = DEX.deploy({'from':account1})56# call the buy function to swap ether for token # panggil fungsi buy untuk menukar ether dengan token7# 1e18 is 1 ether denominated in wei # 1e18 adalah 1 ether dalam denominasi wei8dex.buy({'from': account2, 1e18})910# get the deployment address for the ERC20 token # dapatkan alamat deployment untuk token ERC2011# that was deployed during DEX contract creation # yang di-deploy selama pembuatan kontrak DEX12# dex.token() returns the deployed address for token # dex.token() mengembalikan alamat yang di-deploy untuk token13token = ERC20Basic.at(dex.token())1415# call the token's approve function # panggil fungsi approve dari token16# approve the dex address as spender # setujui alamat dex sebagai spender17# and how many of your tokens it is allowed to spend # dan berapa banyak token Anda yang diizinkan untuk dibelanjakan18token.approve(dex.address, 3e18, {'from':account2})19Tampilkan semuaKemudian ketika fungsi sell dipanggil, kita akan memeriksa apakah transfer dari alamat pemanggil ke alamat kontrak berhasil dan kemudian mengirimkan Ether kembali ke alamat pemanggil.
1function sell(uint256 amount) public {2 require(amount > 0, "You need to sell at least some tokens");3 uint256 allowance = token.allowance(msg.sender, address(this));4 require(allowance >= amount, "Check the token allowance");5 token.transferFrom(msg.sender, address(this), amount);6 payable(msg.sender).transfer(amount);7 emit Sold(amount);8}Jika semuanya berfungsi, Anda akan melihat 2 event (Transfer dan Sold) dalam transaksi dan saldo token serta saldo ether Anda diperbarui.
Dari tutorial ini kita melihat cara memeriksa saldo dan izin (allowance) dari token ERC-20 dan juga cara memanggil Transfer dan TransferFrom dari kontrak pintar ERC20 menggunakan antarmuka.
Setelah Anda melakukan transaksi, kami memiliki tutorial JavaScript untuk menunggu dan mendapatkan detail tentang transaksi (opens in a new tab) yang dilakukan ke kontrak Anda dan tutorial untuk memecahkan kode event yang dihasilkan oleh transfer token atau event lainnya (opens in a new tab) selama Anda memiliki ABI.
Berikut adalah kode lengkap untuk tutorial ini:
1pragma solidity ^0.8.0;23interface IERC20 {45 function totalSupply() external view returns (uint256);6 function balanceOf(address account) external view returns (uint256);7 function allowance(address owner, address spender) external view returns (uint256);89 function transfer(address recipient, uint256 amount) external returns (bool);10 function approve(address spender, uint256 amount) external returns (bool);11 function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);121314 event Transfer(address indexed from, address indexed to, uint256 value);15 event Approval(address indexed owner, address indexed spender, uint256 value);16}171819contract ERC20Basic is IERC20 {2021 string public constant name = "ERC20Basic";22 string public constant symbol = "ERC";23 uint8 public constant decimals = 18;242526 mapping(address => uint256) balances;2728 mapping(address => mapping (address => uint256)) allowed;2930 uint256 totalSupply_ = 10 ether;313233 constructor() {34 balances[msg.sender] = totalSupply_;35 }3637 function totalSupply() public override view returns (uint256) {38 return totalSupply_;39 }4041 function balanceOf(address tokenOwner) public override view returns (uint256) {42 return balances[tokenOwner];43 }4445 function transfer(address receiver, uint256 numTokens) public override returns (bool) {46 require(numTokens <= balances[msg.sender]);47 balances[msg.sender] = balances[msg.sender]-numTokens;48 balances[receiver] = balances[receiver]+numTokens;49 emit Transfer(msg.sender, receiver, numTokens);50 return true;51 }5253 function approve(address delegate, uint256 numTokens) public override returns (bool) {54 allowed[msg.sender][delegate] = numTokens;55 emit Approval(msg.sender, delegate, numTokens);56 return true;57 }5859 function allowance(address owner, address delegate) public override view returns (uint) {60 return allowed[owner][delegate];61 }6263 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {64 require(numTokens <= balances[owner]);65 require(numTokens <= allowed[owner][msg.sender]);6667 balances[owner] = balances[owner]-numTokens;68 allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;69 balances[buyer] = balances[buyer]+numTokens;70 emit Transfer(owner, buyer, numTokens);71 return true;72 }73}747576contract DEX {7778 event Bought(uint256 amount);79 event Sold(uint256 amount);808182 IERC20 public token;8384 constructor() {85 token = new ERC20Basic();86 }8788 function buy() payable public {89 uint256 amountTobuy = msg.value;90 uint256 dexBalance = token.balanceOf(address(this));91 require(amountTobuy > 0, "You need to send some ether");92 require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");93 token.transfer(msg.sender, amountTobuy);94 emit Bought(amountTobuy);95 }9697 function sell(uint256 amount) public {98 require(amount > 0, "You need to sell at least some tokens");99 uint256 allowance = token.allowance(msg.sender, address(this));100 require(allowance >= amount, "Check the token allowance");101 token.transferFrom(msg.sender, address(this), amount);102 payable(msg.sender).transfer(amount);103 emit Sold(amount);104 }105106}Tampilkan semuaPembaruan terakhir halaman: 3 Maret 2026

