# [Ride v4 и v3] Вызываемая функция
⚠️ Это документация Стандартной библиотеки версии 4 и 3. Рекомендуем использовать версию 6. Перейти к версии 6
Вызываемая функция — функция dApp-скрипта, которая может быть вызвана извне при помощи транзакции вызова скрипта.
dApp-скрипт может содержать несколько вызываемых функций.
Возможности вызываемых функций зависят от версии стандартной библиотеки.
Версия 3 | Версия 4 |
---|---|
Добавление и изменение записей в хранилище данных аккаунта | Добавление, изменение, удаление записей в хранилище данных аккаунта |
Переводы токенов | Переводы токенов |
Выпуск, довыпуск, сжигание токенов | |
Настройка спонсирования |
К транзакции вызова скрипта можно приложить платежи в пользу dApp. В переводы токенов могут быть включены средства, полученные в этих платежах.
Стандартная библиотека версии 4 доступна с момента активации фичи № 15 “Ride V4, VRF, Protobuf, Failed transactions”.
⚠️ После активации фичи № 15 становится невозможной оплата комиссии за транзакцию вызова скрипта за счет средств, переведенных dApp-скриптом отправителю. Если баланс отправителя недостаточен для оплаты комиссии, dApp-скрипт не выполняется.
# Аннотация
Вызываемая функция помечается аннотацией @Callable(i)
, где i
— структура Invocation, которая содержит поля транзакции вызова скрипта, доступные вызываемой функции. Имя переменной в аннотации обязательно, даже если вызываемая функция ее не использует.
# Версия 4
# Аргументы
Вызываемая функция может принимать аргументы следующих типов:
- Boolean,
- ByteVector,
- Int,
- String,
- Union, элементы которого относятся к перечисленным выше типам данных.
- List, элементы которого могут относиться к следующим типам:
- Boolean,
- ByteVector,
- Int,
- String,
- Union.
# Результат выполнения
Результат выполнения вызываемой функции в Стандартной библиотеке версии 4 представляет собой список действий скрипта. Действия будут выполнены в порядке, в котором они перечислены в списке.
Пример:
[
BooleanEntry("key1", true),
IntegerEntry("key2", 42),
StringEntry("key3", "some string"),
BinaryEntry("key4", base58'encoded'),
DeleteEntry("key4"),
ScriptTransfer(Address(base58'3Ms8fSfAxBLDjKvNVgACRzQoBLCtCWxtawu'), 100, base58'someAssetid'),
Issue("RegularToken", "This is an ordinary token", 10000, 2, true),
Reissue("4ZzED8WJXsvuo2MEm2BmZ87Azw8Sx7TVC6ufSUA5LyTV", 1000, true),
Burn("4ZzED8WJXsvuo2MEm2BmZ87Azw8Sx7TVC6ufSUA5LyTV", 1000)]
SponsorFee("4ZzED8WJXsvuo2MEm2BmZ87Azw8Sx7TVC6ufSUA5LyTV", 300)
]
# Действия скрипта
Действия скрипта, выполняемые вызываемой функцией, задаются при помощи структур Ride.
Структура Ride, задающая действие | Описание |
---|---|
- BinaryEntry - BooleanEntry - IntegerEntry - StringEntry | Добавление/изменение записи хранилища данных аккаунта. Тип структуры должен соответствовать типу добавляемой/изменяемой записи. - Если в хранилище запись с указанным в структуре ключом отсутствует, то запись будет добавлена. - Если в хранилище присутствует запись с указанным в структуре ключом, то запись будет изменена |
DeleteEntry | Удаление записи |
Issue | Выпуск токена |
Reissue | Довыпуск токена |
Burn | Сжигание токена |
SponsorFee | Настройка спонсирования |
ScriptTransfer | Перевод токена |
# Ограничения
- Количество
BinaryEntry
,BooleanEntry
,IntegerEntry
,StringEntry
,DeleteEntry
, выполняемых вызываемой функцией, — не более 100. - Количество
Issue
,Reissue
,Burn
,SponsorFee
,ScriptTransfer
, выполняемых вызываемой функцией, — до 10 включительно. - Количество платежей в пользу dApp, приложенных к транзакции вызова скрипта — 2.
См. также раздел Ограничения.
# Пример
Приведенный ниже пример представляет собой приложение-кошелек, которое позволяет отправлять WAVES на адрес и выводить только собственные средства с этого адреса (вывод чужих WAVES запрещен). В примере используются две вызываемые функции:
deposit
— обеспечивает размещение токенов,withdraw
— обеспечивает вывод токенов.
{-# STDLIB_VERSION 4 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt =
if i.payments.size() == 1 then
i.payments[0]
else throw("Attached payment is required")
if (isDefined(pmt.assetId))
then throw("works with waves only")
else {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount;
[IntegerEntry(currentKey, newAmount)]
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else [
IntegerEntry(currentKey, newAmount),
ScriptTransfer(i.caller, amount, unit)
]
}
@Verifier(tx)
func verify() = false
# Версия 3
# Аргументы
Вызываемая функция может принимать аргументы следующих типов:
- Boolean,
- ByteVector,
- Int,
- String,
- Union, элементы которого относятся к перечисленным выше типам данных.
# Результат выполнения
Результат выполнения вызываемой функции в Стандартной библиотеке версии 3 представляет собой одну из следующих структур:
WriteSet — содержит список действий над записями хранилища данных аккаунта.
Пример:
WriteSet([ DataEntry("key", true), DataEntry("another_key", base58'someBase58VaLue'), DataEntry("yet_another_key", 42), DataEntry("one_more_key", "value") ])
TransferSet — содержит список переводов.
Пример:
TransferSet([ScriptTransfer(Address(base58'3Ms8fSfAxBLDjKvNVgACRzQoBLCtCWxtawu'), 100, base58'someAssetid')])
ScriptResult — содержит
WriteSet
иTransferSet
.Пример:
ScriptResult( WriteSet([ DataEntry("key", true), DataEntry("other_key", base58'someBase58VaLue'), DataEntry("yet_another_key", 42), DataEntry("one_more_key", "value") ]), TransferSet([ScriptTransfer(Address(base58'3Ms8fSfAxBLDjKvNVgACRzQoBLCtCWxtawu'), 100, base58'someAssetid')]) )
# Действия скрипта
Действия скрипта, выполняемые вызываемой функцией, задаются при помощи структур Ride.
Структура Ride, задающая действие | Описание |
---|---|
DataEntry | - Если в хранилище данных аккаунта запись с указанным в DataEntry ключом отсутствует, то запись будет добавлена. - Если в хранилище данных аккаунта присутствует запись с указанным в DataEntry ключом, то запись будет изменена |
ScriptTransfer | Перевод токена |
# Ограничения
- Количество записей в хранилище данных аккаунта dApp, которое может быть добавлено/изменено в рамках транзакции вызова скрипта, — до 100 записей.
- Количество переводов токенов, которое dApp может выполнить в рамках транзакции вызова скрипта, — до 10 включительно.
- Количество платежей в пользу dApp, приложенных к транзакции вызова скрипта, — 1.
# Пример
Приведенный ниже пример представляет собой приложение-кошелек, которое позволяет отправлять WAVES на адрес и выводить только собственные средства с этого адреса (вывод чужих WAVES запрещен). В примере используются две вызываемые функции:
deposit
— обеспечивает размещение токенов,withdraw
— обеспечивает вывод токенов.
{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt = extract(i.payment)
if (isDefined(pmt.assetId))
then throw("works with waves only")
else {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount
WriteSet([DataEntry(currentKey, newAmount)])
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else ScriptResult(
WriteSet([DataEntry(currentKey, newAmount)]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Verifier(tx)
func verify() = false
# Порог сложности для сохранения неуспешных транзакций
С момента активации фичи № 15 “Ride V4, VRF, Protobuf, Failed transactions” транзакция вызова скрипта сохраняется на блокчейне и с отправителя взимается комиссия, даже если результат выполнения dApp-скрипта или скрипта ассета был неудачным (при условии что транзакция прошла проверку подписи отправителя или проверку скриптом аккаунта).
Однако если вызываемая функция завершилась ошибкой или выбрасыванием исключения прежде, чем сложность выполненных вычислений превысила порог для сохранения неуспешных транзакций, транзакция вызова скрипта отклоняется и комиссия не взимается.
Этот порядок действует независимо от используемой версии Стандартной библиотеки. Учитывайте его при разработке dApp-скрипта. Подробнее см. в разделе Валидация транзакции.