اہم مواد پر جائیں

ایک solidity اسمارٹ کنٹریکٹ سے ERC-20 ٹوکنز کی منتقلی اور منظوری

اسمارٹ معاہدات
tokens
solidity
erc-20
متوسط
jdourlens
7 اپریل، 2020
8 منٹ کی پڑھائی

پچھلے ٹیوٹوریل میں ہم نے Ethereum بلاک چین پر Solidity میں ERC-20 ٹوکن کی ساخت کا مطالعہ کیا تھا۔ اس مضمون میں ہم دیکھیں گے کہ ہم Solidity زبان کا استعمال کرتے ہوئے ٹوکن کے ساتھ تعامل کرنے کے لیے اسمارٹ کنٹریکٹ کا استعمال کیسے کر سکتے ہیں۔

اس اسمارٹ کنٹریکٹ کے لیے، ہم ایک حقیقی ڈمی غیر مرکزی تبادلہ بنائیں گے جہاں ایک صارف ہمارے نئے ڈیپلائے کیے گئے ERC-20 ٹوکن کے لیے ایتھر کی تجارت کر سکتا ہے۔

اس ٹیوٹوریل کے لیے ہم اس کوڈ کا استعمال کریں گے جسے ہم نے پچھلے ٹیوٹوریل میں ایک بنیاد کے طور پر لکھا تھا۔ ہمارا DEX اپنے کنسٹرکٹر میں کنٹریکٹ کا ایک انسٹینس بنائے گا اور درج ذیل آپریشنز انجام دے گا:

  • ٹوکنز کو ایتھر میں تبدیل کرنا
  • ایتھر کو ٹوکنز میں تبدیل کرنا

ہم اپنا سادہ ERC20 کوڈ بیس شامل کرکے اپنا غیر مرکزی تبادلے کا کوڈ شروع کریں گے:

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
سب دکھائیں

ہمارا نیا DEX اسمارٹ کنٹریکٹ ERC-20 کو ڈیپلائے کرے گا اور فراہم کردہ تمام چیزیں حاصل کرے گا:

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}
سب دکھائیں

تو اب ہمارے پاس اپنا DEX ہے اور اس میں تمام ٹوکن ریزرو دستیاب ہیں۔ کنٹریکٹ میں دو فنکشنز ہیں:

  • buy: صارف ایتھر بھیج سکتا ہے اور بدلے میں ٹوکن حاصل کر سکتا ہے
  • sell: صارف ایتھر واپس حاصل کرنے کے لیے ٹوکن بھیجنے کا فیصلہ کر سکتا ہے

خریدنے کا فنکشن

آئیے خریدنے کا فنکشن کوڈ کریں۔ ہمیں پہلے یہ چیک کرنے کی ضرورت ہوگی کہ پیغام میں ایتھر کی کتنی مقدار ہے اور اس بات کی تصدیق کرنی ہوگی کہ کنٹریکٹس کے پاس کافی ٹوکنز ہیں اور یہ کہ پیغام میں کچھ ایتھر موجود ہے۔ اگر کنٹریکٹ کے پاس کافی ٹوکنز ہیں تو وہ صارف کو ٹوکنز کی تعداد بھیجے گا اور Bought ایونٹ کو ایمٹ کرے گا۔

نوٹ کریں کہ اگر ہم خرابی کی صورت میں require فنکشن کو کال کرتے ہیں تو بھیجا گیا ایتھر براہ راست ریورٹ ہو جائے گا اور صارف کو واپس کر دیا جائے گا۔

چیزوں کو آسان رکھنے کے لیے، ہم صرف 1 Wei کے بدلے 1 ٹوکن کا تبادلہ کرتے ہیں۔

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}

اس صورت میں جہاں خرید کامیاب ہوتی ہے ہمیں ٹرانزیکشن میں دو ایونٹس نظر آنے چاہئیں: ٹوکن Transfer اور Bought ایونٹ۔

ٹرانزیکشن میں دو ایونٹس: Transfer اور Bought

فروخت کا فنکشن

فروخت کے لیے ذمہ دار فنکشن کے لیے پہلے یہ ضروری ہوگا کہ صارف نے پہلے سے approve فنکشن کو کال کرکے رقم کی منظوری دی ہو۔ ٹرانسفر کی منظوری کے لیے ضروری ہے کہ DEX کے ذریعے انسٹینشیئٹ کردہ ERC20Basic ٹوکن کو صارف کے ذریعے کال کیا جائے۔ یہ پہلے DEX کنٹریکٹ کے token() فنکشن کو کال کرکے اس ایڈریس کو حاصل کرکے کیا جا سکتا ہے جہاں DEX نے token نامی ERC20Basic کنٹریکٹ ڈیپلائے کیا تھا۔ پھر ہم اپنے سیشن میں اس کنٹریکٹ کا ایک انسٹینس بناتے ہیں اور اس کے approve فنکشن کو کال کرتے ہیں۔ پھر ہم DEX کے sell فنکشن کو کال کرنے اور اپنے ٹوکنز کو واپس ایتھر کے لیے سواپ کرنے کے قابل ہوتے ہیں۔ مثال کے طور پر، ایک انٹرایکٹو براؤنی سیشن میں یہ اس طرح نظر آتا ہے:

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
سب دکھائیں

پھر جب sell فنکشن کو کال کیا جاتا ہے، تو ہم چیک کریں گے کہ کالر کے ایڈریس سے کنٹریکٹ ایڈریس پر منتقلی کامیاب تھی یا نہیں اور پھر ایتھرز کو کالر کے ایڈریس پر واپس بھیج دیں گے۔

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}

اگر سب کچھ کام کرتا ہے تو آپ کو ٹرانزیکشن میں 2 ایونٹس (Transfer اور Sold) نظر آنے چاہئیں اور آپ کا ٹوکن بیلنس اور ایتھر بیلنس اپ ڈیٹ ہونا چاہیے۔

ٹرانزیکشن میں دو ایونٹس: Transfer اور Sold

اس ٹیوٹوریل سے ہم نے دیکھا کہ ERC-20 ٹوکن کا بیلنس اور الاؤنس کیسے چیک کیا جائے اور انٹرفیس کا استعمال کرتے ہوئے ERC20 اسمارٹ کنٹریکٹ کے Transfer اور TransferFrom کو کیسے کال کیا جائے۔

ایک بار جب آپ کوئی ٹرانزیکشن کرتے ہیں تو ہمارے پاس ایک JavaScript ٹیوٹوریل ہے ٹرانزیکشنز کے بارے میں تفصیلات کا انتظار کرنے اور حاصل کرنے کے لیےopens in a new tab جو آپ کے کنٹریکٹ میں کی گئی تھیں اور ایک ٹیوٹوریل ہے جو ٹوکن ٹرانسفرز یا کسی دوسرے ایونٹس کے ذریعے پیدا ہونے والے ایونٹس کو ڈی کوڈ کرنے کے لیے ہےopens in a new tab جب تک کہ آپ کے پاس ABI ہو۔

ٹیوٹوریل کے لیے مکمل کوڈ یہ ہے:

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}
سب دکھائیں

صفحہ کی آخری تازہ کاری: 15 فروری، 2026

کیا یہ ٹیوٹوریل کارآمد تھا؟