Bir Solidity akıllı sözleşmesinden ERC-20 jetonlarının transferleri ve onaylanması
Önceki öğreticide, Ethereum blokzincirindeki bir ERC-20 jetonunun Solidity'deki anatomisi üzerine çalıştık. Bu makalede, bir akıllı sözleşmeyi bir jetonla 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ılan ERC-20 jetonumuz karşılığında ether takas edebileceği, deneme amaçlı bir merkeziyetsiz borsa oluşturacağız.
Bu öğreticide, önceki öğreticide yazdığımız kodu temel olarak kullanacağız. Merkeziyetsiz borsamız (DEX), kurucusunda sözleşmenin bir örneğini oluşturacak ve aşağıdaki işlemleri gerçekleştirecektir:
- jetonları ether ile takas etme
- ether'ı jetonlar ile takas etme
Merkeziyetsiz borsa kodumuza basit ERC20 kod tabanımızı ekleyerek başlayacağız:
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}7475Tümünü gösterYeni DEX akıllı sözleşmemiz ERC-20'yi dağıtacak ve tüm arzı alacaktır:
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 // TODO14 }1516 function sell(uint256 amount) public {17 // TODO18 }1920}Tümünü gösterBöylece artık kendi DEX'imiz var ve mevcut tüm jeton rezervine sahip. Sözleşmenin iki fonksiyonu vardır:
buy: Kullanıcı ether gönderip karşılığında jeton alabilirsell: Kullanıcı, ether'larını geri almak için jeton göndermeyi seçebilir
Satın alma fonksiyonu
buy fonksiyonunu kodlayalım. Öncelikle mesajın içerdiği ether miktarını kontrol etmemiz ve sözleşmelerin yeterli jetona sahip olduğunu ve mesajda bir miktar ether bulunduğunu doğrulamamız gerekecek. Sözleşme yeterli jetona sahipse, kullanıcıya ilgili sayıda jetonu gönderir ve Bought olayını yayar.
Bir hata durumunda require fonksiyonunu çağırırsak gönderilen ether'in doğrudan geri çevrileceğini ve kullanıcıya iade edileceğini unutmayın.
İşleri basitleştirmek için, 1 jetonu 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}Satın alma işleminin başarılı olduğu durumda, işlemde iki olay görmeliyiz: Jeton Transfer olayı ve Bought olayı.
Satış fonksiyonu
Satıştan sorumlu fonksiyon, öncelikle kullanıcının approve (onaylama) fonksiyonunu önceden çağırarak miktarı onaylamış olmasını gerektirecektir. Transferin onaylanması, DEX tarafından örneği oluşturulan ERC20Basic jetonunun 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() fonksiyonu çağrılarak sağlanabilir. Ardından, oturumumuzda bu sözleşmenin bir örneğini oluşturur ve approve fonksiyonunu çağırırız. Ardından DEX'in sell fonksiyonunu çağırabilir ve jetonlarımızı tekrar ether ile takas edebiliriz. Örneğin, etkileşimli bir brownie oturumunda bu şöyle görünür:
1#### Etkileşimli brownie konsolunda Python...23# DEX'i dağıt4dex = DEX.deploy({'from':account1})56# ether'ı jetonla takas etmek için buy fonksiyonunu çağır7# 1e18, wei cinsinden 1 ether'dir8dex.buy({'from': account2, 1e18})910# DEX sözleşmesi oluşturulurken dağıtılan11# ERC20 jetonunun dağıtım adresini al12# dex.token(), jetonun dağıtım adresini döndürür13token = ERC20Basic.at(dex.token())1415# jetonun approve fonksiyonunu çağır16# dex adresini harcayıcı olarak onayla17# ve jetonlarından ne kadarını harcamasına izin verildiğini belirt18token.approve(dex.address, 3e18, {'from':account2})19Tümünü gösterArdından sell fonksiyonu çağrıldığında, çağıranın adresinden sözleşme adresine transferin başarılı olup olmadığını kontrol edecek ve ardından ether'i çağıranın adresine 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}Her şey yolunda giderse, işlemde 2 olay (Transfer ve Sold) görmeli ve jeton bakiyeniz ile ether bakiyenizin güncellendiğini görmelisiniz.
Bu öğreticide, bir ERC-20 jetonunun bakiyesini ve harcama iznini (allowance) nasıl kontrol edeceğimizi ve ayrıca arayüzü kullanarak bir ERC20 akıllı sözleşmesinin Transfer ve TransferFrom fonksiyonlarını nasıl çağıracağımızı gördük.
Bir işlem gerçekleştirdiğinizde, sözleşmenize yapılan işlemlerin tamamlanmasını beklemek ve ayrıntılarını almakopens in a new tab ve ABI'niz olduğu sürece jeton transferleri veya diğer herhangi bir olay tarafından oluşturulan olayların kodunu çözmekopens in a new tab için bir JavaScript öğreticimiz var.
Öğreticinin tam kodu aşağıdadır:
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}Tümünü gösterSayfanın son güncellenmesi: 21 Ağustos 2025

