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



Для экономии времени я написал контракт заранее. Давайте разберем его по шагам.

Смартконтракт является программой написанной на языке программирования. В нашем случае на языке Solidity. Для разработки простых контрактов я использую онлайн редактор и компилятор Remix.

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

/*
This file is part of the EasyCrowdsale Contract.

The EasyCrowdsale Contract is free software: you can redistribute it and/or
modify it under the terms of the GNU lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

The EasyCrowdsale Contract is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU lesser General Public License for more details.

You should have received a copy of the GNU lesser General Public License
along with the EasyCrowdsale Contract. If not, see <http://www.gnu.org/licenses/>.

@author Ilya Svirin <i.svirin@prover.io>
*/

Сразу после идет строка, которая указывает, какую версию компиллятора следует использовать. Если этой строки не будет, то смартконтракт не скомпилируется.

pragma solidity ^0.4.0;

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

Прежде всего следует понимать, что после загрузки смартконтракта в виртуальную машину Ethereum вы будете взаимодействовать с ним на общих основаниях, как и все остальные пользователи. Логично, что мы, как команда проекта, хотели бы находиться в привилегированных условиях, которые должны как минимум выражаться в том, что контракт должен сформировать именно на командные токены и конечно же отдал именно нам собранный эфир. Для этого контракт должен знать своего владельца и именно за это отвечает контракт «owned».

contract owned {

    address public owner;

    function owned() payable {
        owner = msg.sender;
    }
    
    modifier onlyOwner {
        require(owner == msg.sender);
        _;
    }

    function changeOwner(address _owner) onlyOwner public {
        owner = _owner;
    }
}

Контракт «owned» содержит лишь одно публичное поле «owner», значение которого инициализируется в конструкторе значением поля «sender» глобальной структуры «msg», таким образом, изначально владельцем контракта становится тот, кто осуществил его деплой.

Логично предусмотреть возможность смены владельца на случай, если наш private key будет скомпрометирован, для этого предусмотрена функция «changeOwner», которая получает в качестве параметра адрес нового владельца. Следует обратить на модификатор «onlyOwner», который определен внутри этого же смартконтракта. Модификаторы представляют собой очень удобную конструкцию, позволяющую сгруппировать и присвоить название условиям вызова функций смартконтракта. Модификатор «onlyOwner» проверяет, что вызов функции осуществляется с адреса, который сохранен в поле «owner».

Контракт «owned» полностью работоспособен и предельно прост, однако несет в себе одну скрытую угрозу, ведь при вызове функции «changeOwner» мы можем по ошибке указать несуществующий адрес, а значит, потеряем контроль над контрактом. Чтобы исправить этот недостаток, достаточно ввести еще поле, назовем его «candidate», а при вызове функции «changeOwner» будем сохранять новое значение сначала в «candidate», а перемещать его в «owner» будем, как только кандидат подтвердит свое вступление в права, вызвав со своего адресу функцию «confirmOwner».

Следующий в иерархии контракт – «Crowdsale», отвечает непосредственно за сбор средств и выдачу токенов и наследует рассмотренный ранее контракт «owned».

contract Crowdsale is owned {
    
    uint256 public totalSupply;
    mapping (address => uint256) public balanceOf;

    event Transfer(address indexed from, address indexed to, uint256 value);

    function Crowdsale() payable owned() {
        totalSupply = 21000000;
        balanceOf[this] = 20000000;
        balanceOf[owner] = totalSupply - balanceOf[this];
        Transfer(this, owner, balanceOf[owner]);
    }

    function () payable {
        require(balanceOf[this] > 0);
        uint256 tokensPerOneEther = 5000;
        uint256 tokens = tokensPerOneEther * msg.value / 1000000000000000000;
        if (tokens > balanceOf[this]) {
            tokens = balanceOf[this];
            uint valueWei = tokens * 1000000000000000000 / tokensPerOneEther;
            msg.sender.transfer(msg.value - valueWei);
        }
        require(tokens > 0);
        balanceOf[msg.sender] += tokens;
        balanceOf[this] -= tokens;
        Transfer(this, msg.sender, tokens);
    }
}

Особое внимание следует обратить на следующие элементы контракта:

  • Публичное поле «totalSupply», которое должно содержать общее количество токенов, выпущенных смартконтрактом;
  • Публичная карта «balanceOf», которое содержит информацию о балансах всех держателей токенов;
  • Событие Transfer, которое должно испускаться смартконтрактом при каждой операции перемещения токенов между держателями токенов.

Все эти три элемента объединяет одно, они являются обязательной частью стандарта ERC20, который необходимо соблюдать, чтобы информация о наших токенах корректно отображалась в кошельках пользователей и etherscan.io.

Конструктор смартконтракта «Crowdsale» предельно прост. Прежде всего инициализируется значение поля «totalSupply». Наш контракт выпускает 21 миллион токенов, из которых 20 миллионов сразу будут перемещены на баланс смартконтракта. Будем считать, что токены с адреса смартконтракта как раз и доступны для продажи. Оставшиеся токены, в нашем случае 1 миллион, будут записаны на адрес владельца контракта. Ну и в конце конструктора испускается событие «Transfer», которое помещается в блокчейн и информирует пользователей контракта о том, что с баланса контракта на баланс владельца контракта переведено соответствующее количество токенов. Именно испускание этого события позволит etherscan.io корректно отобразить держателей токенов и их балансы.

Ну и самая главная функция смартконтракта «Crowdsale», так называемая payback функция, которая вызывается каждый раз, когда эфир поступает на адрес нашего смартконтракта. В самом начале осуществляется проверка, что на балансе смартконтракта есть хоть какое-то количество токенов для продажи. Далее устанавливаем фиксированную цену токенов – 5000 штук за 1 эфир. Затем вычисляем, сколько токенов необходимо отправить отправителю эфира. Количество переданных в транзакции средств записано в поле «value» глобальной структуры «msg» и указано оно в «wei», поэтому при определении количества токенов осуществляем перевод «wei» в «ether».

Затем осуществляется проверка того, что на балансе смартконтракта есть достаточное количество токенов для продажи. Если запрошено больше токенов, чем есть у смартконтракта, то будем переводить все оставшиеся токены. Определяем стоимость в «wei» оставшихся токенов и возвращаем отправителю излишне переведенный эфир. Убеждаемся, что количество покупаемых токенов ненулевое, после чего записываем это количество токенов на баланс покупателя и списываем их с баланса смартконтракта. В конце не забываем испустить событие Transfer.

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

contract EasyToken is Crowdsale {
    
    string  public standard    = 'Token 0.1';
    string  public name        = 'EasyTokens';
    string  public symbol      = "ETN";
    uint8   public decimals    = 0;

    function EasyToken() payable Crowdsale() {}

    function transfer(address _to, uint256 _value) public {
        require(balanceOf[msg.sender] >= _value);
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        Transfer(msg.sender, _to, _value);
    }
}

Прежде всего определим 4 публичных поля, которые сейчас практически не используются никакими кошельками, но для порядка все же определим их. Здесь укажем полное и сокращенное наименование токена, а также количество дробных знаков. В нашем случае токен является неделимым, т.к. значение поля «decimals» установлено равным 0.

И наконец, единственной функцией смартконтракта «EasyToken», ради которой мы создавали этот контракт, является «transfer», которая также является частью стандарта ERC20 и позволит кошелькам пользователей осуществлять передачу токенов друг другу, переводить их на биржу и выводить их с нее. Реализация функции крайне проста, проверяется достаточность количества токенов на балансе отправителя, после чего баланс отправителя уменьшается, а баланс получателя увеличивается на запрошенное количество токенов. В конце испускается событие «Transfer». Теперь наш токен является операбельным и осталось сделать самое главное – предоставить владельцу контракта возможность вывести собранные эфиры. Это мы сделаем в контракте «EasyCrowdsale».

contract EasyCrowdsale is EasyToken {

    function EasyCrowdsale() payable EasyToken() {}
    
    function withdraw() public onlyOwner {
        owner.transfer(this.balance);
    }
}

Функция «withdraw» имеет модификатор «onlyOwner», т.е. может быть вызвана только владельцем смартконтракта. Единственное, что она делает – переводит весь баланс смартконтракта на адрес владельца смартконтракта.

Несмотря на то, что рассмотренный нами смартконтракт является полностью функционально законченным и работоспособным, использовать его в реальном проекте я бы не рекомендовал. Чрезмерное упрощение логики контракта привело к тому, что такой контракт не обеспечивает защиту интересов инвесторов в должной мере, а именно, не устанавливает срок проведения crowdsale, не устанавливает минимальной границы сбора, не возвращает средства инвесторам в случае недостижения минимальной границы, а также содержит ряд известных уязвимостей на уровне компилятора языка Solidity, например, подвержен так называемой short address attack.

Многие из этих недостатков устранены в смартконтракте нашего проекта PROVER. Контракт PROOF загружен в Ethereum по этому адресу вместе с исходным кодом, с которым можно познакомиться. Можно даже проверить, как работает контракт, отправив на него реальный эфир, у нас как раз сейчас идет Pre-ICO:). На самом деле, мы будем рады, если вы присоединитесь к presale нашего проекта PROVER, который продлится до конца сентября. PROVER – это уникальная технология подтверждения подлинности видеоматериалов на базе блокчейн и видеоаналитики.

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

Полезные ссылки:

Комментарии (80)


  1. lany
    17.09.2017 07:23
    +17

    Смотрю с точки зрения обычного программиста. В ваших смартконтрактах реально принято код загружать такими константами вида 1000000000000000000? Ведь это какое-то наивное детское программирование, хоть и называется громким словом solidity. Это неправильно на кучу слоёв.


    Слой 1. Можно легко пропустить где-нибудь нолик или неправильно их сосчитать и неправильно понять код. Язык должен позволять писать 1_000_000_000_000_000_000. Если позволяет, программисты должны этим пользоваться.


    Слой 2. Это всё равно неправильно, потому что вероятность ошибки с пропуском нолика существует до сих пор. Должна существовать предопределённая именованная константа вроде WEI_PER_ETHER = 1_000_000_000_000_000_000, и в коде должна использоваться только она. Тогда станет понятнее, что происходит и вероятность ошибки ещё снизится.


    Слой 3. И это всё равно неправильно, потому что можно неправильно сделать вычисления. Например, умножить там, где надо разделить, передав не 10-18, а 10+18 попугаев. Нужны предопределённые функции или макросы с понятными именами вроде convertWeiToEther(weiAmount) и convertEtherToWei(etherAmount).


    Слой 4. И это всё равно неправильно, потому что можно по ошибке забыть вызвать макрос. Должна быть объектная типизированная модель, исключающая возможность присваивания неправильного значения. Что-нибудь вроде WEI.amount(uint256 value) возвращает объект типа Amount, и чтобы получить сумму в эфире, надо вызвать WEI.amount(value).toEther(). При этом не следует использовать сырые значения в числах слишком часто, только в исключительных случаях вроде окончательного обмена данными с внешним источником. В идеале это должно быть спрятано в методах родительских контрактов и всякие msg.value уже должны иметь тип Amount и писать надо msg.value.subtract(MY_TOKEN.amount(tokens)), где константа Currency MY_TOKEN = createStableCurrency(Ether.amount(1/5000)). Я придерживаюсь синтаксиса джавы, но это необязательно. Язык может и перегрузку операторов поддерживать, тогда можно писать msg.value - MY_TOKEN.amount(tokens), но при этом компиляция не пролезет, если попытаетесь эфир вычесть из токенов или сложить токены с веями.


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


    1. superhackkiller1997
      17.09.2017 10:10
      -15

      Слой 1. Можно легко пропустить где-нибудь нолик или неправильно их сосчитать и неправильно понять код. Язык должен позволять писать 1_000_000_000_000_000_000. Если позволяет, программисты должны этим пользоваться.

      Это уродство и никто так писать не должен. Если вам это нравиться — так и пишите, но про «должны» — забудьте.

      Слой 3. И это всё равно неправильно, потому что можно неправильно сделать вычисления. Например, умножить там, где надо разделить, передав не 10-18, а 10+18 попугаев.

      Зачем вообще жить, если можно что-то сделать неправильно? Неважно, какой разрядности числа — всё это теряется и от разрядности ничего не зависит. Это просто рассуждения человека, который не привык к логике за пределами плавучки.

      Должна быть объектная типизированная модель, исключающая возможность присваивания неправильного значения.

      Это тот же самый ЖС, где типизация тут прикручена сбоку. А такой модели нет в и жаве.

      Что-нибудь вроде WEI.amount(uint256 value) возвращает объект типа Amount, и чтобы получить сумму в эфире, надо вызвать WEI.amount(value).toEther().

      И что же это изменит? Мне это в рамках value как-то помешает ошибиться?

      Ну и самое главное, что никакой «суммы в эфире» — нет. Автор сам настроил себе абстракций и сам же их и должен поддерживать. Т.е. WEI.amount(value).toEther() == value по определению. Тут прослеживается, опять же, узость мышления и вас и автора, которые не могут мыслить за рамками плавучки.

      В идеале это должно быть спрятано в методах родительских контрактов и всякие msg.value уже должны иметь тип Amount и писать надо msg.value.subtract(MY_TOKEN.amount(tokens)), где константа Currency MY_TOKEN = createStableCurrency(Ether.amount(1/5000)).

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

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

      Язык может и перегрузку операторов поддерживать, тогда можно писать msg.value — MY_TOKEN.amount(tokens), но при этом компиляция не пролезет, если попытаетесь эфир вычесть из токенов или сложить токены с веями.

      Жава не поддерживает, как и 99% языков. Что дальше?

      Опять же — попытка пихать и рассуждать в придуманных вами абстракциях на уровне «языка». Язык он про сложение чиселок. Так везде. В жаве нет логики «нельзя сложить рубли с доллары» — потому что это логика внешнего уровня.

      Точно так же и тут. Токены — это логика внешнего уровня — на уровне языка/платформы их не существует. Точно так же как на уровне жавы не существует рублей. И почему-то вы не идёте и не жалуетесь на это.

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

      Такого компилятора у жавы нет, как и у 99% языков. Что же с этим поделать? Откуда он должен взяться тут?

      Ну и самое главное, как я уже говорил. Это мир жаваскрипта( и этот «язык» — это жаваскрипт) — там люди не знают о типизации, компиляторах и прочем. Хипстерский мир вообще компилятор увидел только с релизом ллвм. Точно так же, как в мире жавы не знают о компилтайме и мощной типизации, как это знают в том же мире С++.


      1. mayorovp
        17.09.2017 10:30
        +3

        В жаве нет логики «нельзя сложить рубли с доллары» — потому что это логика внешнего уровня.

        Но в "жаву" такую логику можно при желании добавить. А тут — либо нельзя, либо можно, но как нам не рассказали. И на остальные ваши рассуждения — тот же самый ответ.


        1. superhackkiller1997
          17.09.2017 11:31
          -3

          Но в «жаву» такую логику можно при желании добавить.

          Сюда так же.

          А тут — либо нельзя, либо можно, но как нам не рассказали.

          Классы есть, типы есть, перегрузка есть. Вроде как всё необходимое есть, а уже далее — дело техники.

          И на остальные ваши рассуждения — тот же самый ответ.

          Да не тот же. Автор(комментария) предлагает взять из копеек сделать рубли в рамках целых чисел. Он предлагает делать из переменной как минимум пару, а это уже усложнение операций( что явно противоречит его концепции «компилятор все поправит»).

          По мне так автор просто пытается натянуть свои представления из мира плавучки на данную ситуацию.

          А проблема решается просто — не надо вводить новых сущностей. Это в реальном мире есть рубли и копейки, а в данном мире рублей нет.

          Поэтому всё решается очень просто. Есть копейки. Есть цена в копейках за цент(токен). И всё сразу стало ясно и понятно.

          Объясню ситуацию ещё проще. У автора была задача продать центы за копейки. Он ввёл для себя доллары, рубли. Исчисляет цены в них. Потом переводит значения одних в доллары, других в рубли, потом считает и потом переводит обратно. Вопрос — зачем?


          1. lany
            17.09.2017 11:56
            +1

            Автор(комментария) предлагает взять из копеек сделать рубли в рамках целых чисел

            Где я это предлагал? Я предлагал не работать с голыми числами вообще, ни с целыми, ни с дробными. Их надо видеть только в точках взаимодействия с внешними системами. А там уже тип зависит от того, который навязан внешней системой. Я ничего не говорил ни про целые, ни про дробные, ни про пару. Объект класса Amount может всё внутри переводить в ваши любимые вэи, может использовать дробные числа, может хранить пару, это без разницы. В этом суть абстракции. Завтра точности вэев станет недостаточно, поделят их ещё в тысячу раз и что тогда? Если у вас код абстрагирован от представления, поменять придётся только один класс.


            1. superhackkiller1997
              17.09.2017 12:27
              -5

              Где я это предлагал?

              Каноничный пример того, как «я не я и шкура не моя».

              Я предлагал не работать с голыми числами вообще, ни с целыми, ни с дробными.

              Нет, предполагалась логика именно плавучки и не иначе. Абстракция вот так взять и поменялось логику работы с данными/операциями. И попрошу я вас описать «как» и вы ничего не ответите.

              А там уже тип зависит от того, который навязан внешней системой.

              Не верно. В рамках зерокост абстракций( а именно их вы определили) тип очень даже влияет на абстракции.

              Объект класса Amount может всё внутри переводить в ваши любимые вэи, может использовать дробные числа, может хранить пару, это без разницы.

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

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


              А теперь как удобно получается. Уже завелась шарманка об «а если», «а поменять один класс». Об этом вы изначально не говорили, а переобувание на ходу — любимый приём болтунов.


              1. lany
                17.09.2017 12:50
                +2

                Нет, предполагалась логика именно плавучки и не иначе.

                Вы таки считаете, что лучше знаете, что у меня в голове происходит, чем я сам? Боюсь, спорить и в чём-то не соглашаться с человеком, который так считает, абсолютно бессмысленно. Поэтому продолжать не буду.


                1. superhackkiller1997
                  17.09.2017 13:20
                  -3

                  Вы таки считаете, что лучше знаете, что у меня в голове происходит, чем я сам?

                  Глупая попытка. Никто и нигде верить вас не должен. Именно поэтому ваши «я считал так, а не иначе» — никого не волнуют. Вы пишите то, что пишите. И это интерпретирую так, как интерпретирую. Если вы не согласны — аргументируйте. «я так не думаю/ как вы знаете что я имел ввиду» — это глупо и это не работает.

                  Так бы в мире ничего не работало. Сказал одно, а потом «я не то имел ввиду».

                  А поводу плавучки — вот доказательства: habrahabr.ru/post/338084/#comment_10419964


      1. lany
        17.09.2017 11:51
        +2

        Если вам это нравиться — так и пишите, но про «должны» — забудьте.

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


        Выражения про плавучку абсолютно не понимаю. При чём здесь какая-то плавучка? Я говорю, численное представление суммы должно быть абстрагировано. Неважно, что там внутри. А вы мне про какую-то плавучку. Я и слов-то таких не употребляю никогда.


        Жава не поддерживает, как и 99% языков. Что дальше?

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


        Язык он про сложение чиселок. Так везде.

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


        Такого компилятора у жавы нет, как и у 99% языков. Что же с этим поделать? Откуда он должен взяться тут?

        Джавовый JIT (Hotspot C2) вполне способен на такие оптимизации. Я полагаю, Clang с кодом на C++ легко разделается тоже. Тут вполне тривиальная цепочка оптимизаций инлайнинга, эскейп-анализа и констант-фолдинга. Это всё в теории компиляции известно десятилетиями. Не знаю, что там в солидити, но учитывая, какие деньги крутятся в этериуме, хорошего компиляторщика нанять не должно быть большой проблемой.


        Смысл последнего абзаца в том, что этериум = джаваскрипт и ничего с этим не поделаешь? Я думаю, в основу платформы никакая типизация не заложена и на ней вполне можно сделать нормальный язык, компилируемый в этериум. Либо он уже существует, просто автор этой статьи не умеет им пользоваться.


        1. isvirin Автор
          17.09.2017 12:15
          +2

          Друзья, все это не предмет данного поста. На низком уровне есть вполне себе читаемый байткод, при желании можно писать сразу в нем:) А можно создавать любые высокоуровневые абстракции. Сейчас есть два языка «высокого уровня» для написания смартконтрактов для Ethereum Virtual Machine, это Solidity (на основе Javascript) и Serpent (на основе Python). Второй скорее мертв, чем жив, т.к. уже больше года не было обновлений, а в Solidity фиксят регулярно ошибки компилятора. В настоящее время мы своей командой ведем работу над созданием визуального языка программирования смартконтрактов на основе Scratch. Пока еще окончательно не определились, будем ли сразу генерировать байткод или же в качестве промежуточного слоя будем использовать Solidity, чтобы оставить возможность верификации полученного кода. Вобщем, платформа Ethereum достаточно универсальна, чтобы решать на ней широкий класс задач. Вопрос в том, что у разработчиков не дошли руки сделать удобной прикладную разработку.


        1. superhackkiller1997
          17.09.2017 13:08
          -6

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

          Очередная манипуляция. Вам говорили не о какой-то там фиче в каких-то там языках, а ваших заявлениях на тему «программисты ДОЛЖНЫ использовать это».

          Вот именно про «должны» и отвечайте.

          Выражения про плавучку абсолютно не понимаю. При чём здесь какая-то плавучка? Я говорю, численное представление суммы должно быть абстрагировано. Неважно, что там внутри. А вы мне про какую-то плавучку. Я и слов-то таких не употребляю никогда.


          Притом, вся ваша «логика» и ответы — это «пальцем в небо» и не более того. Я уже говорил о том, что это уровень языка, а не уровень ваших абстракций. Вы же это, благополучно, проигнорировали.

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

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

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

          Ярки пример пустой болтовни и глупых ссылок.

          В верхней строке мы видим одну хипстоту, в половине которой вообще ваш синтаксис не работает и нет типизации. Т.е. мимо. В нижней строке из живого и типизированного — это кресты, сишарп — всё.

          Где оно работает? В луа? Без типов и через жопу? Удачи сравнить веи с эфирами. Что там ещё. Пистон? К тому же, это всё рантайм и никакого зерокост.

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

          И того — два языка. Скорее всего даже шарп не подойдёт и того — полтора. Один живой и второй не взлетевший.

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

          Ну дак покажите мне операции уровня языка за рамками сложения чиселок. Это же просто и без болтовни.

          Джавовый JIT (Hotspot C2) вполне способен на такие оптимизации.

          Не способен. Причина проста — жава просто неспособна на подобные абстракции.

          Я полагаю, Clang с кодом на C++ легко разделается тоже.

          Я за вас уже сказал это. Зачем повторять?

          Тут вполне тривиальная цепочка оптимизаций инлайнинга, эскейп-анализа и констант-фолдинга.

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

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

          Опять же. Как мы уже выясниили — на подобное способен сишный компилятор и мистический хотспот. Остальные, как я понимаю, так же не способны нанять хорошего компиляторщика, да? Вот ведь идиоты.

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

          Именно поэтому ни у одного языка не было приличного компилятора до появления ллвм. Они так же — просто не додумались нанять хорошего компиляторщика. Бывает.

          Смысл последнего абзаца в том, что этериум = джаваскрипт и ничего с этим не поделаешь? Я думаю, в основу платформы никакая типизация не заложена и на ней вполне можно сделать нормальный язык, компилируемый в этериум. Либо он уже существует, просто автор этой статьи не умеет им пользоваться.

          Смысл последнего абзаца в том, что есть сообщество. Вы не способны думать в рамках обстоятельств реального мира. Причина — ваша специализация. Так же со всем остальным.

          Вся эта тема существует и базируется в рамках жаваскрипт мира. А жаваскрипт стеком не пользуются «хорошие компиляторщиики» и прочее. Можно глянуть на какой-нибудь там тайпскрипт, который не язык, а хелворд. Но это максимум до чего дошел мир жаваскрипта. Хотя есть причина тому, хотя это больше оправдание — он совместим с ЖС.


          1. Regis
            17.09.2017 18:25
            +1

            Джавовый JIT (Hotspot C2) вполне способен на такие оптимизации.
            Не способен. Причина проста — жава просто неспособна на подобные абстракции.
            WAT? Вы либо лежали в криогенной камере последние лет 10 и не в курсе, что Java-вский JIT сейчас умеет, а что нет. Либо просто болтаете о том, что чего в принципе не знаете. Не изволите ли уточнить, что из двух?


            1. superhackkiller1997
              17.09.2017 19:48
              -2

              Если есть что возразить — я слушаю. Для начала научитесь читать, ведь то, что вы процитировали относится к жаве, а не к житу.


              1. izzholtik
                17.09.2017 20:04
                +1

                uh.
                Вы вообще различаете язык Java, JDK и JRE?


                1. superhackkiller1997
                  18.09.2017 05:59
                  -3

                  Вы вообще различаете язык Java, JDK и JRE?

                  Вот объясните мне, эксперты, что с вами не так? Вы не умеете читать? Хотя что я могу ожидать от верующих — уж явно не объективности.

                  Специально для вас расшифрую.

                  Не способен. Причина проста — жава(язык) просто неспособна на подобные абстракции.

                  Расшифрую ещё более тщательно. Неважно какой там жит. Жит не выпилит ГЦ, жит не выпилит рантайм рефлексию, жит не наделит жаву нормальной типизацией, жит не сделает из дженериков что-то уровня крестовых шаблонов.


                  1. izzholtik
                    18.09.2017 12:19
                    +2

                    Понял, вопросов больше не имею.


              1. Regis
                18.09.2017 00:02

                «Java JIT» — встроенный Just In Time компилятор вирутальной машины Java. Преобразует Java-байткод в высокопроизводительный native-код, в том числе выполяет инлайниг, разворачивание циклов, векторизацию и много других оптимизаций. Именно он позволяет Java держать лидирующие позиции в тестах на производительность. И повторюсь, это не что-то отдельное от Java — это часть стандартной JVM.

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


                1. superhackkiller1997
                  18.09.2017 05:38
                  -2

                  Именно он позволяет Java держать лидирующие позиции в тестах на производительность.

                  В мире влажных мечтаний адептов, возможно.

                  И повторюсь, это не что-то отдельное от Java — это часть стандартной JVM.

                  И что же из этого следует?

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

                  И что же конкретно я своим комментарием подтвердил и на основании чего.


    1. isvirin Автор
      17.09.2017 10:28
      +4

      Константы есть. Строчку

      uint256 tokens = tokensPerOneEther * msg.value / 1000000000000000000;
      

      можно записать как
      uint256 tokens = tokensPerOneEther * msg.value / 1 ether;
      

      Но с точки зрения понимания сути оно мне кажется хуже, хотя и вероятность ошибки ниже.

      Есть и другие полезные константы, типа minutes, days, years и т.п.


      1. lany
        17.09.2017 11:39
        +1

        1 ether получше, чем восемнадцать нулей, хотя скрывается тот факт, что оно выражено в веях. Возможно, это ничего, если все привыкли считать, что всё и всегда выражено в веях. Но оно опять же явно не так. В коде автора, например, есть tokensPerOneEther = 5000, а вовсе не цена одного токена в веях. Очевидно, что не всегда удобно работать с веями, надо с разными единицами уметь.


        1. superhackkiller1997
          17.09.2017 13:14
          -2

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

          Это именно то, о чём я говорил. Вы сознались в том, что не привыкли, а значит привыкли вы к чему? Правильно, к плавучке, где можно менять порядок как угодно и складывать величины разного порядка.

          От того вам и не привычен константный порядок.

          Но оно опять же явно не так.

          Явно так.
          В коде автора, например, есть tokensPerOneEther = 5000, а вовсе не цена одного токена в веях

          Правильно, потому что автор так же пока не отвык от плавучки. И именно в веях она и должна быть выражена.
          Очевидно, что не всегда удобно работать с веями, надо с разными единицами уметь.

          Очевидно, что вам удобно игнорировать те обстоятельства, о которым вас сообщают. Токены — это левая логика. Её не существует в рамках платформы. Это не аналог веям.

          На уровне платформы существуют только веи. И никаких других единиц попросту не существует.


          1. TargetSan
            17.09.2017 14:16
            +1

            На уровне платформы существуют только веи. И никаких других единиц попросту не существует.

            Но на входе-выходе существуют эфирные монеты и много чего ещё. У НАСА был спускаемый аппарат, который навернулся из-за нестыковок между метрической и имперской системой. Вы постоянно "тычете" оппонента в "плавучку", которой в его комментариях нет. Он как раз говорит о такой штуке, как единицы измерения, закодированные в виде типов. Это сильно уменьшает вероятность ошибки, т.к. при попытке комбинирования в одной операции вы либо получите ошибку компиляции, либо корректное преобразование, закодированное один раз в логике типа.


            1. superhackkiller1997
              17.09.2017 15:51
              -2

              Но на входе-выходе существуют эфирные монеты и много чего ещё.

              Не существует.

              У НАСА был спускаемый аппарат, который навернулся из-за нестыковок между метрической и имперской системой.

              Это к теме отношения не имеет. Решение проблемы не в кастылянии, а в приведении всего к одному виду. И именно про это я и говорю.

              Он как раз говорит о такой штуке, как единицы измерения, закодированные в виде типов.

              Нет. Он уже уплыл с темы 10 раз и слушать, что говорят подобные персонажи — себе дороже. Сначала он говорил про зерокост, потом вдруг о зерокосте забыл и прочее и прочее.

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

              Плюс, он путает( как и большинство) язык и рантайм. Т.е. язык и набор библиотек, которые поставляются с языком. Я об этом так же говорил. Так же — он не понимает, что токены — это не сущности платформы, а сущности внешние. Я об этом так же сказал.

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

              Вы постоянно «тычете» оппонента в «плавучку», которой в его комментариях нет.

              Если там нет слова «плавучка» — это не значит, что её там нет. Если вы не можете это вывести сами, то я вам показал цитату, в которой персонаж явно говорил о том, что логика с константным порядком ему непривычна.

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

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

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

              Эти константы позволяют вам приводить любые величины к общему виду — веям. И никаких проблем с преобразование дальше нет. Хотя что-то отличное от веев — вы сами туда тащите.

              Ни в чём другом, кроме веев, считать по определению нельзя.

              закодированное один раз в логике типа.

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

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

              За рамками её просто эфиров быт не может. К эфиру надо прикрутить ещё остаток. И уже у нас не эфир, а пара. И уже во много раз больше операций. И где обещанный зерокост?

              Я даже не понимаю как это должно и может работать. WEI.amount(value).toEther() — что мы получаем? Только эфиры? А где веи? А если это веи, то чем они отличаются от веев? Это веи + эфиры? Как это.


  1. sirocco
    17.09.2017 09:16

    У меня другая беда. Есть кошелёк Mist, и закинул я туда токенов plbt. И теперь никак не пойму как их вывести оттуда, нигде не нашёл этой информации. Вообще одна головная боль с этими эфировскими кошельками.


    1. riartem
      17.09.2017 16:57

      Добавьте в кошелёк смарт-контракт валюты PLBT.
      Вкладка «Contracts», раздел «Custom tokens», кнопка "+ Watch token"

      Данные для добавления (взято из п.23 FAQ на сайте Polybius)
      0x0AfFa06e7Fbe5bC9a764C979aA66E8256A631f02
      Token name: Polybius Token
      decimals: 6
      symbol: PLBT


      1. sirocco
        17.09.2017 19:24

        Нет. Он требует ещё что-то прописать в графе JSON ИНТЕРФЕЙС.


        1. riartem
          18.09.2017 10:47
          +1

          Специально ж расписал названия кнопок.

          Смотреть скриншот


          1. sirocco
            18.09.2017 13:46

            Очень спасибо Вам! Просто интерфейс на русском, несмотря на то, что English выставлен, вот и не верно детранслитил.


    1. riartem
      17.09.2017 17:06

      Технически кастомные токены на базе эфира никуда не передаются и сами не могут потеряться (главное не терять доступ к аккаунту с эфиром, на который эти токены «отправляли»).
      Это просто цифра внутри контракта, которая говорит, что адресу X принадлежит Y токенов. Поэтому переживать не о чем.


      1. isvirin Автор
        17.09.2017 18:16

        Собственно, контракт, рассмотренный в этом посте, наглядно подтверждает этот тезис:)


  1. mayorovp
    17.09.2017 09:47
    +1

    а также содержит ряд известных уязвимостей на уровне компилятора языка Solidity, например, подвержен так называемой short address attack

    ЁПРСТ! Вы хотите сказать, что существует уязвимость компилятора, которая делает нормальные с виду контракты уязвимыми — и она до сих пор не закрыта?


    1. isvirin Автор
      17.09.2017 10:09

      К сожалению, существует и не одна :)


    1. izzholtik
      17.09.2017 11:54
      +2

      Всё это сильно напоминает мир 1С, в котором люди, работающие с деньгами, зачастую не знают основ программирования и лепят код "на пофиг".


      1. isvirin Автор
        17.09.2017 12:07

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


        1. lany
          17.09.2017 13:02

          стоимость выполнения тех или иных операций (выраженная в деньгах)

          В идеале об этом должен компилятор думать. Он должен это измерять, компилировать, оптимизируя именно эту стоимость, выдавать вам советы в виде предупреждений и т. д. В светлом будущем, наверно, так и будет :-)


        1. Alesh
          17.09.2017 13:59

          Кстати, что посоветуете почитать для понимания основ?


          1. isvirin Автор
            17.09.2017 14:40

            Для понимания основ достаточно вот таких постов, как этот.
            Достаточно системно рассматриваются примеры на официальном сайте ethereum.org.
            Если программируете свободно на других языках, то можно попробовать такой формат — learnxinyminutes.com/docs/solidity.
            Ну а перед сном надо читать вот это — solidity.readthedocs.io/en/develop/contracts.html


            1. riartem
              18.09.2017 11:01

              Но я не увидел в вашем примере защиты от вышеупомянутой «short address attack» в методе transfer. Там разве не должно быть проверки на полноту адреса? (Или я неправильно понял суть атаки?)


              1. isvirin Автор
                18.09.2017 11:02

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


  1. vz10
    17.09.2017 10:44

    Вопрос по существу, а зачем мы все время наследуем контракты? То есть на выходе у нас будет несколько разных замайненных контрактов или это просто синтаксический сахар для модульности и контракт на выходи будет один?


    1. isvirin Автор
      17.09.2017 11:09
      +1

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


  1. evgen
    17.09.2017 11:56

    У вас на prover pre-ICO длится до 31 сентября :)


    1. isvirin Автор
      17.09.2017 11:59

      Да, должно было возникнуть переполнение :)
      Спасибо!


    1. isvirin Автор
      17.09.2017 18:13

      Поправили


  1. Serdonda
    17.09.2017 12:12

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


    А как у Вас проверяются «полномочия» нового владельца? Насколько я понимаю в вашем варианте любой желающий может использовать функцию «changeOwner» и стать новым владельцем. Или это не так?


    1. isvirin Автор
      17.09.2017 12:17

      Функцию changeOwner может вызвать только текущий владелец. Обратите внимание на модификатор onlyOwner у этой функции.


      1. Serdonda
        17.09.2017 12:25

        но вы говорите о том что эта функция предназначена для

        смены владельца на случай, если наш private key будет скомпромитирован,

        Скомпрометирован — значит стал известен посторонним/утерян/и т.д…
        Таким образом тот кому стал известен private key меняет владельца на свой адрес. В чем тогда смысл этой функции? Видится что только в гонке — кто быстрее сменит адрес владельца — настоящий владелец или посторонний которому стал известен private key


        1. lany
          17.09.2017 13:06
          +1

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


        1. mayorovp
          17.09.2017 13:26
          +1

          Скомпрометирован не означает "украден". Предполагается, что у владельца есть в запасе какое-то время.


        1. isvirin Автор
          17.09.2017 14:01

          Можно предложить и более параноидальную схему по принципу multisig, когда контракт «знает» нескольких владельцев, а для смены одного из владельцев требуется confirm всех остальных. Реализовать это несложно, но это выходит за рамки «простого смартконтракта для ICO» :)


  1. edogs
    17.09.2017 13:51
    -2

    Также можно указать себя в качестве автора контракта, конечно, если вы не пишете контракт для какого-нибудь скамового проекта, где стесняетесь указать себя в качестве автора.
    Вот это просто убило.
    /sarcasm/
    Разумеется, если ты не указываешь себя как автор, то это только потому что проект скамовый. Не по какой-либо другой причине. Анонимность вообще зло. Даешь доступ в интернет по паспорту. Криптовалюты ведь и созданы для однозначной идентификации пользователей. Открой все данные о себе, ведь тебе нечего скрывать, а если не открываешь, то значит ты занимаешься скамом и твое место тюрьма.
    /sarcasm/
    Нет, понятно, что мы overreacting, но блин, именно фразы вида «если стесняешься указать себя в качестве автора, значит тебе есть что скрывать, значит ты пишешь скамовый проект» и есть тот ручеек, с которого начинается та самая река. И особенно цинично это звучит в проектах связанных с криптой.


    1. isvirin Автор
      17.09.2017 14:06

      Ощущается явная проблема с чувством юмора:) Прошу прощения, что оскорбил Ваши светлые чувства:)

      На самом деле, рассмотренный смартконтракт в чистом виде скам, т.к. объективно никак не защищает интересов инвесторов (покупателей токенов). Такие контракты не должны быть в боевых проектах. Он всего лишь демонстрирует принципы организации краудсейла с технической точки зрения.

      Касательно анонимности и ICO. Не открою америку, если скажу, что и в классическом венчуре и в ICO деньги дают прежде всего команде. Успешные анонимные ICO — большая редкость. Поэтому если вы не делаете скам (в проекте, в смартконтракте), то напишите, кто Вы есть такой, чтобы инвесторы видели, что Вы готовы ответить за базар:) Но это лишь мое мнение, возможно, я идеализирую. Но в нашим проектах PROVER и OpenLongevity мы руководствуемся именно такими принципами.


      1. edogs
        17.09.2017 19:26
        -2

        Ощущается явная проблема с чувством юмора:)
        Выбор темы для шуток лучше характеризует человека, чем его серьезные речи:)

        Поэтому если вы не делаете скам (в проекте, в смартконтракте), то напишите, кто Вы есть такой, чтобы инвесторы видели, что Вы готовы ответить за базар:)
        На самом деле это не дает никакой «ответственности за базар», Вы путаете направление подтверждения:)
        Подпись в ico нужна только если Вы хотите доказать что это Ваш ico.
        А вот ответственность за него Вы будете нести только если Вы вне ico подтвердите что это Ваш ico, подпись в ico для ответственности за базар не нужна.

        Упрощенно говоря если в ico указаны данные Васи Пупкина, то с Васи Пупкина на этом основании Вы ни копейки не стрясете. Это с одной стороны.
        С другой стороны если Вася Пупкин где-то вне ico признался что это его ico, то Вы и без подписи в ico сможете стрясти с него копеечку.


        1. isvirin Автор
          17.09.2017 19:30

          Сразу видно, что ICO Вы не проводили:) Поговорите с юристами, они объяснят, что означает указание данных Васи Пупкина для Васи Пупкина при проведении ICO, кто несет ответственность и перед кем. Это далеко за границами этого поста, я принципиально не хочу выходить за технические рамки, хотя мы и обладаем глубокими юридическими компетенциями в данном вопросе.


          1. edogs
            18.09.2017 05:53

            Указание данных Васи Пупкина неизвестным лицом где бы то ни было не накладывает на Васю Пупкина никаких обязательств.


  1. Urn
    17.09.2017 16:24

    Не упел углубиться еще в код ваших контрактов… Но в чем преимущество по сравнению с уже написаными и оттестироваными реализациями ERC20, например github.com/ConsenSys/Tokens/tree/master/contracts?


    1. isvirin Автор
      17.09.2017 18:12

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

      Ну и контракты по ссылке не стоит считать эталоном — например, они подвержены той же short address attack.

      Вот мой контракт проекта PROVER действительно прекрасен, но он реализует вполне конкретную бизнес-логику, требуемую именно для моего проекта.


  1. isvirin Автор
    17.09.2017 18:19
    +1

    Господа, которые минусуют пост и карму, вы в комментариях намекните, что не нравится, чтобы можно учесть в следующих постах:)


    1. igordata
      17.09.2017 18:52
      +1

      Забей. Кому есть что сказать — пишут в каментах и зачастую не минусут. Минусуют те, кому сказать нечего.


      1. isvirin Автор
        17.09.2017 19:05

        Буду иметь в виду:)


  1. aleks_raiden
    17.09.2017 18:36
    +1

    Еще лучше сразу реализовать ERC223 — как раз поля Symbol/Short name там есть.


  1. igordata
    17.09.2017 18:53
    +1

    А как обновить контракт если что-то нашлось потом критическое?


    1. isvirin Автор
      17.09.2017 19:05
      +1

      Контракт обновить нельзя, но можно загрузить новый и перевести туда всех держателей токенов. Для миграции можно предусмотреть дополнительную функциональность контракта, чтобы не делать это руками. Ну и в стиле децентрализации/блокчейн делать эту миграцию голосованием держателей токенов. Опять же хочу в качестве примера такой реализации привести свой «контракт PROVER»:https://etherscan.io/address/0x5B5d8A8A732A3c73fF0fB6980880Ef399ecaf72E#code. Там можно подсмотреть реализацию миграции НА этот контракт и С этого контракта. Все демократично и безопасно:)


    1. isvirin Автор
      17.09.2017 19:07

      Еще хорошей практикой является реализовывать сложную бизнес-логику в виде набора связанных между собой контрактов, причем отдельные части этой логики можно заменять, опять же голосованием держателей токенов. В блокчейне принято «играть» в демократию:)


  1. spread
    17.09.2017 22:02

    Не пойму как можно увидеть\вызвать, например в MIST, анонимную функцию после конструктора Crowdsale()
    ```contract Crowdsale is owned {

    uint256 public totalSupply;
    mapping (address => uint256) public balanceOf;

    event Transfer(address indexed from, address indexed to, uint256 value);

    function Crowdsale() payable owned() {
    totalSupply = 21000000;
    balanceOf[this] = 20000000;
    balanceOf[owner] = totalSupply — balanceOf[this];
    Transfer(this, owner, balanceOf[owner]);
    }

    function () payable {
    ```
    ?


    1. isvirin Автор
      17.09.2017 22:03

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


  1. spread
    17.09.2017 22:11

    А почему 1 параметер в owner.transfer(this.balance);
    contract EasyCrowdsale is EasyToken {

    function EasyCrowdsale() payable EasyToken() {}

    function withdraw() public onlyOwner {
    owner.transfer(this.balance);
    }
    }
    ИМХО должен быть первым адрес кошелька куда владелец отправит\снимет токены? как определено выше
    function transfer(address _to, uint256 _value) public {…


    1. isvirin Автор
      17.09.2017 22:12

      Тут передаются не токены, а собранный эфир.
      owner — это и есть адрес.


  1. spread
    17.09.2017 22:35
    -2

    А если юзер хочет вывести на свой холодный кошелёк свои EasyToken правильно так?
    function withdrawToUserWallet(address _to, uint256 _value) public returns(bool success){
    balanceOf[msg.sender] > _value;
    return msg.sender.transfer(_to, _value);
    }


    1. aleks_raiden
      17.09.2017 23:21

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


    1. isvirin Автор
      17.09.2017 23:35

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


      1. mayorovp
        18.09.2017 08:34

        Так холодный кошелек же на то и холодный что он должен находиться в оффлайне до востребования.


  1. knott
    18.09.2017 01:50

    Я конечно не эксперт, но не подвержен ли ваш контракт проблемам с reentrancy?


    Перевод эфира должен вызвать такой же обработчик по умолчанию на sender, который в ответ может передать еще эфира контракту ICO, вызвав тем самым обработчик по умолчанию...


    1. isvirin Автор
      18.09.2017 01:57

      Не вижу, где может возникнуть, описанная вами ситуация. Перевод эфира на рассмотренный контракт приведет к вызову payback функции, которая отгрузит токены. В ответ на отгрузку токенов у sender-а ничего не вызовется, т.к. это по сути внутреннее дело нашего контракта.


      1. mayorovp
        18.09.2017 08:45

        Насколько я понял, речь шла о вот этой строчке: msg.sender.transfer(msg.value - valueWei);


        Такая ситуация может возникнуть например вот в каком случае. Рассмотрим немного модифицированный контракт, который умеет делать withdraw не только владельцу — но и на любой указанный владельцем адрес. И предположим, что владелец того контракта решил сделать withdraw на адрес нашего (не спрашивайте зачем, допустим это была ошибка). При этом суммарная переведенная сумма оказалась больше чем у нас оставалось токенов.


        В итоге делается посылка "сдачи" обратно отправителю, что интерпретируется тем контрактом как покупка токенов, но поскольку токены там уже закончились, сумма возвращается обратно к нам.


        Что произойдет в таком случае? Это будет цикл или рекурсия?


        1. isvirin Автор
          18.09.2017 10:13

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


          1. mayorovp
            18.09.2017 10:26

            То есть все-таки рекурсия, а не цикл?


            Но тогда это можно попробовать превратить в атаку, за счет того что balanceOf[this] меняется уже после перевода "сдачи". Например, если в такой смартконтракт добавить миграцию на новую версию с голосованием токенами, злоумышленник может купить себе количество токенов, достаточное для "кворума", и сменить контракт на свой.


    1. mayorovp
      18.09.2017 08:37

      (сообщение удалено)


  1. quantum
    18.09.2017 09:44
    +1

    Основной функционал токенов уже реализован в zeppelin solidity и проверен многими людьми. Рекомендую наследоваться от их токенов.

    Также пр разработке посмотрите на фреймворк truffle, позволяет запускать юниттесты


    1. isvirin Автор
      18.09.2017 10:08

      Юнит-тесты крайне полезная штука, достойны отдельного поста. Только использовать truffle для этого вовсе не обязательно.