Reference

An archetype contract is composed of declarations, actions (aka entry points) and optionally specification for formal verification.

Declarations

  • constant and variables declare global variables. A constant value cannot be modified in the contract's actions.

constant rate : rational = 0.2
variable price : tez = 10tz
  • states declares contract's possible states. It is then possible to use transitions to change the contract states (see below)

states =
| Created initial
| Confirmed
| Canceled
| Success
| Fail

initial is used to declare the initial state value of the contract.

  • action declares an entry point of the contract. An action has the following sections:

    • specification (optional) to provide the post conditions the action is supposed to have

    • accept transfer (optional) to specify that transfer of tez is accepted

    • called by (optional) to declare which role may call this action

    • require (optional) to list the necessary conditions for the action to be executed

    • failif (optional)to list the conditions which prevent from execution

    • effect is the code to execute by the action

action an_action_1 (arg1 : string, arg2 : int) {
specification {
// see 'specification' section below
}
called by a_role
require {
r1 : arg2 > 0
}
failif {
f1 : arg2 > 10
}
effect {
// ...
}
}
  • transition declares an entry point of the contract that changes the state of the contract. A transition has the same sections as an action (except effect, see above) plus:

    • from to specify the states the transition starts from

    • to to specify the states after the transition

    • when (optional) to specify the transition condition

    • with effect to specify the effect of the transition

states
| Created initial
| Confirmed
| Canceled
| Success
| Fail
transition confirm {
from Created
to Confirmed
when { transferred > 10 tz }
with effect {
transfer 1tz to @tz1RNB9PXsnp7KMkiMrWNMRzPjuefSWojBAm
}
}

It is possible to specify several to ... when .... with effect ... sections in a transition. It is possible to specify a list of original states for the transition to start from:

transition fail {
from Created or Confirmed
to Fail
when { ... }
}

Builtin types

  • bool : boolean values

  • int : integer values

  • rational : floating value that can be expressed as the quotient or fraction of two integers

  • address : account address

  • role : an address that can be used in action's called by section

  • date : date values

  • duration : duration values (in second, minute, hour, day, week)

  • string : string of characters

  • tez : Tezos currency

  • bytes : bytes sequence

Composite types

  • * declares a tuple made of other types.

constant pair : int * string = (1, "astr")
  • option declares an option of type.

constant value : int option = none
  • list declares a list of any type (builtin or composed)

variable vals : string list = []
  • asset declares a collection of asset and the data an asset is composed of. For example the following declares a collection of real estates described by an address, a location and an owner:

asset real_estate identified by addr {
addr : string;
xlocation : string;
ylocation : string;
owner : address;
}
  • enum declares an enumeration value. It is read with a match ... with command (see below).

enum color =
| White
| Red
| Green
| Blue

It is then possible to declare a variable of type color:

variable c : color = Green
  • contract declares the signature of another existing contract to call in actions.

contract called_contract_sig {
action set_value (n : int)
action add_value (a : int, b : int)
}

It is then possible to declare a contract value of type called_contract_sig and set its address:

constant c : called_contract_sig = @KT1RNB9PXsnp7KMkiMrWNMRzPjuefSWojBAm
  • collection declares an asset field as a collection of another asset.

asset an_asset identified by id {
id : string;
a_val : int;
asset_col : another_asset collection
}
  • partition declares an asset field as a collection of another asset. The difference with collection is that a partition ensures at compilation that every partitioned asset (i.e. element of the partition) belongs to one and only partitioning asset.

asset partitioning_asset identified by id {
id : string;
asset_part : partitioned_asset partition;
}

As a consequence of the partition, a partitioned asset cannot be straightforwardly added or removed to its global collection with add and remove (see operation below). This has to be done via a partition field:

my_partitioning_asset.asset_part.add(a_new_partitioned_asset)

Effect

An action's effect is composed of instructions separated by a semi-colon.

Declaration

  • var declares a local variable with its value. While possible, it is not necessary to declare the type a local variable. Local variables' identifier must be unique (no name capture in Archetype).

var i = 0;

Assignment

  • := enables to assign a new value to a global or local variable.

i := 1;
  • += , -= , *= and /= enable to respectively increment and decrement an integer variable (local or global).

i *= 2; // i := i * 2
d += 3w; // d := i + 3w, date d is now previous d plus 3 weeks

Effects on asset collection

  • add enables to add an asset to an asset collection. It fails if the asset key is already present in the collection.

an_asset.add({ id = "RJRUEQDECSTG", asset_col = [] }); // see 'collection' example
  • update enables to update an existing asset; it takes as arguments the id of the asset to update and the list of effects on the asset. It fails if the id is not present in the asset collection.

an_asset.update("RJRUEQDECSTG", { a_value += 3 });
  • addupdate is similar to update except that it adds the asset if its identifier is not present in the collection.

an_asset.addupdate("RJRUEQDECSTG", { a_value += 3 });
  • remove removes a an asset from its collection.

an_asset.remove("RJRUEQDECSTG");
  • removeif enables removing assets under a condition.

an_asset.removeif(a_val > 10); // "a_val" is an asset field
  • clear clears an asset collection.

an_asset.clear();

Control

  • ; sequence

res := 1;
res := 2;
res := 3;
  • if then and if then else are the conditional branchings instructions.

if i > 0 then (
// (* effect when i > 0 *)
) else (
// (* effect when i <= 0 *)
);
  • match ... with ... end FIXME

archetype effect_control_matchwith
enum t =
| C1
| C2
| C3
| C4
| C5
variable res : int = 0
action exec () {
specification {
s0: res = 1;
}
effect {
var x : t = C3;
match x with
| C1 | C2 -> res := 0
| C3 -> res := 1
| _ -> res := 2
end
}
}
  • for in do done iterates over a collection.

var res = 0;
for a in an_asset do
res += a.a_val;
done;
  • iter to do done iterates over a sequence of integer values (starting from 1).

var res = 0
iter i to 3 do // iterates from 1 to 3 included
res += i;
done; // res is 6
  • transfer transfers an amount of tez to an address or a contract.

transfer 2tz to @tz1RNB9PXsnp7KMkiMrWNMRzPjuefSWojBAm;

With the contract keyword presented above, it is possible to transfer to a contract and call an entry point. In the example below, the entry point set_value of contract c is called and 2tz is transferred.

contract contract_called_sig {
action set_value (n : int)
action add_value (a : int, b : int)
}
constant c : called_contract_sig = @KT1RNB9PXsnp7KMkiMrWNMRzPjuefSWojBAm
action update_value(n : int) {
effect {
transfer 2tz to c call set_value(n);
}
}
  • fail aborts the execution. It prevents from deploying the contract on the blockchain. As a consequence the storage is left unchanged when executed.

fail("a message");
  • require and failif fail if the argument condition is respectively false and true. require(t) is sugar for if t then fail("").

require(val > 0);
failif(val <= 0);

Expressions

Literals

  • boolean

constant x : bool = true
constant y : bool = false
  • integer

constant i : int = 1
constant j : int = -42
  • rational

constant f : rational = 1.1
constant g : rational = -1.1
constant r : rational = 2 div 6
constant t : rational = -2 div 6
  • string

constant s : string = "hello world"
  • tez

constant ctz : tez = 1tz
constant cmtz : tez = 1mtz
constant cutz : tez = 1utz
  • address / role

constant a : address = @tz1Lc2qBKEWCBeDU8npG6zCeCqpmaegRi6Jg
  • duration

// duration of 3 weeks 8 days 4 hours 34 minutes 18 seconds
constant d : duration = 3w8d4h34m18s
  • date

constant date0 : date = 2019-01-01
constant date1 : date = 2019-01-01T01:02:03
constant date2 : date = 2019-01-01T01:02:03Z
constant date3 : date = 2019-01-01T00:00:00+01:00
constant date4 : date = 2019-01-01T00:00:00-05:30
  • list

constant mylist : int list = [1; 2; 3]
  • option

constant op1 : int option = none
constant op2 : int option = some(0)
  • bytes

constant bl : bytes = 0x12f12354356a

Operators

Logical

  • and operator of logical conjunction

var bool_bool_and : bool = (true and false);
  • or operator of logical disjunction

var bool_bool_or : bool = (true or false);
  • not operator of logical negation

var bool_bool_not : bool = not true;

Operator

  • = FIXME

var int_int_eq : bool = 1 = 2;
var rat_int_eq : bool = (1 div 2) = 2;
var int_rat_eq : bool = 1 = (2 div 3);
var rat_rat_eq : bool = (1 div 3) = (2 div 3);
var tez_tez_eq : bool = 1tz = 2tz;
var dur_dur_eq : bool = 1h = 2h;
var date_date_eq : bool = 2020-01-01 = 2020-12-31;
var bool_bool_eq : bool = true = false;
var addr_addr_eq : bool = @tz1Lc2qBKEWCBeDU8npG6zCeCqpmaegRi6Jg = @tz1bfVgcJC4ukaQSHUe1EbrUd5SekXeP9CWk;
var str_str_eq : bool = "a" = "b";
  • <> FIXME

var int_int_ne : bool = 1 <> 2;
var rat_int_ne : bool = (1 div 2) <> 2;
var int_rat_ne : bool = 1 <> (2 div 3);
var rat_rat_ne : bool = (1 div 2) <> (2 div 3);
var tez_tez_ne : bool = 1tz <> 2tz;
var dur_dur_ne : bool = 1h <> 2h;
var date_date_ne : bool = 2020-01-01 <> 2020-12-31;
var bool_bool_ne : bool = true <> false;
var addr_addr_ne : bool = @tz1Lc2qBKEWCBeDU8npG6zCeCqpmaegRi6Jg <> @tz1bfVgcJC4ukaQSHUe1EbrUd5SekXeP9CWk;
var str_str_ne : bool = "a" <> "b";
  • < FIXME

var int_int_lt : bool = 1 < 2;
var rat_int_lt : bool = (1 div 2) < 2;
var int_rat_lt : bool = 1 < (2 div 3);
var rat_rat_lt : bool = (1 div 2) < (2 div 3);
var tez_tez_lt : bool = 1tz < 2tz;
var dur_dur_lt : bool = 1h < 2h;
var date_date_lt : bool = 2020-01-01 < 2020-12-31;
  • <= FIXME

var int_int_le : bool = 1 <= 2;
var rat_int_le : bool = (1 div 2) <= 2;
var int_rat_le : bool = 1 <= (2 div 3);
var rat_rat_le : bool = (1 div 2) <= (2 div 3);
var tez_tez_le : bool = 1tz <= 2tz;
var dur_dur_le : bool = 1h <= 2h;
var date_date_le : bool = 2020-01-01 <= 2020-12-31;
  • > FIXME

var int_int_gt : bool = 1 > 2;
var rat_int_gt : bool = (1 div 2) > 2;
var int_rat_gt : bool = 1 > (2 div 3);
var rat_rat_gt : bool = (1 div 2) > (2 div 3);
var tez_tez_gt : bool = 1tz > 2tz;
var dur_dur_gt : bool = 1h > 2h;
var date_date_gt : bool = 2020-01-01 > 2020-12-31;
  • >= FIXME

var int_int_ge : bool = 1 >= 2;
var rat_int_ge : bool = (1 div 2) >= 2;
var int_rat_ge : bool = 1 >= (2 div 3);
var rat_rat_ge : bool = (1 div 2) >= (2 div 3);
var tez_tez_ge : bool = 1tz >= 2tz;
var dur_dir_ge : bool = 1h >= 2h;
var date_date_ge : bool = 2020-01-01 >= 2020-12-31;

Arithmetic

  • + FIXME

var int_int_plus : int = 1 + 2;
var rat_rat_plus : rational = 1.1 + 1.2;
var int_rat_plus : rational = 1 + 1.2;
var rat_int_plus : rational = 1.1 + 2;
var dur_dur_plus : duration = 1h + 2s;
var date_dur_plus : date = 2020-01-01 + 1d;
var dur_date_plus : date = 1d + 2020-01-01;
var str_str_plus : string = "str1" + "str2"; (* concat *)
var tez_tez_plus : tez = 2tz + 1tz;
  • - FIXME

var int_int_minus : int = 1 - 2;
var rat_rat_minus : rational = 1.1 - 1.2;
var int_rat_minus : rational = 1 - 1.2;
var rat_int_minus : rational = 1.1 - 2;
var date_date_minus : duration = 2020-01-01 - 2019-12-31; (* absolute value *)
var dur_dur_minus : duration = 1h - 2s; (* absolute value *)
var date_dur_minus : date = 2020-01-01 - 1d;
var tez_tez_minus : tez = 2tz - 1tz;
  • * FIXME

var int_int_mult : int = 1 * 2;
var rat_rat_mult : rational = 1.1 * 1.2;
var int_rat_mult : rational = 1 * 1.2;
var rat_int_mult : rational = 1.1 * 2;
var int_dur_mult : duration = 2 * 1h;
var int_tez_mult : tez = 1 * 1tz;
var rat_tez_mult : tez = 1.1 * 1tz;
  • / FIXME

var int_int_div : int = 1 / 2;
var rat_rat_div : rational = 1.1 / 1.2;
var int_rat_div : rational = 1 / 1.2;
var rat_int_div : rational = 1.1 / 2;
var dur_int_div : duration = 1h / 2;
  • % FIXME

var int_int_modulo : int = 1 % 2;

Constant

  • caller FIXME

var v : address = caller; (* SENDER *)
  • source FIXME

var v : address = source; (* SOURCE *)
  • balance FIXME

var v : tez = balance; (* BALANCE *)
  • transferred FIXME

var v : tez = transferred; (* AMOUNT *)
  • now FIXME

var v : date = now; (* NOW *)
  • state FIXME

archetype sample_state
states =
| First
| Second
| Third
transition mytr () {
from First
to Second
with effect {
require (state = First)
}
}

Builtin functions

  • min FIXME

var int_int_min : int = min(1, 2);
var rat_int_min : rat = min(1 div 2, 1);
var int_rat_min : rat = min(2, 1 div 3);
var rat_rat_min : rat = min(1 div 2, 1 div 3);
var date_date_min : date = min(2020-01-01, 2020-12-31);
var dur_dur_min : dur = min(1h, 1s);
var tez_tez_min : tez = min(1tz, 2tz);
  • max FIXME

var int_int_max : int = max(1, 2);
var rat_int_max : rat = max(1 div 2, 1);
var int_rat_max : rat = max(2, 1 div 3);
var rat_rat_max : rat = max(1 div 2, 1 div 3);
var date_date_max : date = max(2020-01-01, 2020-12-31);
var dur_dur_max : dur = max(1h, 1s);
var tez_tez_max : tez = max(1tz, 2tz);
  • abs FIXME

var int_abs : int = abs(-1);
var rat_abs : rat = abs(-1 div 2);

List

  • contains FIXME

archetype expr_list_contains
variable res : bool = false
action exec () {
specification {
s0: res = true;
}
effect {
var l : string list = ["1"; "2"; "3"];
res := contains(l, "2")
}
}
  • count FIXME

archetype expr_list_count
variable res : int = 0
action exec () {
specification {
s0: res = 3;
}
effect {
var l : string list = ["1"; "2"; "3"];
res := count(l)
}
}
  • nth FIXME

archetype expr_list_nth
variable res : string = ""
action exec () {
specification {
s0: res = "2";
}
effect {
var l : string list = ["1"; "2"; "3"];
res := nth(l, 1)
}
}
  • prepend adds an element to a list at the first position.

archetype expr_list_prepend
variable res : string list = []
action exec () {
specification {
s0: res = ["0"; "1"; "2"; "3"];
}
effect {
var l : string list = ["1"; "2"; "3"];
res := prepend(l, "0");
}
}

Asset Collection

  • contains FIXME

archetype expr_method_asset_contains
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : bool = false
action exec () {
specification {
s0: res = true;
}
effect {
res := my_asset.contains("id0")
}
}
  • count FIXME

archetype expr_method_asset_count
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 3;
}
effect {
res := my_asset.count()
}
}
  • get FIXME

archetype expr_method_asset_get
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 1;
}
effect {
var a = my_asset.get("id1");
res := a.value
}
}
  • nth FIXME

archetype expr_method_asset_nth
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 1;
}
effect {
var a = my_asset.nth(1);
res := a.value
}
}
  • head FIXME

archetype expr_method_asset_head
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 4};
{"id1"; 3};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 3;
}
effect {
var l = my_asset.head(2);
var a = l.nth(1);
res := a.value
}
}
  • tail FIXME

archetype expr_method_asset_tail
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 1;
}
effect {
var l = my_asset.tail(2);
var a = l.nth(0);
res := a.value
}
}
  • select FIXME

archetype expr_method_asset_select
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 2;
}
effect {
var l = my_asset.select(the.id = "id2");
var a = l.nth(0);
res := a.value
}
}
  • sort FIXME

archetype expr_method_asset_sort
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 3};
{"id1"; 2};
{"id2"; 1}
}
variable res : int = 0
action exec () {
specification {
s0: res = 1;
}
effect {
var l = my_asset.sort(value);
var a = l.nth(0);
res := a.value
}
}

you can also sort with several criteria

archetype multi_sort
asset my_asset identified by id {
id : string;
v1 : int;
v2 : int;
v3 : int;
} initialized by {
{"id0"; 1; 2; 7};
{"id1"; 1; 3; 9};
{"id2"; 1; 3; 8};
{"id3"; 1; 2; 6}
}
action exec () {
effect {
var res = my_asset.sort(v1, asc(v2), desc (v3))
(* res = ["id0"; "id3", "id1", "id2"] *)
}
}
  • sum FIXME

archetype expr_method_asset_sum
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
variable res : int = 0
action exec () {
specification {
s0: res = 3;
}
effect {
res := my_asset.sum(value)
}
}

Verification

Specification

Here is a full example with all sections of an action specification

archetype contract_with_full_specification
asset myasset {
id: string;
val: bool;
}
asset col1 {
id1 : string;
}
asset col2 {
id2 : string;
}
action exec () {
specification {
definition mydef {
x : myasset | forall y in col1, x.id = y.id1
}
predicate mypredicate (a : int) {
forall x in col1, forall y in col2, x.id1 = y.id2
}
variable myvar : int = 0
shadow effect {
myvar := 3
}
assert a1 {
x = y
invariant for myloop {
x = 0;
y = 0
}
}
postcondition s1 {
x = y
invariant for myloop {
x = 0;
y = 0
}
}
}
effect {
var x : int = 0;
var y : int = 0;
for : myloop c in col1 do
require(true)
done;
assert a1
}
}
  • definition FIXME

definition mydef {
x : myasset | forall y in col1, x.id = y.id1
}
  • predicate FIXME

predicate mypredicate (a : int) {
forall x in col1, forall y in col2, x.id1 = y.id2
}
  • variable FIXME

variable myvar : int = 0
  • shadow effect FIXME

shadow effect {
myvar := 3
}
  • assert FIXME

assert a1 {
x = y
invariant for myloop {
x = 0;
y = 0
}
}
  • invariant FIXME

invariant for myloop {
x = 0;
y = 0
}
  • postcondition FIXME

postcondition s1 {
x = y
invariant for myloop {
x = 0;
y = 0
}
}

One specification section is available at the top of the contract. But there is neither shadow effect nor postcondition, which is replaced by contract invariant for the last one.

  • contract invariant FIXME

contract invariant c1 {
true <> false
}

Expression

All expression in effect are available in formula part.

  • forall universal quantifier

q1: forall x : int, x = x;
q2: forall x in my_asset, x.value = x.value;
  • exists existential quantifier

q3: exists x : int, x = x;
q4: exists x in my_asset, x.value = x.value;
  • -> imply

o1: true -> true;
  • <-> equivalence

o2: true <-> true;

Asset expression

  • subsetof FIXME

archetype expr_formula_asset_method_subset
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
action exec () {
specification {
s: my_asset.subsetof(my_asset);
}
effect {
require (true)
}
}
  • isempty FIXME

archetype expr_formula_asset_method_isempty
asset my_asset identified by id {
id : string;
value : int;
} initialized by {
{"id0"; 0};
{"id1"; 1};
{"id2"; 2}
}
action exec () {
specification {
s: my_asset.isempty();
}
effect {
require (true)
}
}

Extra asset collection

  • before FIXME

s1: before.my_asset.isempty();
  • at FIXME

s2: at(lbl).my_asset.isempty();
  • unmoved FIXME

s3: my_asset.unmoved.isempty();
  • added FIXME

s4: my_asset.added.isempty();
  • removed FIXME

s5: my_asset.removed.isempty();
  • iterated FIXME

action exec2 () {
specification {
postcondition p1 {
true
invariant for loop {
iterated.isempty()
}
}
}
effect {
var res : int = 0;
for:loop i in my_asset do
res += 1;
done
}
}
  • toiterate FIXME

action exec3 () {
specification {
postcondition p1 {
true
invariant for loop {
toiterate.isempty()
}
}
}
effect {
var res : int = 0;
for:loop i in my_asset do
res += 1;
done
}
}

Security predicate

archetype lang_security
constant admin : role = @tz1aazS5ms5cbGkb6FN1wvWmN7yrMTTcr6wB
asset my_asset identified by id {
id : string;
value : int;
}
action exec () {
effect {
require true
}
}
security {
s00 : only_by_role (anyaction, admin);
s01 : only_in_action (anyaction, exec);
s02 : only_by_role_in_action (anyaction, admin, exec);
s03 : not_by_role (anyaction, admin);
s04 : not_in_action (anyaction, exec);
s05 : not_by_role_in_action (anyaction, admin, exec);
s06 : transferred_by (anyaction);
s07 : transferred_to (anyaction);
s08 : no_storage_fail (anyaction);
}
  • only_by_role FIXME

s00 : only_by_role (anyaction, admin);
  • only_in_action FIXME

s01 : only_in_action (anyaction, exec);
  • only_by_role_in_action FIXME

s02 : only_by_role_in_action (anyaction, admin, exec);
  • not_by_role FIXME

s03 : not_by_role (anyaction, admin);
  • not_in_action FIXME

s04 : not_in_action (anyaction, exec);
  • not_by_role_in_action FIXME

s05 : not_by_role_in_action (anyaction, admin, exec);
  • transferred_by FIXME

s06 : transferred_by (anyaction);
  • transferred_to FIXME

s07 : transferred_to (anyaction);
  • no_storage_fail FIXME

s08 : no_storage_fail (anyaction);