Skip to content

Commit 29b8a95

Browse files
feat(doc): updated taco shop tutorial
1 parent fc24410 commit 29b8a95

File tree

32 files changed

+1416
-1770
lines changed

32 files changed

+1416
-1770
lines changed

gitlab-pages/docs/tutorials/getting-started/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,4 +575,4 @@ octez-client get contract storage for counter
575575
Now you have a simple LIGO smart contract and can test it, deploy it, and call it.
576576
You can use it as a starting point to write your own contracts and experiment with LIGO.
577577

578-
You can also continue with the [Taco shop tutorial](../taco-shop/tezos-taco-shop-smart-contract) to learn more about programming with LIGO.
578+
You can also continue with the [Taco shop tutorial](../taco-shop/selling-tacos) to learn more about programming with LIGO.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
title: "Part 3: Getting the payouts"
3+
---
4+
5+
Now that the customer-facing entrypoint of the contract is ready, you can set up the administrator-related entrypoint.
6+
In this case, Pedro needs a way to reset the stock of tacos and send the tez from the contract to his account.
7+
You could do this in two entrypoints, but for simplicity this tutorial shows how to do both of these things in one entrypoint named `payout`.
8+
9+
## Adding administrator information
10+
11+
Also for the sake of simplicity, the contract provides no way to change Pedro's account address after the contract is deployed.
12+
In production applications, the address of the administrator should be in the contract storage and an entrypoint should allow the current administrator to change the administrator address.
13+
As it is, this contract cannot change the administrator address after it is deployed, so use caution.
14+
15+
1. In the `payout` entrypoint, add this code to verify that the administrator is calling the entrypoint:
16+
17+
```jsligo skip
18+
// Ensure that only the admin can call this entrypoint
19+
if (Tezos.get_sender() != storage.admin_address) {
20+
failwith("Only the admin can call this entrypoint");
21+
}
22+
```
23+
24+
The function `Tezos.get_sender` returns the address of the account that called the smart contract.
25+
26+
1. Add this code to generate the operation that sends tez to the administrator account:
27+
28+
```jsligo skip
29+
// Create contract object that represents the target account
30+
const receiver_contract = match(Tezos.get_contract_opt(storage.admin_address)) {
31+
when(Some(contract)): contract;
32+
when(None): failwith("Couldn't find account");
33+
};
34+
35+
// Create operation to send tez
36+
const payout_operation = Tezos.Operation.transaction(unit, Tezos.get_balance(), receiver_contract);
37+
```
38+
39+
Sending tez to a user account means treating the user account as though it is a smart contract account.
40+
This way, sending tez to a user account works in the same way as sending tez to a smart contract.
41+
42+
The `Tezos.Operation.transaction` function creates a Tezos transaction.
43+
There are many kinds of internal transactions in Tezos, but most smart contracts deal with these transactions:
44+
45+
- Transferring tez to another account
46+
- Calling an entrypoint on a smart contract
47+
48+
Calling an entrypoint on a smart contract (either the current contract or another contract) is beyond the scope of this tutorial.
49+
For information, see [Calling a contract](../../syntax/contracts/operation#calling-a-contract).
50+
51+
The `Tezos.Operation.transaction` function takes these parameters:
52+
53+
1. The parameter to pass, in this case `unit`, which means no value
54+
1. The amount of tez to include with the transaction, in this case all of the tez the contract has, denoted by the `Tezos.get_balance` function
55+
1. The address of the target contract
56+
57+
1. Add this code to calculate the new value of the storage, using the existing admin address and the default taco data:
58+
59+
```jsligo skip
60+
// Restore stock of tacos
61+
const new_storage: storage = {
62+
admin_address: storage.admin_address,
63+
taco_data: default_taco_data,
64+
};
65+
```
66+
67+
1. Replace the `payout` entrypoint's `return` statement with this code:
68+
69+
```jsligo skip
70+
return [[payout_operation], new_storage];
71+
```
72+
73+
Creating the transaction is not enough to run it; you must return it in the list of operations at the end of the entrypoint.
74+
75+
The complete entrypoint looks like this:
76+
77+
```jsligo skip
78+
@entry
79+
const payout = (_u: unit, storage: storage): [
80+
list<operation>,
81+
storage
82+
] => {
83+
84+
// Ensure that only the admin can call this entrypoint
85+
if (Tezos.get_sender() != storage.admin_address) {
86+
failwith("Only the admin can call this entrypoint");
87+
}
88+
89+
// Create contract object that represents the target account
90+
const receiver_contract = match(Tezos.get_contract_opt(storage.admin_address)) {
91+
when(Some(contract)): contract;
92+
when(None): failwith("Couldn't find account");
93+
};
94+
95+
// Create operation to send tez
96+
const payout_operation = Tezos.Operation.transaction(unit, Tezos.get_balance(), receiver_contract);
97+
98+
// Restore stock of tacos
99+
const new_storage: storage = {
100+
admin_address: storage.admin_address,
101+
taco_data: default_taco_data,
102+
};
103+
104+
return [[payout_operation], new_storage];
105+
}
106+
```
107+
108+
That's all you need to do to reset the storage and send the contract's tez to the administrator.
109+
If you want to extend this logic, try separating the `payout` entrypoint into separate entrypoints for paying out the tez and resetting the stock of tacos.
110+
111+
## Testing the new entrypoint
112+
113+
Of course, after you implement the `payout` entrypoint, you should add tests for it.
114+
115+
1. At the end of the test function, add this code to get the current balance of Pedro's account before calling the entrypoint:
116+
117+
```jsligo skip
118+
// Test the payout entrypoint as the administrator
119+
const admin_balance_before = Test.Address.get_balance(admin_address);
120+
```
121+
122+
1. Add this code to set the account that smart contract calls come from in the test scenario:
123+
124+
```jsligo skip
125+
Test.State.set_source(admin_address);
126+
```
127+
128+
Now when you call the `Test.Contract.transfer` function, the transaction comes from Pedro's account.
129+
130+
1. Add this code to call the `payout` entrypoint and verify that the storage was updated, as in previous tests:
131+
132+
```jsligo skip
133+
const payout_result =
134+
Test.Contract.transfer(
135+
Test.Typed_address.get_entrypoint("payout", contract.taddr),
136+
unit,
137+
0tez
138+
);
139+
match(payout_result) {
140+
when(Success(_s)):
141+
do {
142+
const storage = Test.Typed_address.get_storage(contract.taddr);
143+
// Check that the stock has been reset
144+
Assert.assert(
145+
eq_in_map(
146+
Map.find(1n, TacoShop.default_taco_data),
147+
storage.taco_data,
148+
1n
149+
));
150+
Assert.assert(
151+
eq_in_map(
152+
Map.find(2n, TacoShop.default_taco_data),
153+
storage.taco_data,
154+
2n
155+
));
156+
Test.IO.log("Successfully reset taco storage");
157+
}
158+
when(Fail(_err)): failwith("Failed to reset taco storage");
159+
};
160+
```
161+
162+
1. Add this code to verify that Pedro's account received the tez from the contract:
163+
164+
```jsligo skip
165+
// Check that the admin account got a payout
166+
const admin_balance_after = Test.Address.get_balance(admin_address);
167+
Assert.assert(Test.Compare.lt(admin_balance_before, admin_balance_after));
168+
```
169+
170+
The exact amounts differ because calling the `payout` entrypoint costs a small fee.
171+
172+
1. Add this code to generate a test account and verify that it can not call the `payout` entrypoint because it is not the administrator:
173+
174+
```jsligo skip
175+
// Verify that the entrypoint fails if called by someone else
176+
const other_user_account = Test.Account.address(1n);
177+
Test.State.set_source(other_user_account);
178+
const payout_result =
179+
Test.Contract.transfer(
180+
Test.Typed_address.get_entrypoint("payout", contract.taddr),
181+
unit,
182+
0tez
183+
);
184+
match(payout_result) {
185+
when(Success(_s)): failwith("A non-admin user was able to call the payout entrypoint");
186+
when(Fail(_err)): Test.IO.log("Successfully prevented a non-admin user from calling the payout entrypoint");
187+
};
188+
```
189+
190+
1. Run the test with `ligo run test taco_shop.jsligo` and verify that the test runs successfully.
191+
192+
Now you can allow different users to do different things in the contract.
193+
194+
## Conclusion
195+
196+
Now you have a contract that Pedro can use to sell tacos and manage the profits and the taco stock.
197+
From here you can expand the contract in many ways, such as:
198+
199+
- Adding more types of tacos
200+
- Changing how the price of tacos is calculated
201+
- Expanding the administrator functionality
202+
- Accepting more than the price of the taco as a tip
203+
- Adding more tests
204+
205+
You can also try deploying the contract to a test network and trying it in a real Tezos environment.
206+
For a tutorial that covers deploying a contract, see [Deploy a smart contract](https://docs.tezos.com/tutorials/smart-contract) on docs.tezos.com.

0 commit comments

Comments
 (0)