В статье я расскажу о том, как поучаствовал в первом (из двух) конкурсе Telegram по блокчейну, не занял призовое место и решил зафиксировать опыт в статье, чтобы он не канул в Лету и, возможно, помог кому-нибудь.  Так как мне не хотелось писать абстрактный код, а сделать что-то рабочее, для статьи я написал смарт-контракт моментальную лотерею и сайт, который показывает данные смарт-контракта напрямую из TON без использования промежуточных хранилищ.  Статья будет полезна тем, кто хочет сделать свой первый смарт-контракт в TON, но не знает с чего начать.  На примере лотереи я пройду от установки окружения до публикации смарт-контракта, взаимодействия с ним и напишу сайт для получения и публикации данных.  В октябре прошлого года Telegram объявил конкурс по блокчейну с новыми языками Fift и FunC. Нужно было на выбор написать любые из пяти предложенных смарт-контрактов. Я посчитал, что будет неплохо заняться чем-то необычным, изучить язык и сделать что-нибудь, даже если в будущем не придется писать что-либо еще. Плюс, тема постоянно на слуху.  Стоит сказать, что опыта разработки смарт-контрактов у меня не было.  Я планировал участвовать до самого конца пока получается и после написать обзорную статью, но зафейлился сразу на первом этапе. Я написал кошелек с мульти-подписью на FunC и он в общем работал. За основу взял смарт-контракт на Solidity.  На тот момент я посчитал, чтобы занять хотя бы какое-то призовое место этого точно достаточно. В итоге, около 40 из 60 участников стали призерами и меня среди них не было. В общем, в этом ничего страшного, но меня напрягла одна вещь. На момент объявление результатов ревью с тестом к моему контракту не было сделано, я спросил у участников в чате есть ли кто еще у кого его нет, таких не было.  Как мне кажется, обратив внимание на мои сообщения, через два дня судьи опубликовали комментарий и я так и не понял, они случайно пропустили мой смарт-контракт во время судейства или просто посчитали, что он настолько плох, что не нуждается в комментарии. Я задал вопрос на странице конкурса, но ответа не получил. Хотя кто судил — не секрет, писать личные сообщения посчитал лишним.  Времени на понимание было потрачено не мало, поэтому было решено написать статью. Так как информации пока не много, статья поможет сэкономить время всем заинтересованным.  Прежде чем что-то писать надо разобраться с какой стороны вообще подойти к этой штуке. Поэтому сейчас я расскажу из каких частей система состоит, точнее какие части нужно знать чтобы написать хотя бы какой-то рабочий смарт-контракт.  Мы сосредоточимся на написании смарт-контракта на FunC и Fift, который будет компилироваться в Fift-ассемблер и выполняться в TON Virtual Machine (TVM). Поэтому статья больше похожа на описание разработки обычной программы. На том как работает сама платформа тут останавливаться не будем.  Про то, как работает TVM и язык Fift хорошо описано в официальной документации. Во время участия в конкурсе и сейчас во время написания текущего контракта я часто обращался к ней.  Основной язык на котором пишутся смарт-контракты — FunC. Документации по нему на данный момент нет, поэтому чтобы что-то написать надо изучать примеры смарт-контрактов из официального репозитория, саму реализацию языка там же и еще можно смотреть примеры смарт-контрактов за прошедшие два конкурса. Ссылки в конце статьи. Допустим мы уже написали смарт-контракт на FunC, после этого мы компилируем код в Fift-ассемблер.  Скомпилированный смарт-контракт остается опубликовать. Для этого нужно написать код на Fift, который на вход будет принимать код смарт-контракта и еще некоторые параметры, а на выходе получится файл с расширением .boc (что означает "bag of cells"), и, в зависимости от того как напишем, приватный ключ и адрес, который генерируется на основе кода смарт-контракта.  На адрес смарт-контракта, который еще не опубликован уже можно отправлять грамы.  Так как за хранение и тразнакции TON берет комиссию, перед тем как публиковать смарт-контракт нужно перевести грамов на сгенерированный адрес, иначе он не будет опубликован.  Чтобы опубликовать смарт-контракт в TON полученный .boc файл нужно отправить в блокчейн с помощью лайт-клиента (о чем ниже). После публикации со смарт-контрактом можно будет взаимодейстовать, отправляя ему сообщения снаружи (например, с помощью лайт-клиента) или изнутри (например, один смарт-контракт шлет другому сообщение внутри TON).  Теперь, когда мы поняли как публикуется код, дальше становится проще. Мы примерно знаем, что хотим написать и как будет работать наша программа. Во время написания ищем как это уже реализовано в существующих смарт-контрактах, или заглядываем в код реализации Fift и FunC в официальном репозитории, или смотрим в официальной документации.  Очень часто я искал по ключевым словам в Telegram-чате, где во время конкурса собрались все участники и сотрудники Telegram в том числе, и начали обсуждать Fift и FunC. Ссылка в конце статьи.  Пора перейти к практике.  Все что будет описано в статье я делал на MacOS и перепроверил в чистой Ubuntu 18.04 LTS на Docker.  Первое что нужно сделать скачать и установить lite-client с помощью, которого можно отправлять запросы в TON.  Инструкция на официальном сайте довольно понятно описывает процесс установке. Тут мы следуем инструкции попутно устанавливая недостающие зависимости. Я не стал сам компилировать каждую библотеку по отдельности и устанавливал из официального репозитория Ubuntu (на MacOS я использовал brew).  После того как все зависимости установлены мы установим lite-client, Fift и FunC. Сначала клонируем репозиторий TON вместе с зависимостями. Для удобства все будем делать в папке ~/TON. В репозитортии также хранятся реалзиации Fift и FunC.  Теперь мы готовы собрать проект. Код репозитория склонирован в папку ~/TON/ton. В ~/TON создаем папку build и собираем в ней проект.  Так как мы собираемся писать смарт-контракт нам нужен не только lite-client, но и Fift с FunC, поэтому компилируем все. Не быстрый процесс поэтому ждем.  Далее скачиваем конфигурационный файл в котором лежат данные о ноде к которой lite-client будет подключаться.  Теперь запустим lite-client.  Если сборка прошла успешно, то после запуска мы увидим лог подключения лайт клиента к ноде.  Можно выполнить команду help и посмотреть какие команды доступны.  Перечислим команды, которые мы будем использовать в этой статье.  Теперь мы готовы к написанию самого смарт-контракта.  Как уже писал выше, смарт-контракт который мы пишем это лотерея.  Причем это не лотерея в которой надо купить билет и ждать час, день или месяц, а моментальная в которой пользователь переводит на адрес смарт-контракта N грамов, и моментально получает обратно 2 * N грамов или проигрывает. Вероятность победы сделаем около 40%. Если грамов для выплаты не достаточно, то будем считать транзакцию пополнением.  Причем важно чтобы ставки можно было видеть в реальном времени и в удобном виде, чтобы пользователь сразу мог понять выиграл он или проиграл. Поэтому нужно сделать веб-сайт, который покажет ставки и результат напрямую из TON.  Для удобства я сделал подстветку кода для FunC, плагин можно найти и установить в поиске Visual Studio Code, если вдруг захочется добавить что-то, то выложил плагин в открытый доступ. Также ранее кем-то был сделан плагин для работы с Fift, тоже можно и установить найти в VSC.  Сразу создадим репозиторий куда будем комитить промежуточные результаты.  Чтобы облегчить себе жизнь мы будем писать смарт-контракт и тестировать локально, до тех пор пока он не будет готов. Только после этого опубликуем его в TON. У смарт-контракта есть два внешних метода к которым можно обращаться. Первый, recv_external() эта функция выполняется когда запрос к контракту происходит из внешнего мира, то есть не из TON, например когда мы сами формируем сообщение и отправляем его через lite-client. Второй, recv_internal() это когда внутри самого TON какой-либо контракт обращается к нашему. В обоих случаях можно передать параметры в функцию.  Давайте начнем с простого примера, который будет работать если его опубликовать, но никакой функциональной нагрузки в нем нет.  Тут надо пояснить что такое slice. Все хранящиееся данные в TON Blockchain это коллекция TVM cell или просто cell, в такой ячейке можно хранить до 1023 бит данных и до 4 ссылок на другие ячейки.  TVM cell slice или slice это часть существующей cell используется для ее парсинга, дальше будет понятно. Главное для нас, что в смарт-контракт мы можем передать slice и в зависимости от вида сообщения обработать данные в recv_external() или recv_internal().  impure — ключевое слово, которое указывает на то, что функция изменяет данные смарт-контракта.  Сохраним код контракта в lottery-code.fc и скомпилируем.  Значение флагов можно посмотреть с помощью команды  У нас получился скомпилированный Fift-ассемблер код в lottery-compiled.fif.  Его можно запустить локально, для этого подготовим окружение.  Заметим, первой строчкой подключается Asm.fif, это код написанный на Fift реализации Fift-ассемблера.  Так как мы хотим запускать и тестировать смарт-контракт локально создадим файл lottery-test-suite.fif и скопируем туда скомпилированный код заменив в нем последнюю строчку, которая записывает код смарт-контракта в константу code, чтобы потом передать его в виртуальную машину:  Пока вроде понятно, теперь добавим в тот же файл код, который мы будем исполльзовать для запуска TVM.  В c7 мы записываем контекст, то есть данные с которыми будет запускаться TVM (или состояние сети). Еще во время конкурса один из разработчиков показал как создается c7 и я скопировал. В этой статье нам возможно нужно будет менять rand_seed так как от него зависит генерация случайного числа и не менять, то каждый раз будет возвращаться тоже самое число.  recv_internal и recv_external константы со значением 0 и -1 будут отвечать за вызов соотвествующих фунций в смарт-контракте.  Теперь мы готовы создать первый тест к нашему пустому смарт-контракту. Для наглядности пока все тесты мы будем добавлять в этот же файл lottery-test-suite.fif.  Создадим переменную storage и запишем в нее пустой cell, это будет хранилище смарт-контракта.  message это сообщение, котрое мы передадим смарт-конртакту извне. Его тоже сделаем пока пустым.  После того как мы подготовили конастанты и переменные мы запускаем TVM с помощью команды runvmctx и передаем созданные параметры на вход.  В итоге у нас получится вот такой промежуточный код на Fift.  Теперь мы можем запустить получшившийся код.  Программа должна отработать без ошибок и в выводе увидим лог выполнения.  Отлично, мы написали первую рабочую версию смарт-контракта вместе с тестом.  Теперь нужно добавлять функционал. Сначала займемся сообщениями, которые приходит из внешнего мира в recv_external().  Разработчик сам выбирает формат сообщения которое контракт может принять. Но обычно,  Поэтому почти в каждом контракте решаются эти две проблемы, так как наш контракт будет принимать внешние сообщения, нам тоже нужно позаботиться об этом. Сделаем мы в обратно порядке, сначала вторую, а потом первую.  Есть разные способы решить проблему с повторяющимися сообщениями. Мы сделаем вот как. В смарт-контракте инициализируем счетчик принятых сообщений с первоначальным значением 0. В каждом сообщении смарт-контракту помимо других параметров мы будем добавлять текущее значения счетчика. Если значение счетчика в сообщении не совпадает со значением в смарт-контракте, то мы не обрабатываем его. Если совпадает, то обрабатываем и увеличиваем счетчик в смарт-контракте на 1.  Возвращаемся в lottery-test-suite.fif и дописываем в него второй тест. Отправим неверный номер, код должен выкинуть исключение. Например, пусть в данных контракта хранится 166, а мы отправим 165.  Запустим.  И увидим что тест выполняется с ошибкой.  На этом этапе lottery-test-suite.fif должен выглядеть как по ссылке.  Теперь давайте допишем логику счетчика в смарт-контракта в lottery-code.fc.  В slice in_msg лежит сообщение, которые мы отправляем.  Сначала проверяем если в сообщении есть данные, если нет, то просто выходим.  Далее мы парсим сообщение. in_msg~load_uint(32) загружает 32-х битное unsigned int число 165 из переданного сообщения.  Дальше мы загружаем 32 бита из хранилища смарт-контракта. Проверяем, что загруженное число совпадает с переданным, если нет выбрасываем исключение. В нашем случае, так как мы передаем несовпадающее, должно выбрасываться исключение.  Теперь скомпилируем.  Получившийся код скопируем в lottery-test-suite.fif, не забывая заменить последнюю строчку. Проверяем, что тест проходит.  Вот тут можно посмотреть соотвествующий коммит с текущими результатами.  Заметим, что постоянно копировать скомпилированный код смарт-контракта в файл с тестами неудобно. Поэтому напишем скрипт, который будет записывать код в константу за нас, а мы просто подключим скомпилированный код в наши тесты с помощью "include".  В папке с проектом создадим файл build.sh со следующим содержанием.  Сделаем его исполняемым.  Теперь, достаточно запустить наш скрипт, чтобы скомпилировать контракт в lottery-compiled.fif. Но кроме этого нам надо записать его в константу code.  Добавим в sh скирпт код, который будет просто дублировать скомплированный файл в lottery-compiled-for-test.fif и менять в нем последнюю строчку. Его и включим в файле lottery-test-suite.fif.  Теперь чтобы проверить, запустим получившийся скрипт и у нас сгенерируется файл lottery-compiled-for-test.fif, который мы включим в наш lottery-test-suite.fif.  В lottery-test-suite.fif удаляем код контракт и добавляем строчку "lottery-compiled-for-test.fif" include.  Запускаем тесты, чтобы проверить, что они проходят.  Отлично, теперь, чтобы автоматизировать запуск тестов создаим файл test.sh, который сначала будет выполнять build.sh, а потом запускать тесты.  Внутрь пишем test.sh. Проверяем, что контракт компилируется и тесты выполняются.  Отлично, теперь при запуске test.sh сразу будет происходить компиляция и запуск тестов. Вот ссылка на коммит.  Окей, прежде чем мы продолжим давайте для удобства сделаем еще одну вещь.  Создадим папку build где будем хранить скопилированный контракт и его клон записанный в константу lottery-compiled.fif, lottery-compiled-for-test.fif. Также создадим папку test где будут хранится файл с тестами lottery-test-suite.fif и потенциально другие вспомогательные файлы. Ссылка на соответствующие изменения. Продолжим разработку смарт-контракта.  Дальше должен быть тест, который проверяет, что сообщение принимается и счетчик обновляется в хранилище, когда мы отправляем правильное число. Но мы сделаем это позже.  Сейчас подумаем над тем какая структура данных и какие данные нужно сохранять в смарт-контракте. Опишу все что мы храним.  Далее нужно написать две функции. Первую назовем pack_state(), которая будет упаковывать данные для последующего сохранения его в хранилище смарт-контракта. Вторую, назовем unpack_state() будет считывать и возвращать данные из хранилища.  Добавляем эти две функции вначало смарт-контракта. Получится вот такой промежуточный результат. Чтобы сохранить данные нужно будет вызвать встроенную фунцкии set_data() и она запишет данные из pack_state() в хранилище смарт-контракта.  Теперь когда у нас есть удобные функции записи и чтения данных мы можем двигаться дальше.  Нам нужно проверить, что входящее извне сообщение подписано владельцем контракта (ну или другим пользователем, который имеет доступ к приватному ключу).  Когда мы публикуем смарт-контракт мы можем инициализировать его с нужными нам данными в хранилище. Мы запишем туда публичный ключ, чтобы можно было проверить, что подпись входящего сообщения была сделана соответствующим приватным ключом.  Перед тем как продолжить создадим пару приватный/публичные ключи и запишем приватный в test/keys/owner.pk. Для этого запустим Fift в интерактивном режиме и выполним четыре команды. Создадим папку keys внутри папки test и туда запишем приватный ключ.  Видим в текущей папке файл owner.pk. Заметим, что мы удаляем публичный ключ из стека, когда понадобится можем получить его из приватного.  Теперь нам нужно написать проверку подписи. Начнем с теста. Сначала мы считываем приватный ключ из файла с помощью функции file>B и записываем его в переменную owner_private_key. Дальше с помощью функции priv>pub конвертируем приватный ключ в публичный и запишем результат в owner_public_key.  Оба ключа нам понадобятся.  Инициализируем хранилище смарт-контракта. Произвольными данными заполним данными в той же самой последовательности, как в функции pack_state()и запишем в переменную storage.  Далее составим подписанное сообщение, в нем будет только подпись и значение счетчика.  Сначала создаем данные, которые хотим передать, потом подписываем их приватным ключом и наконец формируем подписанное сообщение.  В итоге, сообщение, которое мы отправим в смарт-контракт записано в переменную message_to_send, про функции hashu, ed25519_sign_uint можно почитать в документации по Fift.  И для запуска теста снова вызываем.  Вот так должен выглядть файл с тестами на данном этапе.  Запустим тест и он упадет, поэтому изменим смарт-контракт, чтобы он смог получать сообщения такого формата и проверять подпись. Сначала считаем из сообщения 512 бит подписи и запишем в переменную, далее считаем 32 бита переменной счетчика.  Так как у нас есть функция считывания данных из хранилища смарт-конракта будем использовать ее.  Дальше проверка счетчика переданного с хранилищем и проверка подписи. Если что-то не совпадет, то выбрасываем исключение с соответствующим кодом.  Соотвествуюший коммит вот тут.  Запустим тесты и увидим, что второй тест падает. По двум причинам, нехватка битов в сообщении и нехватка битов в хранилище, поэтому код падает при парсинге. Надо добавить подпись сообщения, которое мы отправляем и скопировать хранилище из последнего теста.  Во втором тесте добавим подпись сообщения и изменим хранилище смарт-контракта. Вот так выглядит файл с тестами в данный момент.  Напишем четвертый тест, в котором будем отправлять сообщение подписанное чужим приватным ключом. Создадим еще один приватный ключ и сохраним в файл not-owner.pk. Этим приватным ключом подпишем сообщение. Запустим тесты и убедимся, что все тесты проходят. Коммит на текущий момент.  Теперь наконец мы можем перейти к реализации логики смарт-контракта. В recv_external() мы будем принимать два типа сообщений.  Так как наш контракт будет аккумулировать проигрыши игроков, эти грамы надо перечислять создателю лотереи. Адрес кошелька создателя лотереи записывается в хранилище при создании контракта. На всякий случай нам нужна возможность менять адрес на который отправлять грамы проигравших.  Начнем с первого. Напишем сначала тест, который будет проверять, что после отправки сообщения смарт-контракт сохранил новый адрес в хранилище. Обратим внимание, что в сообщение помимо счетчика и нового адреса мы передаем еще action 7-ми битное целое неотрицательное число, в зависиомсти от него, мы будем выбирать как обрабатывать сообщение.  В тесте можно увидеть как происходит десереализация хранилища смартконтратка storage в Fift. Десериализация переменных описана в документации по Fift. Ссылка на коммит с добавлением теста. Запускаем тест и убедимся, что он падает.  Теперь добавим логику по изменению адреса владельца лотереи. В смарт-контракте мы продолжаем парсить message, считываем в action. Напомним, что у нас будет два action: изменение адреса и отправка грамов. Потом считываем новый адрес владельца контракта и сохраняем в хранилище. Запускаем тесты и видим, что третий тест падает. Падает из-за того, что контракт теперь дополнительно парсит 7 бит из сообщения, которых не хватает в тесте. Добавим в сообщение несуществущий action. Запустим тесты и видим, что все проходят. Тут коммит на изменения. Отлично.  Теперь напишем логику отправки указанного количества грамов на сохраненный ранее адрес. Сначала напишем тест. Мы напишем два теста один когда баланса не хватает, второй когда все должно пройти успешно. Тесты можно посмотреть в этом коммите.  Теперь допишем код. Сначала напишем два вспомогательных метода. Первый гет метод для того чтобы узнать текущий баланс смарт-контракта.  И второй для отправки грамов на другой смарт-контракт. Этот метод я полностью скопировал из другого смарт-контракта.  Добавим эти два метода в смарт-контракт и напишем логику. Сначала парсим количество грамов из сообщения. Дальше проверяем баланс, если не хватает выбрасываем исключение. Если все хорошо, то отправляем грамы на сохраненный адрес и обновляем счетчик.  Вот так выглядит смарт-контракт на данный момент. Запустим тесты и убедимся, что они проходят.  Кстати, за обработанное сообщение у смарт-контракта каждый раз списывается комиссия. Чтобы смарт-контракт выполнил запрос, после базовых проверок нужно вызывать accept_message().  Теперь займемся внутренними сообщениями. По факту мы будем только принимать грамы и отсылать обратно игроку двойную сумму при выигрыше и треть владельцу при проигрыше.  Сначала напишем простой тест. Для этого нам понадобится тестовый адрес смарт-контракта с которого мы будто отправляем грамы на смарт-контракт.  Адрес смартконтракта состоит из двух чисел, 32-х битное целое число отвечает за workchain и 256-ти целое неотрицательное уникальный номер аккаунта в этом workchain. Например, -1 и 12345, этот адрес и сохраним в файл.  Я скопировал функцию по сохранению адреса из TonUtil.fif.  Давайте разберем, как работает функция, это даст понимание как работает Fift. Запускаем Fift в интерактивном режиме.  Сначала мы кладем в стек -1, 12345 и название будущего файла "sender.addr": Следующим шагом выполняется функция -rot, которая сдвигает стек, таким образовам, что наверху стека оказывается уникальный номер смарт-контракта:  256 u>B конвертирует 256-ти битное неотрицательное целое в байты.  swap меняет местами два верхних элемента стека.  32 i>B конвертирует 32-х битное целое в байты.  B+ соединяет две последовательности из байтов в одну. Снова swap.  И наконец функция B>file принимает на вход два параметра, байты и имя файла, и выполняет запись байтов в файл. После этого наш стек пуст. Останавливаем Fift. В текущей папке создан файл sender.addr. Перенесем файл в созданную папку test/addresses/.  Напишем простой тест, который будет отправлять грамы на смарт-контракт. Вот коммит.  Теперь займемся логикой внутреннего сообщения лотереи.  Первое, что мы делаем, проверяем сообщение bounced или нет, если bounced, то игнорируем. bounced значит, что контракт вернет грамы если произойдет какая-то ошибка. Мы не будем возвращать грамы, если вдруг возникнет ошибка.  Проверяем, количество отправленных грамов, если меньше чем полграма, то просто принимаем сообщение и больше ничего не делаем.  Далее, парсим адрес смарт-контракта с которого пришло сообщение.  Считываем данные из хранилища и дальше удаляем старые ставки из истории если их больше двадцати. Для удобства я написал три дополнительные функции pack_order(), unpack_order(), remove_old_orders().  Дальше мы смотрим если баланса не хватает на выплату, то считаем, что это не ставка, а пополенение и сохраняем пополнение в orders.  Дальше наконец суть смарт-контракта.  Если игрок проиграл мы сохраняем его в историю ставок и если сумма больше 3 грамов отправялем 1/3 владельцу смарт-контракта.  Если же игрок выиграл, то мы отправляем удвоенную сумму на адрес игрока и дальше сохраняем информкцию о ставке в историю.  Вот и все. Соответствующий коммит.  Сделаем гет-методы, чтобы из внешнего мира можно было получить информацию о состоянии контракта (по факту считать данные из хранилища смартконтракта).  Добавим гет-методы. О том как получать информацию о смарт-контракте напишем ниже.  Еще я забыл добавить код, который будет обрабатывать самый первый запрос, который происходит при публикации смарт-контракта. Соответствующий коммит. И еще исправил баг с отправлением 1/3 суммы на аккаунт владельца. Остается опубликовать смарт-контракт. Создадим папку requests.  За основу я взял код публикации обычного кошелька, можно найти в официальном репозитории и немного изменил его.  Из того на что стоит обратить внимание. Мы формируем хранилище смарт-контракта и сообщение на вход. После этого генерируется адрес смарт-контракта, то есть адрес известен еще до публикации в TON. Дальше на этот адрес нужно отправить несолько грам. И только после этого с помощью лайт-клиента нужно отправить файл с самим смарт-контрактом, так как за его хранение и операции в нем сеть берет комиссию. Код публикации можно посмотреть тут.  Дальше мы исполняем код публикации и получаем lottery-query.boc файл и адрес смартконтракта.  Не забываем сохранить сгенерированные файлы: lottery.addr, lottery.pk.  Среди прочего в логах выполнения увидим адрес смарт-контракта.  Ради интереса сделаем запрос в TON.  И увидим, что аккаунт с таким адресом пуст.  Отправялем на адрес 0QAESRAUnb6vjq27KyhyLn1qLcbiZOwvHZvr1vsgkHm8Ksyd 2 грама и через несколько секунд выполняем туже команду. Для отправки грамов я использую официальный кошелек, а тестовые грамы можно попросить у кого-нибудь из чата, о котором я скажу в конце статьи.  Смотрит, что смарт-контракт изменил статус с пустого на неинициализированный (state:account_uninit) и балансом 2 000 000 000 нанограм.  Теперь опубликуем смарт-контракт. Запустим lite-client и выполним.  Проверим, что контракт опубликован.  Среди прочего получим.  Видим, что account_active.  Соответствующий коммит с изменениями вот тут.  Теперь создадим запросы для взаимодействия со смарт-контрактом.  Точнее первый для изменения адреса мы оставим в качестве самостоятельной работы, а второй для отправки грамов на адрес владельца сделаем. По факту нам нужно будет сделать тоже самое, что и в тесте номер 6.  Вот такое сообщение мы будем отправлять на смартконтракт, где msg_seqno 165, action 2 и 9.5 грам для отправки.  Не забываем подписать сообщение приватным ключом lottery.pk, который сгенерировался ранее при создании смарт-контракта. Вот соотвествующий комит.  Теперь рассмотрим как запускать гет-методы смарт-контракта.  Запускаем lite-client и вызываем runmethod с адресом смарт-контракта и нужным гет-методом.  В result содержится значение, которое возвращает функция balance() из нашего смарт-контракта.
Тоже самое выполним еще для нескольких методов.  Запросим историю ставок.  Мы будем использовать lite-client и гет-методы чтобы выводить информацию о смарт-контракте на сайте.  Я написал простой веб-сайт на Python для того чтобы показать данные из смарт-контракта в удобном виде. Тут я не буду подробно останавливаться на нем и опубликую сайт одним коммитом.  Запросы к TON делаются из Python с помощью lite-client. Для удобства сайт пакуется в Docker и публикуется на Digital Ocean. Ссылка на сайт. Теперь попробуем отправить туда 64 грамa для пополнения из кошелька. И сделаем пару ставок для наглядности. Видим, что сайт показывает историю ставок, текущий процент выигрыша и другую полезную информацию.  Статья получилась намного длинне чем я предполагал. Может можно было и короче, а может как раз для человека, который ничего не знает о TON и хочет написать и опубликовать не самый простой смарт-контракт с возможностью с ним взаимодействовать.  Возможно какие-то вещи можно было объяснить проще. Некоторые моменты в реализации можно было сделать эффективнее, например, не хранить историю ставок в смарт-контаркте, а парсить данные из блокчейна, но тогда не удалось бы показать работу со словарем.  Так как я мог где-то ошибиться или что-то понять не правильно, нужно опираться на официальную документацию или официальный репозиторий с кодом TON в том числе.  Надо заметить, что так как сам TON еще в активной стадии разработки могут произойти изменения, которые сломают какой-либо из шагов в этой статье (что и произошло пока я писал, уже исправил).  Про будущее TON рассуждать не буду. Возможно платформа станет чем-то большим и нам стоит потратить время на ее изучение и создавать свои решения. А может и нет.  Есть еще Libra от Facebook, у которой потенциальная аудитория пользователей еще больше чем у TON. О Libra я почти ничего не знаю, судя по форуму активности там намного больше чем в сообществе TON. Хотя разработчики и сообщество TON больше похоже на андеграунд движение, что тоже круто.  7 июля 2020: так как Telegram сегодня объявил, что прекращает поддержку тестовых серверов сети TON, я тоже перестаю поддерживать сайт смарт-контракта. Код доступен на GitHub. 28 января 2022: Статья обновлена и проверена на актуальность. Software Engineer