فهم العقد الذكي للرمز المميز ERC-20
يُعرف أحد أهم معايير العقود الذكية على إيثيريوم باسم ERC-20، والذي برز كمعيار تقني يُستخدم لجميع العقود الذكية على سلسلة الكتل لإيثيريوم لتنفيذ الرموز القابلة للاستبدال.
يحدد ERC-20 قائمة مشتركة من القواعد التي يجب أن تلتزم بها جميع رموز إيثيريوم القابلة للاستبدال. وبالتالي، يُمكّن معيار الرمز المميز هذا المطورين من جميع الأنواع من التنبؤ بدقة بكيفية عمل الرموز المميزة الجديدة داخل نظام إيثيريوم الأوسع. وهذا يبسط ويسهل مهام المطورين، حيث يمكنهم المضي قدمًا في عملهم، مع العلم أن كل مشروع جديد لن يحتاج إلى إعادة صياغته في كل مرة يتم فيها إصدار رمز مميز جديد، طالما أن الرمز المميز يتبع القواعد.
إليك الدوال التي يجب أن ينفذها ERC-20، معروضة كواجهة. إذا لم تكن متأكدًا من ماهية الواجهة: تحقق من مقالتنا حول البرمجة كائنية التوجه (OOP) في Solidity (opens in a new tab).
pragma solidity ^0.6.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
إليك شرح سطر بسطر للغرض من كل دالة. بعد ذلك سنقدم تنفيذًا بسيطًا للرمز المميز ERC-20.
دوال الجلب (Getters)
function totalSupply() external view returns (uint256);
تُرجع كمية الرموز المميزة الموجودة. هذه الدالة هي دالة جلب (getter) ولا تعدل حالة العقد. ضع في اعتبارك أنه لا توجد أرقام عشرية عائمة (floats) في Solidity. لذلك تتبنى معظم الرموز المميزة 18 منزلة عشرية وستُرجع إجمالي المعروض والنتائج الأخرى على النحو التالي 1000000000000000000 مقابل رمز مميز واحد (1). لا يحتوي كل رمز مميز على 18 منزلة عشرية وهذا شيء يجب عليك الانتباه إليه حقًا عند التعامل مع الرموز المميزة.
function balanceOf(address account) external view returns (uint256);
تُرجع كمية الرموز المميزة المملوكة لعنوان (account). هذه الدالة هي دالة جلب ولا تعدل حالة العقد.
function allowance(address owner, address spender) external view returns (uint256);
يسمح معيار ERC-20 لعنوان بإعطاء سماحية لعنوان آخر ليكون قادرًا على استرداد الرموز المميزة منه. تُرجع دالة الجلب هذه العدد المتبقي من الرموز المميزة التي سيُسمح لـ spender بإنفاقها نيابة عن owner. هذه الدالة هي دالة جلب ولا تعدل حالة العقد ويجب أن تُرجع 0 افتراضيًا.
الدوال
function transfer(address recipient, uint256 amount) external returns (bool);
تنقل amount من الرموز المميزة من عنوان مستدعي الدالة (msg.sender) إلى عنوان المستلم. تُصدر هذه الدالة حدث Transfer المُعرّف لاحقًا. وتُرجع true إذا كان التحويل ممكنًا.
function approve(address spender, uint256 amount) external returns (bool);
تُعيّن كمية allowance التي يُسمح لـ spender بتحويلها من رصيد مستدعي الدالة (msg.sender). تُصدر هذه الدالة حدث الموافقة (Approval). وتُرجع الدالة ما إذا كان قد تم تعيين السماحية بنجاح.
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
تنقل amount من الرموز المميزة من sender إلى recipient باستخدام آلية السماحية. يتم بعد ذلك خصم الكمية (amount) من سماحية المستدعي. تُصدر هذه الدالة حدث Transfer.
أحداث
event Transfer(address indexed from, address indexed to, uint256 value);
يتم إصدار هذا الحدث عندما يتم إرسال كمية من الرموز المميزة (القيمة) من عنوان from إلى عنوان to.
في حالة عملية سك رموز مميزة جديدة، يكون التحويل عادةً from العنوان 0x00..0000 بينما في حالة حرق الرموز المميزة يكون التحويل to 0x00..0000.
event Approval(address indexed owner, address indexed spender, uint256 value);
يتم إصدار هذا الحدث عندما تتم الموافقة على كمية الرموز المميزة (value) من قِبل owner ليتم استخدامها بواسطة spender.
تنفيذ أساسي للرموز المميزة ERC-20
إليك أبسط كود يمكنك بناء الرمز المميز ERC-20 الخاص بك عليه:
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract ERC20Basic is IERC20 {
string public constant name = "ERC20Basic";
string public constant symbol = "ERC";
uint8 public constant decimals = 18;
mapping(address => uint256) balances;
mapping(address => mapping (address => uint256)) allowed;
uint256 totalSupply_ = 10 ether;
constructor() {
balances[msg.sender] = totalSupply_;
}
function totalSupply() public override view returns (uint256) {
return totalSupply_;
}
function balanceOf(address tokenOwner) public override view returns (uint256) {
return balances[tokenOwner];
}
function transfer(address receiver, uint256 numTokens) public override returns (bool) {
require(numTokens <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender]-numTokens;
balances[receiver] = balances[receiver]+numTokens;
emit Transfer(msg.sender, receiver, numTokens);
return true;
}
function approve(address delegate, uint256 numTokens) public override returns (bool) {
allowed[msg.sender][delegate] = numTokens;
emit Approval(msg.sender, delegate, numTokens);
return true;
}
function allowance(address owner, address delegate) public override view returns (uint) {
return allowed[owner][delegate];
}
function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
require(numTokens <= balances[owner]);
require(numTokens <= allowed[owner][msg.sender]);
balances[owner] = balances[owner]-numTokens;
allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;
balances[buyer] = balances[buyer]+numTokens;
emit Transfer(owner, buyer, numTokens);
return true;
}
}
تنفيذ ممتاز آخر لمعيار الرمز المميز ERC-20 هو تنفيذ أوبن زبلن لـ ERC-20 (opens in a new tab).