# dApp-скрипт
dApp-скрипт позволяет определить вызываемые (сallable) функции, которые могут быть вызваны с других аккаунтов путем отправки транзакции вызова скрипта или путем вызова dApp из dApp. Вызываемые функции могут принимать платежи в пользу dApp и выполнять различные действия на блокчейне. Кроме того, dApp-скрипт может содержать функцию-верификатор, которая разрешает или отклоняет транзакции и ордера, отправляемые аккаунтом.
Аккаунт с прикрепленным к нему dApp-скриптом часто называется просто dApp. О том, как работает dApp, читайте в разделе Что такое dApp; о том, как создать dApp — в разделе Создание и запуск dApp.
# Формат скрипта dApp
Код скрипта состоит из следующих частей:
# Директивы
dApp-скрипт начинается с директив:
{-# STDLIB_VERSION 8 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
Приведенные директивы сообщают компилятору, что:
- в скрипте используется Стандартная библиотека версии 8;
- скрипт содержит набор определений;
- скрипт будет привязан к аккаунту (не к ассету).
# Вспомогательные определения
После директив можно определить вспомогательные переменные и функции, которые будут доступны в пределах всего dApp. Обратите внимание: функции без аннотаций не могут быть вызваны с других аккаунтов.
Пример определений:
let someConstant = 42
func doSomething() = {
height + someConstant
}
# Вызываемые функции
Вызываемая функция может быть вызвана с другого аккаунта при помощи транзакции вызова скрипта.
Вызываемая функция помечается аннотацией @Callable(i)
, где i
— структура Invocation, которая содержит поля вызова, доступные вызываемой функции. Имя переменной в аннотации обязательно, даже если вызываемая функция ее не использует.
Результат выполнения вызываемой функции — набор действий скрипта, которые будут выполнены на блокчейне: добавление/удаление/изменение записей в хранилище данных аккаунта, выпуск/довыпуск/сжигание/перевод токена и др. Формат результата и доступные действия зависят от версии Стандартной библиотеки.
Подробное описание вызываемых функций приведено в разделе Вызываемая функция.
Ниже приведен пример вызываемой функции, которая переводит вызвавшему ее аккаунту 1 WAVES и записывает информацию об этом в хранилище данных аккаунта. Если тот же аккаунт снова пытается вызвать функцию, она выбрасывает исключение.
@Callable(i)
func faucet () = {
let isKnownCaller = match getBoolean(this, toBase58String(i.caller.bytes)) {
case hist: Boolean =>
hist
case _ =>
false
}
if (!isKnownCaller) then
(
[
BooleanEntry(toBase58String(i.caller.bytes), true),
ScriptTransfer(i.caller, 100000000, unit)
],
unit
)
else throw("Can be used only once")
}
# Функция-верификатор
Функция-верификатор проверяет транзакции и ордера, отправляемые от имени аккаунта dApp, на соответствие заданным условиям (то есть работает аналогично скрипту аккаунта).
Функция-верификатор помечается аннотацией @Verifier(tx)
, где tx: Transaction|Order
— текущая проверяемая транзакция или ордер. Имя переменной в аннотации обязательно, даже если функция ее не использует.
Функция-верификатор не имеет аргументов.
Возможными результатами выполнения функции являются:
true
— транзакция/ордер разрешена,false
— транзакция/ордер отклонена,- ошибка — транзакция/ордер отклонена.
Подробное описание приведено в разделе Функция-верификатор.
С помощью оператора match ... case можно настроить разные условия в зависимости от типа транзакции/ордера. Например, следующая функция-верификатор разрешает только транзакции перевода: отправка транзакций другого типа и ордеров запрещена.
@Verifier(tx)
func verify() = {
match tx {
case ttx: TransferTransaction => sigVerify(ttx.bodyBytes, ttx.proofs[0], ttx.senderPublicKey)
case _ => false
}
}
Если в dApp нет функции-верификатора, то выполняется верификация по умолчанию, то есть проверка, что транзакция или ордер действительно подписаны этим аккаунтом.
# Неуспешные транзакции
Если при добавлении транзакции в блок выполнение вызываемой функции завершилось ошибкой или выбрасыванием исключения, при этом:
- транзакция вызова скрипта прошла проверку подписи отправителя или проверку скриптом аккаунта-отправителя,
- сложность выполненных вычислений превысила порог для сохранения неуспешных транзакций,
то такая транзакция сохраняется на блокчейне с атрибутом
"applicationStatus": "script_execution_failed"
С отправителя транзакции взимается комиссия. Других изменений на блокчейне транзакция не влечет.
Подробнее о валидации транзакций
Подробнее о работе с неуспешными транзакциями
# Данные, доступные dApp-скрипту
Данные, доступные вызываемой функции:
- Часть полей вызова dApp-скрипта, в том числе платежи, комиссия за транзакцию, адрес и открытый ключ отправителя. Cм. раздел Invocation. Подтверждения (
proofs
) недоступны. - Данные блокчейна: текущая высота, балансы аккаунтов, записи в хранилищах данных аккаунтов, параметры токенов и др.
Начиная с версии 5 Стандартной библиотеки, при выполнении dApp-скрипта приложенные к вызову платежи считаются уже зачисленными на баланс dApp (в отличие от версий 4 и 3, где платежи не отражаются на балансе до окончания выполнения скрипта).
Данные, доступные функции-верификатору:
Поля текущей верифицируемой транзакции/ордера, в том числе подтверждения (
proofs
). Переменная, имя которой указано в аннотации функции-верификатора, содержит эту транзакцию или ордер. Набор полей зависит от типа транзакции/ордера, см. разделы Структуры транзакций, Order.Данные блокчейна.
⚠️ Данные блокчейна доступны только при проверке транзакции и недоступны при проверке ордера (
case t: Order
).
# Примеры
Примеры скриптов dApp можно найти:
- в разделе Практические руководства;
- в Waves IDE в меню Library→ dApps;
- на Github в репозитории ride-examples.