Skip to content

Latest commit

 

History

History
1426 lines (1085 loc) · 24.7 KB

File metadata and controls

1426 lines (1085 loc) · 24.7 KB

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);