Розуміння смарт-контракту токена ERC-20
Одним із найважливіших стандартів смарт-контрактів в Етеріумі є ERC-20, який став технічним стандартом, що використовується для всіх смарт-контрактів у блокчейні Етеріум для реалізації взаємозамінних токенів.
ERC-20 визначає загальний перелік правил, яких повинні дотримуватися всі взаємозамінні токени Етеріуму. Отже, цей стандарт токенів дає розробникам усіх типів можливість точно прогнозувати, як нові токени функціонуватимуть у ширшій системі Етеріуму. Це спрощує та полегшує завдання розробників, оскільки вони можуть продовжувати свою роботу, знаючи, що кожен новий проєкт не потрібно буде переробляти щоразу під час випуску нового токена, за умови, що токен дотримується правил.
Нижче у вигляді інтерфейсу представлені функції, які повинен реалізовувати ERC-20. Якщо ви не впевнені, що таке інтерфейс: перегляньте нашу статтю про об'єктно-орієнтоване програмування (ООП) у 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.
Гетери
function totalSupply() external view returns (uint256);
Повертає кількість існуючих токенів. Ця функція є гетером і не змінює стан контракту. Майте на увазі, що в 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 за допомогою механізму дозволів. Потім ця кількість віднімається від дозволу того, хто викликає функцію. Ця функція генерує подію Transfer.
Події
event Transfer(address indexed from, address indexed to, uint256 value);
Ця подія генерується, коли кількість токенів (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).