Как создать токен ERC20 простым способом

Опубликовано: 2022-03-11

Цель этой статьи — продемонстрировать, как создать токен ERC20 за минимально возможное время.

Начнем с основ: что такое токен ERC20?

В последние годы спецификация токена ERC20 стала стандартом де-факто для токенов Ethereum. Другими словами, большинство контрактов Ethereum сегодня совместимы с ERC20. В этой статье подробно рассказывается, как вы можете создать свой собственный токен Ethereum, но прежде чем мы начнем, давайте подробнее рассмотрим стандарт ERC20.

Иллюстрация токена ERC20

Что делает токены ERC20 такими привлекательными и успешными? В игре несколько факторов:

  1. Токены ERC20 просты и легки в развертывании, как вы увидите в этом руководстве.
  2. Стандарт ERC20 решает серьезную проблему, поскольку основанным на блокчейне рынкам и криптокошелькам требуется единый стандартизированный набор команд для взаимодействия с диапазоном токенов, которыми они управляют. Сюда входят правила взаимодействия между разными токенами, а также правила покупки токенов.
  3. Это была первая популярная спецификация, предлагающая стандартизацию токенов Ethereum. Он ни в коем случае не был первым , но благодаря своей популярности быстро стал отраслевым стандартом.

Как и другие токены Ethereum, токены ERC20 реализованы в виде смарт-контрактов и выполняются на виртуальной машине Ethereum (EVM) децентрализованным образом.

Solidity: язык программирования смарт-контрактов

Смарт-контракты Ethereum написаны на Solidity. Хотя существуют альтернативные языки, вряд ли кто-то использует их для этой цели. Solidity похож на JavaScript, поэтому, если у вас есть некоторые знания JavaScript или даже Java и других C-подобных языков, у вас не должно возникнуть проблем с пониманием того, что делает фрагмент кода в Solidity, даже до того, как вы на самом деле освоите Solidity достаточно, чтобы использовать Это.

Здесь начинается самое интересное, так как вы сможете начать создавать простой контракт ERC20 в кратчайшие сроки. Это простая задача, достаточно простая, чтобы в этой статье было продемонстрировано, как написать и развернуть токен ERC20 менее чем за час.

Токен, который мы будем создавать в этой демонстрации, будет простой реализацией ERC20 без лишних наворотов. Тем не менее, я видел много таких же простых токенов в реальном мире, и они, как правило, работают довольно хорошо.

Обзор стандарта токенов ERC20

Что такое ERC20?

Проще говоря, стандарт ERC20 определяет набор функций, которые должны быть реализованы всеми токенами ERC20, чтобы обеспечить интеграцию с другими контрактами, кошельками или торговыми площадками. Этот набор функций довольно короткий и базовый.

 function totalSupply() public view returns (uint256); function balanceOf(address tokenOwner) public view returns (uint); function allowance(address tokenOwner, address spender) public view returns (uint); function transfer(address to, uint tokens) public returns (bool); function approve(address spender, uint tokens) public returns (bool); function transferFrom(address from, address to, uint tokens) public returns (bool);

Функции ERC20 позволяют внешнему пользователю, скажем, приложению крипто-кошелька, узнать баланс пользователя и перевести средства от одного пользователя к другому с соответствующей авторизацией.

Смарт-контракт определяет два специально определенных события:

 event Approval(address indexed tokenOwner, address indexed spender, uint tokens); event Transfer(address indexed from, address indexed to, uint tokens);

Эти события будут вызываться или создаваться, когда пользователю будут предоставлены права на вывод токенов из учетной записи, и после того, как токены будут фактически переданы.

В дополнение к стандартным функциям ERC20 многие токены ERC20 также имеют дополнительные поля, а некоторые стали де-факто частью стандарта ERC20, если не в письменной форме, то на практике. Вот несколько примеров таких полей.

 string public constant name; string public constant symbol; uint8 public constant decimals;

Вот несколько моментов, касающихся номенклатуры ERC20 и Solidity:

  • public функция может быть доступна вне самого контракта
  • view в основном означает константу, т. е. внутреннее состояние контракта не будет изменено функцией
  • event — это способ, с помощью которого Solidity позволяет клиентам, например интерфейсу вашего приложения, получать уведомления о конкретных событиях в рамках контракта.

Большинство языковых конструкций Solidity должны быть понятны, если вы уже обладаете необходимыми навыками Java/JavaScript.

Запись токена ERC20 в Solidity

Токены ERC20 в солидности

Теперь, когда мы изложили основы и объяснили, что нужно для создания токена ERC20, пришло время приступить к написанию некоторой логики.

Во-первых, нам нужно определить два объекта сопоставления. Это понятие Solidity для ассоциативного массива или массива ключ/значение:

 mapping(address => uint256) balances; mapping(address => mapping (address => uint256)) allowed;

mapping(address => uint256) определяет ассоциативный массив, ключи которого имеют тип address — число, используемое для обозначения адресов учетных записей, и значения которого имеют тип uint256 — 256-битное целое число, обычно используемое для хранения балансов токенов.

Первый объект сопоставления, balances , будет содержать баланс токенов каждой учетной записи владельца.

Второй объект сопоставления, allowed , будет включать в себя все учётные записи, одобренные для снятия средств с данной учётной записи, вместе с суммой снятия, разрешенной для каждой.

Как вы можете видеть, поле значения разрешенного сопоставления само по себе является сопоставлением адреса учетной записи с утвержденной суммой снятия.

Эти сопоставления вместе со всеми другими полями контракта будут храниться в блокчейне и будут анализироваться , что приведет к распространению изменений на все узлы пользователей сети.

Хранение в блокчейне стоит дорого, и пользователям вашего контракта так или иначе придется платить. Поэтому вы всегда должны стараться минимизировать размер хранилища и записи в блокчейн.

Теперь, когда у нас есть необходимые структуры данных, мы можем начать фактически записывать логику ERC20 в соответствующие функции.

Установка количества токенов ICO

Как мы устанавливаем количество токенов ICO? Ну, есть несколько способов установить максимальное количество токенов ICO, и этот вопрос сам по себе может заслуживать длительного обсуждения.

Для нужд нашего руководства по ECR20 мы будем использовать самый простой подход: установить общее количество токенов во время создания контракта и первоначально назначить их всех «владельцу контракта», то есть учетной записи, которая развернула смарт-контракт:

 uint256 totalSupply_; constructor(uint256 total) public { totalSupply_ = total; balances[msg.sender] = _totalSupply; }

Конструктор — это специальная функция, автоматически вызываемая Ethereum сразу после развертывания контракта. Обычно он используется для инициализации состояния токена с использованием параметров, переданных учетной записью развертывания контракта.

msg — это глобальная переменная, объявленная и заполненная самим Ethereum. Он содержит важные данные для выполнения контракта. Поле, которое мы используем здесь: msg.sender содержит учетную запись Ethereum, выполняющую текущую функцию контракта.

Только развертывающая учетная запись может войти в конструктор контракта. Когда контракт запущен, эта функция выделяет доступные токены учетной записи «владельца контракта».

Получить общее количество токенов

 function totalSupply() public view returns (uint256) { return totalSupply_; }

Эта функция вернет количество всех токенов, выделенных этим контрактом, независимо от владельца.

Получить баланс токенов владельца

 function balanceOf(address tokenOwner) public view returns (uint) { return balances[tokenOwner]; }

balanceOf вернет текущий баланс токена учетной записи, идентифицированный по адресу его владельца.

Перевести токены на другую учетную запись

 function transfer(address receiver, uint numTokens) public 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; }

Как следует из названия, функция transfer используется для перемещения количества токенов numTokens с баланса владельца на баланс другого пользователя или receiver . Передающим владельцем является msg.sender , то есть тот, кто выполняет функцию, что означает, что только владелец токенов может передавать их другим.

В Solidity используется способ утверждения предиката require . В этом случае на переводящем счете достаточно средств для выполнения перевода. Если оператор запроса терпит неудачу, транзакция немедленно откатывается без require изменений в блокчейн.

Прямо перед выходом функция запускает событие ERC20 Transfer , позволяя зарегистрированным слушателям реагировать на его завершение.

Утвердить делегата для снятия токенов

Эта функция чаще всего используется в сценарии рынка токенов.

 function approve(address delegate, uint numTokens) public returns (bool) { allowed[msg.sender][delegate] = numTokens; emit Approval(msg.sender, delegate, numTokens); return true; }

Одобрение позволяет владельцу, т.е. msg.sender , approve делегированную учетную запись — возможно, саму торговую площадку — для снятия токенов со своей учетной записи и передачи их на другие учетные записи.

Как видите, эта функция используется для сценариев, когда владельцы предлагают токены на торговой площадке. Это позволяет торговой площадке завершить транзакцию, не дожидаясь предварительного одобрения.

В конце своего выполнения эта функция запускает событие Approval .

Получите одобренное количество токенов для вывода

 function allowance(address owner, address delegate) public view returns (uint) { return allowed[owner][delegate]; }

Эта функция возвращает текущее утвержденное количество токенов владельцем конкретному делегату, как установлено в функции approve .

Передача токенов делегатом

Функция transferFrom является аналогом функции approve , которую мы обсуждали ранее. Это позволяет делегату, одобренному для снятия средств, переводить средства владельца на сторонний счет.

 function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) { require(numTokens <= balances[owner]); require(numTokens <= allowed[owner][msg.sender]); balances[owner] = balances[owner] — numTokens; allowed[owner][msg.sender] = allowed[from][msg.sender] — numTokens; balances[buyer] = balances[buyer] + numTokens; Transfer(owner, buyer, numTokens); return true; }

Два оператора require при запуске функции предназначены для проверки того, что транзакция является законной, т. е. что у владельца достаточно токенов для передачи и что делегат имеет разрешение на вывод (по крайней мере) numTokens .

В дополнение к передаче суммы numTokens от владельца к покупателю, эта функция также вычитает numTokens из разрешения делегата. Это в основном позволяет делегату с заданным допуском разбить его на несколько отдельных выводов, что является типичным поведением на рынке.

Мы могли бы остановиться здесь и получить действующую реализацию ERC20. Однако мы хотим пойти еще дальше, так как нам нужен токен промышленного уровня. Это требует от нас сделать наш код немного более безопасным, хотя мы все равно сможем сохранить токен относительно простым, если не базовым.

Библиотека SafeMath Solidity

SafeMath — это библиотека Solidity, предназначенная для борьбы с одним из известных способов нарушения контрактов хакерами: атакой с переполнением целых чисел. При такой атаке хакер заставляет контракт использовать неверные числовые значения, передавая параметры, которые будут принимать соответствующие целые числа выше их максимальных значений.

Библиотека Safemath в Solidity: иллюстрация

SafeMath защищает от этого, проверяя переполнение перед выполнением арифметического действия, тем самым устраняя опасность атаки переполнения. Библиотека настолько мала, что влияние на размер контракта минимально, не влияет на производительность и требует небольших затрат на хранение.

Давайте добавим SafeMath в наш код:

 library SafeMath { // Only relevant functions function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a — b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } }

SafeMath использует assert утверждений для проверки правильности переданных параметров. В случае сбоя assert выполнение функции будет немедленно остановлено, а все изменения в блокчейне будут отменены.

Далее добавим следующий оператор, представляющий библиотеку компилятору Solidity:

using SafeMath for uint256;

Затем мы заменяем наивную арифметику, которую мы использовали в начале, функциями SafeMath:

 balances[msg.sender] = balances[msg.sender].sub(numTokens); balances[receiver] = balances[receiver].add(numTokens); balances[buyer] = balances[buyer].add(numTokens); balances[owner] = balances[owner].sub(numTokens);

Собираем все вместе

В Solidity функции и события смарт-контракта заключены в объект, называемый контрактом , который вы можете незаметно преобразовать в «класс блокчейна». Ниже представлен созданный нами контракт, совместимый с ERC20, включая суть нашего кода. Поля имени и символа могут быть изменены по желанию. Большинство токенов сохраняют десятичное значение равным 18, поэтому мы сделаем то же самое.

Развертывание контракта Ethereum

Пришло время развернуть наш контракт в блокчейне. После развертывания наш контракт будет передан всем узлам, участвующим в сети. Любые и все изменения, внесенные в контракт, будут распространены на все участвующие узлы.

Разработчики Ethereum обычно используют инструменты развертывания, такие как Truffle. Даже Truffle является излишним для ограниченных потребностей этой статьи, и простого онлайн-инструмента под названием Remix будет достаточно.

Чтобы использовать его, вам необходимо установить плагин MetaMask в свой браузер и учетную запись Rinkeby (тестовая сеть Ethereum), по крайней мере, с некоторым количеством Rinkeby Ether. Это относительно простые шаги, поэтому мы не будем вдаваться в подробности.

Если у вас их нет, перейдите на сайты MetaMask и Rinkeby, чтобы получить ссылки для скачивания и четкие инструкции по установке и использованию.

Теперь, когда у нас есть все строительные блоки, мы перейдем к Remix и вставим приведенный выше код, включая строку pragma и библиотеку SafeMath, в онлайн-редактор.

Затем мы перейдем на вторую вкладку справа под названием « Выполнить » и нажмем « Развернуть ». Появится всплывающее окно MetaMask с просьбой подтвердить транзакцию. Конечно, одобрим.

альтернативный текст изображения

  • Зеленое поле: убедитесь, что вы находитесь на Ринкеби.
  • Синее поле: установите общее количество токенов.
  • Красная коробка: Развернуть!

Суть : https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be#file-basicerc20-sol

Поздравляю! Вы только что развернули свой первый токен ERC20, как настоящий профессионал Ethereum. Как и было обещано, токен простой и легкий, но при этом полностью функциональный, совместимый со стандартом ERC20 и защищенный с помощью MathSafe. Он готов к покупке, оплате и передаче по блокчейну.

Это все, что нужно знать о смарт-контрактах?

Нет, даже не близко, так как наша краткая демонстрация едва затрагивает поверхность и касается исключительно одного аспекта разработки смарт-контрактов.

Смарт-контракты могут быть гораздо более сложными в зависимости от вашей бизнес-логики, вашего моделирования взаимодействия с пользователем, того, разрешаете ли вы чеканку и сжигание токенов, изменений жизненного цикла, которые вы вносите в контракт, необходимости в возможностях уровня администратора, которые обычно сопровождаются набор функций, авторизованный администратором, и так далее. Вы получаете картину.

Тем не менее, если вы сможете воспроизвести то, что мы сделали здесь, это станет прочной основой для расширения ваших знаний и перехода к более сложным контрактам, когда это необходимо.