New Features in The Love Smart Contract Language

David Declerck
Dune Network
Published in
3 min readMay 9, 2020
Photo by Ray Hennessy on Unsplash

It’s been three months since the release of the first version of the Love VM. With the new protocol revision, the Love VM has been improved in several ways. There have been some bug fixes, of course, and some work has been done to improve the error messages. There are also new features, that we present in detail in the following.

Improvements on views

Contract views can now be made recursive, support multiple arguments, and can even be used as ordinary functions in their parent contract.

For instance, one can now write the following view:

type storage = int listval%view rec has_either_value s (x : int) (y : int) : bool =
match s with
| [] ->
false
| z :: s' ->
if z =[:int] x || z =[:int] y then
true
else
has_either_value s' x y

This view has two arguments, is recursive, and the recursive call just looks like an ordinary function call, where the storage is explicitly given as argument (contrary to view calls from external contracts, where the storage must not be specified — nor it can be).

New RPCs to call functions and views

It is now possible to call any contract function or view with arbitrary data using RPCs. This is particularly useful when one wants to unit test its contract functions and views.

Say you have the following (not so useful) contract:

type storage = stringval%init storage (() : unit) =
"Dune is a cool blockchain !"
val add (x : int) (y : int) : int =
x + y
val%view get s (() : unit) : string =
s

The function add can then be called using dune-client (or ix) as follows:

./dune-client dune execute add from mycontract --arg '#love:(14,42)'

Which yields:

Result: 56

Similarly, the view get may be called as follows:

./dune-client dune execute get from mycontract --arg '#love:()'

And gives the following result:

Result: "Dune is a cool blockchain !"

Support for collect call

The collect call feature, introduced in this this article, is now supported in Love. For the record, this feature allows for a contract to pays the transactions fees for the contract caller. The following contract will accept to pay up to 0.021 DUN of fees and the price of 16 bytes of storage if the length of the string given as argument is less or equal 16, otherwise it will just refuse to pay for the caller:

type storage = stringval%init storage (() : unit) = ""val%entry update s d (p : string) =
[%fee
if String.length p <=[:nat] 16p then
(0.021DUN, 16p)
else
(0DUN, 0p)
]
[][:operation], p

Record and “or” pattern matching

Finally, we added two common pattern matching cases that were not considered in the first version of Love. The record pattern matching allows to deconstruct records easily, while the “or” pattern matching allows to group several cases. The following contract illustrates both patterns:

type storage = unittype t1 = A | B | C | a | b | c
type t2 = { x : int; y : int; z : int }
val is_upper (x : t1) : bool =
match x with
| A | B | C -> true
| a | b | c -> false
val to_tuple (x : t2) : (int * int * int) =
let { x; y; z } = x in
(x, y, z)

These are some of the resources you might find interesting in building your own smart contracts:

And other resources on the Dune Network:

--

--