-
Notifications
You must be signed in to change notification settings - Fork 39
/
README.md
280 lines (202 loc) · 10.5 KB
/
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# Zoe Overview
## What is Zoe?
Zoe is Agoric's smart contract framework. Use Zoe to:
* **Run your code on-chain**
* **Mint new digital assets**
* **Credibly trade assets**
## Why Use Zoe?
### For Users ###
**Zoe is safer.** Traditionally, putting digital assets in a smart
contract has carried the risk of losing them. But Zoe guarantees you get either
what you wanted or a full refund of the assets you put in. You will
never leave a smart contract empty-handed, even if it is buggy or malicious.
### For Developers ###
**Zoe is easier.** Traditionally, writing a smart contract meant
learning a new, untried language. And don't make any mistakes - if you
do, your users might lose millions.
However, you write Zoe contracts in a secure subset of JavaScript.
Moreover, Zoe automatically escrows all user digital assets and
handles their subsequent payout. **Even a buggy contract can't cause
users to lose their assets.**
### Contracts on Zoe
Agoric has written [a number of example contracts that you can
use](/zoe/guide/contracts/), including:
* an [Automated Market Maker (AMM)
implementation](/zoe/guide/contracts/constantProductAMM.md)
* a [covered call option contract](./contracts/covered-call.md)
* an [OTC Desk market maker contract](./contracts/otc-desk.md)
* contracts for [minting fungible](./contracts/mint-payments.md) and
[non-fungible tokens](./contracts/mint-and-sell-nfts.md)
## Using an Example Zoe Smart Contract
You must have a Zoe invitation to a specific contract instance to join
and participate in it. Let's imagine your friend Alice has sent an
invitation for a contract instance to your [wallet](/guides/wallet/).
Compare this to a smart contract on Ethereum. On Ethereum, the smart
contract developer must guard against malicious calls and store an
internal access control list to check whether the message sender is
allowed to send such a message. Zoe, built on Agoric's [object
capability](/glossary/#object-capabilities) security model, is just
easier.
This particular invitation is for an [Atomic Swap
contract](/zoe/guide/contracts/atomic-swap.md).
In an Atomic Swap, one party puts up digital assets they want to
exchange and sends an invitation to a second party for them to
possibly complete the exchange. In this example, Alice has already
escrowed the assets she wants to swap and is asking you to pay a
specified price to receive her digital assets.
### Inspecting an Invitation
So you have an invitation, but how do you use it? First, you use Zoe
to inspect and validate the invitation.
<<< @/snippets/test-intro-zoe.js#details
::: warning Note
E() is part of the Agoric platform and is used to [call methods on
remote objects and receive a promise for the
result](/guides/js-programming/eventual-send.md).
Code on the Agoric platform is put in separate environments, called
[vats](/glossary/#vat), for security. Zoe is a remote object in its own vat,
so we must use E().
:::
Invitations include information about their contract's installation.
Essentially, this is the contract's source code as installed on Zoe.
From this overall contract installation, people use Zoe to create and
run specific instances of the contract. For example, if a real estate
company has a contract for selling a house, they would create an
instance of the contract for each individual house they have up for
sale.
You use object identity comparison to quickly check that you recognize
this contract installation, without having to compare source code
line-by-line. If the installation matches, you're
sure the invitation is for participating in an instance of the
expected contract rather than an unknown and possibly malicious one.
<<< @/snippets/test-intro-zoe.js#isCorrectCode
However, if you don't recognize the installation, you can inspect its
code directly by calling:
<<< @/snippets/test-intro-zoe.js#inspectCode
In most cases, the bundle contains a base64-encoded zip file that you can
extract for review:
```sh
echo "$endoZipBase64" | base64 -d > bundle.zip
unzip bundle.zip
```
Contracts can add their own specific information to invitations. In
this case, the Atomic Swap contract adds information about what is
being traded: the `asset` [amount](/guides/ertp/amounts.md#amounts)
Alice has escrowed, and the `price` amount that you must pay to get it.
Note that both are _descriptions_ of digital assets with no intrinsic value of their own.
### Making an Offer
You've successfully checked out the invitation, so now you can make an
offer.
An offer has three required parts:
* a Zoe invitation
* a proposal
* a [payment](/guides/ertp/purses-and-payments.md#payments) containing
the digital assets you're offering to swap
The `proposal` states what you want from the offer, and what you will
give in return. Zoe uses the proposal as an invariant to ensure you
don't lose your assets in the trade. This invariant is known as **offer
safety**.
You use the invitation's `asset` and `price` amounts to make your
proposal. Let's say `asset` is an amount of 3 Moola, and `price` is an amount
of 7 Simoleans (Moola and Simoleans are made-up currencies for this example).
<<< @/snippets/test-intro-zoe.js#ourProposal
Proposals must use Keywords, which are
[identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier)
properties that start with an upper case letter and contain no non-ASCII characters.
Here, the specific keywords, `Asset` and `Price`, are [determined by the
contract code](/zoe/guide/contracts/atomic-swap.md).
You said you would give 7 Simoleans, so you must send 7 Simoleans as a payment.
You happen to have some Simoleans lying around in a Simolean
[purse](/guides/ertp/purses-and-payments.md) (used to hold digital
assets of a specific type). You withdraw a payment of 7 Simoleans from
the purse for your offer, and construct an object using the same
Keyword as your `proposal.give`:
<<< @/snippets/test-intro-zoe.js#getPayments
Now you need to [harden](https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.md) your
just created `proposal` and `payments` objects. Hardening is
transitively freezing an object. For security reasons, we must harden
any objects that will be passed to a remote object like Zoe.
<<< @/snippets/test-intro-zoe.js#harden
You've put the required pieces together, so now you can make an offer:
<<< @/snippets/test-intro-zoe.js#offer
At this point, Zoe confirms your invitation's validity and [burns](/glossary/#burn) it.
Zoe also escrows your payments, representing their value as
amounts in your **[Allocation](/reference/zoe-api/zoe-data-types.md#allocation)**
in the contract.
::: tip Troubleshooting missing brands in offers
If you see...
```
Error#1: key Object [Alleged: IST brand] {} not found in collection brandToIssuerRecord
```
then it may be that your offer uses brands that are not known to the contract.
Use [E(zoe).getTerms()](/reference/zoe-api/zoe.md#e-zoe-getterms-instance) to find out what issuers
are known to the contract.
If you're writing or instantiating the contract, you can tell the contract about issuers
when you are [creating an instance](#creating-an-instance) or by using
[zcf.saveIssuer()](/reference/zoe-api/zoe-contract-facet.md#zcf-saveissuer-issuer-keyword).
:::
### Using Your UserSeat
Making an offer as a user returns a [UserSeat](/reference/zoe-api/user-seat.md)
representing your position in the ongoing contract instance (your
"seat at the table"). You can use this seat to:
1. Exit the contract.
2. Get information about your position such as your current allocation.
3. Get your payouts from Zoe.
Check that your offer was successful:
<<< @/snippets/test-intro-zoe.js#offerResult
In response to your offer, the `atomicSwap` contract returns the
message: "The offer has been accepted. Once the contract has been
completed, please check your payout." Other contracts and offers may
return something different. The offer's result is entirely up to the
contract.
### Getting Payouts
The `atomicSwap` contract of this example is over once the second
party escrows the correct assets. You can get your payout of Moola
with the Keyword you used ('Asset'):
<<< @/snippets/test-intro-zoe.js#getPayout
Alice also receives her payouts:
<div class="language-js secondary">
<<< @/snippets/test-intro-zoe.js#alicePayout
</div>
## Writing and Installing a Contract
Now that you've seen how to participate in a contract instance, let's
look at how you'd create a contract and its instances.
Let's pretend Alice wrote that contract from scratch, even though
`atomicSwap` is one of Agoric's example contracts (see [Atomic Swap](./contracts/atomic-swap.md)).
Note: All Zoe contracts must have this format:
::: details Show contract format
<<< @/snippets/contract-format.js#contractFormat
:::
Alice fills in this code template with `atomicSwap`'s particulars.
To install this particular code, Alice first must bundle it off-chain,
meaning the code and its imports are flattened together:
<<< @/snippets/test-intro-zoe.js#importBundleSource
<<< @/snippets/test-intro-zoe.js#bundle
Then Alice must install it on Zoe:
<<< @/snippets/test-intro-zoe.js#install
The return value is an `installation`, which we saw
[earlier](#inspecting-an-invitation). It is an
object identifying a particular piece of code installed on Zoe. It can
be compared to other installations, and you can call
`E(atomicSwapInstallation).getBundle()` to see the code itself.
### Creating an Instance
Now Alice uses the installation to create a new instance. She must
also tell Zoe about the ERTP issuers she wants to use, by specifying
their role with Keywords. Alice was escrowing Moola, so she uses the
keyword `Asset` to label the `moolaIssuer`. She wanted Simoleans, so
she uses the keyword `Price` to label the `simoleanIssuer`.
<<< @/snippets/test-intro-zoe.js#startInstance
Even the creator of a contract instance needs an invitation to
participate in it. Alice uses the returned `creatorInvitation` to
make an offer, from which she gets an invitation that can be sent to
the counter-party.
<<< @/snippets/test-intro-zoe.js#aliceOffer
## Zoe's Two Sides: Zoe Service and Zoe Contract Facet (ZCF)
You may have noticed the contract code's `start` method has a `zcf`
parameter. This is the Zoe Contract Facet. Zoe has two sides: the Zoe
Service, which you've seen users interact with, and the Zoe Contract
Facet (ZCF), which is accessible to the contract code. Note that users
have access to the Zoe Service, but do not have access to ZCF.
Contract code has access to ZCF *and* can get access to the Zoe
Service.
To learn more about the Zoe Service, Zoe Contract Facet, and Zoe
Helper APIs, [see our Zoe API documentation](/reference/zoe-api/).