LIGO views
Defining On-Chain Views
On-chain views can be defined using the @view
attribute. For more information see here.
type storage = string
type ret = operation list * storage
[@entry]
let main (word : string) (store : storage) : ret
= [] , store ^ " " ^ word
(* view 'view1', simply returns the storage *)
[@view] let view1 (() : unit) (s : storage) : storage
= s
(* view 'v2', returns true if the storage has a given length *)
[@view] let v2 (expected_length : nat) (s : storage) : bool
= (String.length s = expected_length)
(* view 'v3' does not use its parameters and returns a constant int *)
[@view] let v3 (() : unit) (_ : storage) : int
= 42
type storage = string
type ret = [list<operation>, storage];
const main = (word : string, store : storage) : ret
=> [list([]) , store + " " + word]
/* view 'view1', simply returns the storage */
@view
const view1 = (_arg : unit, s : storage) : storage
=> s;
/* view 'v2', returns true if the storage has a given length */
@view
const v2 = (expected_length : nat , s : storage) : bool
=> (String.length (s) == expected_length);
/* view 'view3' does not use its parameters and returns a constant int */
@view
const view3 = (_arg : unit , _s : storage) : int
=> 42;
Calling On-Chain Views
val call_view : string -> 'arg -> address -> 'ret option
let call_view : string => 'arg => address => option <'ret>
The primitive Tezos.call_view
will allow you to call another contract view and get its result by providing the view name; the contract address and the parameter of the view. If the address is nonexistent; the name does not match of of the contract
view or the parameter type do not match, Tezos.call_view
will return None
.
Defining Off-Chain Views
In addition to on-chain views, LIGO views can be compiled and used as off-chain views (e.g. to be placed in metadata).
To compile an expression as a off-chain view, we can use the LIGO sub-command compile expression
, passing the --function-body
flag. Moreover, the --init-file
argument can be passed to
re-use expressions from a file.
For example, if we have the following off_chain
file containing a contract C
:
module C = struct
type storage = string
[@entry] let append (a : string) (s : storage) : operation list * storage = [] , s ^ a
[@entry] let clear (_ : unit) (_ : storage) : operation list * storage = [] , ""
let v (expected_length: nat) (s: storage) : bool = (String.length s = expected_length)
end
namespace C {
type storage = string
@entry
const append = (a: string, s: storage) : [list<operation> , storage] => [list([]), s + a];
@entry
const clear = (_p: unit, _s: storage) : [list<operation>, storage] => [list([]), ""];
export const v = (expected_length: nat, s: storage) : bool => (String.length (s) == expected_length);
}
We can compile function v
from contract C
as an off-chain view as follows:
Input
❯ ligo compile expression cameligo "C.v" --init-file off_chain.mligo --function-body
Output
{ UNPAIR ; SWAP ; SIZE ; COMPARE ; EQ }
Input
❯ ligo compile expression jsligo "C.v" --init-file off_chain.jsligo --function-body
Output
{ UNPAIR ; SWAP ; SIZE ; COMPARE ; EQ }
Notice that v
is not a contract entry of C
(no @entry
) nor a on-chain view (no @view
), it is just a function declared in the context of the contract, which can be used as an off-chain view.