2020-01-17 09:50:45 +04:00
|
|
|
---
|
|
|
|
id: tezos-specific
|
|
|
|
title: Tezos Domain-Specific Operations
|
|
|
|
---
|
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
LIGO is a programming language for writing Tezos smart contracts. It
|
|
|
|
would be a little odd if it did not have any Tezos specific
|
|
|
|
functions. This page will tell you about them.
|
2020-01-17 09:50:45 +04:00
|
|
|
|
2020-02-10 22:07:20 +04:00
|
|
|
## Pack and Unpack
|
2020-01-17 09:50:45 +04:00
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
Michelson provides the `PACK` and `UNPACK` instructions for data
|
2020-02-12 01:29:12 +04:00
|
|
|
serialization. The former converts Michelson data structures into a
|
|
|
|
binary format, and the latter reverses that transformation. This
|
|
|
|
functionality can be accessed from within LIGO.
|
2020-01-17 09:50:45 +04:00
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
> ⚠️ `PACK` and `UNPACK` are Michelson instructions that are intended
|
|
|
|
> to be used by people that really know what they are doing. There are
|
|
|
|
> several risks and failure cases, such as unpacking a lambda from an
|
2020-02-12 01:29:12 +04:00
|
|
|
> untrusted source or casting the result to the wrong type. Do not use
|
|
|
|
> the corresponding LIGO functions without doing your homework first.
|
2020-01-17 09:50:45 +04:00
|
|
|
|
|
|
|
<!--DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
<!--PascaLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```pascaligo group=a
|
|
|
|
function id_string (const p : string) : option (string) is block {
|
|
|
|
const packed : bytes = bytes_pack (p)
|
2020-02-25 21:07:53 +04:00
|
|
|
} with (Bytes.unpack (packed) : option (string))
|
2020-01-17 09:50:45 +04:00
|
|
|
```
|
|
|
|
|
2020-02-25 21:07:53 +04:00
|
|
|
> Note that `bytes_unpack` is *deprecated*.
|
|
|
|
|
2020-01-17 09:50:45 +04:00
|
|
|
<!--CameLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```cameligo group=a
|
|
|
|
let id_string (p : string) : string option =
|
2020-01-17 09:50:45 +04:00
|
|
|
let packed: bytes = Bytes.pack p in
|
2020-02-05 19:28:40 +04:00
|
|
|
(Bytes.unpack packed : string option)
|
2020-01-17 09:50:45 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--ReasonLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```reasonligo group=a
|
|
|
|
let id_string = (p : string) : option (string) => {
|
|
|
|
let packed : bytes = Bytes.pack (p);
|
|
|
|
(Bytes.unpack(packed) : option (string));
|
2020-01-17 09:50:45 +04:00
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
## Hashing Keys
|
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
It is often desirable to hash a public key. In Michelson, certain data
|
|
|
|
structures such as maps will not allow the use of the `key` type. Even
|
|
|
|
if this were not the case, hashes are much smaller than keys, and
|
2020-02-10 22:22:52 +04:00
|
|
|
storage on blockchains comes at a cost premium. You can hash keys with
|
|
|
|
a predefined functions returning a value of type `key_hash`.
|
2020-01-18 11:19:49 +04:00
|
|
|
|
2020-01-17 09:50:45 +04:00
|
|
|
<!--DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
<!--PascaLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```pascaligo group=b
|
2020-02-10 22:07:20 +04:00
|
|
|
function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash is
|
|
|
|
block {
|
|
|
|
var ret : bool := False;
|
|
|
|
var kh2 : key_hash := crypto_hash_key (k2);
|
|
|
|
if kh1 = kh2 then ret := True else skip
|
|
|
|
} with (ret, kh2)
|
2020-01-17 09:50:45 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--CameLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```cameligo group=b
|
|
|
|
let check_hash_key (kh1, k2 : key_hash * key) : bool * key_hash =
|
2020-01-17 09:50:45 +04:00
|
|
|
let kh2 : key_hash = Crypto.hash_key k2 in
|
2020-02-05 19:28:40 +04:00
|
|
|
if kh1 = kh2 then true, kh2 else false, kh2
|
2020-01-17 09:50:45 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--ReasonLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```reasonligo group=b
|
|
|
|
let check_hash_key = ((kh1, k2) : (key_hash, key)) : (bool, key_hash) => {
|
2020-02-12 01:29:12 +04:00
|
|
|
let kh2 : key_hash = Crypto.hash_key (k2);
|
2020-02-05 19:28:40 +04:00
|
|
|
if (kh1 == kh2) { (true, kh2); } else { (false, kh2); }
|
2020-01-17 09:50:45 +04:00
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
2020-01-17 14:08:07 +04:00
|
|
|
|
|
|
|
## Checking Signatures
|
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
Sometimes a contract will want to check that a message has been signed
|
|
|
|
by a particular key. For example, a point-of-sale system might want a
|
|
|
|
customer to sign a transaction so it can be processed
|
|
|
|
asynchronously. You can do this in LIGO using the `key` and
|
|
|
|
`signature` types.
|
2020-01-18 11:19:49 +04:00
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
> ⚠️ There is no way to *generate* a signed message in LIGO. This is
|
|
|
|
> because that would require storing a private key on chain, at which
|
|
|
|
> point it is not... private anymore.
|
2020-01-17 14:08:07 +04:00
|
|
|
|
|
|
|
<!--DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
<!--PascaLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```pascaligo group=c
|
2020-01-17 14:08:07 +04:00
|
|
|
function check_signature
|
2020-02-05 19:28:40 +04:00
|
|
|
(const pk : key;
|
|
|
|
const signed : signature;
|
|
|
|
const msg : bytes) : bool
|
2020-02-25 21:07:53 +04:00
|
|
|
is Crypto.check (pk, signed, msg)
|
2020-01-17 14:08:07 +04:00
|
|
|
```
|
|
|
|
|
2020-02-25 21:07:53 +04:00
|
|
|
> Note that `crypto_check` is *deprecated*.
|
|
|
|
|
2020-01-17 14:08:07 +04:00
|
|
|
<!--CameLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```cameligo group=c
|
|
|
|
let check_signature (pk, signed, msg : key * signature * bytes) : bool =
|
2020-01-17 14:08:07 +04:00
|
|
|
Crypto.check pk signed msg
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--ReasonLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```reasonligo group=c
|
|
|
|
let check_signature =
|
2020-02-12 01:29:12 +04:00
|
|
|
((pk, signed, msg) : (key, signature, bytes)) : bool =>
|
2020-02-05 19:28:40 +04:00
|
|
|
Crypto.check (pk, signed, msg);
|
2020-01-17 14:08:07 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
2020-01-21 14:45:38 +04:00
|
|
|
|
2020-02-10 22:07:20 +04:00
|
|
|
## Contract's Own Address
|
2020-01-21 14:45:38 +04:00
|
|
|
|
2020-02-05 19:28:40 +04:00
|
|
|
Often you want to get the address of the contract being executed. You
|
2020-02-25 21:07:53 +04:00
|
|
|
can do it with `Tezos.self_address`.
|
|
|
|
|
|
|
|
> Note that `self_address` is *deprecated*.
|
2020-02-05 19:28:40 +04:00
|
|
|
|
2020-02-25 21:07:53 +04:00
|
|
|
> ⚠️ Due to limitations in Michelson, `Tezos.self_address` in a
|
|
|
|
> contract is only allowed at the top-level. Using it in an embedded
|
|
|
|
> function will cause an error.
|
2020-01-21 14:45:38 +04:00
|
|
|
|
|
|
|
<!--DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
<!--PascaLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```pascaligo group=d
|
2020-02-25 21:07:53 +04:00
|
|
|
const current_addr : address = Tezos.self_address
|
2020-01-21 14:45:38 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--CameLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```cameligo group=d
|
2020-02-25 21:07:53 +04:00
|
|
|
let current_addr : address = Tezos.self_address
|
2020-01-21 14:45:38 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--ReasonLIGO-->
|
2020-02-05 19:28:40 +04:00
|
|
|
```reasonligo group=d
|
2020-02-25 21:07:53 +04:00
|
|
|
let current_addr : address = Tezos.self_address;
|
2020-01-21 14:45:38 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
<!--END_DOCUSAURUS_CODE_TABS-->
|
2020-03-02 16:35:26 +04:00
|
|
|
|
|
|
|
## Origination of a contract
|
|
|
|
|
|
|
|
`Tezos.create_contract` allows you to originate a contract given its code, delegate (if any), initial balance and initial storage.
|
|
|
|
The return value is a pair of type `(operation * address)`.
|
|
|
|
|
|
|
|
> ⚠️ Due to limitations in Michelson, `Tezos.create_contract` first argument
|
|
|
|
> must be inlined and must not contain references to free variables
|
|
|
|
|
|
|
|
<!--DOCUSAURUS_CODE_TABS-->
|
|
|
|
|
|
|
|
<!--PascaLIGO-->
|
|
|
|
```pascaligo group=e
|
|
|
|
const origination : operation * address = Tezos.create_contract (
|
|
|
|
function (const p : nat; const s : string): list(operation) * string is ((nil : list(operation)), s),
|
|
|
|
(None : option(key_hash)),
|
|
|
|
3tz,
|
|
|
|
"initial_storage")
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--CameLIGO-->
|
|
|
|
```cameligo group=e
|
|
|
|
let origination : operation * address = Tezos.create_contract
|
|
|
|
(fun (p, s : nat * string) -> (([] : operation list), s))
|
|
|
|
(None: key_hash option)
|
|
|
|
3tz
|
|
|
|
"initial_storage"
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--ReasonLIGO-->
|
|
|
|
```reasonligo group=e
|
|
|
|
let origination : (operation, address) = Tezos.create_contract (
|
|
|
|
((p, s) : (nat,string)) : (list(operation),string) => (([] : list(operation)), s),
|
|
|
|
None: option(key_hash),
|
|
|
|
3tz,
|
|
|
|
"initial_storage")
|
|
|
|
```
|
|
|
|
|
|
|
|
<!--END_DOCUSAURUS_CODE_TABS-->
|