Пишем смарт-контракт Ethereum — это просто: Часть 8 — ICO рефакторинг, выделение токенов для баунти и команды

В прошлом уроке мы написали наш первый ICO смарт-контракт! (полный список уроков тут) В этом уроке мы продолжим изучать как написать смарт-контракт ICO на эфире. И сделаем следующие улучшения:

  1. Установим границу сбора средств — hardcap. Т.е. если необходимая сумма в эфире собрана, то продажу токенов останавливаем. Конечно мы можем продолжить и дальше сбор. Но! Обычно цели на которые собираются средства прописываются в White Paper (информация о проекте для инвесторов). И на каждую цель указывается сумма, чтобы инвестор понимал куда пойдут его деньги. Если нет границы на сбор средств то это будет выглядеть подозрительно и у инвесторов возникнет много вопросов.
  2. После окончания ICO выпустим долю токенов для своих нужд. В White Paper как правило прописывается доля токенов в процентном соотношении, которая остается у основателей. Часть из них может пойти основателям в карман, часть на оплату баунти-кампаний (пиар-кампании в соц.сетях, СМИ, блогах, форумах).

Итак, приступим.

Во первых вынесем код проверки дат ICO в модификатор (код контракта ICO можно посмотреть в конце предыдущего урока). Раньше проверка у нас была такой:

А теперь будет как модификатор:

Тут внимательный читатель заметит, что вместо умножения «24*60*60» мы использовали «1 days». В solidty есть встроенные единицы измерения (ссылка на официальную документацию).  Вот они:

  1. 1 == 1 seconds
  2. 1 minutes == 60 seconds
  3. 1 hours == 60 minutes
  4. 1 days == 24 hours
  5. 1 weeks == 7 days
  6. 1 years == 365 days

Соответственно при их использовании происходит пересчет в секунды. Есть тонкий момент. Если вы используете число с единицей измерения, например вот так:

то все будет работать нормально. Если же вы хотите умножить на переменную и запишите так

То компилятор будет ругаться, поэтому необходимо использовать так:

 

В контракте ICO  обычно полученный эфир не отсылают на адрес владельца контракта, а отсылают его на отдельный адрес. Это делается затем, что на отдельном адресе может быть как обычный аккаунт, так и контракт эскроу (специальный счет, управляемый доверенными лицами,  в целях повышения доверия инвесторов — об этом мы поговорим в следующих уроках). В нашем случае мы будем задавать адрес простого аккаунта в конструкторе. Называться у нас он будет multisig.

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

Пока задавать значение не будем. Все это мы сделаем в конце в конструкторе контракта ICO.

Теперь напишем модификатор, который будет проверять условие по hardcap. Мы имеем верхнюю границу hardcap и адрес на который будут отправляться средства, а баланс аккаунта  хранится в поле balance. Запишем наш модификатор

Еще немного рефакторинга. Вынесем код из fallback (напоминаю — fallback функция вызывается у контракта, когда на него пересылают эфир) функции в отдельную функцию. Заменим условие начала распродажи на модификатор и добавим модификатор верхней границы средств.

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

Тогда наша функция createTokens немного изменится:

Мы используем операции div и mul из библиотеки безопасных математических операций SafeMath (см. урок 6), поэтому не забываем ее подключить.

Обратите внимание что функция createTokens объявлена как payable, потому что принимаем эфир. Частая ошибка когда забывают указать payable!

Теперь давайте разберемся с выпуском токенов для наших нужд. Как мы уже отмечали ранее обычно в White Paper указывается какой процент токенов пойдет на распродажу, а какой останется для разработчиков и других нужд. Наш контракт заранее не выпускает токены, поэтому мы не можем заранее узнать сколько токенов будет выпущено. Поэтому рассчитывать токены себе мы будем в конце ICO. Мы напишем функцию finishMinting, которую самостоятельно будем вызывать в конце ICO.  И она нам рассчитает и выпустит токены. Для этого укажем счет — restricted . А также процент токенов, который мы хотим получить — restricedPercent. 

Осталось написать нашу функцию для расчета:

В ней мы берем у контракта токена количество всех выпущенных токенов, рассчитываем сколько нужно довыпустить нам restrictedTokens. Выпускаем их на счет restricted. А дальше вызываем finishMinting у контракта токена — эта функция запрещает выпускать новые токены (Содержится в шаблоне MintableToken  см. урок 6). Обратите внимание что мы не забыли использовать модификатор onlyOwner (он определен в контракте Ownable), потому как наша функция должна вызываться только владельцем контракта! В противном случае завершить ICO сможет любой посторонний человек.

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

 

Осталось только инициализировать поля в конструкторе, а для этого понадобится:

  1. Адрес куда будет перчислятся эфир — multisig. Пусть будет 0xEA15Adb66DC92a4BbCcC8Bf32fd25E2e86a2A770.
  2. Адрес куда будут перечисляться токены для наших нужд — restricted. Пусть будет — 0xb3eD172CC64839FB0C0Aa06aa129f402e994e7De.
  3. Процент токенов на наши нужды restrictedPercent пусть будет 40%.
  4. Время начала ICO  — GMT в UNIX формате (см. урок 7) — start. Пусть будет как в 7-мом уроке — 18 июля 2017 года в 15 часов. В UNIX — 1500379200. Для тестирования не забывайте поменять дату на свою!
  5. Время проведения ICO в днях — period. У нас будет 28 дней.
  6. rate у нас будет — 100000000000000000000

После всего этого полный контракт со всеми шаблонами выглядит так:

 

В этом уроке мы научились выпускать дополнительные токены по окончанию ICO. А также установили границу по сбору средств. Еще мы сделали несколько небольших улучшений. И теперь наш контракт выглядит почти как настоящий!

Ему не хватает только одной вещи — бонусов для тех инвесторов кто вкладывается пораньше. Поэтому в следующем уроке мы продолжим изучать как написать смарт-контракт ICO на эфире и займемся бонусами!

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

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

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

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

 

  1. 9-ая часть видится мне описанием типовой структуры виртуальной организации с учетом всех вспомогательных контрактов, коллегиальное управление счетом и так далее.

    • Да, это интересная тема.

      Прежде чем к ней приступить необходимо познакомить читателя с возможностью
      тестирования контрактов через тестовую сеть средствами кошельков MyEtherWallet и Mist. (Remix подходит только для простых контрактов).

      Приблизительный план такой.
      1) Отдельно будет статья по тестирования контрактов в тестовой сети.
      2) 9-ая часть — добавим бонусы и мелкие доработки в ICO.

      После этого закрою тему ICO и посмотрим виртуальную организацию.

  2. Спасибо автору за труды. Опишите тему ico подробнее, интересны связи контракта ico с токеном для этого ico. т.е. мы выпускаем токен контракт, потом ico контракт.. какое кол-во токенов закладывать, как курс устанавливать (сколько токенов через ico отправлять инвестору).. тема новая и нюансов много непонятных..

  3. 1. В соответствиис этим кодом, если я олтправлю 1 эфир то сколько мне придет Токенов?
    2. Мы собрали определенную (заранее обозначенную) сумму и после этого к этой сумме прибавляем наши 40% токенов. И таким образом 60% у народа и 40% у нас?

    • Видимо то, что если отослать на контракт 1 эфир, тебе придет 100 SimpleTokenCoin’ов

  4. В функции createTokens, которая вызывается при «оплате», вызывается функция token.mint(msg.sender, tokens). Она имеет модификатор «onlyOwner». Как в таком случае, покупку может совершить «сторонний» покупатель? При смене аккаунтов все работает, но я не могу понять почему.

    • насколько я понимаю, у контракта SimpleTokenCoin есть владелец — адрес контракта Crowdsale (когда Crowdsale разворачивается в сети, то сразу создается контракт SimpleTokenCoin). В итоге мы получаем, что token.mint(msg.sender, tokens); хоть и вызывает якобы отправитель эфира на адрес контракта Crowdsale, но дальше вызов token.mint производится от имени контракта Crowdsale (а он владелец контракта SimpleTokenCoin). Потому условие модификатора onlyOwner срабатывает при продаже токенов любому покупателю.
      Если не прав в формулировках, то коллеги меня поправят.

  5. Как можно получить токены, которые были выделены для баунти? мне не совсем понятно как они(токены для баунти) распределяются вручную или смартконтрактом ? Если смартконтрактом, тогда как это происходить можете подсказать ?

    • Ваш комментарий ожидает проверки.

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

  6. К какому сайту Вы хотите привязать?? Это смарт контракт который выкладываться в Ehter сеть, и зная его адрес вы можете получить все необходимые данные по данному контракту и купить токены.

  7. Подскажите привольно ли я понял, что функцию finishMinting() в Crowdsale контракте владелец должен вызвать самостоятельно(в ручную) после завершения ICO ?? И получается что владелеч может в любое время «прервать» свое ICO просто вызвав эту функцию??

  8. Остается не ясен момент с token.mint(msg.sender, tokens);
    Метод доступен только owner. Значит ли что Crowdsale является onwer для SimpleTokenCoin?
    Если так, то как тогда потом управлять контрактом SimpleTokenCoin? Ведь его владелец навсегда останется Crowdsale и нельзя будет вызвать методы доступные для Owner…

Добавить комментарий