ligo/gitlab-pages/docs/advanced/first-contract.md

205 lines
5.0 KiB
Markdown
Raw Normal View History

---
id: first-contract
title: First contract
---
import Syntax from '@theme/Syntax';
2020-02-10 22:07:20 +04:00
So far so good, we have learned enough of the LIGO language, we are
confident enough to write out first smart contract.
2020-02-10 22:07:20 +04:00
We will be implementing a counter contract.
2020-02-10 22:07:20 +04:00
## Dry-running a Contract
2020-02-10 22:07:20 +04:00
Testing a contract can be quite easy if we utilize LIGO's built-in dry
2020-02-21 21:13:09 +04:00
run feature. Dry-run works by simulating the main function execution,
as if it were deployed on a real chain. You need to provide the
following:
- `file` - contract to run
- `entrypoint` - name of the function to execute
2020-02-21 21:13:09 +04:00
- `parameter` - parameter passed to the main function (in a
theoretical invocation operation)
- `storage` - a mock storage value, as if it were stored on a real chain
2020-02-10 22:07:20 +04:00
Here is a full example:
```shell
ligo dry-run src/basic.ligo main Unit Unit
// Outputs:
// tuple[ list[]
// Unit
// ]
```
2020-02-21 21:13:09 +04:00
Output of the `dry-run` is the return value of our main function, we
can see the operations emitted (in our case an empty list, and the new
storage value being returned) which in our case is still `Unit`.
2020-02-10 22:07:20 +04:00
## A Counter Contract
2020-02-10 22:07:20 +04:00
Our counter contract will store a single `int` as it's storage, and
will accept an `action` variant in order to re-route our single `main`
function to two entrypoints for `add` (addition) and `sub`
(subtraction).
<Syntax syntax="pascaligo">
```pascaligo
type parameter is
2020-02-10 22:07:20 +04:00
Increment of int
| Decrement of int
type storage is int
type return is list (operation) * storage
function add (const n : int; const store : storage) : storage is store + n
function sub (const n : int; const store : storage) : storage is store - n
function main (const action : parameter; const store : storage) : return is
2020-02-10 22:07:20 +04:00
((nil : list(operation)),
case action of
Increment (n) -> add (n, store)
| Decrement (n) -> sub (n, store)
end)
```
</Syntax>
<Syntax syntax="cameligo">
```cameligo
type parameter =
Increment of int
| Decrement of int
type storage = int
type return = (operation) list * storage
let add (n, store : int * storage) : storage = store + n
let sub (n, store : int * storage) : storage = store - n
let main (action, store : parameter * storage) : operation list * storage =
(([]: operation list),
(match action with
Increment n -> add (n, store)
| Decrement n -> sub (n, store)))
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo
type parameter =
Increment (int)
| Decrement (int)
;
type storage = int;
type return = (list (operation), storage);
let add = ((n, store) : (int, storage)) : storage => store + n;
let sub = ((n, store) : (int, storage)) : storage => store - n;
let main = ((action, store) : (parameter, storage)) : return =>
(([]: list (operation)),
(switch (action) {
| Increment (n) => add ((n, store))
| Decrement (n) => sub ((n, store))
}));
```
</Syntax>
To dry-run the counter contract, we will provide the `main` function
with a variant parameter of value `Increment (5)` and an initial
storage value of `5`.
```shell
ligo dry-run src/counter.ligo main "Increment(5)" 5
// tuple[ list[]
// 10
// ]
```
2020-02-10 22:07:20 +04:00
Our contract's storage has been successfuly incremented to `10`.
## Deploying and interacting with a contract on a live-chain
2020-02-10 22:07:20 +04:00
In order to deploy the counter contract to a real Tezos network, we'd
have to compile it first, this can be done with the help of the
`compile-contract` CLI command:
```shell
ligo compile-contract src/counter.ligo main
```
Command above will output the following Michelson code:
```michelson
{ parameter (or (int %decrement) (int %increment)) ;
storage int ;
code { DUP ;
CDR ;
DIP { DUP } ;
SWAP ;
CAR ;
IF_LEFT
{ DUP ;
DIP { DIP { DUP } ; SWAP } ;
PAIR ;
DUP ;
CDR ;
DIP { DUP ; CAR } ;
SUB ;
DIP { DROP 2 } }
{ DUP ;
DIP { DIP { DUP } ; SWAP } ;
PAIR ;
DUP ;
CDR ;
DIP { DUP ; CAR } ;
ADD ;
DIP { DROP 2 } } ;
NIL operation ;
PAIR ;
DIP { DROP 2 } } }
```
2020-02-10 22:07:20 +04:00
However in order to originate a Michelson contract on Tezos, we also
need to provide the initial storage value, we can use
`compile-storage` to compile the LIGO representation of the storage to
Michelson.
```shell
ligo compile-storage src/counter.ligo main 5
// Outputs: 5
```
In our case the LIGO storage value maps 1:1 to its Michelson
representation, however this will not be the case once the parameter
is of a more complex data type, like a record.
## Invoking a LIGO contract
Same rules apply for parameters, as apply for translating LIGO storage
values to Michelson. We will need to use `compile-parameter` to
compile our `action` variant into Michelson, here's how:
```shell
ligo compile-parameter src/counter.ligo main 'Increment(5)'
// Outputs: (Right 5)
```
2020-02-10 22:07:20 +04:00
Now we can use `(Right 5)` which is a Michelson value, to invoke our
contract - e.g., via `tezos-client`