# Callable Function
Callable function is a dApp script function which can be invoked by an Invoke Script transaction or an invoke
or reentrantInvoke
functions (see details in the dApp-to-dApp Invocation article).
dApp script can contain multiple callable functions.
The callable function can perform the following actions:
- Add, modify, delete dApp account data storage entries.
- Transfer tokens.
- Issue tokens on behalf of the dApp, reissue and burn tokens.
- Setup sponsorship.
- Lease, cancel lease.
Available script actions depend on Standard library version used.
The callable function can return a value that is passed to the invoking function in case of the dApp-to-dApp invocation.
The invocation can contain payments to dApp. Tokens obtained in these payments can be used in script actions performed by the callable function and in payments attached to nested invocations.
⚠️ The fee for the Invoke Script transaction cannot be funded by transfer from the dApp to the transaction sender after activation of feature #15 “Ride V4, VRF, Protobuf, Failed transactions”. If sender's balance is insufficient to pay the fee, dApp script is not executed.
# Annotation
The callable function should be marked with the @Callable(i)
annotation, where i
is an Invocation structure that contains invocation fields that are available to the callable function. The variable name in the annotation is required even if the callable function does not use it.
# Arguments
The callable function can have arguments of the following types:
Int,
List which contains elements of one of the above types the types listed above, for example,
List[String]
.⚠️ Nested lists are not allowed as arguments to a callable function (unlike function without annotation).
# Invocation Result
The callable function invocation result is a Tuple of two elements:
- List of script actions. Actions are executed in the same order as the elements in the list.
- Return value that is passed to the invoking function in case of the dApp-to-dApp invocation.
Example:
(
[
BooleanEntry("key1", true),
IntegerEntry("key2", 42),
StringEntry("key3", "some string"),
BinaryEntry("key4", base58'encoded'),
DeleteEntry("key5"),
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),
Lease(Address(base58'3Mn5hzck8nYd52Ytd2ZjzoiQLVoMcn1VAs9',1000),
LeaseCancel(base58'Pxaf8pGKHS5ufGhqjmwRRcHQtC9T3h4d1XaJMnkhR1Vt')
],
42
)
# Script Actions
Script actions performed by the callable function are set by Ride structures.
Ride structure that sets action | Description |
---|---|
BinaryEntry BooleanEntry IntegerEntry StringEntry | Adding/modifying the entry. The type of structure must match the type of entry to be added/changed. - If there is no entry in the account data storage with the key specified in the structure, the entry will be added. - If the entry is present in the account data storage, it will be modified |
DeleteEntry | Entry deletion |
Issue | Token issue |
Reissue | Token reissue |
Burn | Token burn |
SponsorFee | Sponsorship setup |
ScriptTransfer | Token transfer |
Lease | Lease |
LeaseCancel | Lease cancellation |
# Limitations
- The maximum total number of
Issue
,Reissue
,Burn
,SponsorFee
,ScriptTransfer
,Lease
,LeaseCancel
script actions executed by all callable functions in a single transaction is 100. - The maximum total number of
BinaryEntry
,BooleanEntry
,IntegerEntry
,StringEntry
,DeleteEntry
script actions executed by all callable functions in a single transaction is 100. - The maximum number of payments attached to an invocation is 10. The maximum total number of payments attached to dApp script invocations in a single transaction is 100.
See also the Limitations article.
# Example
The example listed below is a wallet application which allows to send WAVES to a certain address and withdraw them (withdrawing others' WAVES is prevented). There are two callable functions in the example:
deposit
— deposits the tokens.withdraw
— withdraws the tokens.
{-# STDLIB_VERSION 8 #-}
{-# 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)
],
unit
)
}
}
@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)
],
unit
)
}
@Verifier(tx)
func verify() = false
# Threshold for Saving Failed Transactions
The Invoke Script transaction is saved on the blockchain and a fee is charged for it even if the dApp script or the asset script failed when a block generator adds the transaction to a block, provided that the sender's signature or account script verification passed.
However, if the callable function failed or threw an exception before the complexity of performed calculations exceeded the threshold for saving failed transactions, the transaction is discarded and the fee is not charged.
This rule is applied after activation of feature #15 “Ride V4, VRF, Protobuf, Failed transactions” and doesn't depend on the Standard library version used. Keep it in mind when developing a dApp script. For more information, see the Transaction Validation article.
# Default Callable Function
The default callable function is a function that is named default
and has no arguments:
@Callable(i)
func default() = {
...
}
If the default callable function is defined in a dApp script, and no call
field is specified in an Invoke Script transaction, the default function is invoked.
Example transaction
[
{
"type": 16,
"id": "FgohhmifAVteaXJo2hdFLY8WZw2mr28ZbGWg4FSTdYCZ",
"sender": "3MsX9C2MzzxE4ySF5aYcJoaiPfkyxZMg4cW",
"senderPublicKey": "AXbaBkJNocyrVpwqTzD4TpUY8fQ6eeRto9k1m2bNCzXV",
"fee": 100500000,
"feeAssetId": null,
"timestamp": 1631535715165,
"proofs": [
"2gmg4vQfuxYyfmNz3sdgcSQJapQnW9Dgvtn7ud1GQxoo9jq1KGL5QV3ibCfEJFFvdhVy2iMTrUsBin7U15hbgDKH"
],
"version": 2,
"chainId": 84,
"dApp": "3MsAegXUbgdqWvVLJwukbHHys6m1h2o8XXi",
"payment": [
{
"amount": 1,
"assetId": null
}
],
"height": 1701274,
"applicationStatus": "succeeded",
"stateChanges": {
"data": [
{
"key": "bin",
"type": "binary",
"value": "base64:ASmhAx9X"
},
{
"key": "bool",
"type": "boolean",
"value": true
},
{
"key": "int",
"type": "integer",
"value": 1
},
{
"key": "str",
"type": "string",
"value": "test"
}
],
"transfers": [
{
"address": "3MsX9C2MzzxE4ySF5aYcJoaiPfkyxZMg4cW",
"asset": "5yWcsRhLqhhVRfbi7VsuZH4ZC4e4sB9SWAcpNVVgv8Ud",
"amount": 1
}
],
"issues": [
{
"assetId": "5yWcsRhLqhhVRfbi7VsuZH4ZC4e4sB9SWAcpNVVgv8Ud",
"name": "Asset",
"description": "",
"quantity": 1,
"decimals": 0,
"isReissuable": true,
"compiledScript": null,
"nonce": 0
}
],
"reissues": [
{
"assetId": "5yWcsRhLqhhVRfbi7VsuZH4ZC4e4sB9SWAcpNVVgv8Ud",
"isReissuable": false,
"quantity": 1
}
],
"burns": [
{
"assetId": "5yWcsRhLqhhVRfbi7VsuZH4ZC4e4sB9SWAcpNVVgv8Ud",
"quantity": 1
}
],
"sponsorFees": [],
"leases": [],
"leaseCancels": [],
"invokes": []
}
}
]