inaword
Блог о разработке и современных технологиях
Пишем смарт-контракт Ethereum — это просто: Часть 7 — ICO
В сегодняшнем уроке вы узнаете как быстро создать смарт-контракт ico на ethereum. Конечно быстрый подход не лучший вариант когда вы работаете с деньгами. Но в учебных целях подойдет. Наш первый пример контракта ico на Solidity для Ethereum будет очень простым. А впоследствии мы будем его дополнять полезными фичами. Итак, приступим.
ICO — Initial Coin Offering. Первичное предложение токенов. Если вы вообще не знакомы с этим понятием, то сперва загляните на википедию. Вкратце на примере.
Допустим у группы людей появилась идея, но на ее реализацию нужны деньги. Тогда они рекламируют свою идею и призывают вложиться. Взамен они дают токены — валюту своего проекта. И как правило владельцам этих токенов что-то обещают. Например разделить между владельцами токенов какую-то часть прибыли проекта.
Жизненный цикл ICO может состоять из следующих стадий:
Мы сосредоточимся на второй части. Технически процесс прост. Инвестор отправляет эфир на контракт, отвечающий за распродажу. А контракт распродажи отдает команду выпустить токены и зачислить на ваш баланс.
Итак ICO состоит из двух контрактов:
В предыдущем уроке мы уже реализовали свой токен ERC20. И он был создан с применением шаблонам MintableToken. Т.е. он уже содержит функцию, которая выпускает новые токены на адрес владельца. Нам осталось только написать контракт распродажи!
Давайте условимся что распродажа токенов будет начинаться 18 июля 2017 года в 15 часов по Москве и длиться будет 30 дней. В solidity дата представляется в UNIX формате. Это количество секунд с 1 января 1970 года (можно воспользоваться сервисом перевода тут). При этом время должно быть указано не местное, а относительно Гринвичевского меридиана GMT. Итак разница между Москвой и GMT у нас + 3 часа. Тогда время начал распродажи по GMT — 18 июля 2017 года 12.00. Теперь воспользуемся сервисом перевода в UNIX формат и получим — 1500379200. Эта дата актуальна момент написания статьи. Поскольку дальше мы будем тестировать наш контракт, то лучше указать дату вчерашнего дня.
Итак в нашем контракте Сrowdsale буду следующие переменные
Когда пользователь нам пришлет деньги мы проверим что текущая дата больше чем дата начала распродажи и меньше чем дата конца распродажи. Если так, то эфир, который нам прислал пользователь мы мы переведем на счет владельца контракта. А затем выполним выпуск токенов на счет пользователя посредством вызова mint. Давайте запишем условие проверки:
Как добавить любой токен в кошелек MetaMask: сети ERC20, BEP20?
После завершения установки кошелька MetaMask по умолчанию отображается только ETH (Ethereum). В вашей учетной записи не будут отображаться другие токены BEP20.
Также некоторые новые и малоизвестные токены могут даже не отображаться в результатах поиска. Вам придется вручную добавлять такие токены в свой кошелек.
Добавить токен очень просто, и это займет у Вас всего несколько секунд.
В этом руководстве мы расскажем Вам как добавить токены ERC20 (Ethereum Chain) и BEP20 (Binance Smart Chain) в кошелек MetaMask.
Как добавить токены в кошелек MetaMask
Перед добавлением токенов в свою учетную запись MetaMask убедитесь, что вы выбрали правильную сеть. То есть; если вы хотите добавить токен ERC20, выберите «Ethereum Mainnet». Если вы хотите добавить токен BEP20, выберите «Binance Smart Chain».
Теперь давайте добавим токены в учетную запись MetaMask.
Попробуйте строку поиска:
Примечание. Функция поиска работает только в сети «Ethereum Mainnet». То есть MetaMask отображает только стандартные токены ERC20 в результатах поиска. Чтобы добавить токены BEP20, вам необходимо использовать параметр пользовательского токена, который мы объяснили ниже.
Как мы уже говорили, на вкладке поиска будут отображаться только самые распространенные и популярные токены. Если токен, который вы ищете, не отображается, используйте опцию пользовательского токена.
Добавление пользовательских токенов в MetaMask
Чтобы добавить токен, нам нужен только адрес контракта соответствующего токена.
Какой адрес токена (адрес контракта) и где их найти?
Зайдите на Etherscan.io, чтобы узнать номер контракта токена ERC20.
Используйте BscScan, чтобы найти детали контракта токена BEP20.
Используйте соответствующие блок эксплореры, найдите имя токена и скопируйте номер контракта. Вы увидите детали адреса контракта под сводкой профиля.
Шаги по добавлению пользовательского токена ERC20 в MetaMask
Пример адреса контракта токена RSR: 0x8762db106b2c2a0bccb3a80d1ed41273552616e8
Как только информация получена; нажмите «Далее» и добавьте токен. Пользовательский токен ERC20 теперь добавлен в ваш кошелек.
Шаги по добавлению пользовательского токена BEP20 в MetaMask
Процедура добавления токенов BEP20 такая же, как указано выше. За исключением того, что вам нужно будет использовать BscScan, чтобы найти адрес контракта BEP20.
Чтобы это сработало, убедитесь, что вы выбрали смарт-цепочку Binance и подключились к ней. Только тогда кошелек может получить информацию о токене BEP20.
Вот и все. Вы успешно добавили свой любимый токен ERC20 и BEP20. Ваш недавно добавленный токен будет отображаться на главном экране в списке токенов.
Где я могу разместить свои токены ERC20?
Для каждого токена не существует отдельного адреса. Просто отправьте токены на свой адрес MetaMask Ethereum, и токены появятся.
Адреса ERC20 и BEP20 начинаются с 0x.
Вы можете использовать ту же процедуру для добавления любых пользовательских токенов ERC20 или BEP20. Просто убедитесь, что вы переключились на правильную сеть.
Для ERC20 вы должны быть в основной сети Ethereum. Для токенов BEP20 вам следует перейти на Binance Smart Chain.
Теперь вы можете подключить свой кошелек и торговать токенами на Uniswap.
Спасибо за прочтение. Если вам нравится это руководство, подпишитесь на нас в Telegram чате и в YouTube канале, чтобы получать больше обновлений.
Смарт контракты Ethereum: структурируем токены как акции
Чтобы говорить вообще о каком-либо структурировании токена, прежде всего нужно иметь хоть какую-то базовую реализацию токена. Листинг контракта среднестатистического токена без изысков на языке Solidity приведен ниже:
Как видно из кода контракта, эмиссия всех токенов осуществляется единовременно в момент загрузки контракта в блокчейн, а все выпущенные токены записываются на баланс адреса, осуществившего эту загрузку. Далее реализуются стандартные функции перемещения токенов между держателями – transfer и transferFrom, а текущий баланс хранится в карте balanceOf.
Не будем думать, каким образом деньги (эфир, ether) попадают на счет данного контракта, это неважно, переводятся ли они напрямую на адрес контракта или попадают туда через какие-то функции, которые могут быть дополнительно реализованы для придания токену прикладной специфичности и функциональности. Важно, что имеет место быть некий ненулевой баланс контракта this.balance, который мы хотим полностью распределить между держателями токенов, пропорционально имеющему у каждого держателя проценту токенов от общей эмиссии.
С точки зрения классического алгоритмического программирования, задача может показаться элементарной и в виде псевдокода выглядит так:
К сожалению, данный псевдокод нереализуем на языке Solidity, т.к. структура данных mapping не является итерируемой и отсутствует какая-либо возможность пройтись по всем ее элементам. На форумах Ethereum эта задача неоднократно обсуждалась, и основной аргумент, почему сделано так, заключается в том, что это банально дорого. Тут самое время вспомнить, что смартконтракт выполняется на распределенной виртуальной машине EVM, т.е. выполняется на каждой полной ноде, а поскольку мы расходуем чужие вычислительные ресурсы, то за это придется платить, причем чем больше мы делаем операций, тем больше комиссия, которую потребуется заплатить тому, кто будет вызывать эти операции. В нашем случае платить будет тот, кто будет вызывать divideUpReward().
Если продолжить упорствовать и пытаться реализовать данный псевдокод на Solidity, то можно изобрести собственный «велосипед» и сделать итерируемый аналог mapping. Пример такой реализации имеется в открытом доступе (тут), но он не решает проблему высокой стоимости выполнения функции divideUpReward(). Более того, мы еще и берем на себя все расходы по оплате транзакций отправки эфиров holder.key.send(reward) всем держателях токенов.
Возникает логичное желание переложить все комиссии по получению собственных дивидендов непосредственно на держателя токенов – в конце концов это его вознаграждение, пусть он сам и платит за него комиссии, а наши расходы, как держателя смарт контракта должны быть минимизированы какой-то простой процедурой.
А почему бы не сделать вот так?
Этот код выглядит уже значительно лучше, т.к. не содержит циклов! Мы, как владелец контракта, или любой другой пользователь Ethereum, вызываем публичную функцию divideUpReward(), которая фиксирует дивиденды на момент вызова, создавая копию контейнера с текущим распределением токенов и запоминая текущий баланс контракта, предоставляя его весь на распределение между держателями токенов. При этом мы запоминаем время последнего вызова divideUpReward() и предотвращаем повторный вызов в течение 30 дней, давая тем самым возможность держателям токенов вывести свои дивиденды через публичную функцию reward(). Если какой-то держатель в течение обозначенного времени не вывел свои дивиденды, то они возвращаются в общую корзину и в течение следующего периода будут доступны к распределению между всеми держателями – как говорится, кто не успел, тот опоздал.
Функцию withdrawReward() вызывают уже непосредственно держатели токенов, а следовательно именно они оплачивают все комиссии, связанные с отправкой средств на их адреса. Можно было бы порадоваться найденному решению, если бы оно не содержало одну конструкцию, недопустимую с точки зрения языка Solidity, а именно “balanceOfOld = balanceOf” – создание копии mapping не предусмотрено в Solidity. Но даже если предположить, что оно было бы, то логично ожидать, что стоимость такого копирования была бы в пределе крайне дорогой, т.к. все равно предполагала бы наличие пусть скрытого, но цикла по всем элементам карты.
Попробуем избавиться от операции явного копирования, введением дополнительного контейнера, который будет динамически заполняться в зависимости от действий конкретного держателя токенов, а следовательно, производиться за его счет.
Следует обратить внимание на функцию beforeBalanceChanged(address _who), которая как раз и заменяет нам копирование карты mapping. Вызов этой функции следует добавить в исходные функции transfer и transferFrom нашего контракта прямо перед модификацией баланса для конкретного адреса. Функция проверит, что осуществляется движение токенов после фиксации периода вывода дивидендов и осуществит сохранения баланса конкретного держателя токенов для периода распределения вознаграждения, т.е. мы делаем копию balanceOf поэлементно, только если баланс конкретного держателя меняется.
Если соединить все сказанное воедино, то получится следующий текст смарт контракта, осуществляющего эмиссию токенов, их структурирование как акций с последующим начислением дивидендов:
Следует помнить, что за рамки обсуждения выведены правовые аспекты эмиссии токенов, структурированных как акции, поэтому применение указанных технических решений остается целиком и полностью ответственностью того, кто выведет такой контракт на ICO.
Полезные ссылки по теме разработки смарт контрактов для Ethereum:
Руководство: Как создать токены на базе Ethereum
Можно ли выпустить собственные токены, провести ICO, заработать миллионы долларов и зажить криптомечтой менее чем за 20 минут? Ответ — да. Рассказываем, как выпустить токены с помощью одного смарт-контракта и кошелька MyEtherWallet.
Токены будут соответствовать стандарту ERC-20 и включать основные функции. Их можно использовать как базу для более сложных приложений, а не только для платежей.
Помните: большие возможности связаны с высокой ответственностью. Будьте осторожны со своей криптовалютой и используйте потенциал технологии во благо.
Для создания собственных токенов потребуются следующие компоненты:
Адрес Ethereum
Текстовый редактор
Выберите один из следующих текстовых редакторов:
Контракт
Ropsten-эфир
Получить немного Ropsten-эфира можно по адресу https://faucet.bitfwd.xyz/. Для этого введите адрес своего Ropsten-кошелька, пройдите тест CAPTCHA и нажмите «Get ETH!» (ограничитесь одним разом, пожалуйста).
Теперь давайте напишем немного кода:

Значения «decimals» и «_totalSupply» в 118-й и 119-й строках можно не менять. Поле «decimals» указывает на минимальное дробное значение токена (в данном случае токен можно разделить на 10 в 18 степени, или квинтиллион частей). Если вы собираетесь выпустить 100 токенов, необходимо в _totalSupply указать полное число их минимальных частей (т. е. 100 000 000 000 000 000 000).
На этом редактирование завершено; сохраните файл.
Нажмите на подтверждение транзакции или перейдите на сайт https://ropsten.etherscan.io чтобы убедиться, что контракт был создан (можно провести поиск по адресу). Если этого не произошло, попытайтесь снова и постарайтесь понять, что пошло не так. Если все получилось — можете гордиться собой. В этом случае вы увидите страницу примерно следующего содержания:
Теперь нужно зарегистрировать контракт. Для этого на странице «Contract Overview» перейдите по ссылке «Contract Address», выберите вкладку «Code», нажмите на ссылку «Verify and Publish».
Все почти готово. Следующие шаги крайне важны, поэтому отнеситесь к ним с максимальным вниманием. По сути мы должны подтвердить, что это действительно наш код, и зарегистрировать его в сети навсегда.
Так что если вы наделаете ошибок, они останутся навечно.
На этой странице необходимо сделать 5 вещей:
Оставьте остальные поля без изменений и нажмите «Verify And Publish»
Именно к этому моменту вы стремились. Скрестите пальцы и ждите…
Если появилась страница подтверждения с фразой «Successfully generated ByteCode and ABI for Contract Address» зеленого цвета — поздравляем, вы успешно зарегистрировали свой токен и можете гордиться! Теперь вы киберпанк и часть криптовалютного движения. Ура!
Если появятся ошибки, вернитесь к предыдущему шагу и проверьте, все ли правильно сделали. Также всегда можно поискать помощи в интернете.
Чтобы убедиться, что токены выпущены, перейдите на сайт https://ropsten.etherscan.io/ и введите свой адрес MyEtherWallet (не контракта, а публичный). Вы должны увидеть свои токены. Теперь можно расслабиться и отпраздновать!
Чтобы иметь возможность отправлять токены, необходимо зайти в свою учетную запись MyEtherWallet, перейти на вкладку «Информация о Кошельке» и нажать на кнопку «Добавить свой токен». После этого их можно переводить на другие счета.
Будь в курсе! Подписывайся на Криптовалюта.Tech в Telegram
Смарт контракты Ethereum: пишем простой контракт для ICO
В последнее время ко мне поступает огромное количество запросов за помощью в разработке смартконтракта для проведения ICO, при этом у меня не хватает времени, чтобы помочь каждому. Поэтому я решил написать этот небольшой пост (ссылка на видео в конце поста), в котором описываю очень простой смартконтракт для проведения crowdsale, который вы можете использовать в своих проектах.
Для экономии времени я написал контракт заранее. Давайте разберем его по шагам.
Смартконтракт является программой написанной на языке программирования. В нашем случае на языке Solidity. Для разработки простых контрактов я использую онлайн редактор и компилятор Remix.
Признаком хорошего тона считается начинать любую программу, в т.ч. и смартконтракт, с указания лицензии, на основе которой она распространяется. В нашем случае это GPL. Также можно указать себя в качестве автора контракта, конечно, если вы не пишете контракт для какого-нибудь скамового проекта, где стесняетесь указать себя в качестве автора.
Сразу после идет строка, которая указывает, какую версию компиллятора следует использовать. Если этой строки не будет, то смартконтракт не скомпилируется.
Далее идет непосредственно исходный код самого смартконтракта, который я структурировал в виде иерархии контрактов, каждый из которых реализует законченную функциональность. Это упрощает понимание и последующее использование кода в ваших контрактах.
Прежде всего следует понимать, что после загрузки смартконтракта в виртуальную машину Ethereum вы будете взаимодействовать с ним на общих основаниях, как и все остальные пользователи. Логично, что мы, как команда проекта, хотели бы находиться в привилегированных условиях, которые должны как минимум выражаться в том, что контракт должен сформировать именно на командные токены и конечно же отдал именно нам собранный эфир. Для этого контракт должен знать своего владельца и именно за это отвечает контракт «owned».
Контракт «owned» содержит лишь одно публичное поле «owner», значение которого инициализируется в конструкторе значением поля «sender» глобальной структуры «msg», таким образом, изначально владельцем контракта становится тот, кто осуществил его деплой.
Логично предусмотреть возможность смены владельца на случай, если наш private key будет скомпрометирован, для этого предусмотрена функция «changeOwner», которая получает в качестве параметра адрес нового владельца. Следует обратить на модификатор «onlyOwner», который определен внутри этого же смартконтракта. Модификаторы представляют собой очень удобную конструкцию, позволяющую сгруппировать и присвоить название условиям вызова функций смартконтракта. Модификатор «onlyOwner» проверяет, что вызов функции осуществляется с адреса, который сохранен в поле «owner».
Контракт «owned» полностью работоспособен и предельно прост, однако несет в себе одну скрытую угрозу, ведь при вызове функции «changeOwner» мы можем по ошибке указать несуществующий адрес, а значит, потеряем контроль над контрактом. Чтобы исправить этот недостаток, достаточно ввести еще поле, назовем его «candidate», а при вызове функции «changeOwner» будем сохранять новое значение сначала в «candidate», а перемещать его в «owner» будем, как только кандидат подтвердит свое вступление в права, вызвав со своего адресу функцию «confirmOwner».
Следующий в иерархии контракт – «Crowdsale», отвечает непосредственно за сбор средств и выдачу токенов и наследует рассмотренный ранее контракт «owned».
Особое внимание следует обратить на следующие элементы контракта:
Конструктор смартконтракта «Crowdsale» предельно прост. Прежде всего инициализируется значение поля «totalSupply». Наш контракт выпускает 21 миллион токенов, из которых 20 миллионов сразу будут перемещены на баланс смартконтракта. Будем считать, что токены с адреса смартконтракта как раз и доступны для продажи. Оставшиеся токены, в нашем случае 1 миллион, будут записаны на адрес владельца контракта. Ну и в конце конструктора испускается событие «Transfer», которое помещается в блокчейн и информирует пользователей контракта о том, что с баланса контракта на баланс владельца контракта переведено соответствующее количество токенов. Именно испускание этого события позволит etherscan.io корректно отобразить держателей токенов и их балансы.
Ну и самая главная функция смартконтракта «Crowdsale», так называемая fallback функция, которая вызывается каждый раз, когда эфир поступает на адрес нашего смартконтракта. В самом начале осуществляется проверка, что на балансе смартконтракта есть хоть какое-то количество токенов для продажи. Далее устанавливаем фиксированную цену токенов – 5000 штук за 1 эфир. Затем вычисляем, сколько токенов необходимо отправить отправителю эфира. Количество переданных в транзакции средств записано в поле «value» глобальной структуры «msg» и указано оно в «wei», поэтому при определении количества токенов осуществляем перевод «wei» в «ether».
Затем осуществляется проверка того, что на балансе смартконтракта есть достаточное количество токенов для продажи. Если запрошено больше токенов, чем есть у смартконтракта, то будем переводить все оставшиеся токены. Определяем стоимость в «wei» оставшихся токенов и возвращаем отправителю излишне переведенный эфир. Убеждаемся, что количество покупаемых токенов ненулевое, после чего записываем это количество токенов на баланс покупателя и списываем их с баланса смартконтракта. В конце не забываем испустить событие Transfer.
На этом собственно реализация функциональности сбора средств закончена, но теперь нужно сделать наш токен операбельным и реализовать еще некоторые функции стандарта ERC20. Это сделано в контракте «EasyToken», который наследуется от рассмотренного ранее контракта «Crowdsale».
Прежде всего определим 4 публичных поля, которые сейчас практически не используются никакими кошельками, но для порядка все же определим их. Здесь укажем полное и сокращенное наименование токена, а также количество дробных знаков. В нашем случае токен является неделимым, т.к. значение поля «decimals» установлено равным 0.
И наконец, единственной функцией смартконтракта «EasyToken», ради которой мы создавали этот контракт, является «transfer», которая также является частью стандарта ERC20 и позволит кошелькам пользователей осуществлять передачу токенов друг другу, переводить их на биржу и выводить их с нее. Реализация функции крайне проста, проверяется достаточность количества токенов на балансе отправителя, после чего баланс отправителя уменьшается, а баланс получателя увеличивается на запрошенное количество токенов. В конце испускается событие «Transfer». Теперь наш токен является операбельным и осталось сделать самое главное – предоставить владельцу контракта возможность вывести собранные эфиры. Это мы сделаем в контракте «EasyCrowdsale».
Функция «withdraw» имеет модификатор «onlyOwner», т.е. может быть вызвана только владельцем смартконтракта. Единственное, что она делает – переводит весь баланс смартконтракта на адрес владельца смартконтракта.
Несмотря на то, что рассмотренный нами смартконтракт является полностью функционально законченным и работоспособным, использовать его в реальном проекте я бы не рекомендовал. Чрезмерное упрощение логики контракта привело к тому, что такой контракт не обеспечивает защиту интересов инвесторов в должной мере, а именно, не устанавливает срок проведения crowdsale, не устанавливает минимальной границы сбора, не возвращает средства инвесторам в случае недостижения минимальной границы, а также содержит ряд известных уязвимостей на уровне компилятора языка Solidity, например, подвержен так называемой short address attack.
Многие из этих недостатков устранены в смартконтракте нашего проекта PROVER. Контракт PROOF загружен в Ethereum по этому адресу вместе с исходным кодом, с которым можно познакомиться. Можно даже проверить, как работает контракт, отправив на него реальный эфир, у нас как раз сейчас идет Pre-ICO:). На самом деле, мы будем рады, если вы присоединитесь к presale нашего проекта PROVER, который продлится до конца сентября. PROVER – это уникальная технология подтверждения подлинности видеоматериалов на базе блокчейн и видеоаналитики.





















