There are three types of scripts:
Features of each script type are described in the table.
| # | dApp script | Account script | Asset script |
|---|---|---|---|
| Directives | {-# CONTENT_TYPE DAPP #-} {-# SCRIPT_TYPE ACCOUNT #-} | {-# CONTENT_TYPE EXPRESSION #-} {-# SCRIPT_TYPE ACCOUNT #-} | {-# CONTENT_TYPE EXPRESSION #-} {-# SCRIPT_TYPE ASSET #-} |
| Content | Set of definitions | Boolean expression | Boolean expression |
| this variable | Address structure containing dApp address | Address structure containing smart account address | Asset structure |
| Transaction or order that is checked | Check is performed by the verifier function only. Annotation of the function sets the name of the variable that contains the outgoing transaction or the order, for example: @Verifier(tx) | Built-in variable tx: Transaction|Order contains the outgoing transaction or the order | Build-in variable tx: Transaction contains the transaction involving the asset. Order check is not supported. |
| Proofs accessibility | \1) Proofs of the outgoing transaction or the order are accessible to the verifier function. 2) Proofs of the invoke script transaction are inaccessible to the callable function | Accessible | Inaccessible |
| Blockchain data | \1) Accessible to the callable function. 2) Accessible to the verifier function when checking a transaction. 3) Inaccessible to the verifier function when checking an order | \1) Accessible when checking a transaction. 2) Inaccessible when checking an order | Accessible |
dApp script enables you to define callable functions that can be called from other accounts by sending an invoke script transaction or by a dApp-to-dApp invocation. Callable functions can accept payments to the dApp and perform various actions on the blockchain. Also dApp script can comprise a verifier function that allows or denies transactions and orders that are sent on behalf of the dApp account. An account with a dApp script assigned to it is called a dApp.
The script code is composed of the following parts:

The dApp script should start with directives:
{-# STDLIB_VERSION 5 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}The above directives tell the compiler that:
After the directives, you can define auxiliary variables and functions. These variables and functions are accessible within the entire script. Please note that functions without annotations cannot be called from other accounts. Let's see an exaxmple:
let someConstant = 42
func doSomething() = {
1+1
}The callable function should be marked with the @Callable(i) annotation, where i is an Invocation structure that contains fields of the script invocation that are accessible to the callable function. The variable name in the annotation is required even if the function does not use it. Callable function result is a set of script actions that are performed on the blockchain: adding/deleting/modifying entries to the account data storages, token transfers, issue/reissue/burning, and others. The result format and the available actions depend on the Standard library version used. For a detailed description, see the callable function article.
In the example below the callable function transfers 1 DecentralCoin to an account that called it and records the request information in the account data storage. If the same account tries to call the function again, the callable function throws an exception.
@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")
}Verifier function checks transactions and orders that are sent on behalf of the dApp account for compliance with the specified conditions (in other words it works similar to the account script). The verifier function should be marked with the @Verifier(tx) annotation, where tx is the transaction or the order that the function is currently checking. The variable name in the annotation is required even if the function does not use it. The verifier function has no arguments.Possible results of the verifier function are:
For a detailed description, see verifier function the article. Using the match ... case operator, you can set up different conditions depending on the type of the transaction/order. For example, the following function allows transfer transactions and denies orders and other types of transactions.
@Verifier(tx)
func verify() = {
match tx {
case ttx:TransferTransaction => sigVerify(ttx.bodyBytes, ttx.proofs[0], ttx.senderPublicKey)
case _ => false
}
}dApp script that has no verifier function performs default verification, that is, checking that the transaction or the order is indeed signed by this account.
If the callable function failed or threw an exception when a block generator adds the transaction to a block, such a transaction is saved on the blockchain and marked with the attribute "applicationStatus": "script_execution_failed", provided that: There are two annotations: @Callable(i) and @Verifier(tx). The variable name in the annotation is required even if the function does not use it. An annotated function cannot be called inside a dApp script.
The transaction sender is charged a fee. The transaction doesn't entail any other changes on the blockchain.
Data accessible to the callable function:
Data accessible to the verifier function:
Annotation is a form of metadata that is added to a function of a dApp script. At the present moment, there are two annotations: @Callable(i) and @Verifier(tx). The variable name in the annotation is required even if the function does not use it. An annotated function cannot be called inside a dApp script.
Annotation of a callable function. Variable i contains an Invocation structure representing certain fields of the invocation.
Annotation of a verifier function. Variable tx contains a structure of transaction or order sent from a dApp's account.
Callable function is a dApp script function which can be invoked by a invoke script transaction or an invoke or reentrantInvoke functions (see details in the dApp-to-dApp invocation functions article).
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 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.
The callable function can have arguments of the following types:
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.
Let's see an example of invocation of an invocation result:
(
[
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 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. 1) If there is no entry in the account data storage with the key specified in the structure, the entry will be added. 2) 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 |
See also the limitations article.
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 fails 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.
The example listed below is a wallet application which allows sending DecentralCoins to a certain address and withdrawing them (withdrawing others' DecentralCoins is prevented). There are two callable functions in the example(deposit and withdraw):
{-# STDLIB_VERSION 5 #-}
{-# 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 DecentralCoins 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() = falseVerifier function is a function of dApp script that is responsible for verification of transactions and orders sent from a dApp account. The verifier function does the same as an account script. dApp script can have only one verifier function. The verifier function should be adorned with the @Verifier(tx) annotation, where tx: Transaction|Order is the transaction or the order that the function is currently checking. Verifier function has no arguments. Verifier function can have one of the following execution results:
dApp that has no verifier function performs default verification, that is, checking that the first proof of the transaction/order has the correct sender's signature. The following function does the same as the default implementation:
@Verifier(tx)
func verify() = {
sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}If the verifier function is defined, only verification by this function is performed, proofs are not checked additionally.
dApp with the verifier function listed below only allows transfer transaction with an amount of token lower than 100. Orders and other transactions are denied. The match operator is used to specify verification rules depending on the type of the transaction/order.
@Verifier(tx)
func verify() = {
match tx {
case ttx:TransferTransaction => ttx.amount < 100 && sigVerify(ttx.bodyBytes, ttx.proofs[0], ttx.senderPublicKey)
case _ => false
}
}See available fields for each transaction type in the transaction structures article.
Account script verifies transactions and orders that are sent on behalf of the account. That is, the account script allows or denies the transaction or the order depending on whether it meets the specified conditions.
The script code is composed of the following parts:

The account script should start with directives:
{- # STDLIB_VERSION 5 # -}
{- # CONTENT_TYPE EXPRESSION # -}
{- # SCRIPT_TYPE ACCOUNT # -}The above directives tell the compiler that:
After the directives, you can define auxiliary variables and functions. Let's see an example:
let someConstant = 42
func doSomething () = {
height + someConstant
}The expression checks transactions and orders that are sent on behalf of the account for compliance with the specified conditions. If the conditions are not met, the transaction/order is denied. Possible results of evaluating the expression are:
Using the match ... case, you can set up different conditions depending on the type of the transaction/order. For example, the following expression prohibits sending orders and changing the account script, and allows other transactions, provided that the array of confirmations (proofs) contains the correct signature of the account at position 0:
match tx {
case t: Order | SetScriptTransaction => false
case _ => sigVerify (tx.bodyBytes, tx.proofs [0], tx.senderPublicKey)
}The following data can be used for checks:
Asset script verifies transactions within the asset (token), that is, allows or denies the transaction depending on the specified conditions. Asset with a script assigned to it is called a smart asset. Keep the following in mind:
The script code is composed of the following parts:

The asset script should start with directives:
{- # STDLIB_VERSION 5 # -}
{- # CONTENT_TYPE EXPRESSION # -}
{- # SCRIPT_TYPE ACCOUNT # -}The above directives tell the compiler that:
After the directives, you can define auxiliary variables and functions. Let's see an example:
let someConstant = 42
func doSomething () = {
height + someConstant
}The expression checks transactions and orders that are sent on behalf of the account for compliance with the specified conditions. If the conditions are not met, the transaction/order is denied. Possible results of evaluating the expression are:
Using the match ... case, you can set up different conditions depending on the type of the transaction/order. For example, the following expression prohibits sending orders and changing the account script, and allows other transactions, provided that the array of confirmations (proofs) contains the correct signature of the account at position 0:
match tx {
case t : SetAssetScriptTransaction => false
case _ => true
}If the asset script denies the Exchange transaction when a block generator adds the transaction to a block (provided that the sender signature verification or the account script verification passed), the transaction is saved on the blockchain but marked as failed ("applicationStatus": "script_execution_failed"). The sender of the transaction (matcher) is charged a fee. The transaction doesn't entail any other changes in balances, in particular, the order senders don't pay the matcher fee.
If the asset script denies the Invoke Script transaction when a block generator adds the transaction to a block (provided that the sender signature verification or the account script verification passed and the complexity of calculations performed by dApp script exceeded the threshold for saving failed transactions), the transaction is saved on the blockchain but marked as failed ("applicationStatus": script_execution_failed"). The transaction sender is charged a fee. The transaction doesn't entail any other changes on the blockchain.
The following data can be used for checks:
Elsewhere on this site