Русский
Русский
English
Статистика
Реклама

Основы программирования смарт-контрактов TON (FreeTON)

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

В предыдущей статье Hello Word смарт-контракт для TON (FreeTON) мы рассмотрели самое начало работы с смарт-контрактами FreeTON и HelloWorld.

Структура данной статьи:

  1. Типы чисел int и uint, pure-функции и event (события): напишем калькулятор на blockchain;

  2. Структуры и массивы: смарт-контракты как база данных;

  3. Хеш-таблицы: mapping;

  4. Публичные ключи и require.

Примечание: в коде далее в начале функций будет присутствовать вызов tvm.accept(); поскольку мы пока что рассматриваем учебные варианты смарт-контрактов.

Калькулятор

Объявить переменную с числовым типом можно с помощью int (целое число со знаком) и uint (целое без знака). Можно указать количество бит для числа в суффиксе указанного числового типа, например: int8, int16, uint128. Типы int и uint - это то же что и int256 и uint256. Над числами в смарт-контракте мы производим арифметические операции.

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

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

pragma ton-solidity >= 0.35.0;pragma AbiHeader expire;contract HelloCalc {    event UnknownOperator(uint op);    function calc(uint a, uint b, uint op) public pure returns (uint) {        tvm.accept();                if(op == 1) {            return a + b;        } else if(op == 2) {            return a - b;        } else if(op == 3) {            return a * b;        } else if(op == 4) {            return a / b;        } else if(op == 5) {            return a % b;        } else if(op == 6) {            return a ** b;        }else {            emit UnknownOperator(op);            return 0;        }    }}

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

Структуры и массивы

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

pragma ton-solidity >= 0.35.0;pragma AbiHeader expire;contract HelloUser {    event NewUser(uint id);        struct User {        uint weight;        uint balance;    }    User[] users;    function AddUser(uint w, uint b) public {        tvm.accept();        users.push(User(w, b));        emit NewUser(users.length - 1);    }    function GetUser(uint id) public view returns (uint w, uint b) {        tvm.accept();        w = users[id].weight;        b = users[id].balance;    }}

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

Обратите внимание на то как выглядит возврат значений функцией GetUser: в данном случае мы объявляем переменные в returns, которым в теле функции присваиваем значения. Также заметьте модификатор pure мы поменяли на view.

Хеш-таблицы: mapping

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

Давайте добавим такой mapping в наш немного переделанный пример:

contract HelloToken {    event TokenCreated(uint owner, uint tid);        struct Token {        string name;        string symbol;    }    Token[] tokens;    mapping (uint => uint) accounts;    function NewToken() public {        tvm.accept();        tokens.push(Token("", ""));        accounts[tokens.length-1] = msg.pubkey();        emit TokenCreated(msg.pubkey(), tokens.length-1);    }   function GetTokenOwner(uint tid) public view returns (uint) {       tvm.accept();       return accounts[tid];   }   function GetTokenInfo(uint tid) public view returns (string _name, string _symbol) {       tvm.accept();       _name = tokens[tid].name;       _symbol = tokens[tid].symbol;   } function SetTokenInfo(uint tid, string _name, string _symbol) public {       require(msg.pubkey() == accounts[tid], 101);       tvm.accept();       tokens[tid].name = _name;       tokens[tid].symbol = _symbol;   }}

Публичные ключи и require

Вызов функции смарт-контракта похож на отправку сообщения, в том плане, что мы отправляем на адрес аккаунта со смарт-контрактом объект, содержащий название вызываемой функции и параметры для нее (если они требуются). Помимо этого в сообщение может быть добавлены дополнительные данные: публичный ключ, подпись, значение value для передачи токенов TON Crystal в вызываемый аккаунт. Поговорим о публичном ключе. Получить значение публичного ключа аккаунта отправившего сообщение нашему смарт-контракту можно путем вызова API функции msg.pubkey(). В функции NewToken() мы выполнили присваивание accounts[tokens.length-1] = msg.pubkey(); в котором для каждого вновь создаваемого ID токена в отображение accounts помещается публичный ключ создавшего этот токен аккаунта, а в качестве ключа мы используем идентификатор этого токена, который вычисляем после пополнения массива tokens. Затем в SetTokenInfo() где мы можем настроить название и символ для нашего токена, мы задаем требование, только при выполнении которого возможно продолжение вызова функции. Мы берем публичный ключ отправителя по значению tid находим в отображении accounts установленный при создании публичный ключ и сравниваем. Только если они равны мы сможем установить или изменить имя и символ токена.

Тут были описаны аспекты, для читателей, изучающих тему смарт-контрактов FreeTON "с нуля", а в следующих статьях мы начнем создавать собственный токен.

Источник: habr.com
К списку статей
Опубликовано: 15.03.2021 22:22:10
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Solidity

Криптовалюты

Smart contracts

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru