Ajută la actualizarea acestei pagini

🌏

Există o nouă versiune a acestei pagini, dar acum este doar în engleză. Ajută-ne să traducem cea mai recentă versiune.

Transferuri și aprobarea de tokenuri ERC-20 dintr-un contract inteligent Solidity

În tutorialul anterior am studiat anatomia unui token ERC-20 în Solidity pe Ethereum blockchain. Î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:

  • schimbarea tokenurilor în eter
  • schimbarea eterului în tokenuri

Vom începe codul nostru de schimb descentralizat prin adăugarea codului nostru de bază simplu ERC20:

1pragma solidity ^0.6.0;
2
3interface IERC20 {
4
5 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);
8
9 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);
12
13
14 event Transfer(address indexed from, address indexed to, uint256 value);
15 event Approval(address indexed owner, address indexed spender, uint256 value);
16}
17
18
19contract ERC20Basic is IERC20 {
20
21 string public constant name = "ERC20Basic";
22 string public constant symbol = "ERC";
23 uint8 public constant decimals = 18;
24
25
26 event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
27 event Transfer(address indexed from, address indexed to, uint tokens);
28
29
30 mapping(address => uint256) balances;
31
32 mapping(address => mapping (address => uint256)) allowed;
33
34 uint256 totalSupply_ = 100 ether;
35
36 using SafeMath for uint256;
37
38 constructor(uint256 total) public {
39 balances[msg.sender] = totalSupply_;
40 }
41
42 function totalSupply() public override view returns (uint256) {
43 return totalSupply_;
44 }
45
46 function balanceOf(address tokenOwner) public override view returns (uint256) {
47 return balances[tokenOwner];
48 }
49
50 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 }
57
58 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 }
63
64 function allowance(address owner, address delegate) public override view returns (uint) {
65 return allowed[owner][delegate];
66 }
67
68 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
69 require(numTokens <= balances[owner]);
70 require(numTokens <= allowed[owner][msg.sender]);
71
72 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}
79
80library SafeMath {
81 function sub(uint256 a, uint256 b) internal pure returns (uint256) {
82 assert(b <= a);
83 return a - b;
84 }
85
86 function add(uint256 a, uint256 b) internal pure returns (uint256) {
87 uint256 c = a + b;
88 assert(c >= a);
89 return c;
90 }
91}
92
Afișează tot
📋 Copiere

Noul nostru contract inteligent DEX va implementa ERC-20 și va obține toate informațiile furnizate:

1contract DEX {
2
3 IERC20 public token;
4
5 event Bought(uint256 amount);
6 event Sold(uint256 amount);
7
8 constructor() public {
9 token = new ERC20Basic();
10 }
11
12 function buy() payable public {
13 // DE_FĂCUT
14 }
15
16 function sell(uint256 amount) public {
17 // DE_FĂCUT
18 }
19
20}
21
Afișează tot
📋 Copiere

Deci acum avem contractul nostru DEX și el are disponibile toate rezervele de tokenuri. Contractul are două funcții:

  • buy: Utilizatorul poate trimite eter și obține tokenuri în schimb
  • sell: Utilizatorul poate decide să trimită tokenuri pentru a obține eter înapoi

Funcția de cumpărare

Să programăm funcția de cumpărare. Mai întâi va trebui să verificăm cantitatea de eter pe care o conține mesajul și să verificăm dacă contractele dețin suficiente tokenuri și dacă mesajul are eter. În cazul în care contractul deține suficiente tokenuri, acesta va trimite numărul de tokenuri utilizatorului și va emite evenimentul "Bought".

Reține că, dacă apelăm funcția „require” în cazul unei erori, eterul trimis va fi reîntors direct și retrimis utilizatorului.

Pentru a păstra lucrurile simple, schimbăm doar 1 token pentru 1 eter.

1function buy() payable public {
2 uint256 amountTobuy = msg.value;
3 uint256 dexBalance = token.balanceOf(address(this));
4 require(amountTobuy > 0, "Trebuie să trimiți niște eter");
5 require(amountTobuy <= dexBalance, "Nu există suficiente tokenuri în rezervă");
6 token.transfer(msg.sender, amountTobuy);
7 emit Bought(amountTobuy);
8}
9
📋 Copiere

În cazul în care cumpărarea are succes, ar trebui să vedem două evenimente în tranzacție: Transfer-ul de token și evenimentul Bought.

Două evenimente în tranzacție: „Transfer” și „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ă „transferFrom" de la adresa apelantului la adresa contractului a avut succes și vom trimite eteri înapoi la adresa apelantului.

1function sell(uint256 amount) public {
2 require(amount > 0, "Trebuie să vinzi cel puțin câteva tokenuri");
3 uint256 allowance = token.allowance(msg.sender, address(this));
4 require(allowance >= amount, "Verifică alocația de tokenuri");
5 token.transferFrom(msg.sender, address(this), amount);
6 msg.sender.transfer(amount);
7 emit Sold(amount);
8}
9
📋 Copiere

Dacă totul merge bine ar trebui să ai 2 evenimente (un „Transfer” și un „Sold”) în tranzacție și soldul tokenului și al Ethereum actualizate.

Două evenimente în tranzacție: „Transfer” și „Sold”

În acest tutorial am văzut cum să verificăm soldul și alocația permisă de tokenuri ERC-20 și, de asemenea, cum să apelăm „Transfer” și „TransferFrom” ale unui contract inteligent ERC20 folosind interfața.

Odată ce ai făcut o tranzacție avem un tutorial JavaScript pentru a aștepta și a obține detalii despre tranzacțiile care au fost făcute contractului tău și un tutorial pentru a decoda evenimente generate de transferurile de token sau orice alte evenimente, atâta timp cât ai ABI-ul.

Aici este codul complet pentru acest tutorial:

1pragma solidity ^0.6.0;
2
3interface IERC20 {
4
5 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);
8
9 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);
12
13
14 event Transfer(address indexed from, address indexed to, uint256 value);
15 event Approval(address indexed owner, address indexed spender, uint256 value);
16}
17
18
19contract ERC20Basic is IERC20 {
20
21 string public constant name = "ERC20Basic";
22 string public constant symbol = "ERC";
23 uint8 public constant decimals = 18;
24
25
26 event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
27 event Transfer(address indexed from, address indexed to, uint tokens);
28
29
30 mapping(address => uint256) balances;
31
32 mapping(address => mapping (address => uint256)) allowed;
33
34 uint256 totalSupply_ = 10 ether;
35
36 using SafeMath for uint256;
37
38 constructor() public {
39 balances[msg.sender] = totalSupply_;
40 }
41
42 function totalSupply() public override view returns (uint256) {
43 return totalSupply_;
44 }
45
46 function balanceOf(address tokenOwner) public override view returns (uint256) {
47 return balances[tokenOwner];
48 }
49
50 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 }
57
58 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 }
63
64 function allowance(address owner, address delegate) public override view returns (uint) {
65 return allowed[owner][delegate];
66 }
67
68 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
69 require(numTokens <= balances[owner]);
70 require(numTokens <= allowed[owner][msg.sender]);
71
72 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}
79
80library SafeMath {
81 function sub(uint256 a, uint256 b) internal pure returns (uint256) {
82 assert(b <= a);
83 return a - b;
84 }
85
86 function add(uint256 a, uint256 b) internal pure returns (uint256) {
87 uint256 c = a + b;
88 assert(c >= a);
89 return c;
90 }
91}
92
93contract DEX {
94
95 event Bought(uint256 amount);
96 event Sold(uint256 amount);
97
98
99 IERC20 public token;
100
101 constructor() public {
102 token = new ERC20Basic();
103 }
104
105 function buy() payable public {
106 uint256 amountTobuy = msg.value;
107 uint256 dexBalance = token.balanceOf(address(this));
108 require(amountTobuy > 0, "Trebuie să trimiți niște eter");
109 require(amountTobuy <= dexBalance, "Nu există suficiente tokenuri în rezervă");
110 token.transfer(msg.sender, amountTobuy);
111 emit Bought(amountTobuy);
112 }
113
114 function sell(uint256 amount) public {
115 require(amount > 0, "Trebuie să vinzi cel puțin câteva tokenuri");
116 uint256 allowance = token.allowance(msg.sender, address(this));
117 require(allowance >= amount, "Verifică alocația de tokenuri");
118 token.transferFrom(msg.sender, address(this), amount);
119 msg.sender.transfer(amount);
120 emit Sold(amount);
121 }
122
123}
124
Afișează tot
📋 Copiere
Ultima editare: , Invalid DateTime
Edit page