Пишем смарт-контракт Ethereum — это просто: Часть 6 — токен ERC20 — рефакторинг

Предыдущий урок можно посмотреть тут.Полный список уроков тут.

В предыдущем уроке мы с вами написали свой первый токен ERC20. Код мы писали на ходу и поместили практически весь функционал в один контракт. Для быстроты изучения это было хорошо. Но теперь пора научиться писать контракты по-взрослому. Вот некоторые рекомендации по написанию хорошего контракта:

  1. Не изобретать велосипед, а стараться брать уже готовые решения и изменять их под себя. Если задача популярная, значит до вас уже наступили на все грабли и нашли решение. Воспользуйтесь этим решением, не надо тратить свое время.  Так токенов ERC20 уже написано довольно много. И на GitHub’е можно всегда посмотреть код. Например вот этот.
  2. Использовать устоявшиеся шаблоны проектирования. Такие шаблоны построены на основе опыта решения задач другими программистами. Так контракт токена ERC20 обычно имеет структуру наследования, которая не существенно отличается от проекта к проекту.
  3. Стараться выделять код который можно переиспользовать. Мы с вами в предыдущих уроках выделили контракт Ownable. И уже убедились что не зря. Мы его использовали в контракте-визитке и в нашем токене.
  4. Выделяйте стандарты в виде интерфейсов. Одна из причин такого подхода — в нашем коде невозможно понять какие из функций относятся к стандарту а какие нет.

Давайте посмотрим на часто-встречающуюся структуру наследования токена ERC20.

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

В предыдущем уроке мы говорили только о стандарте ERC20. А тут появился какой-то ERC179. Тут все просто. Как оказалось не всем нужна часть, которая отвечает за предоставление разрешений на снятие средств. Поэтому все функции не относящиеся к механизму предоставления разрешений вынесли в ERC179. Поэтому стандарт ERC20 этот тот же ERC179 только с дополнительными функциями и событиями.

Контракты StandartToken и BasicToken — это частичные реализации стандартов.

Поскольку наш токен полностью соответствует ERC20 то мы будем наследоваться от контракта StandartToken.

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

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

С учетом всего вышесказанного структура контрактов нашего токена теперь выглядит так

Важно понимать что от библиотек не наследуются. Их «используют», т.е. подключют к контракту. Например для SafeMath это выглядит так:

Возьмем готовый код стандартных шаблонов из репозитория ZeppelinSolidity и перепишем наш токен:

  1. ERC20Basic — интерфейс ERC179 , т.е. ERC20 без механизма предоставления разрешений
  2. ERC20 — интерфейс ERC20
  3. BasicToken — абстрактная реализация ERC179
  4. StandartToken — абстрактная реализация ERC20
  5. Ownable — предоставляет возможность ограничивать доступ к функциям всем кроме владельца контракта
  6. SafeMath — библиотека безопасных математических операций. В случае проблем с выполнением операции работа функции прерывается
  7. MintableToken — предоставляет возможность выпуска новых монет. Если выпуск новых монет больше не нужен, то вызывается finishMinting (в ICO вызывается как правило после окончания распродажи монет). Возобновить выпуск монет больше будет нельзя. Конечно можно было бы дописать функцию, которая разрешает доп.эмиссию монет. Но шаблон скорее всего часто используется в ICO. В случае доп.эмиссии после ICO стоимость монеты может размываться. А это плохо для покупателей нашей монеты. Поэтому если покупатель увидит что после окончания ICO не будет физической возможность выпустить новые монеты, то доверие к нам повысится.

А теперь посмотрите сколько строк кода пришлось бы нам писать с нуля, если бы мы сразу использовали готовые решения:

Все остальное мы бы просто скопировали. А вот полный код:

В этом уроке мы познакомились с общим подходом написания контрактов монеты ERC20. Научились использовать готовые решения, что сильно упростило нам задачу и избавило от ошибок. Следует отметить что многие контракты написаны так, чтобы избежать уязвимости. Это может быть банальное перемещение двух строк кода, что не всегда очевидно для новичка.

Фактически из этих контрактов-кирпичиков мы можем собрать свой контракт на любой вкус с наименьшими усилиями. На самом деле таких устоявшихся шаблонов проектирования в solidity очень много. В дальнейшем мы познакомимся с некоторыми из них. А пока тут можно найти документацию по самым популярным шаблонам от OpenZeppelin.

Продолжение читать тут. Предыдущий урок тут.

Если у вас возникли вопросы то можете смело писать на электронную почту (раздел «контакты«). Также приветствуется критика.

Если статья показалась вам полезной и вы желаете отблагодарить автора, то это можно сделать отослав немного эфира на адрес 0xEA15Adb66DC92a4BbCcC8Bf32fd25E2e86a2A770.

Полный список уроков тут.

 

  1. Подскажите пжс, а что значит такое сообщение при создании токена?
    Такое же сообщение выскакивает при запуске моего токена…

    creation of browser/ballot.sol:SimpleTokenCoin pending…
    [vm] from:0xca3…a733c, to:browser/ballot.sol:SimpleTokenCoin.(constructor), value:0 wei, data:0x606…e0029, 0 logs, hash:0x3eb…c694a
    Details
    Debug
    undefined errored: Cannot read property ‘op’ of undefined
    undefined errored: Cannot read property ‘op’ of undefined
    undefined errored: Cannot read property ‘op’ of undefined
    undefined errored: Cannot read property ‘op’ of undefined
    undefined errored: Cannot read property ‘op’ of undefined
    undefined errored: Cannot read property ‘op’ of undefined

    • Это специфика Remix. В основном на такие ошибки обращать не стоит. Remix недавно обновился и поэтому есть некоторые проблемы.

  2. Доброго времени суток.

    А как подключить в Remix библиотеки (в том числе OpenZeppelin)
    При попытке компиляции Вашего примера, выдаёт:
    browser/ballot.sol:3:29: DeclarationError: Identifier not found or not unique.
    contract SimpleTokenCoin is MintableToken {

    Подчёркивая MintableToken.

    Понимаю, что не видит OpenZeppelin. Но как подключить не пойму ((

  3. Кажется нашёл.

    Надо добавить в начале
    import «github.com/OpenZeppelin/zeppelin-solidity/contracts/token/MintableToken.sol»;

    Вопрос подключения внешних библиотек (файлов) совсем не описан в рунете. ((
    Мелочь, но вгоняет ступор.

    Такая запись так же подгружает всё на что MintableToken.sol ссылается внутри.

    • Реально полезная находка! Спасибо огромное!

    • я не смогла подключить данным способом. Пишет:

      Error: Could not find github.com/OpenZeppelin/zeppelin-solidity/contracts/token/MintableToken.sol from any sources; imported from /Users/…/SimpleTokenCoin.sol
      _____
      Truffle v3.4.11 (core: 3.4.11)
      Solidity v0.4.15 (solc-js)
      ___
      кто-нибудь может помочь с этим?

  4. При компиляции в ремиксе выдает ошибки:

    1. Для функции transferFromParserError:
    Expected token LParen got ‘Identifier’
    и следующей ParserError: Expected identifier, got ‘LBrace’
    2. Для contract Ownable
    ParserError: expected primary expression

    В чем может быть проблема?

  5. Доброго времени суток.
    Правильно, ли я понимаю, что функцию finishMinting() нужно будет вызвать вручную после окончания ICO (к примеру)?
    И вызывать ее нужно будет с адреса смарт-контракта.

  6. У вас тут опечатка:
    saleAgent = newSaleAgnet;
    Что делает команда assert? И не могли бы вы рассказать про address indexed и internal pure returns, чем они от обычных отличаются?

Добавить комментарий для Иван Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *