Как: создать токен в сети PIRL

Поделиться этой записью

Поделиться на facebook
Поделиться на linkedin
Поделиться на twitter
Поделиться на email

Монета

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

МИНИМАЛЬНЫЙ ЖИВОТНЫЙ ЖЕТОН

Стандартный токен-контракт может быть довольно сложным. Но по сути очень простой токен сводится к следующему:

contract MyToken {/ * Это создает массив со всеми балансами * / mapping (address => uint256) public balanceOf; / * Инициализирует договор с начальными токенами поставки для создателя договора * / function MyToken (uint256 initialSupply) {balanceOf [msg.sender] = initialSupply; // Передаем создателю все начальные токены} / * Отправка монет * / передача функции (адрес _to, uint256 _value) {require (balanceOf [msg.sender]> = _value); // Проверяем, достаточно ли у отправителя require (balanceOf [_to] + _value> = balanceOf [_to]); // Проверка на переполнение balanceOf [msg.sender] - = _value; // Вычитаем из отправителя balanceOf [_to] + = _value; // Добавить то же самое к получателю}}

КОД

Но если вы просто хотите скопировать и вставить более полный код, используйте это:

солидность прагмы ^ 0.4.16;

интерфейс tokenRecipient {функция receiveApproval (адрес _from, uint256 _value, адрес _token, байты _extraData) public; }

контракт TokenERC20 {
   // Публичные переменные токена
   строка публичного имени;
   публичный символ строки;
   uint8 общедоступные десятичные дроби = 18;
   // 18 десятичных знаков - строго рекомендуемое значение по умолчанию, избегайте его изменения
   uint256 public totalSupply;

   // Это создает массив со всеми балансами
   отображение (адрес => uint256) public balanceOf;
   mapping (address => mapping (address => uint256)) общественное пособие;

   // Это генерирует публичное событие в блокчейне, которое будет уведомлять клиентов
   передача события (адрес проиндексирован, адрес проиндексирован, значение uint256);

   // Это уведомляет клиентов о сожженной сумме
   событие Burn (адрес проиндексирован, значение uint256);

   /**
    * Функция конструктора
    *
    * Инициализирует контракт с начальной поставкой токенов создателю контракта
    */
   функция TokenERC20 (
       uint256 initialSupply,
       строка tokenName,
       строка tokenSymbol
   ) public {
       totalSupply = initialSupply * 10 ** uint256 (десятичные дроби); // Обновление общего предложения с десятичной суммой
       balanceOf [msg.sender] = totalSupply; // Даем создателю все начальные токены
       name = tokenName; // Установить имя для отображения
       символ = символ токена; // Установить символ для отображения
   }

   /**
    * Внутренний перевод, только по этому договору
    */
   функция _transfer (адрес _from, адрес _to, uint _value) внутренний {
       // Запрет передачи на адрес 0x0. Вместо этого используйте burn ()
       требуют (_to! = 0x0);
       // Проверяем, достаточно ли у отправителя
       require (balanceOf [_from]> = _value);
       // Проверка на переполнение
       требуют (balanceOf [_to] + _value> balanceOf [_to]);
       // Сохраняем это для утверждения в будущем
       uint previousBalances = balanceOf [_from] + balanceOf [_to];
       // вычитаем из отправителя
       balanceOf [_from] - = _value;
       // Добавить то же самое к получателю
       balanceOf [_to] + = _value;
       Передача (_from, _to, _value);
       // Утверждения используются для использования статического анализа для поиска ошибок в вашем коде. Они никогда не должны потерпеть неудачу
       assert (balanceOf [_from] + balanceOf [_to] == предыдущий баланс);
   }

   /**
    * Передача токенов
    *
    * Отправьте токены `_value` на _to` из своего аккаунта
    *
    * @param _to Адрес получателя
    * @param _value сумма для отправки
    */
   функция передачи (адрес _to, uint256 _value) public {
       _transfer (msg.sender, _to, _value);
   }

   /**
    * Перевод токенов с другого адреса
    *
    * Отправьте токены `_value`` _to` от имени `_from`
    *
    * @param _from адрес отправителя
    * @param _to Адрес получателя
    * @param _value сумма для отправки
    */
   Функция TransferFrom (адрес _from, адрес _to, uint256 _value) публичных возвратов (bool success) {
       require (_value <= allowance [_from] [msg.sender]); // Проверка пособия
       пособие [_from] [msg.sender] - = _value;
       _transfer (_from, _to, _value);
       вернуть истину;
   }

   /**
    * Установить скидку на другой адрес
    *
    * Позволяет `_spender` тратить не более чем токены` _value` от вашего имени
    *
    * @param _spender Адрес, на который разрешено тратить
    * @param _значите максимальную сумму, которую они могут потратить
    */
   функция утвердить (адрес _spender, uint256 _value) public
       возвращает (успешный бул) {
       пособие [msg.sender] [_ spender] = _value;
       вернуть истину;
   }

   /**
    * Установите скидку на другой адрес и сообщите
    *
    * Позволяет `_spender` тратить не более чем _value` токенов от вашего имени, а затем проверять договор об этом
    *
    * @param _spender Адрес, на который разрешено тратить
    * @param _значите максимальную сумму, которую они могут потратить
    * @param _extraData некоторая дополнительная информация для отправки в утвержденный контракт
    */
   функция ApproveAndCall (адрес _spender, uint256 _value, байты _extraData)
       общественности
       возвращает (успешный бул) {
       tokenRecipient spender = tokenRecipient (_spender);
       если (одобрить (_spender, _value)) {
           spender.receiveApproval (msg.sender, _value, this, _extraData);
           вернуть истину;
       }
   }

   /**
    * Уничтожить жетоны
    *
    * Необратимое удаление токенов `_value` из системы
    *
    * @param _value количество денег, чтобы сжечь
    */
   функция burn (uint256 _value) публичные возвраты (bool success) {
       require (balanceOf [msg.sender]> = _value); // Проверяем, достаточно ли у отправителя
       balanceOf [msg.sender] - = _value; // вычитаем из отправителя
       totalSupply - = _value; // Обновляет totalSupply
       Burn (msg.sender, _value);
       вернуть истину;
   }

   /**
    * Уничтожить токены с другого аккаунта
    *
    * Удалить необратимые токены `_value` из системы от имени` _from`.
    *
    * @param_от адреса отправителя
    * @param _value количество денег, чтобы сжечь
    */
   функция burnFrom (адрес _from, uint256 _value) public возвращает (bool success) {
       require (balanceOf [_from]> = _value); // Проверяем, достаточно ли целевого баланса
       require (_value <= allowance [_from] [msg.sender]); // Проверка пособия
       balanceOf [_from] - = _value; // Вычитаем из целевого баланса
       пособие [_from] [msg.sender] - = _value; // Вычитаем из пособия отправителя
       totalSupply - = _value; // Обновляем totalSupply
       Burn (_from _value);
       вернуть истину;
   }
}

Понимание Кодекса

Итак, начнем с основ. Откройте приложение «Кошелек», перейдите на вкладку «Контракты» и затем разверните новый контракт. В текстовом поле Исходный код контракта на надежность введите следующий код:

контракт MyToken {
       / * Это создает массив со всеми балансами * /
       отображение (адрес => uint256) public balanceOf;
   }

Отображение означает ассоциативный массив, где вы связываете адреса с балансами. Адреса представлены в основном шестнадцатеричном формате Pirl, а весы - целые числа в диапазоне от 0 до 115 quattuorvigintillion. Если вы не знаете, сколько стоит quattuorvigintillion, это гораздо больше, чем что-либо, для чего вы планируете использовать свои токены. Ключевое слово public означает, что эта переменная будет доступна любому пользователю в блокчейне, а это означает, что все сальдо являются общедоступными (как и должно быть, чтобы их отображали клиенты).

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

function MyToken () {
       balanceOf [msg.sender] = 21000000;
   }

Обратите внимание, что функция MyToken имеет то же имя, что и контракт MyToken. Это очень важно, и если вы переименуете одно, вам придется переименовать и другое: это специальная функция запуска, которая запускается только один раз и только при первой загрузке контракта в сеть. Эта функция установит баланс msg.sender, пользователя, который развернул контракт, с балансом 21 миллион.

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

функция MyToken (uint256 initialSupply) public {
       balanceOf [msg.sender] = initialSupply;
   }

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

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

/ * Отправить монеты * /
   передача функции (адрес _to, uint256 _value) {
       / * Добавить и вычесть новые остатки * /
       balanceOf [msg.sender] - = _value;
       balanceOf [_to] + = _value;
   }

Это очень простая функция: у нее есть получатель и значение в качестве параметра, и всякий раз, когда кто-то ее вызывает, она вычитает значение _value из своего баланса и добавляет его в баланс _to. Сразу возникает очевидная проблема: что произойдет, если человек захочет отправить больше, чем имеет? Поскольку мы не хотим обрабатывать задолженность по этому конкретному контракту, мы просто проведем быструю проверку, и если у отправителя не будет достаточно средств, выполнение контракта просто прекратится. Также необходимо проверить наличие переполнений, чтобы избежать того, что число будет таким большим, что оно снова станет нулевым.

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

передача функции (адрес _to, uint256 _value) {
       / * Проверить, есть ли баланс отправителя и нет ли переполнения * /
       require (balanceOf [msg.sender]> = _value && balanceOf [_to] + _value> = balanceOf [_to]);

       / * Добавить и вычесть новые остатки * /
       balanceOf [msg.sender] - = _value;
       balanceOf [_to] + = _value;
   }

 

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

строка публичного имени;
публичный символ строки;
uint8 публичные десятичные дроби;

А теперь мы обновляем функцию конструктора, чтобы разрешить установку всех этих переменных в начале:

/ * Инициализирует контракт с начальными токенами поставки создателю контракта * /
   функция MyToken (uint256 initialSupply, строка tokenName, строка tokenSymbol, uint8 decimalUnits) {
       balanceOf [msg.sender] = initialSupply; // Даем создателю все начальные токены
       name = tokenName; // Установить имя для отображения
       символ = символ токена; // Установить символ для отображения
       десятичные = десятичные единицы; // Количество десятичных знаков для отображения
   }

Наконец, теперь нам нужен somPirling с именем Events. Это специальные пустые функции, которые вы вызываете, чтобы помочь таким клиентам, как Pirl Wallet, отслеживать действия, выполняемые в контракте. События должны начинаться с заглавной буквы. Добавьте эту строку в начале контракта, чтобы объявить событие:

передача события (адрес проиндексирован, адрес проиндексирован, значение uint256);
 

И тогда вам просто нужно добавить эти две строки внутри функции «передача»:

      / * Уведомить всех, кто слушает, что эта передача произошла * /
       Передача (msg.sender, _to, _value);

 

И теперь ваш токен готов!

Заметили комментарии?

Вы можете спросить, что это за комментарии @notice и @param? Это Natspec новый стандарт для спецификации естественного языка, который позволяет кошелькам показывать пользователю описание на естественном языке того, что контракт собирается сделать. Хотя в настоящее время не поддерживается многими кошельками, это изменится в будущем, поэтому приятно быть готовым.

Как развернуть

Если вы еще не там, откройте Pirl Wallet, перейдите на вкладку контрактов и нажмите «развернуть новый контракт».

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

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

Вы будете перенаправлены на главную страницу, где вы увидите свою транзакцию, ожидающую подтверждения. Нажмите на учетную запись, и через не более минуты вы увидите, что ваша учетная запись покажет, что у вас есть 100% из только что созданных вами акций. Чтобы отправить сообщения нескольким друзьям: выберите «отправить», а затем выберите валюту, которую вы хотите отправить (Pirl или только что созданный вами ресурс), вставьте адрес вашего друга в поле «to» и нажмите «отправить».

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

Чтобы добавить токен для просмотра, перейдите на страницу контрактов и нажмите «Смотреть токен». Появится всплывающее окно, и вам нужно только вставить адрес договора. Имя токена, символ и десятичное число должны быть заполнены автоматически, но если это не так, вы можете поместить все, что захотите (это повлияет только на то, как оно будет отображаться на вашем кошельке). Как только вы это сделаете, вам автоматически будет показан любой остаток на вашем токене, и вы сможете отправить его кому-либо еще.

И теперь у вас есть свой собственный крипто-токен! Сами по себе токены могут быть полезны в качестве обмена ценностями в местных сообществах, способов отслеживания рабочего времени или других программ лояльности. Но можем ли мы сделать валюту иметь внутреннюю ценность, сделав ее полезной?

Улучшите свой токен

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

Более основные функции

Вы заметите, что в вашем базовом контракте на токены есть еще несколько функций, таких как Approve, SendFrom и другие. Эти функции предназначены для взаимодействия вашего токена с другими контрактами: если вы хотите, скажем, продавать токены на децентрализованной бирже, просто отправки их по адресу будет недостаточно, поскольку биржа не будет знать о новых токенах или о том, кто отправил их, потому что контракты не могут подписаться на события только для вызовов функций. Поэтому для контрактов вы должны сначала утвердить количество токенов, которые они могут переместить с вашей учетной записи, а затем проверить их, чтобы сообщить им, что они должны делать свое дело - или выполнить два действия в одном, с ApproveAndCall.

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

/ * Внутренний перевод, может быть вызван только по этому контракту * /
   функция _transfer (адрес _from, адрес _to, uint _value) внутренний {
       требуют (_to! = 0x0); // Запрет передачи на адрес 0x0. Вместо этого используйте burn ()
       require (balanceOf [_from]> = _value); // Проверяем, достаточно ли у отправителя
       требуют (balanceOf [_to] + _value> balanceOf [_to]); // Проверка на переполнение
       требуют (frozenAccount [_from]!); // Проверяем, заморожен ли отправитель
       требуют (frozenAccount [_to]!); // Проверяем, заморожен ли получатель
       balanceOf [_from] - = _value; // вычитаем из отправителя
       balanceOf [_to] + = _value; // Добавить то же самое к получателю
       Передача (_from, _to, _value);
   }

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

Централизованный администратор

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

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

Для этого мы изучим очень полезное свойство контрактов: наследование. Наследование позволяет договору приобретать свойства родительского договора без необходимости переопределять их все. Это делает код чище и проще для повторного использования. Добавьте этот код в первую строку кода перед контрактом MyToken {.

Контракт принадлежит {
       адрес публичного владельца;

       функция own () {
           владелец = msg.sender;
       }

       модификатор onlyOwner {
           требовать (msg.sender == владелец);
           _;
       }

       функция TransferOwnership (адрес newOwner) onlyOwner {
           владелец = newOwner;
       }
   }

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

 Контракт MyToken принадлежит {
       / * остальная часть контракта как обычно * /

Это означает, что все функции внутри MyToken теперь могут обращаться к владельцу переменной и модификатору onlyOwner. Контракт также получает функцию передачи права собственности. Поскольку может быть интересно установить владельца контракта при запуске, вы также можете добавить это в функцию конструктора:

функция MyToken (
       uint256 initialSupply,
       строка tokenName,
       uint8 decimalUnits,
       строка tokenSymbol,
       адрес централМинтер
       ) {
       if (centralMinter! = 0) owner = centralMinter;
   }

Центральный монетный двор

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

Во-первых, нам нужно добавить переменную для хранения totalSupply и присвоить ее нашей функции конструктора.

контракт MyToken {
       uint256 public totalSupply;

       function MyToken (…) {
           totalSupply = initialSupply;
           …
       }
       …
   }

Теперь, наконец, добавим новую функцию, которая позволит владельцу создавать новые токены:

функция mintToken (целевой адрес, uint256 mintedAmount) onlyOwner {
       balanceOf [target] + = mintedAmount;
       totalSupply + = mintedAmount;
       Трансфер (0, владелец, mintedAmount);
       Трансфер (владелец, цель, mintedAmount);
   }

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

Замораживание активов

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

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

отображение (адрес => bool) public frozenAccount;
   событие FrozenFunds (адрес целевой, бул заморожен);

   function freezeAccount (адресная цель, bool freeze) onlyOwner {
       frozenAccount [target] = freeze;
       FrozenFunds (цель, заморозить);
   }

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

передача функции (адрес _to, uint256 _value) {
       требуют (frozenAccount [msg.sender]!);

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

требуется (approvedAccount [msg.sender]);

Автоматическая продажа и покупка

До сих пор вы полагались на полезность и доверие, чтобы ценить свой токен. Но если вы хотите, вы можете сделать так, чтобы ценность токена была подкреплена Pirl (или другими токенами), создав фонд, который автоматически продает и покупает их по рыночной стоимости.

Во-первых, давайте установим цену для покупки и продажи:

uint256 публичная цена продажи;
   uint256 публичная цена покупки;

   функция setPrices (uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
       sellPrice = newSellPrice;
       buyPrice = newBuyPrice;
   }

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

Следующим шагом является создание функций покупки и продажи:

function buy () подлежащие возврату суммы (сумма uint) {
       сумма = msg.value / buyPrice; // рассчитывает сумму
       требуют (balanceOf [это]> = сумма); // проверяет, достаточно ли для продажи
       balanceOf [msg.sender] + = сумма; // добавляет сумму к балансу покупателя
       balanceOf [this] - = количество; // вычитаем сумму из баланса продавца
       Перевод (это, msg.sender, сумма); // выполнить событие, отражающее изменение
       сумма возврата; // заканчиваем функцию и возвращаем
   }

   функция sell (сумма в uint) возвращает (доход в uint) {
       требовать (balanceOf [msg.sender]> = сумма); // проверяет, достаточно ли у отправителя продать
       balanceOf [this] + = сумма; // добавляет сумму на баланс владельца
       balanceOf [msg.sender] - = сумма; // вычитаем сумму из баланса продавца
       доход = сумма * sellPrice;
       msg.sender.transfer (доход); // отправляет Pirl продавцу: важно сделать это последним, чтобы предотвратить рекурсивные атаки
       Перевод (msg.sender, this, сумма); // выполняет событие, отражающее изменение
       возврат доходов; // заканчиваем функцию и возвращаем
   }

Обратите внимание, что это не создаст новые токены, но изменит баланс, которым владеет контракт. Контракт может содержать как свои собственные токены, так и Pirl и владельца контракта, в то время как он может устанавливать цены или, в некоторых случаях, создавать новые токены (если применимо), он не может касаться токенов банка или Pirl. Единственный способ, которым этот контракт может перемещать средства, - это продавать и покупать их.

Примечание «Цены» на покупку и продажу устанавливаются не в Pirl, а в минимальной валюте системы wei (эквивалентно центу в евро и долларе или сатоши в биткойнах). Один Пирл составляет 1000000000000000000 Вэй. Поэтому, устанавливая цены на свой токен в Pirl, добавьте 18 нулей в конце.

При создании контракта отправьте ему достаточно Pirl, чтобы он мог выкупить все токены на рынке, иначе ваш контракт будет неплатежеспособным, и ваши пользователи не смогут продавать свои токены.

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

Autorefill

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

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

uint minBalanceForAccounts;

   функция setMinBalance (uint минимумBalanceInFinney) onlyOwner {
        minBalanceForAccounts =imumBalanceInFinney * 1 finney;
   }

 

Затем добавьте эту строку в функцию передачи, чтобы отправителю было возвращено:

  / * Отправить монеты * /
   передача функции (адрес _to, uint256 _value) {
       …
       if (msg.sender.balance <minBalanceForAccounts)
           продать ((minBalanceForAccounts - msg.sender.balance) / sellPrice);
   }

 

Вместо этого вы также можете изменить его, чтобы отправитель выплачивал комиссию за пересылку:

  / * Отправить монеты * /
   передача функции (адрес _to, uint256 _value) {
       …
       если (_to.balance            _to.send (sell ((minBalanceForAccounts - _to.balance) / sellPrice));
   }

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

Доказательство Работы

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

function giveBlockReward () {
       balanceOf [block.coinbase] + = 1;
   }

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

uint currentChallenge = 1; // Можете ли вы выяснить кубический корень этого числа?

   функция rewardMathGeniuses (uint answerToCurrentReward, uint nextChallenge) {
       require (answerToCurrentReward ** 3 == currentChallenge); // Если ответ неверен, не продолжайте
       balanceOf [msg.sender] + = 1; // Награда игрока
       currentChallenge = nextChallenge; // Установить следующую задачу
   }

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

Этот процесс был впервые предложен Адамом в 1997 году как Hashcash а затем был внедрен в биткойны Сатоши Накамото в качестве доказательства работы в 2008 году.

Если вам нравится хеширование как форма случайного выпуска монет, вы все равно можете создать свою собственную валюту на основе Pirl, которая имеет подтверждение выдачи работы:

bytes32 public currentChallenge; // Монета начинается с вызова
   uint public timeOfLastProof; // Переменная, чтобы отслеживать, когда были даны награды
   общественная сложность = 10 ** 32; // Трудность начинается достаточно низко

   function proofOfWork (uint nonce) {
       bytes8 n = bytes8 (sha3 (nonce, currentChallenge)); // Генерируем случайный хеш на основе ввода
       require (n> = bytes8 (затруднение)); // Проверяем, находится ли он под сложностью

       uint timeSinceLastProof = (сейчас - timeOfLastProof); // Расчет времени с момента получения последнего вознаграждения
       require (timeSinceLastProof> = 5 секунд); // Награды не могут быть даны слишком быстро
       balanceOf [msg.sender] + = timeSinceLastProof / 60 секунд; // Награда победителю растет с каждой минутой

       сложность = сложность * 10 минут / времяSinceLastProof + 1; // Регулирует сложность

       timeOfLastProof = сейчас; // Сброс счетчика
       currentChallenge = sha3 (nonce, currentChallenge, block.blockhash (block.number - 1)); // Сохраняем хеш, который будет использоваться в качестве следующего доказательства
   }

Также измените функцию Constructor (имя которой совпадает с именем контракта, которое вызывается при первой загрузке), чтобы добавить эту строку, чтобы корректировка сложности не сходила с ума:

timeOfLastProof = сейчас;

После того, как контракт будет в сети, выберите функцию «Доказательство работы», добавьте ваш любимый номер в поле «nonce» и попробуйте выполнить его. Если в окне подтверждения отображается красное предупреждение «Данные не могут быть выполнены», вернитесь назад и выберите другой номер, пока не найдете тот, который позволяет транзакции идти вперед: этот процесс является случайным. Если вы найдете его, вы будете получать 1 жетон за каждую минуту, прошедшую с момента получения последней награды, а затем сложность задания будет увеличена или уменьшена, чтобы достичь в среднем 10 минут за вознаграждение.

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

Улучшенная монета

ПОЛНЫЙ КОД МОНЕТЫ
Если вы добавите все дополнительные параметры, вот как должен выглядеть окончательный код:

солидность прагмы ^ 0.4.16;

Контракт принадлежит {
   адрес публичного владельца;

   функция own () public {
       владелец = msg.sender;
   }

   модификатор onlyOwner {
       требовать (msg.sender == владелец);
       _;
   }

   функция TransferOwnership (адрес newOwner) onlyOwner public {
       владелец = newOwner;
   }
}


солидность прагмы ^ 0.4.16;

Контракт принадлежит {
   адрес публичного владельца;

   функция own () public {
       владелец = msg.sender;
   }

   модификатор onlyOwner {
       требовать (msg.sender == владелец);
       _;
   }

   функция TransferOwnership (адрес newOwner) onlyOwner public {
       владелец = newOwner;
   }
}

интерфейс tokenRecipient {функция receiveApproval (адрес _from, uint256 _value, адрес _token, байты _extraData) public; }

контракт TokenERC20 {
   // Публичные переменные токена
   строка публичного имени;
   публичный символ строки;
   uint8 общедоступные десятичные дроби = 18;
   // 18 десятичных знаков - строго рекомендуемое значение по умолчанию, избегайте его изменения
   uint256 public totalSupply;

   // Это создает массив со всеми балансами
   отображение (адрес => uint256) public balanceOf;
   mapping (address => mapping (address => uint256)) общественное пособие;

   // Это генерирует публичное событие в блокчейне, которое будет уведомлять клиентов
   передача события (адрес проиндексирован, адрес проиндексирован, значение uint256);

   // Это уведомляет клиентов о сожженной сумме
   событие Burn (адрес проиндексирован, значение uint256);

   /**
    * Функция Constrctor
    *
    * Инициализирует контракт с начальной поставкой токенов создателю контракта
    */
   функция TokenERC20 (
       uint256 initialSupply,
       строка tokenName,
       строка tokenSymbol
   ) public {
       totalSupply = initialSupply * 10 ** uint256 (десятичные дроби); // Обновление общего предложения с десятичной суммой
       balanceOf [msg.sender] = totalSupply; // Даем создателю все начальные токены
       name = tokenName; // Установить имя для отображения
       символ = символ токена; // Установить символ для отображения
   }

   /**
    * Внутренний перевод, только по этому договору
    */
   функция _transfer (адрес _from, адрес _to, uint _value) внутренний {
       // Запрет передачи на адрес 0x0. Вместо этого используйте burn ()
       требуют (_to! = 0x0);
       // Проверяем, достаточно ли у отправителя
       require (balanceOf [_from]> = _value);
       // Проверка на переполнение
       требуют (balanceOf [_to] + _value> balanceOf [_to]);
       // Сохраняем это для утверждения в будущем
       uint previousBalances = balanceOf [_from] + balanceOf [_to];
       // вычитаем из отправителя
       balanceOf [_from] - = _value;
       // Добавить то же самое к получателю
       balanceOf [_to] + = _value;
       Передача (_from, _to, _value);
       // Утверждения используются для использования статического анализа для поиска ошибок в вашем коде. Они никогда не должны потерпеть неудачу
       assert (balanceOf [_from] + balanceOf [_to] == предыдущий баланс);
   }

   /**
    * Передача токенов
    *
    * Отправьте токены `_value` на _to` из своего аккаунта
    *
    * @param _to Адрес получателя
    * @param _value сумма для отправки
    */
   функция передачи (адрес _to, uint256 _value) public {
       _transfer (msg.sender, _to, _value);
   }

   /**
    * Перевод токенов с другого адреса
    *
    * Отправить `_value` токены в` _to` от имени `_from`
    *
    * @param _from адрес отправителя
    * @param _to Адрес получателя
    * @param _value сумма для отправки
    */
   Функция TransferFrom (адрес _from, адрес _to, uint256 _value) публичных возвратов (bool success) {
       require (_value <= allowance [_from] [msg.sender]); // Проверка пособия
       пособие [_from] [msg.sender] - = _value;
       _transfer (_from, _to, _value);
       вернуть истину;
   }

   /**
    * Установить скидку на другой адрес
    *
    * Позволяет `_spender` тратить не более чем токены` _value` от вашего имени.
    *
    * @param _spender Адрес, на который разрешено тратить
    * @param _значите максимальную сумму, которую они могут потратить
    */
   функция утвердить (адрес _spender, uint256 _value) public
       возвращает (успешный бул) {
       пособие [msg.sender] [_ spender] = _value;
       вернуть истину;
   }

   /**
    * Установите скидку на другой адрес и сообщите
    *
    * Позволяет `_spender` тратить не более чем токены` _value` от вашего имени, а затем пинговать контракт об этом
    *
    * @param _spender Адрес, на который разрешено тратить
    * @param _значите максимальную сумму, которую они могут потратить
    * @param _extraData некоторая дополнительная информация для отправки в утвержденный контракт
    */
   функция ApproveAndCall (адрес _spender, uint256 _value, байты _extraData)
       общественности
       возвращает (успешный бул) {
       tokenRecipient spender = tokenRecipient (_spender);
       если (одобрить (_spender, _value)) {
           spender.receiveApproval (msg.sender, _value, this, _extraData);
           вернуть истину;
       }
   }

   /**
    * Уничтожить жетоны
    *
    * Необратимое удаление токенов `_value` из системы
    *
    * @param _value количество денег, чтобы сжечь
    */
   функция burn (uint256 _value) публичные возвраты (bool success) {
       require (balanceOf [msg.sender]> = _value); // Проверяем, достаточно ли у отправителя
       balanceOf [msg.sender] - = _value; // вычитаем из отправителя
       totalSupply - = _value; // Обновляет totalSupply
       Burn (msg.sender, _value);
       вернуть истину;
   }

   /**
    * Уничтожить токены с другого аккаунта
    *
    * Удалить необратимые токены `_value` из системы от имени` _from`.
    *
    * @param_от адреса отправителя
    * @param _value количество денег, чтобы сжечь
    */
   функция burnFrom (адрес _from, uint256 _value) public возвращает (bool success) {
       require (balanceOf [_from]> = _value); // Проверяем, достаточно ли целевого баланса
       require (_value <= allowance [_from] [msg.sender]); // Проверка пособия
       balanceOf [_from] - = _value; // Вычитаем из целевого баланса
       пособие [_from] [msg.sender] - = _value; // Вычитаем из пособия отправителя
       totalSupply - = _value; // Обновляем totalSupply
       Burn (_from _value);
       вернуть истину;
   }
}

/******************************************/
/ * ADVANCED TOKEN НАЧИНАЕТСЯ ЗДЕСЬ * /
/******************************************/

Контракт MyAdvancedToken принадлежит TokenERC20 {

   uint256 публичная цена продажи;
   uint256 публичная цена покупки;

   отображение (адрес => bool) public frozenAccount;

   / * Это генерирует публичное событие в блокчейне, которое будет уведомлять клиентов * /
   событие FrozenFunds (адрес целевой, бул заморожен);

   / * Инициализирует контракт с начальными токенами поставки создателю контракта * /
   функция MyAdvancedToken (
       uint256 initialSupply,
       строка tokenName,
       строка tokenSymbol
   ) TokenERC20 (initialSupply, tokenName, tokenSymbol) public {}

   / * Внутренний перевод, может быть вызван только по этому контракту * /
   функция _transfer (адрес _from, адрес _to, uint _value) внутренний {
       требуют (_to! = 0x0); // Запрет передачи на адрес 0x0. Вместо этого используйте burn ()
       require (balanceOf [_from]> = _value); // Проверяем, достаточно ли у отправителя
       требуют (balanceOf [_to] + _value> balanceOf [_to]); // Проверка на переполнение
       требуют (frozenAccount [_from]!); // Проверяем, заморожен ли отправитель
       требуют (frozenAccount [_to]!); // Проверяем, заморожен ли получатель
       balanceOf [_from] - = _value; // вычитаем из отправителя
       balanceOf [_to] + = _value; // Добавить то же самое к получателю
       Передача (_from, _to, _value);
   }

   /// @notice Создаем токены mintedAmount и отправляем их на target
   /// @param target Адрес для получения токенов
   /// @param mintedAmount количество полученных токенов
   функция mintToken (целевой адрес, uint256 mintedAmount) onlyOwner public {
       balanceOf [target] + = mintedAmount;
       totalSupply + = mintedAmount;
       Transfer (0, this, mintedAmount);
       Перевод (this, target, mintedAmount);
   }

   /// @notice `заморозить? Предотвратить | Разрешить `` цель` от отправки и получения токенов
   /// @param target Адрес для замораживания
   /// @param freeze или заморозить его или нет
   Функция freezeAccount (адрес цели, bool freeze) onlyOwner public {
       frozenAccount [target] = freeze;
       FrozenFunds (цель, заморозить);
   }

   /// @notice Разрешить пользователям покупать токены для `newBuyPrice` Pirl и продавать токены для` newSellPrice` Pirl
   /// @param newSellPrice Цена, которую пользователи могут продать по контракту
   /// @param newBuyPrice Price пользователи могут покупать по контракту
   функция setPrices (uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
       sellPrice = newSellPrice;
       buyPrice = newBuyPrice;
   }

   /// @notice Купить токены из контракта, отправив Pirl
   функция buy () оплачивается публично {
       сумма uint = msg.value / buyPrice; // рассчитывает сумму
       _transfer (это, msg.sender, сумма); // делает переводы
   }

   /// @notice Продаем `количество` токенов к контракту
   /// @ param количество проданных токенов
   функция sell (сумма uint256) public {
       требуют (this.balance> = сумма * sellPrice); // проверяет, достаточно ли в контракте Pirl для покупки
       _transfer (msg.sender, this, количество); // делает переводы
       msg.sender.transfer (сумма * sellPrice); // отправляет Pirl продавцу. Важно сделать это последним, чтобы избежать атак рекурсии
   }
}

Развертывание

Прокрутите вниз, и вы увидите примерную стоимость развертывания. Если вы хотите, вы можете изменить ползунок, чтобы установить меньшую комиссию, но если цена слишком ниже средней рыночной ставки, ваша транзакция может занять больше времени, чтобы забрать. Нажмите Deploy и введите свой пароль. Через несколько секунд вы будете перенаправлены на панель инструментов, а в разделе Последние транзакции вы увидите строку с надписью «создание контракта». Подождите несколько секунд, пока кто-нибудь выберет вашу транзакцию, и затем вы увидите медленный синий прямоугольник, представляющий, сколько других узлов видели вашу транзакцию и подтвердили их. Чем больше у вас подтверждений, тем больше уверенности в том, что ваш код был развернут.

Перейдите по ссылке, на которой написано «Страница администратора», и вы попадете на самую простую в мире панель инструментов центрального банка, где вы можете делать все, что захотите, с помощью только что созданной валюты.

С левой стороны в разделе «Чтение из контракта» у вас есть все опции и функции, которые вы можете использовать для бесплатного чтения информации из контракта. Если у вашего токена есть владелец, он отобразит его адрес здесь. Скопируйте этот адрес и вставьте его в Баланс, и он покажет вам баланс любой учетной записи (баланс также автоматически отображается на любой странице учетной записи, имеющей токены).

Справа в разделе «Запись в контракт» вы увидите все функции, которые вы можете использовать для изменения или изменения блокчейна любым способом. Это будет стоить газ. Если вы создали договор, который позволяет чеканить новые монеты, у вас должна быть функция под названием «Жетон мяты». Выберите это.

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

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

Используя вашу монету

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

Если вы хотите добавить чужой токен, просто перейдите на вкладку «Контракты» и нажмите «Просмотреть токен». Например, чтобы добавить токен Pirl Vortex в свой список наблюдения, просто добавьте адрес 0x0489A975393A1cD0330740040141D702C35180cb

Что теперь?

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

Справочный материал: ethereum.org


Подписывайтесь на нашу новостную рассылку

Получайте обновления и учитесь у лучших

Больше, чтобы исследовать

ru_RUРусский
en_USEnglish fr_FRFrançais nl_NLNederlands tr_TRTürkçe es_ESEspañol pt_PTPortuguês ko_KR한국어 zh_CN简体中文 hi_INहिन्दी ru_RUРусский