Liquidity is a high-level typed smart-contract language that compiles down to Michelson (for Dune Network and Tezos) and to Love for Dune Network. A formal verification framework for it is under development. See also our testing framework for Michelson, Techelson.

Try Online About Services Documentation Github Repo

About Liquidity

Liquidity is a high-level language to program Smart Contracts for Dune Network and Tezos. It is a fully typed functional language, it uses the syntaxes of OCaml and ReasonML, and strictly complies with Michelson security restrictions.

The Liquidity language provides the following features:

  • full coverage of the Michelson language: anything that can be written in Michelson can be written in Liquidity,
  • local variables instead of stack manipulations: values can be stored in local variables,
  • high-level types: types like sum-types and record-types can be defined and used in Liquidity programs,
  • a module and contract system to write reusable code and libraries,
  • a powerful type inference mechanism with polymorphism,
  • an alternative ReasonML syntax to write contracts in a Javascript-like language,
  • an efficient and optimizing compiler,
  • a decompiler of Michelson program to Liquidity ones: all Michelson programs can be decompiled into a readable form.

Liquidity already covers 100% of the Michelson features, and contracts generated with Liquidity can be submitted on the current Dune mainnet and testnet (as well as on the various Tezos networks).

The idea of creating a user-friendly language for writing Tezos smart-contracts stemmed in the Summer of 2017, and a very first version was released in October 2017. The team put many efforts to improve the whole framework, which the Tezos Foudation unfortunately decided not to support.

The development of Liquidity is now supported by the Dune Foundation and Origin Labs.

Liquidity Online

Liquidity editors will soon be available to program online and submit contracts on the Dune testnet. For now, you can use our Try Liquidity Site to get a taste of the upcoming environment.


Need any services around Dune Network Smart Contracts? Contact us at OCamlPro!

We can provide the following services:

  • Smart-contract review in-depth analysis
  • Smart-contract development
  • Ad hoc tooling
  • Training sessions
  • Customization of the language / DSL conception

Documentation & Examples

Liquidity Documentation is available Here. Examples are also available in the Github project, or in the online editor.

A typical example of a voting smart contract is:

(* Smart contract for voting. Winners of vote split the contract
   balance at the end of the voting period. *)

(** Type of storage for this contract *)
type storage = {
  voters : (address, unit) big_map; (** Used to register voters *)
  votes : (string, nat) map; (** Keep track of vote counts *)
  addresses : (string, key_hash) map; (** Addresses for payout *)
  deadline : timestamp; (** Deadline after which vote closes *)

(** Initial storage *)
let%init storage addresses = {
  (* Initialize vote counts to zero *)
  votes = Map.fold (fun ((name, _kh), votes) ->
      Map.add name 0p votes
    ) addresses Map;
  voters = BigMap ; (* No voters *)
  deadline = Current.time () + 3600 * 24 (* 1 day from now *)

(** Entry point for voting.
    @param choice A string corresponding to the candidate *)
let%entry vote choice storage =
  (* Only allowed while voting period is ongoing *)
  if Current.time () > storage.deadline then failwith "Voting closed";
  (* Voter must send at least 5tz to vote *)
  if Current.amount () < 5.00tz then
    failwith "Not enough money, at least 5tz to vote";
  (* Voter cannot vote twice *)
  if Map.mem (Current.sender ()) storage.voters then
    failwith ("Has already voted", Current.sender ());
  let votes = storage.votes in
  match Map.find choice votes with
  | None ->
    (* Vote must be for an existing candidate *)
    failwith ("Bad vote", choice)
  | Some x ->
    (* Increase vote count for candidate *)
    let storage = storage.votes <- Map.add choice (x + 1p) votes in
    (* Register voter *)
    let storage =
      storage.voters <- Map.add (Current.sender ()) () storage.voters in
    (* Return updated storage *)
    ([], storage)

(* Auxiliary function : returns the list of candidates with the
   maximum number of votes (there can be more than one in case of
   draw). *)
let find_winners votes =
  let winners, _max =
    Map.fold (fun ((name, nb), (winners, max)) ->
        if nb = max then
          name :: winners, max
        else if nb > max then
          [name], nb
        else winners, max
      ) votes ([], 0p) in

(** Entry point for paying winning candidates. *)
let%entry payout () storage =
  (* Only allowed once voting period is over *)
  if Current.time () <= storage.deadline then failwith "Voting ongoing";
  (* Indentify winners of vote *)
  let winners = find_winners storage.votes in
  (* Balance of contract is split equally between winners *)
  let amount = match Current.balance () / List.length winners with
    | None -> failwith "No winners"
    | Some (v, _rem) -> v in
  (* Generate transfer operations *)
  let operations = (fun name ->
      let dest = match Map.find name storage.addresses with
        | None -> failwith () (* This cannot happen *)
        | Some d -> d in
      Account.transfer ~amount ~dest
    ) winners in
  (* Return list of operations. Storage is unchanged *)
  operations, storage

Liquidity Team

Fabrice Le Fessant
Alain Mebsout
David Declerck
Adrien Champion
Steven De Oliveira


2.0   2020/06/23
    * Support for Babylon+
      - Only write entry points' type parameter in signatures [BREAKING CHANGE]
      - Multiple entry points (compiler/client)
      - Lifting of restictions on big maps
      - New instruction `Big_map.create`
      - Big map constants
      - Use new Michelson instructions `DIP n`, `DROP n`
      - Compile DUP n with DIP+DIG instead of DU.UP macro to avoid bubbling
        expansion to `DIP { DUP; SWAP }`
      - Deprecate `Current.gas`
      - Type `chain_id` and instruction ` : unit -> chain_id`
    * Remove contract instances, and use contract handles instead [BREAKING CHANGE]
    * Allow polymorphic variants (so as to not have to declare type)
    * Allow capitalized entry point names with syntax
      `let%entry `Entry = fun param -> fun storage -> body`
    * New instruction `Contract.address` returns address without entry point
      handle [BREAKING CHANGE]
    * Previous behaviour can be accessed with `Contract.untype`
    * Addresses can have an entry point handle with syntax

    * Better simplifications (for sequences) and inlining
    * Decompilation of Michelson entry points with arbitrary names
    * Modular client in separate executable `liquidity-client`
    * Documenation

1.057 2020/01/14
    * Fix scoping bug in inlining
    * Don't use _ as a variable name when decompiling

1.056 2020/01/08
    * Fix conflicts in internal names with multiple contracts

1.055 2019/11/28
    * Estimate fees and storage (burn) in Client

    * Updated documentation

1.053 2019/10/08
    * Fee code (only Dune Network)
    * Decompilation of Michelson fee code

    * Switch to Dune Network backend
    * Remove unecessary type annotation in decompiled Liquidity

1.044 2019/09/02
    * Generate contracts whose parameter is compatible with upcoming version of

1.042 2019/07/19
    * Client update wrt. Tezos protocol

    * Decompilation of failing branches
    * Restriction on timestamp operations

1.041 2019/07/09
    * Allow lambdas in constants

1.04  2019/05/24
    * GPL license

    * Client update wrt. Tezos protocol

    * Occur check with physiscal equality (in inlining phase)

1.03  2019/04/03
    * Uncurrying of totally applied functions

    * Bytes.pack is polymorphic
    * Better simplifications
    * Better error reporting
    * Inlining of closures and constants
    * Better name/strucuture recovery when decompiling

    * Monomorphisation global values/variables
    * Dependencies when using sub-contract as main (#201)
    * Fix issue in decompilation of sub-contracts
    * Fix namespace for first class contract types (#202)

1.02  2019/04/02
    * Debug information with --verbose

    * Fix issue in monomophisation
    * Normalize types wrt current namesapce (#197)
    * Fix issue with module and contract aliases

1.0   2019-03-08
    * Revamped module system for function exports
      (This allows to write reusable libraries.)
    * Private functions/values with [@private]
    * Disable inlining per function with [@noinline]
    * Modules and contract aliases

    * Lambdas in constants
    * Better type inference when overloading

    * Fix bad computation of free variables in Contract.create

0.53  2019-02-13
    * Parse ReasonML expressions
    * Option `--call-arg` to print arguments for tezos clients
    * More peephole optimizations

0.52  2019-02-11
    * ReasonML syntax

0.51  2019-02-09
    * Parameterized type definitions

    * Tezos as submodule

    * Bring back support for string amounts, keys, etc.

0.5  2019-01-21
    * Type inference
    * Polymorphic values and polymorphic inference

    * Allow unit patterns `()`
    * Client command `--pack`

    * Fix printing Michelson list and set constants

0.405 2018-12-06
    * Examples of documentation are in the test suite
      (This way, the documentation is always up to date.)
    * Namespacing for externals

    * Fix Travis ubuntu reop
    * Fix parsing of Tezos node json errors
    * Remove unsupported, Set.map_fold

0.404 2018-11-21
    * External custom instructions

    * Support type annotations in expressions
    * Support for digestif 0.7
    * Warning for failing code

    * Bring --no-annot option back
    * Forbid Contract.self in non-inlined functions
    * Prevent redefinition of Map, Set constructors
    * Workaround Micheline pretty-printing bug

0.402 2018-10-17
    * Multiple entry points
    * Encoding of types with Michelson annotations
    * Decompilation of records, enumerations and operations
    * New syntaxes for contract calls
    * Labelled arguments for some built-in functions
    * Contract signatures
    * Instruction Loop.left
    * Compilation of tail-recursive functions
    * Compile multiple contracts in separate files
    * Option `--main` to compile a specific contract

    * Better compilation of wildcard pattern matching
    * Syntax ` addr` for `( addr : C.instance option)
    * Better locations reporting
    * Syntactic sugar `val%entry : param -> _` in signatures
    * Allow empty (non-toplevel) contracts
    * Patterns in entry point arguments
    * Better decompilation

    * Documentation
    * Fix deployment issue with big maps
    * Fix json output of constants
    * Forbid source, sender in initializer

0.37  2018-10-05
    * Compatibility with Tezos's Mainnet/Zeronet/Alphanet
    * Support bytes constants for key, key_hash, address, contract and signature
    * Attribute [@@inlining] to force inlining when not dangerous
    * Command --init-storage (Pierre Michard)
    * Command --inject to inject signed operation

    * Client: Show failing calls and deployments
    * Inline bodies of lambdas
    * Sphinx documentation
    * Easier build with make build-deps
    * More optimizations on Michelson code

    * Fix issue with printing of signatures
    * Missing decompilation for LSL, LSR
    * Fix inlining bug in decompilation
    * Code elimination after FAILWITH in code generation
    * Fix erroneous pretty-printing of tez values
    * Forbid source, sender in initializer

0.32  2018-07-11
    * Compatibility with Tezos's Betanet
    * New calling convention, Contract.transfer returns an operations
      which has to be returned
    * Current.failwith : 'a -> 'b, instead of fail
    * Type bytes, and 0xab... bytes constants
    * Bytes.pack, Bytes.unpack
    * Type address
    * Contract and address constants (KT1..., tz...)
    * Type big_map, and constants BigMap [...], and BigMap.find,
      BigMap.add, BigMap.remove, BigMap.update
    * New compilation of Map/Set/
    * New instruction Map/Set/List.map_fold
    * Current.self renamed to Contract.self
    * New functions Crypto.blake2b/sha256/sha512 instead of Crypto.hash
    * Current.sender
    * Remove Contract.manager
    * (  : p contract option)

    * Better locations reporting
    * Show runtime failures source locations
    * Light type inferrence in specific places
    * Unary negation on int and tez
    * Somewhat better error messages
    * Compile with OCaml 4.06.1
    * Better decompilation naming heuristic

    * Fix issue with decompiling multiple nested failing branches
    * Fix issue with decompilation of ITER
    * Fix some incorrect peephole optimizations
    * Reject maps and sets with non comparable keys

0.14  2018-01-23
    * Support for decompilation of ITER
    * New instructions Map.iter, Set.iter, List.iter
    * Storage initializer
    * Run Liquidity contracts on Tezos node directly (--run)
    * Deploy Liquidity contracts on Tezos node directly (--deploy)
    * Call Liquidity contracts on Tezos node directly (--call)
    * Retrieve Tezos contract storage in Liquidity syntax (--get-storage)

    * Define type abbreviations when decompiling
    * Support timestamp date with Z timezone
    * Encode reduce with closures using ITER
    * Constant of type signature start with backquote and are hex encoded
    * Ready for javascript compilation

    * int and nat are not comparable
    * bool is comparable
    * Division on type tez

0.13  2017-11-30
    * match%nat construct for int -> nat coercion
    * abs is now int -> int
    * Command line options --parse-only, --type-only
    * Command line options --single-line, --compact to output
      Michelson on a single line
    * Support &&, || Boolean connectors
    * Support Map.add, Map.remove, Set.add, Set.remove
    * Lambda types are now written as t1 -> t2 instead of
      (t1, t2) lambda
    * Constant amounts written as litterals: 1.00tz
    * Constant keys and key_hashes as litterals: edpk... tz1...
    * Timestamps as litterals in ISO-8601 format

    * Split typechecking and encoding phases
    * Allow transfers in conditions (for if-then-else and match)
    * Encode to constants when possible
    * Better error messages
    * Accept any name for result of
    * Recover variable names when decompiling

    * Fix bug in encoding of closures
    * Fix bug in compilation of branches with transfers

0.11  2017-10-16
    * Compilation of Liquidity contracts to OCaml bytecode
    * Deconstruct tuples in let, fun and pattern matching
    * Support _ for pattern
    * OCaml syntax for return type of contract's entry point
    * Support for type key_hash

    * Allow compilation without Tezos
    * Better error messages
    * Error location in Michelson source when decompiling
    * Declare type storage when decompiling
    * More efficient encoding of closures

0.1   2017-10-05
    Initial release
© 2017-2019 OCamlPro SAS, All rights reserved.
Get in touch with us
Mentions L├ęgales