Entries, Functions

A contract is operated through entry points.

Entry point

The keyword entry is used to declare an entry point followed by its name.

entry main() {
...
}

If the required entry point name conflicts with a language keyword, you may prefix the id with % to bypass these constraints. For example, transfer is a the identifier reserved for the transfer instruction. The following enables us to declare an entry point named transfer.

entry %transfer () {
...
}

Arguments

An entry may take arguments. For example, the entry below named "complete" takes two arguments value and amount , respectively of type string and int:

entry complete (value : string, amount : int) {
...
}

Sections

An entry is made of sections listed below:

name

description

optional

called by

specifies which role(s) may call the action

yes

refuse transfer

specifies whether the action refuses incoming currency transfer (accepted by default).

yes

require

lists the required condition to pass in order to execute the action.

yes

specification

specifies formal properties the action effect has (see "specification" section)

yes

effect

codes the effect of the action:

  • changes in data storage

  • transfers of currencies

yes

For example, the complete entry example may be enhanced as follows:

constant owner : role = @tz1KksC8RvjUWAbXYJuNrUbontHGor25Cztk
variable threshold : tez = 10tz
action complete (value : string, amount : int) {
called by owner
require {
r : transferred > threshold
}
effect {
...
}
}

transferred is the amount of tez transferred to the entry.

In the expression line 9 above, r is a label for the require expression (see Label section below).

Label

In Archetype, some expressions are named. The following syntax is used to name an expression:

lbl : ... expression ... /* lbl is a label */

The following is the list of expressions that require a label:

Type

Example

Require

require {

r1 otherwise "NotEnoughTransferred" : transferred > threshold

}

Fail if

failif {

f1 with "NotEnoughTransferred" : transferred <= threshold

}

Asset invariant

asset mile {

quantity : int

} with {

quant_strictly_pos : quantity > 0

}

(see Contract specification)

Security predicate

security {

s1 : only_by_role(anyaction, admin)

}

(see Contract specification)

Effect

Local variable

A local variable is declared as exampled below:

var p = amount + 10tz;

Data assignment

A variable (global or local) is assigned a new value as exampled below:

p := amount;

Note that is it not possible to assign a value to an input value.

Conditional

The basic conditional expression is exampled below :

if transferred > threshold then (
transfer price to owner;
transfer 1tz to coder
) else
fail("not enough");

Failing

The fail instruction interrupts the execution. It reverts the contract storage to its initial state.

fail("Error");

The dorequire expression fails if the condition is not met:

dorequire (balance > threshold,"NotEnoughBalance")

The dofailif expression fails if the condition is met:

dofailif (balance <= threshold, "NotEnoughBalance")

It is possible to pass any Michelson-compliant typed value as the error message of the fail instructions above.

For example, the following passes the balance and the threshold as additional error message information:

dofailif (balance <= threshold, ("NotEnoughBalance",(balance,threshold)))

Function

It is possible to declare functions with the function keyword. The main differences between entries and functions are:

  • functions return a value with the return keyword

  • functions cannot modify the contract's storage (they are "pure")

Typically functions help factorize computation codes.

function get_rate (amount : tez) : rational {
var a : int = amount;
return (a / 3600);
}

Functions are called with the standard call syntax:

effect {
var r = get_rate(transferred);
if r < 3.14125 then fail("invalid transferred amount");
}