waves_logo Docs
  • O Ride
    O Ride
  • Начало работы
    Начало работы
  • Основы синтаксиса
    • Директивы
      Директивы
    • Определение
      Определение
    • Выражение
      Выражение
    • Переменная
      Переменная
    • Функция
      Функция
    • Исключение
      Исключение
    • Комментарий
      Комментарий
    Основы синтаксиса
  • Типы скриптов
    • dApp-скрипт
      • Аннотации
        Аннотации
      • Вызываемая функция
        Вызываемая функция
      • Функция-верификатор
        Функция-верификатор
      dApp-скрипт
    • Скрипт аккаунта
      Скрипт аккаунта
    • Скрипт ассета
      Скрипт ассета
    Типы скриптов
  • Стандартная библиотека
    Стандартная библиотека
  • Типы данных
    • Any
      Any
    • BigInt
      BigInt
    • Boolean
      Boolean
    • ByteVector
      ByteVector
    • Int
      Int
    • String
      String
    • Unit
      Unit
    • List
      List
    • Кортеж
      Кортеж
    • Объединение
      Объединение
    Типы данных
  • Структуры
    • Действия скрипта
      • BinaryEntry
        BinaryEntry
      • BooleanEntry
        BooleanEntry
      • Burn
        Burn
      • DeleteEntry
        DeleteEntry
      • IntegerEntry
        IntegerEntry
      • Issue
        Issue
      • Lease
        Lease
      • LeaseCancel
        LeaseCancel
      • Reissue
        Reissue
      • ScriptTransfer
        ScriptTransfer
      • SponsorFee
        SponsorFee
      • StringEntry
        StringEntry
      Действия скрипта
    • Общие структуры
      • Address
        Address
      • Alias
        Alias
      • Asset
        Asset
      • AssetPair
        AssetPair
      • AttachedPayment
        AttachedPayment
      • BalanceDetails
        BalanceDetails
      • BlockInfo
        BlockInfo
      • Invocation
        Invocation
      • Order
        Order
      • Transfer
        Transfer
      Общие структуры
    • Структуры транзакций
      • BurnTransaction
        BurnTransaction
      • CreateAliasTransaction
        CreateAliasTransaction
      • DataTransaction
        DataTransaction
      • ExchangeTransaction
        ExchangeTransaction
      • GenesisTransaction
        GenesisTransaction
      • InvokeScriptTransaction
        InvokeScriptTransaction
      • IssueTransaction
        IssueTransaction
      • LeaseCancelTransaction
        LeaseCancelTransaction
      • LeaseTransaction
        LeaseTransaction
      • MassTransferTransaction
        MassTransferTransaction
      • ReissueTransaction
        ReissueTransaction
      • SetAssetScriptTransaction
        SetAssetScriptTransaction
      • SetScriptTransaction
        SetScriptTransaction
      • SponsorFeeTransaction
        SponsorFeeTransaction
      • TransferTransaction
        TransferTransaction
      • UpdateAssetInfoTransaction
        UpdateAssetInfoTransaction
      Структуры транзакций
    Структуры
  • Встроенные переменные
    Встроенные переменные
  • Встроенные функции
    • Математические функции
      Математические функции
    • Функции блокчейна
      Функции блокчейна
    • Функции верификации
      Функции верификации
    • Функции вызова dApp из dApp
      Функции вызова dApp из dApp
    • Функции декодирования
      Функции декодирования
    • Функции исключения
      Функции исключения
    • Функции кодирования
      Функции кодирования
    • Функции конвертации
      Функции конвертации
    • Функции массива байтов
      Функции массива байтов
    • Функции объединения
      Функции объединения
    • Функции списка
      Функции списка
    • Функции строки
      Функции строки
    • Функции транзакции данных
      Функции транзакции данных
    • Функции хеширования
      Функции хеширования
    • Функции хранилища данных аккаунта
      Функции хранилища данных аккаунта
    Встроенные функции
  • Операторы
    Операторы
  • match-case: сопоставление с шаблоном
    match-case: сопоставление с шаблоном
  • Итерации: FOLD<N>
    Итерации: FOLD<N>
  • Вызов dApp из dApp
    Вызов dApp из dApp
  • Ограничения
    • Сложность
      Сложность
    • Вес данных
      Вес данных
    Ограничения
  • Предыдущие версии
    • Версия 5
      • Вызываемая функция
        Вызываемая функция
      • Типы данных
        • Any
          Any
        • BigInt
          BigInt
        • Boolean
          Boolean
        • ByteVector
          ByteVector
        • Int
          Int
        • String
          String
        • Unit
          Unit
        • List
          List
        • Кортеж
          Кортеж
        • Объединение
          Объединение
        Типы данных
      • Структуры
        • Действия скрипта
          • BinaryEntry
            BinaryEntry
          • BooleanEntry
            BooleanEntry
          • Burn
            Burn
          • DeleteEntry
            DeleteEntry
          • IntegerEntry
            IntegerEntry
          • Issue
            Issue
          • Lease
            Lease
          • LeaseCancel
            LeaseCancel
          • Reissue
            Reissue
          • ScriptTransfer
            ScriptTransfer
          • SponsorFee
            SponsorFee
          • StringEntry
            StringEntry
          Действия скрипта
        • Общие структуры
          • Address
            Address
          • Alias
            Alias
          • Asset
            Asset
          • AssetPair
            AssetPair
          • AttachedPayment
            AttachedPayment
          • BalanceDetails
            BalanceDetails
          • BlockInfo
            BlockInfo
          • Invocation
            Invocation
          • Order
            Order
          • Transfer
            Transfer
          Общие структуры
        • Структуры транзакций
          • BurnTransaction
            BurnTransaction
          • CreateAliasTransaction
            CreateAliasTransaction
          • DataTransaction
            DataTransaction
          • ExchangeTransaction
            ExchangeTransaction
          • GenesisTransaction
            GenesisTransaction
          • InvokeScriptTransaction
            InvokeScriptTransaction
          • IssueTransaction
            IssueTransaction
          • LeaseCancelTransaction
            LeaseCancelTransaction
          • LeaseTransaction
            LeaseTransaction
          • MassTransferTransaction
            MassTransferTransaction
          • ReissueTransaction
            ReissueTransaction
          • SetAssetScriptTransaction
            SetAssetScriptTransaction
          • SetScriptTransaction
            SetScriptTransaction
          • SponsorFeeTransaction
            SponsorFeeTransaction
          • TransferTransaction
            TransferTransaction
          • UpdateAssetInfoTransaction
            UpdateAssetInfoTransaction
          Структуры транзакций
        Структуры
      • Встроенные переменные
        Встроенные переменные
      • Встроенные функции
        • Математические функции
          Математические функции
        • Функции блокчейна
          Функции блокчейна
        • Функции верификации
          Функции верификации
        • Функции вызова dApp из dApp
          Функции вызова dApp из dApp
        • Функции декодирования
          Функции декодирования
        • Функции исключения
          Функции исключения
        • Функции кодирования
          Функции кодирования
        • Функции конвертации
          Функции конвертации
        • Функции массива байтов
          Функции массива байтов
        • Функции объединения
          Функции объединения
        • Функции списка
          Функции списка
        • Функции строки
          Функции строки
        • Функции транзакции данных
          Функции транзакции данных
        • Функции хеширования
          Функции хеширования
        • Функции хранилища данных аккаунта
          Функции хранилища данных аккаунта
        Встроенные функции
      • Operators
        Operators
      • Limitations
        • Вес данных
          Вес данных
        Limitations
      Версия 5
    • Версии 4 и 3
      • Вызываемая функция
        Вызываемая функция
      • Типы данных
        • Boolean
          Boolean
        • ByteVector
          ByteVector
        • Int
          Int
        • String
          String
        • Unit
          Unit
        • List
          List
        • Кортеж
          Кортеж
        • Объединение
          Объединение
        Типы данных
      • Структуры
        • Действия скрипта
          • BinaryEntry (v4)
            BinaryEntry (v4)
          • BooleanEntry (v4)
            BooleanEntry (v4)
          • Burn (v4)
            Burn (v4)
          • DataEntry (v3)
            DataEntry (v3)
          • DeleteEntry (v4)
            DeleteEntry (v4)
          • IntegerEntry (v4)
            IntegerEntry (v4)
          • Issue (v4)
            Issue (v4)
          • Reissue (v4)
            Reissue (v4)
          • ScriptTransfer (v3 and v4)
            ScriptTransfer (v3 and v4)
          • SponsorFee (v4)
            SponsorFee (v4)
          • StringEntry (v4)
            StringEntry (v4)
          Действия скрипта
        • Результаты скрипта (v3)
          • ScriptResult
            ScriptResult
          • TransferSet
            TransferSet
          • WriteSet
            WriteSet
          Результаты скрипта (v3)
        • Общие структуры
          • Address
            Address
          • Alias
            Alias
          • Asset
            Asset
          • AssetPair
            AssetPair
          • AttachedPayment
            AttachedPayment
          • BalanceDetails
            BalanceDetails
          • BlockInfo
            BlockInfo
          • Invocation
            Invocation
          • Order
            Order
          • Transfer
            Transfer
          Общие структуры
        • Структуры транзакций
          • BurnTransaction
            BurnTransaction
          • CreateAliasTransaction
            CreateAliasTransaction
          • DataTransaction
            DataTransaction
          • ExchangeTransaction
            ExchangeTransaction
          • GenesisTransaction
            GenesisTransaction
          • InvokeScriptTransaction
            InvokeScriptTransaction
          • IssueTransaction
            IssueTransaction
          • LeaseCancelTransaction
            LeaseCancelTransaction
          • LeaseTransaction
            LeaseTransaction
          • MassTransferTransaction
            MassTransferTransaction
          • ReissueTransaction
            ReissueTransaction
          • SetAssetScriptTransaction
            SetAssetScriptTransaction
          • SetScriptTransaction
            SetScriptTransaction
          • [en] SponsorFeeTransaction
            [en] SponsorFeeTransaction
          • TransferTransaction
            TransferTransaction
          • UpdateAssetInfoTransaction
            UpdateAssetInfoTransaction
          Структуры транзакций
        Структуры
      • Встроенные переменные
        Встроенные переменные
      • Встроенные функции
        • Функции хранилища данных аккаунта
          Функции хранилища данных аккаунта
        • Функции блокчейна
          Функции блокчейна
        • Функции массива байтов
          Функции массива байтов
        • Функции конвертации
          Функции конвертации
        • Функции транзакции данных
          Функции транзакции данных
        • Функции декодирования
          Функции декодирования
        • Функции кодирования
          Функции кодирования
        • Функции исключения
          Функции исключения
        • Функции хеширования
          Функции хеширования
        • Функции списка
          Функции списка
        • Математические функции
          Математические функции
        • Функции строки
          Функции строки
        • Функции объединения
          Функции объединения
        • Функции верификации
          Функции верификации
        Встроенные функции
      • Операторы
        Операторы
      • Ограничения
        • Вес данных
          Вес данных
        Ограничения
      Версии 4 и 3
    Предыдущие версии
  • Подключение библиотек
    Подключение библиотек
  • Компоненты Ride
    Компоненты Ride
      • English
      • Русский
      On this page
        • Введение
        • Общие сведения
        • “Hello world!”
        • Блокчейн
        • Комментарии
        • Директивы
        • Переменные
        • Функции
        • Базовые типы
        • Специальные типы
        • Функции чтения данных
        • If
        • Исключения
        • Предопределенные структуры данных
        • Итерации с макросом FOLD<N>
        • Аннотации
        • Функция-верификатор
        • Вызываемая функция
        • Тестирование и инструменты
        • Отличной работы!
      waves_logo Docs

          # Начало работы

          # Введение

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

          Этот раздел содержит введение в Ride, примеры, описание дополнительных инструментов и ресурсов. Его изучение займет около часа.

          # Общие сведения

          Ride — это компилируемый, функциональный, статически типизированный язык программирования на основе выражений. Он является неполным по Тьюрингу, поскольку не имеет циклов (итерации можно реализовать с помощью макроса FOLD<N>, см. ниже). Благодаря этому сложность скрипта известна заранее и комиссия за выполнение предсказуема.

          Несмотря на простой синтаксис, Ride предоставляет множество возможностей разработчикам. Он во многом похож на Scala и отчасти на F#.

          # “Hello world!”

          Начнем с базового примера:

          func say() = {
            "Hello world!"
          }
          

          Для объявления функций в Ride используется ключевое слово func (см. ниже). Тип возвращаемого значения автоматически определяется компилятором, и объявлять его не нужно. В приведенном выше примере say возвращает строку Hello World!. В языке нет оператора return, потому что Ride основан на выражениях (всё является выражением), а последний оператор является результатом функции.

          # Блокчейн

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

          # Комментарии

          Комментарии в Ride похожи на комментарии в Python:

          # Это комментарий
          
          # Многострочные комментарии не предусмотрены
          
          "Hello world!" # Комментировать можно и так
          

          # Директивы

          Каждый скрипт на Ride должен начинаться с директив для компилятора. Предусмотрено три типа директив с различными возможными значениями.

          {-# STDLIB_VERSION 6 #-}
          {-# CONTENT_TYPE DAPP #-}
          {-# SCRIPT_TYPE ACCOUNT #-}
          

          STDLIB_VERSION задает версию стандартной библиотеки. Последняя версия, доступная в Mainnet, — 6.

          CONTENT_TYPE определяет содержание скрипта:

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

          SCRIPT_TYPE определяет тип объекта, к которому прикреплен скрипт: ACCOUNT или ASSET.

          Не все комбинации директив допустимы. Следующий пример не будет работать, поскольку тип содержания DAPP допустим только для аккаунтов. Тип EXPRESSION применим как для аккаунтов, так и ассетов.

          {-# STDLIB_VERSION 6 #-}
          {-# CONTENT_TYPE DAPP #-}
          {-# SCRIPT_TYPE ASSET #-} # тип содержания DAPP недопустим для ассетов
          

          # Переменные

          Для объявления переменных используется ключевое слово let.

          let a = "Bob"
          let b = 1
          

          Значения переменных в Ride недоступны для изменения.

          Ride строго типизирован, а тип переменной определяется исходя из значения.

          Ride позволяет вам определять переменные глобально, внутри любой функции или даже внутри определения переменной.

          func lazyIsGood() = {
            let a = "Bob"
            let b = {
               let x = 1
               "Alice"
              }  
            true
          }
          

          Функция, определенная выше, возвращает значение true, но переменная a не будет инициализирована, поскольку инициализация с помощью let ленивая: значения неиспользуемых переменных не вычисляются. Для нетерпеливой инициализации используется ключевое слово strict.

          # Функции

          Функции в Ride можно использовать только после их объявления.

          func greet(name: String) = {
            "Hello, " + name
          }
          
          func add(a: Int, b: Int) = {
            func m(a:Int) = a
            m(a) + b
          }
          

          Тип аргумента (Int, String) указывается после имени.

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

          func calc() = {
            42
          }
          
          func do() = {
            let a = calc()
            true
          }
          

          Функция calс не будет вызвана, так как переменная a не используется.

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

          Вызовы функции могут быть префиксные или постфиксные:

          let list = [1, 2, 3]
          let a1 = list.size()
          let a2 = size(list)
          
          let b1 = getInteger(this, "key")
          let b2 = this.getInteger("key")
          

          В этом примере a1 — то же самое, что и a2, а b1 — то же самое, что и b2.

          # Базовые типы

          Основные базовые типы:

          Boolean    #   true
          String     #   "Hey"
          Int        #   1610
          ByteVector #   base58'...', base64'...', base16'...', fromBase58String("...") и т. д.
          

          Мы рассмотрим строки и специальные типы.

          # Строки

          let name = "Bob"   # используйте только "двойные" кавычки
          let coolName = name + " is cool!" # для конкатенации строк используется знак +
          
          name.indexOf("o")  # 1
          

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

          В строковых данных используется кодировка UTF-8. Для обозначения строк используйте только двойные кавычки.

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

          let age = 21
          "Bob is " + age # не компилируется
          

          Чтобы исправить это, нужно преобразовать age в строку:

          let age = 21
          "Alice is " + age.toString() # работает!
          

          # Специальные типы

          В Ride есть несколько основных типов, которые работают так же, как в Scala.

          # Unit

          В Ride нет типа null, как во многих других языках. Многие встроенные функции возвращают значение типа unit вместо null.

          "String".indexOf("substring") == unit # true
          

          # Ничто

          Ничто — тривиальный тип в системе типов Ride. Ни одно значение не может быть типа «ничто», но выражение с типом «ничто» можно использовать где угодно. В функциональных языках это необходимо для поддержки исключений:

          2 + throw() # это выражение компилируется, 
              # поскольку определена функция +(Int, Int).
                # Тип второго операнда — «ничто»,
                # которое совместимо с любым другим типом.
          

          # Список

          let list = [16, 10, 1997, "birthday"]       # может содержать данные различных типов
          
          let second = list[1]                        # 10 — второе значение в списке
          

          У списков нет полей, но функции и операторы Cтандартной библиотеки упрощают работу с ними.

          let list = [16, 10, 1997, "birthday"]
          
          let last = list[(list.size() - 1)] # "birthday", постфиксный вызов функции size()
          
          let lastAgain = getElement(list, size(list) - 1) # то же самое
          

          Функция .size() возвращает длину списка. Обратите внимание: это значение доступно только для чтения и не может быть изменено. Кстати, last может быть разного типа: тип определяется только после того, как вычислено значение.

          let initList = [16, 10]                       # начальное значение
          let newList = cons(1997, initList)            # [1997, 16, 10]
          let newList2 = 1997 :: initList               # [1997, 16, 10]
          let newList2 = initList :+ 1                  # [16, 10, 1]
          let newList2 = [4, 8, 15, 16] ++ [23, 42]     # [4 8 15 16 23 42]
          
          • Чтобы добавить элемент в начало списка, используйте функцию cons или оператор ::.
          • Чтобы добавить элемент в конец списка, используйте оператор :+.
          • Чтобы объединить два списка, используйте оператор ++.

          # Кортеж

          Кортеж — упорядоченный набор элементов любого типа.

          let x=("Hello Waves",42,true)
          let num = x._2                                # 42
          let (a,b,c) = x
          let bool = c                                  # true
          

          # Union-типы. Сравнение типов

          let valueFromBlockchain = getString("3PHHD7dsVqBFnZfUuDPLwbayJiQudQJ9Ngf", "someKey") # Union(String | Unit)
          

          Union-типы — это удобный способ работы с абстракциями. Union(String | Unit) означает, что результат представляет собой пресечение этих типов.

          Простой пример (пожалуйста, имейте в виду, что определение пользовательских типов будет поддержано в следующих версиях Ride):

          type Human : { firstName: String, lastName: String, age: Int}
          type Cat : {name: String, age: Int }
          

          Union(Human | Cat) — объект с одним полем age:

          Human | Cat => { age: Int }
          

          Сравнение типов:

            let t = ...               # Cat | Human
            t.age                     # OK
            t.name                    # Ошибка компиляции
            let name = match t {      # OK
              case h: Human => h.firstName
              case c: Cat   => c.name
            }
          

          Механизм сравнения типов используется для работы с транзакциями:

          let amount = match tx {              # tx — исходящая транзакция
            case t: TransferTransaction => t.amount
            case m: MassTransferTransaction => m.totalAmount
            case _ => 0
          }
          

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

          # Функции чтения данных

          let readOrZero = match getInteger(this, "someKey") { # чтение данных
              case a:Int => a
              case _ => 0
          }
          
          readOrZero + 1
          

          getString возвращает Union(String | Unit), поскольку при чтении данных блокчейна (записей в виде ключ-значение в хранилищах данных аккаунтов) некоторые пары ключ-значение могут не существовать.

          let v = getInteger("3PHHD7dsVqBFnZfUuDPLwbayJiQudQJ9Ngf", "someKey")
          v + 1    # приведет к ошибке компиляции, нужно предусмотреть 
                   # возможность отсутствия значения по этому ключу
          
          v.valueOrErrorMessage("oops") +  1 # компилируется и выполняется
          
          let realStringValue2 = getStringValue(this, "someKey")
          

          Чтобы получить реальный тип и значение из Union-типа, используйте функцию value, которая прервет выполнение скрипта в случае значения unit. Другой вариант — используйте специализированные функции, такие как getStringValue, getIntegerValue и др.

          # If

          let amount = 1610
          if (amount > 42) then "Сумма больше 42"
            else if (amount > 100500) then "Сумма слишком большая"
            else "Что-то еще"
          

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

          let a = 16
          let result = if (a > 0) then a / 10 else 0 
          

          # Исключения

          throw("Here is exception text")
          

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

          let a = 12
          if (a != 100) then
            throw ("a is not 100, actual value is " + a.toString())
            else throw("A is 100")
          

          # Предопределенные структуры данных

          #LET THE HOLY WAR BEGIN

          В Ride есть много предопределенных структур данных, характерных для блокчейна Waves, например: Address, Alias, Invocation, Issue, Lease, ScriptTransfer, StringEntry, ExchangeTransaction, SetScriptTransactions.

          let keyValuePair = StringEntry("someKey", "someStringValue")
          

          Например, StringEntry — это структура, которая описывает запись со строковым значением, например, для хранилища данных аккаунта.

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

          # Итерации с макросом FOLD<N>

          Поскольку в виртуальной машине Ride не предусмотрены циклы, они реализованы на уровне компилятора с помощью макроса FOLD<N>. Этот макрос ведет себя как функция свертки fold в других языках программирования, принимая на вход количество итераций, начальные значения и сворачиваемую функцию.

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

          Следующий код подсчитывает сумму числе в массиве:

          let a = [1, 2, 3, 4, 5]
          func foldFunc(acc: Int, e: Int) = acc + e
          FOLD<5>(a, 0, foldFunc) # Результат: 15
          

          FOLD<N> также может использоваться для фильтрации и преобразования данных. Вот пример инвертирования списка:

          let a = [1, 2, 3, 4, 5]
          func foldFunc(acc: List[Int], e: Int) = (e + 1) :: acc
          FOLD<5>(a, [], foldFunc) # Результат: [6, 5, 4, 3, 2]
          

          # Аннотации

          Функции могут быть объявлены без аннотаций либо с аннотацией @Callable или @Verifier. Функции с аннотациями используются только в скриптах с типом DAPP.

          {-# STDLIB_VERSION 6 #-}
          {-# CONTENT_TYPE DAPP #-}
          {-# SCRIPT_TYPE ACCOUNT #-}
          
          func getPayment(i: Invocation) = {
            if (size(i.payments) == 0)
              then throw("Payment must be attached")
              else {
                let pmt = i.payments[0]
                if (isDefined(pmt.assetId))
                  then throw("This function accepts WAVES tokens only")
                  else pmt.amount
              }
          }
          
          @Callable(i)
          func pay() = {
            let amount = getPayment(i)
            (
              [
                IntegerEntry(toBase58String(i.caller.bytes), amount)
              ],
              unit
            )
          }
          

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

          Функции без аннотаций недоступны извне. Вызвать их можно только из других функций скрипта.

          # Функция-верификатор

          @Verifier(tx)
          func verifier() = {
            match tx {
              case m: TransferTransaction => tx.amount <= 100 # можно отправить до 100 токенов
              case _ => false
            }
          }
          

          Функция с аннотацией @Verifier устанавливает правила валидации исходящих транзакций (dApp). Функция верификации не может быть вызвана извне, однако она выполняется при каждой попытке отправить транзакцию с аккаунта dApp.

          Функция верификации должна возвращать логическое значение: разрешено отправить транзакцию в блокчейн или нет.

          Скрипты-выражения с директивой {-# CONTENT_TYPE EXPRESSION #-} и функции верификации с аннотацией @Verifier должны возвращать только логические значения. В зависимости от этого значения транзакция будет принята (если true) или отклонена (если false).

          @Verifier(tx)
          func verifier() = {
            sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
          
          }
          

          С функцией верификации связана переменная tx, которая представляет собой объект с полями текущей исходящей транзакции.

          В dApp-скрипте может быть только одна функция верификации.

          # Вызываемая функция

          Функция с аннотацией @Callable может быть вызвана c других аккаунтов: с помощью транзакции вызова скрипта или из другого dApp.

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

          @Callable(i)
          func giveAway(age: Int) = {
            (
              [
                ScriptTransfer(i.caller, age, unit),
                IntegerEntry(toBase58String(i.caller.bytes), age)
              ],
              unit
            )
          }
          

          Каждый аккаунт, вызвавший функцию giveAway, получит столько WAVELET, сколько ему лет. Структура ScriptTransfer задает параметры перевода токена. Кроме того, dApp сохранит информацию об этом в своем хранилище данных. Параметры целочисленной записи — ключ и значение — задает структура IntegerEntry.

          # Тестирование и инструменты

          Вы можете опробовать Ride в REPL как онлайн на https://waves-ide.com/ , так и через терминал с surfboard:

          > npm i -g @waves/surfboard
          > surfboard repl
          

          Для дальнейшей разработки полезны следующие инструменты и утилиты:

          • Плагин Visual Studio Code: waves-ride
          • Инструмент командной строки для компиляции и тестирования surfboard: https://github.com/wavesplatform/surfboard
          • Онлайн IDE с примерами: https://waves-ide.com/

          Подробно об инструментах

          # Отличной работы!

          Надеемся, эта статья дала вам хорошее введение в Ride — простой, безопасный, мощный язык программирования для смарт-контрактов и dApps на блокчейне Waves.

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

          Если вам нужна помощь в изучении основ языка Ride, вы можете изучить уроки Waves .

          O Ride
          Основы синтаксиса
          O Ride
          Основы синтаксиса