Уязвимости смарт-контрактов Etherium. Примеры кода
Данным постом начинаю цикл статей на тему безопасности смарт-контрактов Ethereum. Считаю эту тему весьма актуальной, так-как количество разработчиков лавинообразно растет, а уберечь от «граблей» — некому. Пока — переводы…
1. Сканирование Live Ethereum контрактов на ошибку «Unchecked-Send»
Начиная с марта 2015 года программисты смарт-контрактов были предупреждены о конкретных опасностях программирования, которые могут возникнуть, когда контракты отправляют сообщения друг другу [6].
В нескольких руководствах по программированию содержится рекомендация, как избежать распространенных ошибок (в официальных документах Ethereum [3] и в независимом руководстве от UMD [2] ). Хотя эти опасности достаточно понятны, чтобы избегать их, последствия такой ошибки являются ужасными: деньги могут быть заблокированы, потеряны или украдены.
Насколько распространены ошибки, возникающие в результате этих опасностей? Есть ли еще уязвимые, но живые контракты на block-chain Ethereum? В этой статье мы отвечаем на этот вопрос, анализируя контракты на живом block-chain Ethereum с помощью нового инструмента анализа, который мы разработали.
Что такое ошибка «unchecked-send»?
Для отправки контрактом эфира на другой адрес, самым простым способом является использование ключевого слова send. Это действует как метод, определенный для каждого объекта. Например, следующий фрагмент кода может быть найден в смарт-контракте, который реализует настольную игру.
Проблема здесь в том, что метод send может выполниться с ошибкой. Если он не сработает, то победитель не получит деньги, однако переменная prizePaidOut будет установлена в True.
Как можно избежать этой ошибки?
В документации Ethereum содержится краткое предупреждение об этой потенциальной опасности [3] :»Есть некоторая опасность при использовании send — передача завершается с ошибкой, если глубина стека вызовов составляет 1024 (это всегда может быть вызвано вызывающим), и также терпит неудачу, если у получателя заканчивается «газ». Поэтому, чтобы обеспечить безопасную передачу эфира, всегда проверяйте возвращаемое значение send или даже лучше: используйте шаблон, в котором получатель изымает деньги.»
Два предложения. Первое — проверить возвращаемое значение send, чтобы убедиться, успешно ли оно завершено. Если это не так, то генерируйте исключение, чтобы откатить состояние назад.
Это адекватное исправление для текущего примера, но не всегда это правильное решение. Предположим, мы модифицируем наш пример, чтобы, когда игра закончилась, победитель и проигравший откатили свое состояние назад. Очевидным применением «официального» решения было бы следующее:
Однако это ошибка, поскольку она вводит дополнительную уязвимость. В то время как этот код защищает winner от атаки callstack, он также делает winner и loser уязвимыми друг для друга. В этом случае мы хотим предотвратить атаку callstack, но продолжаем выполнение, если команда send по какой-либо причине не сработает.
Поэтому даже лучшая передовая практика (рекомендованная в нашем «Руководстве программиста для Ethereum и Serpent», хотя она одинаково применима к Solidity), заключается в проверке наличия ресурса callstack. Мы можем определить макрос callStackIsEmpty (), который вернет ошибку, если и только если callstack пустой.
Еще лучше рекомендация из документации Ethereum — «Использовать шаблон, в котором получатель забирает деньги», является немного загадочной, но имеет объяснение. Предложение состоит в том, чтобы реорганизовать ваш код, чтобы эффект неудачи send был изолирован, и влиял только на одного получателя за раз. Ниже приведен пример этого подхода. Однако этот совет также является анти-шаблоном. Он принимает на себя ответственность за проверку callstack самим получателям, что делает вероятными попадание в одну и ту же ловушку.
Какие уязвимости смарт-контрактов бывают и как с ними бороться
В этой статье расскажем про основные уязвимости смарт-контрактов, которые описывает Проект по безопасности децентрализованных приложений. В некоторых примерах будем давать ссылки на англоязычные статьи, где можно посмотреть примеры кода.
Каждый может внести свой вклад в безопасность экосистемы и работать совместно с DASP через GithHub.
Специфика смарт-контрактов
Одним из самых больших преимуществ блокчейна является то, что он может действовать как децентрализованная система, которая не предполагает посредников. Смарт-контракты рекламируются как нечто, что может заменить третью сторону. Идея в использовании контрактов, которые хранятся в цепочке и могут автоматически активироваться, если выполняются определенные условия.
Смарт-контракты могут безопасно храниться на множестве компьютеров, они доступны всем сторонам через децентрализованную систему. Любые попытки изменить контракт одной стороной отклоняются, все заинтересованные стороны будут автоматически проинформированы об этом. Они просты тогда, когда инфраструктура возведена и эффективно функционирует.
Из-за этого смарт-контракты, как правило, быстрее и удобнее, поэтому все чаще люди подключаются к блокчейну для оптимизации своих рабочих процессов. Это экономит деньги, ведь нет необходимости платить гаранту.
Но в текущих реализациях часто есть ошибки, которые могут привести к фатальным последствиям. Отдавая все на автоматизацию, компания должна быть максимально уверена в реализации.
Самыми популярными и значимыми были такие уязвимости:
В официальном блоге Эфириума эти ошибки классифицируют таким образом:
Повторный вход/Reentrancy
Также эта атака известна как:
Эксплойт наиболее сильно потряс всех, став самым известным, поскольку он стал причиной краха DAO. Эта уязвимость в смарт-контракте часто не замечается рецензентами, которые, как правило, просматривают функции по одной.
Атака Reentrancy впервые осуществилась во время многомиллионной кражи, которая привела к хардфорку Ethereum. Reentrancy возникает, когда внешним вызовам разрешено совершать новые вызовы до завершения первоначального исполнения. Для функции это означает, что состояние контракта может измениться в середине его выполнения в результате вызова ненадежного контракта или использования функции низкого уровня с внешним адресом.
Убыток от этой уязвимости оценивается в 3.5M ETH (
50 миллионов долларов на то время).
Следующая функция содержит функцию msg.sender, уязвимую для атаки повторного вызова. Когда функция низкого уровня call() посылает Эфир на адрес msg.sender, он становится уязвимым. Если адрес является смарт-контрактом, платеж вызовет резервную функцию fallback () с тем, что осталось от транзакционного газа:
Таким образом, пользователь получит в два раза больше своего баланса из контракта.
Как избежать этого:
Что еще почитать по теме:
Контроль доступа
Можно было превратить контракт библиотеки Parity Wallet в обычный кошелек с несколькими подписями и стать его владельцем, вызвав функцию initWallet.
Проблемы контроля доступа распространены во всех программах, а не только с смарт-контрактах. Фактически, это номер 5 в топ-10 OWASP. Обычно вы получаете доступ к функциям контракта через публичные или внешние функции.
Уязвимости могут возникать, когда контракты используют устаревший tx.origin для проверки обращающихся (callers), обработки большой логики авторизации и использовании делегирования в прокси-библиотеках или прокси-контрактах.
Убыток оценивается в 150 000 ETH (
30 миллионов долларов в то время)
Проблема всплыла с Parity. Пользователь под ником Devops199 превратил проблемную библиотеку в кошелек, стал его владельцем, выполнил команду «самоуничтожение контракта», и в итоге заблокировал средства множества других кошельков. Кстати, сам Devops199 был новичком, а не хакером. По крайней мере, он так утверждает.
Другой случай состоялся с пирамидой Rubixi. Сборы были украдены, поскольку функция конструктора имела неправильное имя, позволяя любому стать владельцем.
Не отслеживается тот факт, что владелец контракта уже вызван.
В кошельке Parity эта функция инициализации была отделена от самих кошельков и определена в контракте из библиотеки. К сожалению, функция не проверила, был ли кошелек уже инициализирован. Хуже того, поскольку библиотека была смарт-контрактом, любой мог инициализировать библиотеку и запросить ее уничтожение.
Arithmetic Issues
Уязвимость компьютерной арифметики также известна как целочисленное переполнение через нижнюю границу.
Это дает неверные результаты, и, если такая возможность не ожидалась, это угрожает безопасности программы.
Изначально peckshield (компания, которая занимается блокчейн-безопасностью) заметили странное поведение смарт-контракта:

Уязвимая функция находится в batchTransfer:
При анализе другого кода, более десятка смарт-котрактов ERC20 также уязвимы для batchOverflow.
Непроверенные возвращаемые значения для вызовов низкого уровня
Также известна как непроверенная отправка, silent failing sends.
Следует избегать «call» низкого уровня, когда это возможно. Это может привести к неожиданному поведению, если возвращаемые значения не обрабатываются правильно.
Особенность Solidity — функции низкого уровня call(), callcode(), delegatecall() и send(). Их поведение в случае ошибок сильно отличается. Они возвращают значение false, а код продолжает выполнение. Если возвращаемое значение не будет проверено, это может привести к сбоям и другим нежелательным результатам.
Впервые проблема возникла в игре King of Ether. Эта атака произошла из-за неправильного распределения газа.
Итак, «Король Эфирного Трона» (KotET) — это игра, в которой участники соревновались друг с другом за титул «Король эфира». Как это работало:
Проще говоря, это была пирамида.
Так что же случилось с KotET?
Контракты KotET работали нормально, за исключением одного сценария. Когда контракт отправил платеж на «контрактную учетную запись», он выделил лишь небольшое количество газа, в 2300 единиц. Этого недостаточно для покрытия расходов.
Когда платеж не обработался, уплаченный эфир был возвращен в контракт KotET. Организация не знала, что платеж не прошел и продолжал обработку.
Когда программист забывает проверить возвращаемое значение send () EVM (виртуальная машина эфириума) заменит возвращаемое значение на false. Но изменения функции в состоянии контракта не будут отменены, а переменная etherLeft закончит отслеживание некорректного значения.
Denial of Service
Отказ в обслуживании также включает в себя достижение предела газа, нарушение контроля доступа, неожиданный крах.
Отказ в обслуживании смертелен в мире Ethereum: в то время как другие типы приложений могут в итоге восстановиться, смарт-контракты могут быть отключены навсегда всего лишь одной из этих атак. Многие способы приводят к отказу в обслуживании, в том числе к вредоносному поведению. Этот класс атаки включает в себя множество различных вариантов.
Убыток оценивается в 514 874 ETH (
300 миллионов долларов в то время).
Впервые случилось с GovernMental и описанным выше багом в Parity (когда пользователь «убил» смарт-контракт).
GovernMental был популярной пирамидой на блокчейне. Игра была незамысловата: есть таймер, когда он достигает нуля, весь джекпот получает кто-то один.
Собственно, проблема в том, что участников было очень много. Для покрытия всех расходов нужна сумма газа 5057945, но там было заложено всего 4712388.
И PonziGovernment застрял, 1100 ETH находятся в подвешенном состоянии.
Также возможна намеренная атака. Например:
Bad Randomness
Также уязвимость известна под названием nothing is secret (ничего в секрете).
Случай впервые обнаружился в лотерее SmartBillions.
Смарт-контракт использует номер блока как источник случайности для игры. Также приватный сид используется в сочетании с номером и хэш-функцией keccak256, чтобы определить, победит ли пользователь. Несмотря на то, что сид является закрытым, он должен быть установлен через транзакцию, поэтому виден в блокчейне.
Вот так делается псевдослучайность:
В результате длительных операций (много кода с объяснением), злоумышленник может вручную извлечь приватный сид.
Также есть возможность рандомного подбора и вызова выигрышного контракта. В этой статье описаны уязвимости генераторов псевдослучайных чисел.
Вот еще несколько уязвимостей:
Собственно, из-за обилия уязвимостей и неочевидных мест писать качественные смарт-контракты может не каждый. Особенно проблема усугубляется тем, что код часто связан с деньгами и передачей ценности, что привлекает злоумышленников.
Это лишь некоторые уязвимости и возможные атаки: какие-то раскрыты, но не афишированы, какие-то только предстоит найти. Надеемся, что после этой статьи вы будете серьезнее относиться к кодовой базе: будучи и разработчиком, и пользователем.
Простыми словами: смарт-контракты, Ethereum, ICO
Смарт-контракты сделали криптовалюту Ethereum второй по величине. Рассказываем о том, что это такое и как это связано с модным понятием ICO.
Про Биткойн слышали многие, что и не удивительно — эта криптовалюта была первой и до сих пор остается самой популярной и самой крупной. Успех Биткойна вдохновил на подвиги кучу людей, поэтому за последние пару лет разных криптовалют — так называемых альткойнов — насоздавали ужас сколько, больше 1000.
Так вот, Биткойн — на данный момент однозначно номер один. А знаете, какая криптовалюта на втором месте? Ethereum. Когда мы говорим про места, мы имеем в виду капитализацию, то есть суммарную стоимость всех монет валюты.
Капитализация и цены TOP-5 криптовалют. Источник
Как видите, Ethereum с большим отрывом опережает другие «альткойны», а в июне 2017 чуть было даже не обогнал Биткойн, «великий и ужасный». Давайте разберемся, что же в Ethereum такого особенного и почему подавляющее большинство проводимых в этом году ICO используют именно его.
Идея Ethereum
Ethereum запустился совсем недавно, 30 июля 2015 года. Одним из его создателей был нынче известный в блокчейн-тусовке и, не побоюсь этого слова, влиятельный Виталик Бутерин. Он родился в России, но с шести лет жил в Канаде. На тот момент, когда он изложил свои идеи, которые в итоге легли в основу сети Ethereum, ему было 19 лет.
Так вот, в чем же идея? В сети Биткойн с точки зрения пользователя все устроено довольно просто. Есть кошельки, можно передавать деньги с одного кошелька на другой или на несколько сразу. Сеть построена на весьма остроумных принципах, позволяющих обходиться без единого центра, но задачи решаются вполне классические. Обычная платежная система, по большому счету: люди, деньги, переводы — все, больше ничего нет.
Но можно пойти дальше и создать такую платежную сеть, которая позволяет писать программы, которые бы работали с кошельками, сами бы принимали с кошельков деньги, решали, кому сколько отправить и так далее. С важным условием: для всех пользователей каждая такая программа будет работать по известным принципам, предсказуемо, одинаково, прозрачно, и чтобы никто не мог ее изменить.
Собственно, создатели Ethereum как раз и добавили к базовой функциональности криптовалют возможность создавать подобные программы. Все кошельки в Ethereum делятся на два типа: те, что управляются людьми, и те, что управляются автономно программами.
Программы — их называют смарт-контрактами — записываются в блокчейн. Таким образом, эта программа запоминается навсегда, у всех участников сети есть ее копия (блокчейн ведь у всех одинаковый), соответственно и выполняется смарт-контракт у всех тоже идентично.
И вот это нововведение существенно расширило сферу применения блокчейн-валют.
Примеры смарт-контрактов
Какие программы можно написать? Да какие угодно. Например, финансовую пирамиду. Для этого в сети Ethereum достаточно создать смарт-контракт со следующими правилами:
Или можно устроить аукцион. Пишем программу:
Есть еще миллион применений: кошельки с несколькими владельцами, финансовые инструменты, самоисполняющиеся пари, голосования, лотереи, игры, казино, нотариат и прочее.
Напомним преимущество: это блокчейн — все уверены, что никто не жульничает, все видят текст программы и понимают, что она работает именно так, как в ней написано. Программа — не человек. Она не скроется с деньгами, не обанкротится, и так далее. Если, конечно, в ней нет багов или «неожиданного поведения».
Ограничения смарт-контрактов
Но есть и существенные ограничения, вот некоторые из них:
Иными словами, как и в других областях, многое зависит от профессионализма авторов контрактов.
Главное использование смарт-контрактов
Простой смарт-контракт Ethereum. Имеющаяся ошибка позволяет украсть все деньги, кто нашел — молодец
Пирамиды, голосования, казино, лотереи — это все здорово. Но что оказалось действительно удобно делать при помощи смарт-контрактов — это надувать пузыри собирать деньги на свой стартап.
Ведь при помощи смарт-контракта можно автоматизировать всю «бухгалтерию»: контракт сам запомнит, от кого и сколько пришло денег, сам начислит «акции», а также даст возможность каждому участнику передавать и продавать эти акции. Не нужно никакой возни с адресами почты, кредитными картами, проверкой карт, авторизацией инвесторов и тому подобного. Вдобавок все видят, сколько всего было выпущено акций и как они распределились по участникам. От скрытого допечатывания акций и продажи одной акции несколько раз защищает блокчейн.
Смарт-контракты дали миллиону «криптоинвесторов» возможность «швырять деньги в монитор».
ICO — Initial Coin Offering
График стоимости Ethereum. Источник
Обсудим ICO поподробнее. Типичная схема криптостартапа такова:
Сумма обычно составляет 10-20 миллионов долларов и собирается буквально за несколько минут, иногда дней. Как правило, ICO ограничено по времени или собираемой сумме — и это формирует ажиотаж.
Окупаемость криптоинвестиций
Что будет дальше с выданными инвесторам токенами, зависит от проекта. Кто-то обещает выплачивать дивиденды с будущей прибыли, кто-то планирует принимать эти токены к оплате услуг, реализуемых проектом, кто-то ничего не обещает.
Как правило, сами токены выводятся на криптобиржу, и открываются торги. Те, кто не успел поучаствовать в ICO, могут купить их уже на бирже — скорее всего, подороже. Те, кто участвовал в ICO, чтобы потом перепродать подороже, могут их на бирже продать.
Иногда первых настолько больше, что цена растет стремительно, и капитализация проекта раздувается до миллиарда долларов. При том, что у него нет прибыли нет продукта, есть только идея, план и, в лучшем случае, команда.
Так как автор проекта собрал много денег, он этими же деньгами имеет возможность на бирже выкупать свои же токены, подогревая цену токена еще больше. На обычных биржах с обычными акциями такое поведение запрещено, но в криптоиндустрии регуляторов нет.
В 2017 году (к сентябрю) на ICO разные проекты уже собрали порядка 1,7 миллиарда долларов. Об успешных проектах слышно мало, но инвесторы не теряют оптимизма.
Смарт контракты Ethereum: что делать при ошибке в смартконтракте или техники миграции
При написании смартконтрактов важно помнить, что после загрузки в блокчейн, они уже не могут быть изменены, а следовательно, не могут быть внесены какие-либо улучшения или исправлены какие-то найденные ошибки! Все мы знаем, что ошибки есть в любой программе, а вернувшись к написанному пару месяцев назад коду мы всегда найдем, что там можно улучшить. Как же быть? Единственно возможный вариант – это загрузить новый контракт с исправленным кодом. Но как же быть, если на базе имеющегося контракта уже выпущены токены? На помощь нам приходит миграция! За последний год я попробовал много разных техник ее реализации, проанализировал применяемые в других крупных блокчейн проектах и что-то поизобретал сам. Подробности под катом.
Сразу оговорюсь, что в рамках данного поста я не буду приводить простыни готовых смартконтрактов, а буду лишь рассматривать и анализировать различные техники. Почти все они в том или ином виде были мной реализованы в контрактах для проектов, в которых мне доводилось участвовать, и многое можно взять с моего GitHub.
Миграция с ERC20-совместимого контракта
Начнем рассмотрение с самого простого и распространенного случая, когда исходный контракт, уже загруженный в блокчейн, не содержит каких-либо специальных механизмов для того, чтобы помочь нам с миграцией, т.е. по сути мы имеем обычный ERC20-совместимый контракт. Единственное, что мы полезного можем взять из исходного контракта, это балансы всех держателей токенов и общее количество выпущенных токенов для проверки, что мы никого не забыли при миграции.
К сожалению, интерфейс ERC20-совместимого контракта не позволяет узнать список всех держателей токенов, поэтому при миграции нам придется выяснить полный список держателей из какого-то другого источника, например, выгрузив его из etherscan.io. Пример контракта, на который осуществляется миграция, приведен в следующем листинге:
Конструктор контракта получает в качестве параметров адрес исходного ERC20-совместимого контракта, а также список держателей токенов, выгруженный вручную через etherscan.io. Следует обратить внимание, что в последней сроке конструктора проверяем, что количество токенов после миграции не изменилось, а следовательно, ни один держатель токенов не забыт. Необходимо учитывать, что такая миграция возможна лишь в том случае, если количество держателей токенов невелико и цикл по ним всем возможен в рамках одной транзакции (лимита газа, установленного в Ethereum для одной транзакции). Если все же количество держателей токенов не позволяет мигрировать за одну транзакцию, то эту функциональность придется вынести в отдельную функцию, которую можно будет вызвать необходимое количество раз, а контракт в этом случае будет выглядеть так:
В конструкторе данного контракта запоминается адрес исходного контракта, а также инициализируется поле owner, чтобы запомнить адрес владельца контракта, чтобы только он имел право вызывать функцию migrate(), вызвав которую несколько раз, мы можем мигрировать любое количество держателей токенов с исходного контракта.
Недостатки данного решения заключаются в следующем:
Миграция между этапами краудсейла
В мире современных ICO довольно распространена практика, когда для различных этапов сбора средств делают отдельные контракты, мигрируя выданные токены на новые контракты нового этапа. Это, конечно, можно делать так, как мы рассмотрели выше, но, если мы точно знаем, что нам придется мигрировать, то почему бы сразу не упростить себе жизнь? Для этого достаточно ввести публичное поле
В это поле необходимо добавлять всех держателей токенов. Если контракт уже на ранних этапах сбора разрешает делать держателям перемещения токенов, т.е. реализует transfer(), необходимо позаботиться о том, чтобы массив обновлялся, например, как-то так
Теперь на стороне приемного контракта можно использовать аналогичную рассмотренной ранее технологию миграции, но теперь нет необходимости передавать массив в качестве параметра, достаточно обратиться к уже готовому массиву в исходном контракте. Также следует помнить, что размер массива может не позволить проитерировать его за одну транзакцию по причине ограничения газа на одну транзакцию, а следовательно, нужно предусмотреть функцию migrate(), которая будет получать два индекса – номера начального и конечного элементов массива для обработки в рамках данной транзакции.
Недостатки данного решения вобщем-то такие же как у предыдущего, разве что теперь нет необходимости делать выгрузку списка держателей токенов через etherscan.io.
Миграция со сжиганием исходных токенов
Все-таки раз мы говорим про миграцию, а не про дублирование токенов в новом смартконтракте, то необходимо озаботиться вопросом уничтожения (сжигания) токенов на исходном контракте при создании их копии на новом. Очевидно, что недопустимо оставлять в смартконтракте «дыру», которая позволила бы кому угодно, будь он даже владельцем смартконтракта, сжигать токены других держателей. Такой смартконтракт будет просто скамовым! Осуществлять такого рода манипуляции над своими токенами может только их держатель, а следовательно, и осуществлять миграцию должен сам держатель. Владелец смартконтракта в данном случае может только запустить эту миграцию (перевести смартконтракт в состояние миграции). Пример реализации такой миграции я встретил в проекте GOLEM (ссылка на их гитхаб в конце поста), затем реализовал ее в нескольких своих проектах.
В исходном контракте определим интерфейс MigrationAgent, который впоследствии должен быть реализован в контракте, на который осуществляется миграция.
В исходном контракте токена должна быть реализована следующая дополнительная функциональность:
Таким образом, владелец исходного смартконтракта должен вызвать setMigrationAgent(), передав ему в качестве параметра адрес смартконтракта, на который осуществляется миграция. После этого все держатели токенов исходного смартконтракта должны вызвать функцию migrate(), которая осуществит уничтожение их токенов в исходном смартконтракте и добавление в новом (путем вызова функции migrateFrom() нового контракта). Ну а новый контракт должен собственно содержать реализацию интерфейса MigrationAgent, например, так:
В этом решении прекрасно все! Кроме того, что пользователю надо вызвать функцию migrate(). Ситуация существенно осложняется тем, что вызов функций поддерживают лишь единицы кошельков и они, как правило, не являются самыми удобными. Поэтому, поверьте, если среди держателей ваших токенов есть не только криптогики, но и простые смертные люди, они вас просто проклянут, когда вы будете объяснять им, что надо установить какой-нибудь Mist, а затем вызвать какую-то функцию (слава Богу, хоть без параметров). Как же быть?
А можно поступить очень просто! Ведь любой пользователь криптовалюты, даже самый-самый начинающий, умеет хорошо делать одно – отправлять крипту со своего адреса на какой-то другой. Так пусть таким адресом будет адрес нашего смартконтракта, а его fallback функция в режиме «миграции» будет просто вызвать migrate(). Таким образом, держателю токенов для осуществления миграции будет достаточно перевести хотя бы 1 wei на адрес смартконтракта, находящегося в режиме «миграции», чтобы произошло чудо!
Заключение
Рассмотренные решения концептуально покрывают все возможные способы осуществления миграции токенов, хотя возможны вариации в конкретных реализациях. Отдельного внимания достоин подход «перегонного сосуда» (ссылка в конце поста). Независимо от используемого вами подхода к миграции, помните, что смартконтракт – это не просто программа, выполняемая внутри виртуальной машины Ethereum, а это некий отчужденный независимый договор, а любая миграция предполагает, что вы меняете условия этого договора. Уверены ли вы, что держатели токенов хотят поменять условия договора, который заключили, приобретая токены? Это на самом деле хороший вопрос. И существует очень правильная практика, «спрашивать» держателей токенов о том, хотят ли они «переехать» на новый контракт. Именно осуществление миграции через голосование я реализовал в смартконтракте своего проекта PROVER, с текстом контракта можно познакомиться на моем GitHub-е. Ну и конечно приглашаю присоединяться к ICO моего проекта PROVER.
Надеюсь, что все это кому-то полезно и нужно :).











