Для самых любопытных читателей мы приготовили JavaScript для тестирования составленного контракта. Он использует taquito, чтобы развернуть и запустить функции смарт-контракта в сети Babylon.
Если вы предпочитаете читать на английском — можете прочитать англоязычную версию статьи тут.
Атомарные свопы
Для нашей цели мы собираемся транспилировать атомарные свопы. Главная цель этого dApp — позволить проводить обмен между двумя криптовалютами без каких-либо централизованных посредников.
Это отличный пример, потому что в нём есть структуры, перечни, разные переменные, разные публичные функции — как те, что подлежат оплате, так и те, что не подлежат. Есть и функции просмотра.
Возможно, вам захочется взглянуть на оригинальный контракт Solidity. То Вам сюда.
Теперь давайте посмотрим, как sol2ligo “переводит” разные компоненты этого контракта.
Структуры
Структуры в Solidity
Swap — это структура, которая описывает каждый обмен;
timelock — время, необходимое для блокировки токенов;
value — число заблокированных токенов;
ethTrader — отправитель токена;
withdrawTrader — его получатель;
secretLock — хэш для блокировки токена.
Хэш данных secretKey равен secretLock.
Это все преобразуется в:
Преобразованные структуры в LIGO
struct преобразовывается в record-тип. Каждое поле тоже преобразовывается в соответствующие типы:
- uint256 в nat;
- address в address;
- bytes32/bytes в bytes;
Так мы получаем объявление структуры.
Default-структура
Solidity автоматически настраивает переменные согласно параметрам, заданными по умолчанию, если переменную объявили, но не определили. LIGO требует, чтобы все переменные были определены еще во время объявления, так что транспайлер автоматически выставляет вам значения неопределенных перемен по умолчанию. Чтобы получившийся код получился чище, мы объявляем специальные default-структуры еще в начале входящего файла.
Структура, заполненная default-значениями в LIGO
Перечни
Объявления enum в Solidity
Тип “variant” — это самый прямой аналог перечням в LIGO. Так как сейчас в LIGO с ними нельзя проводить операцию сравнения, мы немного хакнули систему и объявили каждый enum — подтип уникальным неподписанным числом. Их названия начинаются с префикса enum name — это позволяет нам избежать конфликтов. Также в будущих операциях первое значение такого enum будет считаться default-значением.
Преобразованный перечень в Ligo
Хранилище контракта
Объявление хранилища в Solidity
У хранилища этого контракта есть два типа: swaps и swapStates. Первый нужен для хранения всей информации о свопе, а другой — для отслеживания стадии, на которой находится своп.
В LIGO все переменные хранилища являются одним и тем же типом записи. Полям достаются их названия и типы “в наследство” от оригинальных контрактов. Однако, скрыть частные или внутренние переменные хранилищ невозможно, так что мы просто опускаем их. Таким образом, хранилище преобразуется в запись, которую мы вам показываем на рисунке ниже. Поскольку LIGO является чисто функциональной штукой, далее мы передаем один образец хранилища почти каждой функции. Мы ожидаем, что получим его модифицированную версию в качестве возвращаемого значения.
“Переведённое” хранилище LIGO
Объявление ивентов
Ивенты в Solidity
LIGO не поддерживает ни ивенты, ни логи, так что мы просто “комментируем” их с помощью аргументов и ихних типов, чтобы в будущем разработчики смогли воспользоваться этой информацией и прийти к какому-либо системному решению.
Ивенты, преобразованные в LIGO
Модификаторы
Объявление модификаторов в Solidity
В атомарных свопах контрактные модификаторы используются для проверки условий для запуска каждой функции. Первые четыре модификаторы проверяют, допустима ли вообще стадия свопа. Последний модификатор проверяет, совпадают ли тайные ключи. Если условия не выполняются, транзакцию заворачивают.
У LIGO нет модификаторов, так что транспилятор “комментирует” объявления деклараций и использует их коды прямо в функциях. Тут вы можете посмотреть, как модификатор встраивается в LIGO:
Модификатор, встроенный в функцию LIGO
Комплексная функция
Комплексная функция в Solidity
open используется, чтобы запустить обмен, то есть отправить токены на контракт и заблокировать их до истечения locktime, а затем отправить withdrawalTrader, если хэш предоставленного secretKey равен secretLock.
Тут создаётся Swap структура. Она хранится в хранилище контракта, а именно в типе “swaps”. В конце концов фаза свопа станет Open и получит собственный swapID.
Открытые функции в LIGO
В преобразованном коде наша функция использует те же аргументы, что и оригинальная функция, но у нее есть еще два возвращаемых значения — для списков операций и типов хранилищ. Это позволяет функциям осуществлять внешние действия и модифицировать хранилище.
Первая строка из основного “тела” функции — это встроенный код из модификатора onlyInvalidSwaps. В коде Solidity это было выражением require — оно заботилось о том, чтобы своп не создавался заново, если тот уже был создан. Соответственно, в преобразованном коде появляется выражение assert.
После assert создается новая структура свопа. Она сохраняется в определенный тип. Позже происходит апдейт стадии свопа.
Ивент пропускается. Ставится соответствующий комментарий.
Simpler function (Функция попроще)
Функция проверки в Solidity
check — это функция, которая вызывается для проверки обмена, то есть проверки всех параметров на корректность.
Эта функция интересна благодаря модификатору просмотра и возвращаемым значениям.
Из-за них преобразованная версия не возвращает хранилище. Она возвращает лишь список операций.
Функция проверки в LIGO
Также оно содержит дополнительный параметр, receiver. Он нужен для контракта, который запрашивает возвращаемые значения. В конце функции у нас появится opList с единичной транзакцией для контракта, которая вернёт всю информацию о свопе. Вот как в LIGO выполняются вызовы внешних функций.
Роутер
Solidity позволяет контрактам иметь множество точек входа, тогда как в LIGO контракты обычно могут иметь только одну точку входа — main.
Записи, которые генерируются для аргументов в LIGO
Чтобы сделать доступными все публичные функции с main, мы объявляем router_enum с подтипами, которые называем так же, как и функции и типы аргументов функции.
Variant-тип роутера (enum) в LIGO
Далее этот enum становится первым аргументом главной функции и отправляется отдельным аргументам, которые отошли выбранной функции.
Главная функция LIGO-контракта
Фиксим вручную
Мы преобразовали код, но он всё ещё не готов к развертыванию. Компилятор LIGO все еще жалуется на определенные нюансы, так что давайте рассмотрим их поподробнее.
Подсвечена некорректная часть LIGO
LIGO выдаёт ошибку: невозможно поставить точку после закрывающей скобки “)”. Почему так? Потому что оно не поддерживает такой символ, а оператор точки к записям можно применять только напрямую.
Чтобы решить эту проблему, нам просто нужно разбить процесс извлечения структуры и получения доступа к полю на две отдельные операции.
Вот как теперь всё будет:
Пофиксили проблему, объявив struct перед доступом к полю
Та же проблема возникает, когда поле, к которому нужно получить доступ, располагается прямо под типом доступа к индексу:
И снова решение заключается в том, чтобы разбить его на две отдельные линии так, чтобы сначала объявлялась структура. Типа такого:
Повторяем и повторяем, сохраняя спокойствие, пока не достигнем корректного контракта и не сделаем развертывание возможным!
Тестирование
Если вам хочется посмотреть на преобразованный контракт в действии, вам, возможно, захочется протестировать его лично. Вы можете развернуть и протестировать его вручную или же воспользоваться нашим скриптом. В репозитории Readme вы найдете простые и понятные инструкции к тому, как запустить порядок тестирования.
Выводы
По мере того, как развивается и расширяется блокчейн, рынок нуждается во всё большем и большем количестве разработчиков. За всеми новыми языками смарт-контрактов уследить сложновато, но транспайлеры типа sol2ligo облегчат эту задачу.
Девелоперы могут переносить в Ligo свои решения, написанные на Solidity. Большая часть кода будет сгенерирована транспайлаером, так что для его полной адаптации понадобится внести всего несколько изменений.
Если хотите попробовать это прямо сейчас, взгляните на нашу чудесную новую веб-версию.
Чтобы посмотреть на источник кода и приложение CLI, зайдите на наш репозиторий.
Подписывайтесь, чтобы быть в курсе наших новостей