# Love primitives¶

## Prefix & Infix primitives¶

There are two kinds of primitives in the language:

**Prefix primitives**are used by putting the primitive before the arguments:`prim x y z`

.**Infix primitves**are used by putting the primitive between the arguments:`x prim y`

. Infix primitives are always operators (`+`

,`-`

, etc.).

When the type of a primitive is specified, we extend the notation for functions like this:

`TYPE_ARG -> TYPE_RESULT`

for a primitive with one argument`TYPE_ARG1 -> TYPE_ARG2 -> TYPE_RESULT`

for a primitive with two arguments`forall TYPES. ... -> TYPE_RESULT`

for a polymorphic primitive

Whereas functions can only take one argument in Liquidity/Michelson (possibly a tuple), primitives can take multiple arguments.

## Comparison between values¶

All values are not comparable. Only two values of the following types can be compared with each other:

`unit`

`bool`

`int`

`dun`

`string`

`bytes`

`timestamp`

`keyhash`

`address`

`'a * 'b`

when`'a`

and`'b`

are comparable`'a option`

,``’a list``,`'a set`

when`'a`

is comparable`('a, 'b) map`

when`'a`

and`'b`

are comparable`{field1 : 'a; field2 : 'b; ...}`

when`'a`

,`'b`

, … are comparable`A of 'a | B of 'b ...`

when`'a`

,`'b`

, … are comparable

The following comparison operators are available:

`=`

: equal`<>`

: not-equal`<`

: strictly less`<=`

: less or equal`>`

: strictly greater`>=`

: greater or equal

These operators have type `forall 'a. 'a -> 'a -> bool`

, hence their type
must be provided with the type application `[:TYPE]`

Example: `=[:bool]`

defines the equality on booleans and has type
`bool -> bool -> bool`

.

The function `compare : forall 'a. 'a -> 'a -> int`

is a polymorphic function returning an integer, as follows.

`compare[:TYPE] x y`

* returns 0 if `x`

and `y`

are equal
* returns a strictly positive integer if `x > y`

* returns a strictly negative integer if `x < y`

## Raising exceptions¶

There exist two kind of exceptions in Love: user-defined exceptions
and the `Failure`

polymorphic exception.

User-defined exceptions are declared in contracts with the keyword

`exception`

and a list of types. They are raised with they keywork`raise`

, and can be catched when encapsulated in`try ... with EXCEPTION ->`

.`raise`

is a special primitive that takes an exception in argument and returns a value of type`forall 'a, 'a`

.exception MyException of bool val test (p : bool) : int = try ( if p then (raise (MyException true)) [:int] else 0 ) with | MyException b -> -1

`failwith : forall 'a. 'a -> (forall 'b. 'b)`

: makes the current transaction and all its internal transactions fail. No modification is done to the context. The argument can be any value (often a string and some argument), the system will display it to explain why the transaction failed. The argument and return type must be specified as the function is polymorphic.val%entry default storage d (p : unit) = let unit_value = (failwith [:string] "The transaction failed") [:unit] in ([][:operation], storage)

## Operations on tuples¶

Simple projection:

`t.n`

where`n`

is a constant positive-or-nul int: returns the`n`

-th element of the tuple`t`

. Starts at`0`

.type storage = int val%entry default storage d (p : int * int) = let new_storage = p.1 in ([][:operation], new_storage)

Tuple projection:

`t.(n_1,n_2,...)`

where`n_i`

is a constant positive-or-nul int for each`i`

: returns the tuple with the elements corresponding to`(n_1,n_2,...)`

type storage = int * int val%entry default storage d (p : int * int * bool) = let new_storage = p.(0,1) in ([][:operation], new_storage)

Tuple update:

`t <- (EXP_1,EXP_2,...)`

returns the tuple where each element`i`

has been replaced by`EXP_i`

.`EXP_i`

can either be an expression or`_`

, which does not change the`i`

-th element of the tuple.

type storage = int * int * int val%entry default storage d (p : unit) = let new_storage = storage <- (_, storage.1 + 1) in ([][:operation], new_storage)

## Operations on numeric values¶

Operations on numeric values are not polymorphic, each operator define a specific numeric operation.

- Additions
`+ : int -> int -> int`

`++ : nat -> nat -> nat`

`++! : nat -> int -> int`

`+!+ : int -> nat -> int`

`+$ : dun -> dun -> dun`

`+:! : timestamp -> int -> timestamp`

`+!: : int -> timestamp -> timestamp`

`+:+ : timestamp -> nat -> timestamp`

`++: : nat -> timestamp -> timestamp`

- Substraction
`- : int -> int -> int`

`-+ : nat -> nat -> int`

`-+! : nat -> int -> int`

`-!+ : int -> nat -> int`

`-$ : dun -> dun -> dun`

`-: : timestamp -> timestamp -> int`

`-:! : timestamp -> int -> timestamp`

`-!: : int -> timestamp -> timestamp`

`-:+ : timestamp -> nat -> timestamp`

`-+: : nat -> timestamp -> timestamp`

- Multiplication
`* : int -> int -> int`

`*+ : nat -> nat -> nat`

`*+! : nat -> int -> int`

`*!+ : int -> nat -> int`

`*$! : dun -> int -> dun option`

`*!$ : int -> dun -> dun option`

`*$+ : dun -> nat -> dun`

`*+$ : nat -> dun -> dun`

- Division (returns
`None`

when the second argument is zero)`/ : int -> int -> (int * int) option`

`/+ : nat -> nat -> (nat * nat) option`

`/+! : nat -> int -> (int * int) option`

`/!+ : int -> nat -> (int * int) option`

`/$ : dun -> dun -> (int * dun) option`

`/$! : dun -> int -> (dun * dun) option`

`/$+ : dun -> nat -> (dun * dun) option`

NB: Arithmetic operators syntax follows a certain logic. The first characher represents the operation, followed by symbols representing the argument types.

`!`

for`int`

`+`

for`nat`

`$`

for`dun`

`:`

for`timestamp`

For example, `+!:`

is the operator adding `int`

s
to `timestamp`

s.

- Bitwise operators
`land | lor | lxor | lsl | lsr : int -> int -> int`

`nand | nor | nxor | nlsl | nlsr : nat -> nat -> nat`

- Boolean operators (not lazy)
`&&`

: boolean and`||`

: boolean or`|&`

: boolean xor`not`

: boolean negation

## Translators¶

`Int.of_nat : nat -> int`

Transforms a positive integer to a signed integer.val decr (x : nat) : int = Int.of_nat x - 1

`Nat.of_int : int -> nat option`

Transforms an integer to a positive integer. If the integer in argument is negative, it returns`None`

.val is_positive (x : int) : bool = match Nat.of_int x with None -> false | Some _ -> true

`Address.of_keyhash : keyhash -> address`

Transforms a keyhash to an addressval to_address (x : keyhash) : address = Address.of_keyhash x

`Keyhash.of_address : address -> keyhash option`

Transforms an address to a keyhash. If the address in argument is a contract, it returns`None`

.val is_contract (x : address) : bool = match Keyhash.of_address x with None -> true | Some _ -> false

## Operations on lambdas¶

`( |> ) : 'a -> ('a -> 'b) -> 'b`

Applies a function to its argument.type storage = nat val%entry default storage d (b : unit) = let b = storage |> Bytes.pack [:storage] |> Bytes.unpack<:nat> in match b with None -> ([][:operation], storage) | Some b -> ([][:operation], b)

## Operation on lists¶

Lists are immutable data structures containing values (of any type)
that can only be accessed in a sequential order. Since they are
immutable, all **modification** primitives return a new list, and the
list given in argument is unmodified.

`[] : forall 'a. 'a list`

The empty list.val int_list : int list = [] [:int] val nat_list : nat list = [] [:nat] val fun_list : (int -> int) list = [] [:int -> int]

`List.cons : forall 'a. 'a -> 'a list -> 'a list`

Add a new element at the head of the list. The previous list becomes the tail of the new list. It is equivalent to`CONS`

in Michelson.type storage = int list val%entry default storage d (p : int) = let new_storage = p :: storage in ([][:operation], new_storage)

`( :: ) : forall 'a. 'a -> 'a list -> 'a list`

Same as`List.cons`

, but is an infix operator. The type`'a`

is automatically inferred and is not required.type storage = int list val%entry default storage d (p : int) = let new_storage = List.cons p storage in ([][:operation], new_storage)

`( @ ) : forall 'a. 'a list -> 'a list -> 'a list`

. Concatenate two lists into a single list.type storage = int list val%entry default storage d (p : int list) = ([][:operation], storage @ [:int] p)

`List.rev : forall 'a. 'a list -> 'a list`

Returns the list in the reverse order.type storage = int list val%entry default storage d (p : unit) = ([][:operation], List.rev[:int] storage)

`List.length : forall 'a. 'a list -> nat`

. Returns the length of the list. It is equivalent to`SIZE`

in Michelson.type storage = int list val%view storage_size storage (p : unit) : nat = List.length[:int] storage

`List.iter: forall 'a. ('a -> unit) -> 'a list -> unit`

. Iter the function on all the elements of a list. Since no value can be returned, it can only be used for side effects, i.e. to fail the transaction. It is equivalent to`ITER`

in Michelson.exception Fail type storage = int list val%view check_storage storage (p : unit) : unit = List.iter[:int] (fun (elt : int) -> if (elt <[:int] 0) then (raise Fail) [:unit]) storage

`List.fold: forall 'elt. forall 'acc. ('elt -> 'acc -> 'acc) -> 'elt list -> 'acc -> 'acc`

. Iter on all elements of a list, while modifying an accumulator. It is equivalent to`ITER`

in Michelson.type storage = int list val%view sum_storage storage (p : unit) : int = List.fold [:int] [:int] (fun (stor_elt : int) (acc : int) -> acc + stor_elt) storage 0

`List.map: forall 'a. forall 'b. ('a -> 'b) -> 'a list -> 'b list`

. Returns a list with the result of applying the function on each element of the list. It is equivalent to`MAP`

in Michelson.type storage = int list val%entry default storage d (p : int) = let new_storage = List.map[:int][:int] (fun (i : int) -> i + p) storage in ([][:operation], new_storage)

`List.map_fold: forall 'a. forall 'acc. forall 'b. ('a * 'acc -> 'b * 'acc) -> 'a list -> 'acc -> 'b list * 'acc`

. Returns a list with the result of applying the function on each element of the list, plus an accumulator. It is equivalent to`MAP`

in Michelson.type storage = int list val%entry default storage d (p : int) = let (new_storage, acc) = List.map_fold[:int] [:int] [:int] (fun (elt : int) (acc : int) -> ( elt + p, elt + acc )) ([1; 2; 3; 4; 5] [:int]) 0 in ([][:operation], new_storage)

## The Bytes module¶

`Bytes.pack: forall 'a. 'a -> bytes`

. Serialize any data to a binary representation in a sequence of bytes. It is equivalent to`PACK`

in Michelson.type storage = bytes val%entry default storage d (k : address) = let b = Bytes.pack [:address] k in ([][:operation], b)

`Bytes.unpack<:TYPE>: bytes -> TYPE option`

. Deserialize a sequence of bytes to a value from which it was serialized. The expression should be annotated with the (option) type that it should return. It is equivalent to`UNPACK`

in Michelson.type storage = address val%entry default storage d (k : bytes) = match Bytes.unpack<:address> k with None -> ([][:operation], storage) | Some a -> ([][:operation], a)

`Bytes.length : bytes -> nat`

. Returns the size of the sequence of bytes. It is equivalent to`SIZE`

in Michelson.type storage = nat val%entry default storage d (b : bytes) = ([][:operation], Bytes.length b)

`Bytes.concat: bytes list -> bytes`

. Append all the sequences of bytes of a list into a single sequence of bytes. It is equivalent to`CONCAT`

in Michelson.type storage = bytes val%entry default storage d (b : bytes) = ([][:operation], Bytes.concat ([storage; b][:bytes]))

`Bytes.slice : nat -> nat -> bytes -> bytes option`

. Extract a sequence of bytes within another sequence of bytes.`Bytes.slice start len b`

extracts the bytes subsequence of`b`

starting at index`start`

and of length`len`

. A return value`None`

means that the position or length was invalid. It is equivalent to`SLICE`

in Michelson.type frame = {start : nat; size : nat} type storage = bytes val%view get_sub storage (b : frame) : bytes option = Bytes.slice b.start b.size storage

## Operation on strings¶

A string is a fixed sequence of characters. They are restricted to the
printable subset of 7-bit ASCII, plus some escaped characters (`\n`

,
`\t`

, `\b`

, `\r`

, `\\`

, `\"`

).

`String.length : string -> nat`

. Returns the size of the string in characters. It is equivalent to`SIZE`

in Michelson.type storage = string val%view length storage (p : unit) : nat = String.length storage

`String.slice : nat -> nat -> string -> string option`

.`String.slice start len s`

returns a substring of a string`s`

at the given starting at position`len`

with the specified length`len`

, or`None`

if invalid. It is equivalent to`SLICE`

in Michelson.type frame = {start : nat; size : nat} type storage = string val%view get_sub storage (b : frame) : string option = String.slice b.start b.size storage

`String.concat: string list -> string`

. Append all strings of a list into a single string. It is equivalent to`CONCAT`

in Michelson.type storage = string val%entry default storage d (b : string) = ([][:operation], String.concat ([storage; b][:string]))

`^: string -> string -> string`

. Infix operator for concatenating two strings.type storage = string val%entry default storage d (k : string) = let new_storage = storage ^ " and then " ^ k in ([][:operation], new_storage)

## The `Set`

module¶

Sets are immutable data structures containing unique values (a
comparable type). Since they are immutable, all **modification**
primitives return a new updated set, and the set given in argument is
unmodified.

`Set.empty: forall 'a. 'a set`

. The empty settype storage = int set val%entry default s d (p : unit) = ([][:operation], Set.empty [:int])

`Set.cardinal: forall 'a. 'a set -> nat`

. The number of elements in a set.type storage = int set val%view storage_size s (p : unit) : nat = Set.cardinal [:int] s

`Set.add: forall 'a. 'a -> 'a set -> 'a set`

. Add an element to a set, if not present.type storage = int set val%entry add_elt s d (p : int) = ([][:operation], Set.add [:int] p s)

`Set.remove: forall 'a. 'a -> 'a set -> 'a set`

. Removes an element to a set, if present.type storage = int set val%entry remove_elt s d (p : int) = ([][:operation], Set.remove [:int] p s)

`Set.mem: forall 'a. 'a -> 'a set -> bool`

. Returns`true`

if the element is in the set,`false`

otherwise. It is equivalent to`MEM`

in Michelson.type storage = int set val%view contains storage (p : int) : bool = Set.mem [:int] p storage

`Set.iter: forall 'elt. ('elt -> unit) -> 'elt set -> unit`

. Apply a function on all elements of the set. Since no value can be returned, it can only be used for side effects, i.e. to fail the transaction. It is equivalent to`ITER`

in Michelson.exception Fail type storage = int set val%view check_storage storage (p : unit) : unit = Set.iter [:int] (fun (elt : int) -> if (elt <[:int] 0) then (raise Fail) [:unit]) storage

`Set.fold: forall 'elt. forall 'acc. ('elt -> 'acc -> 'acc) -> 'elt set -> 'acc -> 'acc`

. Iter on all elements of a set, while modifying an accumulator.type storage = int set val%view sum_storage storage (p : int) : int = Set.fold[:int][:int] (fun (i : int) (acc : int) -> i + acc) storage 0

`Set.map: forall 'a. forall 'b. ('a -> 'b) -> 'a set -> 'b set`

. Returns a list with the result of applying the function on each element of the list.type storage = int set val%view incr_storage storage (p : int) : int set = Set.map[:int][:int] (fun (i : int) -> i + 1 ) storage

`Set.map_fold: forall 'a. forall 'acc. forall 'b. ('a -> 'acc -> 'b * 'acc) -> 'a set -> 'acc -> 'b set * 'acc`

. Returns a list with the result of applying the function on each element of the list, plus an accumulator.type storage = int set val%view incr_storage storage (p : int) : int set * int = Set.map_fold[:int][:int][:int] (fun (acc : int) (i : int) -> i + acc, i + 1 ) storage 0

## The `Map`

module¶

Maps are immutable data structures containing associations between
keys (a comparable type) and values (any type). Since they are
immutable, all **modification** primitives return a new updated map,
and the map given in argument is unmodified.

`Map.empty: forall 'key. forall 'elt. ('key, 'elt) map`

. The empty map that binds elements of type`'key`

to elements of type`'elt`

.type storage = (int, bool) map val%entry restart storage d (p : unit) = let new_storage = Map.empty [:int] [:bool] in ([][:operation], new_storage)

`Map.cardinal: forall 'key. forall 'elt. ('key, 'elt) map -> nat`

. The number of bindings registered in a map.type storage = (int, bool) map val%view size_storage storage (p : unit) : nat = Map.cardinal [:int] [:bool] storage

`Map.add: forall 'key. forall 'elt. 'key -> 'elt -> ('key, 'elt) map -> ('key, 'elt) map`

. Binds a key to a value into a map, if the key is not present.type sign = Plus | Minus type storage = (int, sign) map val%entry add storage d (p : int) = let new_storage = if (p <[:int] 0) then Map.add [:int] [:sign] p Minus storage else Map.add [:int] [:sign] p Plus storage in ([][:operation], new_storage)

`Map.remove: forall 'key. forall 'elt. 'key -> 'elt -> ('key, 'elt) map -> ('key, 'elt) map`

. Removes a binding from a map, if present.type sign = Plus | Minus type storage = (int, sign) map val%entry remove storage d (p : int) = let new_storage = Map.remove [:int] [:sign] p storage in ([][:operation], new_storage)

`Map.mem: forall 'key. forall 'map 'key -> ('key, 'elt) map -> bool`

. Returns`true`

if the key belong to the map,`false`

otherwise.type sign = Plus | Minus type storage = (int, sign) map val%view exists storage (p : int) : bool = Map.mem [:int] [:sign] p storage

`Map.find: forall 'key. forall 'map 'key -> ('key, 'elt) map -> 'elt option`

. Returns`Some elt`

if`elt`

is bound to the key in argument,`None [:'elt]`

otherwise.type sign = Plus | Minus type storage = (int, sign) map val%view get_elt storage (p : int) : sign option = Map.find [:int] [:sign] p storage

`Map.iter: forall 'key. forall 'elt. ('elt -> 'key -> unit) -> ('key, 'elt) map -> unit`

. Applies a function on all elements of the set. Since no value can be returned, it can only be used for side effects, i.e. to fail the transaction.exception Fail type sign = Plus | Minus type storage = (int, sign) map val%view check_storage storage (forbidden_val : int) : unit = Map.iter [:int] [:sign] (fun (elt : int) (_ : sign) -> if (elt =[:int] forbidden_val) then (raise Fail) [:unit]) storage

`Map.fold: forall 'key. forall 'elt. forall 'acc. ('key -> 'elt -> 'acc -> 'acc) -> ('key, 'elt) map -> 'acc -> 'acc`

. Iter on all elements of a set, while modifying an accumulator.type sign = Plus | Minus type storage = (int, sign) map val%view abs_sum storage (p : unit) : int = Map.fold [:int] [:sign] [:int] (fun (elt : int) (s : sign) (acc : int) -> match s with Plus -> acc + elt | Minus -> acc - elt ) storage 0

`Map.map: forall 'key. forall 'elt. forall 'new_elt. ('key -> 'elt -> 'new_elt) -> ('key, 'elt) map -> ('key, 'new_elt) map`

. Returns a list with the result of applying the function on each element of the list.type sign = Plus | Minus type storage = (int, sign) map val%entry reverse storage d (p : unit) = let new_storage = Map.map [:int] [:sign] [:sign] (fun (elt : int) (s : sign) -> match s with Plus -> Minus | Minus -> Plus ) storage in ([][:operation], new_storage)

`Map.map_fold: forall 'key. forall 'elt. forall 'acc. forall 'new_elt. ('key -> 'elt -> 'acc -> 'new_elt * 'acc) -> ('key, 'elt) map -> 'acc -> ('key, 'new_elt) map * 'acc`

. Returns a list with the result of applying the function on each element of the list, plus an accumulator.type sign = Plus | Minus type storage = (int, sign) map * int val%entry reverse storage d (p : unit) = let new_storage = Map.map_fold [:int] [:sign] [:int] [:sign] (fun (elt : int) (s : sign) (acc : int) -> match s with Plus -> Minus, acc + elt | Minus -> Plus, acc - elt ) storage.0 0 in ([][:operation], new_storage)

## The `BigMap`

module¶

Big maps are a specific kind of maps, optimized for storing. They can be updated incrementally and scale to a high number of associations, whereas standard maps will have an expensive serialization and deserialization cost. You are limited by Michelson to one big map per smart contract, that should appear as the first element of the storage. Big maps cannot be iterated.

`BigMap.empty<:TYPE, TYPE'>: (TYPE,TYPE') bigmap`

. Returns the value associated with a key in the map. It is equivalent to`GET`

in Michelson.type storage = (int, address) bigmap val%entry reinit s d (p : unit) = ([][:operation], BigMap.empty<<int, address>>)

`BigMap.add: forall 'key. forall 'val. 'key -> 'val -> ('key, 'val) big_map -> ('key, 'val) bigmap`

Returns the big map in argument with the new binding

`('key, 'val)`

if`'key`

is not binded.

type storage = {last : int; addresses : (int, address) bigmap} val%entry add s d (p : address) = let new_storage = { last = s.last + 1; addresses = BigMap.add [:int] [:address] s.last p s.addresses } in ([][:operation], new_storage)

`BigMap.remove: forall 'key. forall 'val. 'key -> ('key,'val) big_map -> ('key,'val) bigmap`

. Returns the big map without the binding`'key`

.type storage = {last : int; addresses : (int, address) bigmap} val%entry add s d (p : int) = let new_storage = {s with addresses = BigMap.remove [:int][:address] p s.addresses} in ([][:operation], new_storage)

`BigMap.mem: forall 'key. forall 'val. 'key -> ('key, 'val) bigmap -> bool`

. Returns`true`

if an association exists in the big map for the key,`false`

otherwise.type storage = {last : int; addresses : (int, address) bigmap} val%view exists s (p : int) : bool = BigMap.mem [:int] [:address] p s.addresses

`BigMap.find: forall 'key. forall 'val. 'key -> ('key,'val) bigmap -> 'val option`

. Returns`Some elt`

if the argument is bound to`elt`

in the big map,`None`

otherwise.type storage = {last : int; addresses : (int, address) bigmap} exception Fail val%view get s (p : int) : address = match BigMap.find [:int] [:address] p s.addresses with Some a -> a | None -> (raise Fail) [:address]

## The `Current`

module¶

`Current.balance: unit -> dun`

: returns the balance of the current contract. The balance contains the amount of dun that was sent by the current operation. It is equivalent to`BALANCE`

in Michelson.val%entry default storage d (p : unit) = let b = Current.balance () in ([][:operation], storage)

`Current.time: unit -> timestamp`

: returns the timestamp of the block in which the transaction is included. This value is chosen by the baker that is including the transaction, so it should not be used as a reliable source of alea. It is equivalent to`NOW`

in Michelson.type storage = unit val%entry default storage d (p : unit) = let b = Current.time () in ([][:operation], storage)

`Current.amount: unit -> dun`

: returns the amount of dun transferred by the current operation (standard or internal transaction). It is equivalent to`AMOUNT`

in Michelson.type storage = unit val%entry default storage d (p : unit) = let a = Current.amount () (* dun = a *) in ([][:operation], storage)

`Current.gas: unit -> nat`

: returns the amount of gas available to execute the rest of the transaction. It is equivalent to`STEPS_TO_QUOTA`

in Michelson.type storage = unit val%entry default storage d (p : unit) = let a = Current.gas () in ([][:operation], storage)

`Current.self: unit -> address`

: returns the address of the current contract.type storage = address val%entry default storage d (p : unit) = let me = Current.self () in ([][:operation], me)

`Current.source: unit -> address`

: returns the address that initiated the current top-level transaction in the blockchain. It is the same one for all the transactions resulting from the top-level transaction, standard and internal. It is the address that paid the fees and storage cost, and signed the operation on the blockchain. It is equivalent to`SOURCE`

in Michelson.type storage = unit val%entry default storage d (p : unit) = let a = Current.source () in ([][:operation], storage)

`Current.sender: unit -> address`

: returns the address that initiated the current transaction. It is the same as the source for the top-level transaction, but it is the originating contract for internal operations. It is equivalent to`SENDER`

in Michelson.type storage = unit val%entry default storage d (p : unit) = let a = Current.sender () in ([][:operation], storage)

`Current.cycle: unit -> cycle`

: returns the cycle in which the transaction initiating the execution of the current smart contract has been performed.type storage = nat val%entry default storage d (p : unit) = let now = Current.cycle () in ([][:operation], now)

`Current.level: unit -> address`

: returns the cycle in which the transaction initiating the execution of the current smart contract has been performed.type storage = nat val%entry default storage d (p : unit) = let now = Current.level () in ([][:operation], now)

## The `Contract`

module¶

`Contract.self<:CONTRACT TYPE> -> (instance CONTRACT TYPE) option`

. Returns the current executing contract. If the contract does not matched the signature in argument, returns`None`

. It is equivalent to`SELF`

in Michelson.type storage = int contract type CT = sig val x : int end val x : int = 5 val%entry default storage d (() : unit) = let c = Contract.self<:CT> () in match c with None -> ([][:operation], storage) | Some (contract C : CT) -> ([][:operation], C.x)

`Contract.at<:CONTRACT TYPE>: address -> (instance CONTRACT TYPE) option`

. Returns the contract associated with the address. As for`Contract.self`

, it must be annotated with the type of the contract.type storage = int contract type CT = sig val x : int end val%entry default storage d (k : address) = let c = Contract.at<:CT> k in match c with None -> ([][:operation], storage) | Some (contract C : CT) -> ([][:operation], C.x)

`Contract.call: forall 'a. 'a entrypoint -> dun -> 'a -> operation`

. Forges an internal contract call. It is equivalent to`TRANSFER_TOKENS`

in Michelson. The entry point name is optional (`default`

by default).type storage = unit contract type CT = sig val%entry default : int end val x : int = 5 val%entry default storage d (k : address) = let c = Contract.at<!CT> k in match c with None -> ([][:operation], storage) | Some (contract C : CT) -> ( let op = Contract.call [:int] C.default d x in ([op][:operation], storage) )

`Contract.view: forall 'a. 'a view -> 'a`

. Calls a view from a contract. Views does not initiate transaction when they are called, i.e. they are called in the contect of the calling contract, but with the storage of the target contract.`Contract.view [:typ] view`

deserializes the storage, which means that any change of the storage*after*is not taken into account.type storage = int contract type CT = sig type storage val%view storage_size : unit -> int end val%entry default storage d (k : address) = let c = Contract.at <:CT> k in match c with None -> ([][:operation], storage) | Some (contract C : CT) -> ( let size = Contract.view [:unit -> int] C.storage_size () in ([][:operation], storage) )

`Contract.set_delegate: keyhash option -> operation`

. Forge a delegation operation for the current contract. A`None`

argument means that the contract should have no delegate (it falls back to its manager). The delegation operation will only be executed in an internal operation if it is returned at the end of the`%entry`

function. It is equivalent to`SET_DELEGATE`

in Michelson.type storage = unit val%entry default storage d (k : keyhash) = let op = Contract.set_delegate (Some k) in ([op][:operation], storage)

`Contract.address: UnitContract instance -> address`

. Returns the address of a contract. It is equivalent to`ADDRESS`

in Michelson.type storage = unit val%entry default storage d (k : unit) = let c = Contract.self<<UnitContract>> () in let self_addr = Contract.address c in ([][:operation], storage)

`Contract.create: forall 'a. keyhash option -> dun -> (sig type storage val%init storage : 'a end contract) ->'a -> (operation * address)`

. Forges an operation to originate a contract with code. The contract is only created when the operation is executed, so it must be returned by the transaction. Note that the code must be specified as a contract structure (inlined or not).`Contract.create manager_opt initial_amount (contract C) arg`

forges an an origination operation for contract C with manager`manager`

, optional delegate`delegate`

, initial balance`initial_amount`

and initial storage`C.init arg`

.Warning :

`'a`

must be a built-in type or a public alias of a built-in type.type storage = unit contract C = struct type storage = A | B val init (() : unit) : storage = A end val%entry default storage d (k : keyhash) = let (op, addr) = Contract.create [:unit] (Some k) d (contract C) () in ([op][:operation], storage)

## The `Account`

module¶

`Account.transfer: address -> dun -> operation`

. Forges an internal transaction to the implicit (_i.e._ default) account contract in argument.type storage = int val%entry default storage d (k : address) = let op = Account.transfer k d in ([op][:operation], storage)

`Account.default: keyhash -> instance UnitContract`

. Returns the contract associated to the given`keyhash`

with an empty signature. It is equivalent to`IMPLICIT_ACCOUNT`

in Michelson.val get_contract (k : keyhash) : instance UnitContract = Account.default k

`Account.manage: address -> int option -> bool -> address option -> address list -> operation`

Returns an operation that updates the account informations. The operation will fail if the operation creator is not the administrator of the adress in argument.type info = (int option * bool * address option * address list) type storage = address val%entry manage storage d (info : info) = let manage_op = Account.manage storage info.0 info.1 info.2 info.3 in match manage_op with Some op -> ([op][:operation], storage) | None -> ([][:operation], storage)

`Account.balance: address -> dun`

Returns the amount of dun at a given address.type storage = (address, dun) map val%entry default storage d (k : address) = let amount = Account.balance k in ([][:operation], Map.add [:address] [:dun] k amount storage)

## The `Crypto`

module¶

`Crypto.blake2b: bytes -> bytes`

. Computes the cryptographic hash of a bytes with the cryptographic Blake2b function. It is equivalent to`BLAKE2B`

in Michelson.type storage = bytes val%entry default storage d (k : bytes) = let blakehash = Crypto.blake2b k in ([][:operation], blakehash)

`Crypto.sha256: bytes -> bytes`

. Computes the cryptographic hash of a bytes with the cryptographic Sha256 function. It is translated to`SHA256`

in Michelson.type storage = bytes val%entry default storage d (k : bytes) = let hash = Crypto.sha256 k in ([][:operation], hash)

`Crypto.sha512: bytes -> bytes`

. Computes the cryptographic hash of a bytes with the cryptographic Sha512 function. It is equivalent to`SHA512`

in Michelson.type storage = bytes val%entry default storage d (k : bytes) = let hash = Crypto.sha512 k in ([][:operation], hash)

`Crypto.hash_key: key -> keyhash`

. Hash a public key and encode the hash in B58check. It is equivalent to`HASH_KEY`

in Michelson.type storage = keyhash val%entry default storage d (k : key) = let kh = Crypto.hash_key k in ([][:operation], kh)

`Crypto.check: key -> signature -> bytes -> bool`

. Check that the signature corresponds to signing the (Blake2b hash of the) sequence of bytes with the public key. It is equivalent to`CHECK_SIGNATURE`

in Michelson. Signatures generated by`dune-client sign bytes ...`

can be checked this way.type data = abstract key * signature * bytes type storage = data list val%entry default storage d (k : data) = if Crypto.check k.0 k.1 k.2 then ([][:operation], k :: storage) else ([][:operation], storage)