Ana içeriğe geç

ERC-20 token'larının bir solidity akıllı sözleşmesinden transferleri ve doğrulanması

akıllı sözleşmelertoken'larkatılıkerc-20
Orta düzey
✍️jdourlens
📚EthereumDev(opens in a new tab)
📆 7 Nisan 2020
⏱️6 dakikalık okuma minute read
comp-tutorial-metadata-tip-author 0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE

Önceki öğreticide Ethereum blok zincirindeki bir ERC-20 token'ının Solidity içindeki anatomisi üzerine çalıştık. Bu makalede, bir akıllı sözleşmeyi bir token'la etkileşime geçmek için Solidity diliyle nasıl kullanabileceğimizi göreceğiz.

Bu akıllı sözleşme için bir kullanıcının yeni dağıtılmış ERC-20 jetonumuz karşılığında ether takas edebileceği sahte bir merkeziyetsiz borsa oluşturacağız.

Bu öğreticide, önceki öğreticide yazdığımız kodu temel olarak kullanacağız. DEX'imiz, kendi inşasında sözleşmenin bir örneğini oluşturacak ve bu işlemleri gerçekleştirecektir:

  • token'ları ether ile takas etmek
  • ether'ı token'lar ile takas etmek

Merkeziyetsiz borsa kodumuza basit ERC20 kod temelimizi ekleyerek başlayacağız:

1pragma solidity ^0.8.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 mapping(address => uint256) balances;
27
28 mapping(address => mapping (address => uint256)) allowed;
29
30 uint256 totalSupply_ = 10 ether;
31
32
33 constructor() {
34 balances[msg.sender] = totalSupply_;
35 }
36
37 function totalSupply() public override view returns (uint256) {
38 return totalSupply_;
39 }
40
41 function balanceOf(address tokenOwner) public override view returns (uint256) {
42 return balances[tokenOwner];
43 }
44
45 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 }
52
53 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 }
58
59 function allowance(address owner, address delegate) public override view returns (uint) {
60 return allowed[owner][delegate];
61 }
62
63 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
64 require(numTokens <= balances[owner]);
65 require(numTokens <= allowed[owner][msg.sender]);
66
67 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}
74
75
Tümünü göster
📋 Kopyala

Yeni DEX akıllı sözleşmemiz ERC-20'yi dağıtacak ve tüm arzı alacak:

1contract DEX {
2
3 IERC20 public token;
4
5 event Bought(uint256 amount);
6 event Sold(uint256 amount);
7
8 constructor() {
9 token = new ERC20Basic();
10 }
11
12 function buy() payable public {
13 // TODO
14 }
15
16 function sell(uint256 amount) public {
17 // TODO
18 }
19
20}
Tümünü göster
📋 Kopyala

Artık kendi DEX'imize sahibiz ve DEX'imiz mevcut tüm token rezervlerine sahip. Sözleşmede iki fonksiyon bulunur:

  • buy: Kullanıcı ether gönderip karşılığında token alabilir
  • sell: Kullanıcı token göndererek karşılığında ether almayı seçebilir

"Buy" Fonksiyonu

"Buy" fonksiyonunu kodlayalım. İlk olarak, mesajın içerdiği ether miktarını kontrol etmemiz; sözleşmenin yeterli token'a sahip olduğunu ve mesajın ether içerdiğini doğrulamamız gerekir. Eğer sözleşme yeterli token'a sahipse token miktarını kullanıcıya gönderecek ve Bought olayını yayacaktır.

Bir hata durumunda "require" fonksiyonunu çağırırsak gönderilen ether'ın doğrudan eskiye döndürüleceğini ve kullanıcıya geri verileceğini unutmayın.

İşleri basitleştirmek için 1 token'ı 1 Wei ile takas ediyoruz.

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}
📋 Kopyala

"Buy" fonksiyonunun başarılı olduğu durumda işlemde iki olay görmeliyiz: token Transfer olayı ve Bought olayı.

İşlemdeki iki olay: Transfer ve Bought

"Sell" fonksiyonu

Satıştan sorumlu olan fonksiyon, ilk olarak kullanıcının önceden doğrulama fonksiyonunu çağırarak miktarı doğrulamış olmasını gerektirecektir. Aktarımı onaylamak, DEX tarafından somutlaştırılan ERC20Basic token'ınını kullanıcı tarafından çağrılmasını gerektirir. Bu, DEX'in token adlı ERC20Basic sözleşmesini dağıttığı adresi almak için önce DEX sözleşmesinin token() fonksiyonunu çağırarak başarılabilir. Ardından, oturumumuzda bu sözleşmenin bir örneğini oluşturur ve onay fonksiyonunu çağırırız. Ardından, DEX'in sell fonksiyonunu çağırabilir ve token'larımızı ether için geri değiştirebiliriz. Örneğin, etkileşimli bir kek oturumunda bu, şöyle görünür:

1#### Python in interactive brownie console...
2
3# deploy the DEX
4dex = DEX.deploy({'from':account1})
5
6# call the buy function to swap ether for token
7# 1e18 is 1 ether denominated in wei
8dex.buy({'from': account2, 1e18})
9
10# get the deployment address for the ERC20 token
11# that was deployed during DEX contract creation
12# dex.token() returns the deployed address for token
13token = ERC20Basic.at(dex.token())
14
15# call the token's approve function
16# approve the dex address as spender
17# and how many of your tokens it is allowed to spend
18token.approve(dex.address, 3e18, {'from':account2})
19
Tümünü göster
📋 Kopyala

Sonra "sell" fonksiyonu çağırıldığında, çağıran adresten sözleşme adresine olan transferin başarılı olup olmadığını kontrol edeceğiz ve çağıran adrese ether'ları geri göndereceğiz.

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}
📋 Kopyala

Her şey çalışıyorsa işlemde 2 olay görmelisiniz (Transfer ve Sold) ve jeton bakiyeniz ile ether bakiyeniz güncellenmiş olmalıdır.

İşlemdeki iki olay: Transfer ve Sold

Bu öğreticide, bir ERC-20 tokenin bakiyesi ve ödeneği nasıl kontrol edilir ve bir ERC20 akıllı sözleşmesinden Transfer ve TransferFrom arayüzleri kullanılarak nasıl çağırılır gördük.

Bir işlem yaptıktan sonra, beklemek ve sözleşmenizde yapılan işlemlerle ilgili detayları almak(opens in a new tab) için bir JavaScript öğreticimiz ve ABI'ye sahip olduğunuz sürece token transferleri veya diğer olaylar tarafından oluşturulan olayların kodunu çözmek için bir öğreticimiz bulunuyor(opens in a new tab).

Öğretici için tam kod buradadır:

1pragma solidity ^0.8.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 mapping(address => uint256) balances;
27
28 mapping(address => mapping (address => uint256)) allowed;
29
30 uint256 totalSupply_ = 10 ether;
31
32
33 constructor() {
34 balances[msg.sender] = totalSupply_;
35 }
36
37 function totalSupply() public override view returns (uint256) {
38 return totalSupply_;
39 }
40
41 function balanceOf(address tokenOwner) public override view returns (uint256) {
42 return balances[tokenOwner];
43 }
44
45 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 }
52
53 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 }
58
59 function allowance(address owner, address delegate) public override view returns (uint) {
60 return allowed[owner][delegate];
61 }
62
63 function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
64 require(numTokens <= balances[owner]);
65 require(numTokens <= allowed[owner][msg.sender]);
66
67 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}
74
75
76contract DEX {
77
78 event Bought(uint256 amount);
79 event Sold(uint256 amount);
80
81
82 IERC20 public token;
83
84 constructor() {
85 token = new ERC20Basic();
86 }
87
88 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 }
96
97 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 }
105
106}
Tümünü göster
📋 Kopyala

Son düzenleme: @kaanmetu(opens in a new tab), Invalid DateTime

Bu rehber yararlı oldu mu?