diff --git a/main/guides/zoe/README.md b/main/guides/zoe/README.md index 4a64d76a7..bf38c8f9f 100644 --- a/main/guides/zoe/README.md +++ b/main/guides/zoe/README.md @@ -72,6 +72,22 @@ The test uses `createRequire` from the node `module` API to resolve the main mod <<< @/snippets/zoe/contracts/test-bundle-source.js#testBundleSource{1} +::: details Getting the zip file from inside a bundle + +An endo bundle is a zip file inside JSON. To get it back out: + +```sh +jq -r .endoZipBase64 bundle-xyz.json | base64 -d >xyz.zip +``` + +You can then, for example, look at its contents: + +```sh +unzip -l xyz.zip +``` + +::: + ## Contract Installation To identify the code of contracts that parties consent to participate in, Zoe @@ -217,6 +233,24 @@ She then requests an _invitation_ to join the game; makes an _offer_ with this i <<< @/snippets/zoe/contracts/test-alice-trade.js#trade +::: details 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). + +::: + The contract gets Alice's `E(publicFacet).makeJoinInvitation()` call and uses `zcf` to make an invitation with an associated handler, description, and proposal shape. Zoe gets Alice's `E(zoe).offer(...)` call, checks the proposal against the proposal shape, escrows the payment, and invokes the handler. <<< @/snippets/zoe/contracts/gameAssetContract.js#makeInvitation @@ -242,7 +276,7 @@ and tests that it's what she wanted. <<< @/snippets/zoe/contracts/test-alice-trade.js#payouts -### Contracts on Zoe +## Example Contracts Agoric has written [a number of example contracts that you can use](/zoe/guide/contracts/), including: @@ -254,247 +288,9 @@ use](/zoe/guide/contracts/), including: - contracts for [minting fungible](./contracts/mint-payments.md) and [non-fungible tokens](./contracts/mint-and-sell-nfts.md) -## Using an Example Zoe Smart Contract +::: warning Beta Features -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/). +These contracts may depend on features from our Beta release +that are not available in mainnet. -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 -@@@@@@ -jq -r .endoZipBase64 bundle-game1aginst.json | base64 -d >game1aginst.zip - -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: - -