Transferurile și aprobarea de tokenuuri ERC-20 dintr-un contract inteligent Solidity
În tutorialul anterior am studiat anatomia unui token ERC-20 în Solidity pe blochain-ul Ethereum. În acest articol vom vedea cum putem folosi un contract inteligent pentru a interacționa cu un token folosind limbajul Solidity.
Pentru acest contract inteligent, vom crea un schimb descentralizat fictiv unde un utilizator poate tranzacționa Ethereum cu tokenul nostru ERC-20 recent implementat.
Pentru acest tutorial vom folosi codul pe care l-am scris în tutorialul anterior ca bază. DEX-ul nostru va crea o instanță a contractului în constructorul său și va efectua operațiunile de:
- schimbare a tokenurilor în ether
- schimbul de ether pe tokenuri
Vom începe codul nostru de schimb descentralizat prin adăugarea codului nostru de bază simplu ERC20:
1pragma solidity ^0.6.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 event Approval(address indexed tokenOwner, address indexed spender, uint tokens);27 event Transfer(address indexed from, address indexed to, uint tokens);282930 mapping(address => uint256) balances;3132 mapping(address => mapping (address => uint256)) allowed;3334 uint256 totalSupply_ = 100 ether;3536 using SafeMath for uint256;3738 constructor(uint256 total) public {39 balances[msg.sender] = totalSupply_;40 }4142 function totalSupply() public override view returns (uint256) {43 return totalSupply_;44 }4546 function balanceOf(address tokenOwner) public override view returns (uint256) {47 return balances[tokenOwner];48 }4950 function transfer(address receiver, uint256 numTokens) public override returns (bool) {51 require(numTokens <= balances[msg.sender]);52 balances[msg.sender] = balances[msg.sender].sub(numTokens);53 balances[receiver] = balances[receiver].add(numTokens);54 emit Transfer(msg.sender, receiver, numTokens);55 return true;56 }5758 function approve(address delegate, uint256 numTokens) public override returns (bool) {59 allowed[msg.sender][delegate] = numTokens;60 emit Approval(msg.sender, delegate, numTokens);61 return true;62 }6364 function allowance(address owner, address delegate) public override view returns (uint) {65 return allowed[owner][delegate];66 }6768 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {69 require(numTokens <= balances[owner]);70 require(numTokens <= allowed[owner][msg.sender]);7172 balances[owner] = balances[owner].sub(numTokens);73 allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);74 balances[buyer] = balances[buyer].add(numTokens);75 emit Transfer(owner, buyer, numTokens);76 return true;77 }78}7980library SafeMath {81 function sub(uint256 a, uint256 b) internal pure returns (uint256) {82 assert(b <= a);83 return a - b;84 }8586 function add(uint256 a, uint256 b) internal pure returns (uint256) {87 uint256 c = a + b;88 assert(c >= a);89 return c;90 }91}Afișează totCopiați
Noul nostru contract inteligent DEX va implementa ERC-20 și va obține toate informațiile furnizate:
1contract DEX {23 IERC20 public token;45 event Bought(uint256 amount);6 event Sold(uint256 amount);78 constructor() public {9 token = new ERC20Basic();10 }1112 function buy() payable public {13 // DE_FĂCUT14 }1516 function sell(uint256 amount) public {17 // DE_FĂCUT18 }1920}Afișează totCopiați
Deci, acum avem DEX-ul nostru, care are toate rezervele de tokenuri disponibile. Contractul are două funcții:
buy
: Utilizatorul poate trimite ether și obține tokenuri în schimbsell
: Utilizatorul poate decide să trimită tokenuri pentru a obține ether în schimb
Funcția de cumpărare
Hai să codificăm funcția de cumpărare. Mai întâi va trebui să verificăm cantitatea de ether pe care o conține mesajul și să verificăm dacă contractele dețin suficiente tokenuri și dacă mesajul are ether. În cazul în care contractul deține suficiente tokenuri, acesta va trimite numărul de tokenuri utilizatorului și va emite evenimentul "Bought"
(cumpărat).
Rețineţi că, dacă apelăm funcția „require” în cazul unei erori, etherul trimis se va întoarce imediat și va fi retrimis utilizatorului.
Pentru simplificare, schimbăm doar 1 token pe 1 ether.
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}Copiați
În cazul în care cumpărarea are succes, ar trebui să vedem două evenimente în tranzacție: Transfer
-ul tokenului și evenimentul Bought
.
Funcția de vânzare
Funcția responsabilă pentru vânzare, „sell” va solicita mai întâi utilizatorului să aprobe suma apelând în prealabil funcția „approve”. Atunci când funcția „sell” este apelată, vom verifica dacă transferul de la adresa apelantului la adresa contractului a avut succes și vom trimite ether-ul înapoi la adresa apelantului.
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 msg.sender.transfer(amount);7 emit Sold(amount);8}Copiați
Dacă totul merge bine, ar trebui să vedeţi 2 evenimente (un „Transfer”
și un „Sold”
) în tranzacție și soldul tokenului dvs. și soldul Ethereum actualizate.
În acest tutorial am văzut cum să verificăm soldul și alocația permisă de tokenurile ERC-20 și de asemenea cum să apelăm „Transfer”
și „TransferFrom”
ale unui contract inteligent ERC20 folosind interfața.
Odată ce aţi efectuat o tranzacție, avem un tutorial JavaScript pentru a aștepta și a obține detalii despre tranzacțiile(opens in a new tab) care au fost efectuate cu contractul dvs. și un tutorial pentru a decoda evenimentele generate de transferurile de token sau orice alte evenimente(opens in a new tab), atâta timp cât aveţi ABI-ul.
Iată codul complet pentru acest tutorial:
1pragma solidity ^0.6.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 event Approval(address indexed tokenOwner, address indexed spender, uint tokens);27 event Transfer(address indexed from, address indexed to, uint tokens);282930 mapping(address => uint256) balances;3132 mapping(address => mapping (address => uint256)) allowed;3334 uint256 totalSupply_ = 10 ether;3536 using SafeMath for uint256;3738 constructor() public {39 balances[msg.sender] = totalSupply_;40 }4142 function totalSupply() public override view returns (uint256) {43 return totalSupply_;44 }4546 function balanceOf(address tokenOwner) public override view returns (uint256) {47 return balances[tokenOwner];48 }4950 function transfer(address receiver, uint256 numTokens) public override returns (bool) {51 require(numTokens <= balances[msg.sender]);52 balances[msg.sender] = balances[msg.sender].sub(numTokens);53 balances[receiver] = balances[receiver].add(numTokens);54 emit Transfer(msg.sender, receiver, numTokens);55 return true;56 }5758 function approve(address delegate, uint256 numTokens) public override returns (bool) {59 allowed[msg.sender][delegate] = numTokens;60 emit Approval(msg.sender, delegate, numTokens);61 return true;62 }6364 function allowance(address owner, address delegate) public override view returns (uint) {65 return allowed[owner][delegate];66 }6768 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {69 require(numTokens <= balances[owner]);70 require(numTokens <= allowed[owner][msg.sender]);7172 balances[owner] = balances[owner].sub(numTokens);73 allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);74 balances[buyer] = balances[buyer].add(numTokens);75 emit Transfer(owner, buyer, numTokens);76 return true;77 }78}7980library SafeMath {81 function sub(uint256 a, uint256 b) internal pure returns (uint256) {82 assert(b <= a);83 return a - b;84 }8586 function add(uint256 a, uint256 b) internal pure returns (uint256) {87 uint256 c = a + b;88 assert(c >= a);89 return c;90 }91}9293contract DEX {9495 event Bought(uint256 amount);96 event Sold(uint256 amount);979899 IERC20 public token;100101 constructor() public {102 token = new ERC20Basic();103 }104105 function buy() payable public {106 uint256 amountTobuy = msg.value;107 uint256 dexBalance = token.balanceOf(address(this));108 require(amountTobuy > 0, "Trebuie să trimiteți ceva ether");109 require(amountTobuy <= dexBalance, "Nu sunt suficiente token-uri în rezervă");110 token.transfer(msg.sender, amountTobuy);111 emit Bought(amountTobuy);112 }113114 function sell(uint256 amount) public {115 require(amount > 0, "Trebuie să vindeți cel puțin câteva token-uri"");116 uint256 allowance = token.allowance(msg.sender, address(this));117 require(allowance >= amount, "Verificați alocația de token-uri");118 token.transferFrom(msg.sender, address(this), amount);119 msg.sender.transfer(amount);120 emit Sold(amount);121 }122123}Afișează totCopiați
Ultima modificare: @nhsz(opens in a new tab), 15 august 2023