Skip to content

Commit 4523fc7

Browse files
committed
doc: tickets with CLI
1 parent ae187f3 commit 4523fc7

File tree

2 files changed

+199
-1
lines changed

2 files changed

+199
-1
lines changed

docs/Deku-Canonical/deku_c_cli.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ This will create a new file called `wallet.json`, containing something like
3434
}
3535
```
3636

37+
### Displaying the balance of an account
38+
39+
Unlike Tezos, Deku does not use a native currency. Instead, accounts directly own tickets, which can
40+
be either Tezos-originated and deposited via the bridge, or Deku-originated tickets.
41+
42+
To display the balance of a given account, use the following command:
43+
44+
```bash
45+
deku-cli show-balance address [ticket ID]
46+
```
47+
where
48+
- `address` is the account's address
49+
- `ticket ID` is an optional parameter to get the result for a specific ticket ID, given with the
50+
form `ticketer bytes`
51+
3752
### Originating a contract
3853

3954
Deku-C uses a WASM virtual machine, for which you can target with a variety of languages. In particular, you can
@@ -104,14 +119,16 @@ the contract and the raw code of the contract.
104119
The `invoke` command allows to call an entrypoint with a specific parameter. Usage:
105120

106121
```bash
107-
deku-cli wallet contract_address parameter
122+
deku-cli wallet contract_address parameter [ticket ID and amount]
108123
```
109124

110125
where
111126

112127
- `wallet` is a path towards a wallet file
113128
- `contract_address` is the address of the smart contract on the Deku-C chain
114129
- `parameter` is the Michelson expression of the entrypoint and its argument
130+
- `ticket ID and amount` is an optional parameter which allows Deku to send tickets when calling an
131+
entrypoint which consumes tickets.
115132

116133
The `parameter` can be provided by the Ligo compiler using the `ligo compile parameter` command.
117134

@@ -125,3 +142,7 @@ where
125142
- `contract_path` is the path towards the contract source code, which is required to compile the
126143
expression
127144
- `expression` is the Ligo expression to compile
145+
146+
Finally, when calling a contract entrypoint which expects tickets, it is necessary to add the ticket
147+
ID and the amount transferred as the last arguments, for security reasons. The next chapter gives
148+
several examples of tickets usage on Deku.
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
---
2+
sidebar_position: 4
3+
---
4+
5+
# Handling tickets in Deku
6+
7+
Unlike Tezos, Deku does not have an native currency, but tickets. These tickets are directly owned
8+
by the accounts, and can be transferred between accounts or directly sent to smart contracts using
9+
the client. In this chapter, we show how to mint and send tickets on Deku.
10+
11+
## Minting tickets in Deku
12+
13+
Here is an example, written in JSLigo, of a smart contract that expects `bytes` and mints a `byte
14+
ticket` before sending it back to the sender:
15+
16+
```jsligo
17+
type storage = unit;
18+
19+
const transfer_ticket = (ticket:ticket<bytes>, target: address) => {
20+
return match(Tezos.get_contract_opt (target), {
21+
None: () => (failwith("Incorrect address")),
22+
Some: (c:contract<unit>) => {
23+
return Tezos.transaction (ticket, (0 as mutez), c);
24+
}
25+
});
26+
};
27+
28+
const main = (payload: bytes, storage: storage) => {
29+
let ticket = Tezos.create_ticket (payload, (100 as nat));
30+
let op = transfer_ticket(ticket, Tezos.get_sender ());
31+
return [list([op]), storage];
32+
}
33+
```
34+
35+
This contract is fairly straightforward: the `storage` does not change, and the `main` function simply takes the bytes `payload` from the sender, uses it to mint 100 tickets and send those to the sender. As on Tezos, implicit accounts are represented as contracts of the `unit` type.
36+
37+
Here is how to compile and originate the contract on Deku:
38+
39+
```bash
40+
$ ligo compile contract ticket.jsligo > ticket.tz
41+
$ deku-cli originate wallet.json ticket.tz 'Unit'
42+
operation hash: Do3UPjj84fPZnsR43shUUUhaj3pRJjbXrketwNThEwjJctAUgHAE
43+
Contract originated at address DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz
44+
```
45+
46+
This contract can now be called to mint some tickets:
47+
48+
```bash
49+
$ deku-cli invoke --endpoint http://0.0.0.0:8080 wallet.json DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz '0x'
50+
operation hash: Do2MZ9egKWCtEXz7MLVcDFGvB19CHaAiaJg5nXU8we5ey4HXL8UJ
51+
$ deku-cli show-balance tz1Vhy8BWXdQNm6wNFi36hWj4iSoGqBrMB4v
52+
[
53+
{
54+
ticket: { ticketer: 'DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz', data: '' },
55+
amount: 100
56+
}
57+
]
58+
```
59+
60+
Fresh tickets, nice!
61+
62+
## Consuming tickets in a smart contract
63+
64+
Let's take a look at tickets consumption by smart contracts. Here's an example of contract that
65+
waits
66+
for a ticket and an address, stores the ticket, and sends the ticket to the user when they request
67+
it.
68+
69+
```jsligo
70+
type deposit = option<[address, ticket<bytes>]>;
71+
72+
type storage = {
73+
deposit: deposit
74+
};
75+
76+
type entrypoint =
77+
| ["Deposit", ticket<bytes>, address]
78+
| ["Withdraw"]
79+
80+
const transfer_ticket = (ticket:ticket<bytes>, target: address) => {
81+
return match(Tezos.get_contract_opt (target), {
82+
None: () => (failwith("Incorrect address")),
83+
Some: (c:contract<unit>) => {
84+
return Tezos.transaction (ticket, (0 as mutez), c);
85+
}
86+
});
87+
};
88+
89+
const main = (action: entrypoint, storage: storage) => {
90+
return match(action, {
91+
Deposit: (deposit:[ticket<bytes>, address]) => {
92+
let [ticket, to_] = deposit;
93+
assert_none(storage.deposit);
94+
let [[_ticketer, [_data, _amount]], ticket] = Tezos.read_ticket(ticket);
95+
let deposit = Some([to_, ticket]);
96+
return [list([]), {deposit}];
97+
},
98+
Withdraw: () => {
99+
let sender = Tezos.get_sender();
100+
let [address, ticket] = Option.unopt_with_error(
101+
storage.deposit, "Nothing to withdraw."
102+
);
103+
assert_with_error(address == sender, "You're not allowed to withdraw");
104+
let transaction = transfer_ticket(ticket, address);
105+
return [list([transaction]), {deposit:None()}];
106+
}
107+
});
108+
}
109+
```
110+
First, notice that this contract's storage is more involved than the previous one, as we need to
111+
store an address and a ticket so that another user can retrieve it. The `main` function waits for a
112+
deposit when the storage is `None`, and a withdraw otherwise.
113+
114+
Let's name this contract `vault.jsligo`. Compilation and origination are the same as before:
115+
116+
```bash
117+
$ ligo compile contract vault.jsligo > vault.tz
118+
$ deku-cli originate wallet.json vault.tz 'None'
119+
operation hash: Do2p2Le3he2kwnng7SKcizNq3715FcsaysCohFrPgVd9zFNfwc56
120+
Contract originated at address DK141PdoGDp9gZea9okEiPJfL3Y9z5GhhZ5T
121+
```
122+
123+
First, let's inspect this contract's storage:
124+
125+
```bash
126+
$ deku-cli show-storage DK141PdoGDp9gZea9okEiPJfL3Y9z5GhhZ5T
127+
{ none: true }
128+
```
129+
130+
This prints the VM's state for this contract, which does not follow Tezos and Michelson's
131+
conventions. However it seems to match the value we provided when we originated — so far, so good.
132+
133+
Let's make a deposit. Unfortunately, we can't ask the Ligo compiler to produce the command line
134+
argument for us, nor we can use the `invoke-ligo` endpoint: indeed, for the moment there is no way
135+
to represent a ticket expression in Ligo to give to these commands! We thus have to write it by
136+
hand.
137+
138+
We know we want to call the first entrypoint, so the expression has to start with `Left`. We also
139+
want to give two arguments: the ticket itself (with an amount) and the deposit address, so we'll
140+
have to use `Pair`s. The ticket is designated by the minting contract (called the "ticketer"), the
141+
data bytes and an amount. Using the ticket from the previous contract, we get the following
142+
Michelson expression:
143+
144+
```
145+
'Left (Pair (Pair "DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz" 0x 10) "tz1Vhy8BWXdQNm6wNFi36hWj4iSoGqBrMB4v")'
146+
```
147+
148+
As noted in the previous chapter though, in order for Deku to accept to change our balance, we have
149+
to explicitely give permission to handle this ticket, by writing its information again after the
150+
`invoke` argument. Finally this gives us the following command:
151+
152+
```bash
153+
$ deku-cli invoke wallet.json DK141PdoGDp9gZea9okEiPJfL3Y9z5GhhZ5T \
154+
'Left (Pair (Pair "DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz" 0x 10) \
155+
"tz1Vhy8BWXdQNm6wNFi36hWj4iSoGqBrMB4v")' \
156+
'(Pair "DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz" 0x 10)'
157+
```
158+
159+
This command can be made shorter using a variable:
160+
161+
```bash
162+
$ TICKET='(Pair "DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz" 0x 10)'
163+
$ deku-cli invoke wallet.json DK141PdoGDp9gZea9okEiPJfL3Y9z5GhhZ5T \
164+
"Left (Pair $TICKET \"tz1Vhy8BWXdQNm6wNFi36hWj4iSoGqBrMB4v\")" "$TICKET"
165+
```
166+
167+
Let's check out balance to see if the deposit worked:
168+
169+
```bash
170+
$ deku-cli show-balance tz1Vhy8BWXdQNm6wNFi36hWj4iSoGqBrMB4v
171+
[
172+
{
173+
ticket: { ticketer: 'DK1JxMLmohbyKXbGhQWLJZyktSsZKGxaM6jz', data: '' },
174+
amount: 90
175+
}z
176+
]
177+
```

0 commit comments

Comments
 (0)