From d637afb1a07e52f54858c7c12a30f6d846ae7574 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:35:37 -0500 Subject: [PATCH 01/36] chore: Replace "here" link text with more descriptive names --- main/glossary/README.md | 6 +++--- main/guides/js-programming/notifiers.md | 2 +- main/reference/repl/README.md | 5 +++-- main/reference/zoe-api/README.md | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index bfea1e66d..104a7d2d5 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -171,7 +171,7 @@ appropriately branded assets to the purse, but cannot withdraw assets from the p ## dIBC Dynamic version of the [Inter-Blockchain Communication](#ibc) protocol. -See [here](https://github.com/Agoric/agoric-sdk/blob/HEAD/packages/SwingSet/docs/networking.md) for more details. +For more details, see the [agoric-sdk `network` package](https://github.com/Agoric/agoric-sdk/tree/master/packages/network). ## E() @@ -280,8 +280,8 @@ Guide](https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.md) for ## IBC -The Inter-Blockchain Communication protocol, used by blockchains to communicate with each other. A short article about IBC -is available [here](https://www.computerweekly.com/blog/Open-Source-Insider/What-developers-need-to-know-about-inter-blockchain-communication). +The Inter-Blockchain Communication protocol, used by blockchains to communicate with each other. +For more details, see [What developers need to know about inter-blockchain communication](https://www.computerweekly.com/blog/Open-Source-Insider/What-developers-need-to-know-about-inter-blockchain-communication). ## Invitation diff --git a/main/guides/js-programming/notifiers.md b/main/guides/js-programming/notifiers.md index 60b9c338f..19af093a2 100644 --- a/main/guides/js-programming/notifiers.md +++ b/main/guides/js-programming/notifiers.md @@ -7,7 +7,7 @@ many clients to receive notifications without the originator having to track a s An object wanting to publish updates to interested clients makes a notifier or a subscription available to them. -In JavaScript, async iterations are manipulated by `AsyncGenerators`, `AsyncIterables`, and `AsyncIterators`. For an introduction to them, see [here](https://javascript.info/async-iterators-generators). +In JavaScript, async iterations are manipulated by `AsyncGenerators`, `AsyncIterables`, and `AsyncIterators`. For an introduction to them, see [Async iteration and generators](https://javascript.info/async-iterators-generators). ## Distributed Asynchronous Iteration diff --git a/main/reference/repl/README.md b/main/reference/repl/README.md index 441441fb1..d31ab1a41 100644 --- a/main/reference/repl/README.md +++ b/main/reference/repl/README.md @@ -1,7 +1,8 @@ # Agoric REPL -**Note**: This page describes the Agoric REPL. For information about the `Node.js` REPL, -click [here](https://nodejs.org/api/repl.html). +**Note**: This page describes the Agoric REPL. +If you are instead looking for information about `node` or the Node.js REPL, see +[Node.js documentation](https://nodejs.org/api/repl.html). ## Introduction diff --git a/main/reference/zoe-api/README.md b/main/reference/zoe-api/README.md index 69b18d25b..c3a16a42b 100644 --- a/main/reference/zoe-api/README.md +++ b/main/reference/zoe-api/README.md @@ -9,7 +9,7 @@ what you're willing to offer. It turns out, many smart contracts (apart from gif involve an exchange of digital assets that can be put in terms of offer proposals. Start creating your own contract or build on any of our existing contracts. -Explore our pre-built contracts [here](/guides/zoe/contracts/README.md). +Explore our [pre-built contracts](/guides/zoe/contracts/README.md). The Zoe API supports the following objects: From 8fe8467c90c2f45550a64c06ccc74b4d3adf35f4 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 18:21:10 -0500 Subject: [PATCH 02/36] feat: Improve the jump-to-fragment fixup for non-heading targets Router logic was swallowing history entries and not scrolling far enough for such targets to clear the fixed header. --- main/.vuepress/config.js | 55 +++++++++++++++++++++++++++++--- main/.vuepress/styles/index.styl | 4 +++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/main/.vuepress/config.js b/main/.vuepress/config.js index ec8b81e2d..3e39794ee 100644 --- a/main/.vuepress/config.js +++ b/main/.vuepress/config.js @@ -53,12 +53,57 @@ module.exports = { } }); - if (location.hash) { - // Re-navigate to the page target once content has loaded. + if (location.hash && location.hash !== '#') { + // Once content has loaded, re-navigate to the page target + // without triggering interfering router/history/scroll logic. + const hash = location.hash; fixups.set(['main'], _elems => { - const old = location.hash; - location.hash = ''; - location.hash = old; + const stopPropagation = evt => { + evt.stopImmediatePropagation(); + + const props = {}; + const proto = Object.getPrototypeOf(evt); + const propSource = proto === Event.prototype ? {} : proto; + for (const name of Object.getOwnPropertyNames(propSource)) { + if (name !== 'constructor') props[name] = evt[name]; + } + console.log('suppress', evt.type, { __proto__: evt, ...props }); + }; + const stopEvents = types => { + const restorers = types.map(type => { + window.addEventListener(type, stopPropagation, true); + return () => window.removeEventListener(type, stopPropagation, true); + }); + const passEvents = () => { + // Run and drop references to all restore functions. + while (restorers.length > 0) restorers.pop()(); + }; + return passEvents; + }; + + // Navigate to the page itself as a blank slate. + const passStateEvents = stopEvents(['hashchange', 'popstate']); + const passScrollEvents = stopEvents(['scroll']); + location.replace('#'); + + // Restore state-change events, then navigate back to the target. + passStateEvents(); + try { + const target = document.getElementById(decodeURIComponent(hash.slice(1))); + if (target && target.innerHTML.trim() === '') { + document.documentElement.classList.add('scrollingToTarget'); + target.scrollIntoView({ behavior: 'instant' }); + document.documentElement.classList.remove('scrollingToTarget'); + } + } catch (err) { + console.warn(err); + } + location.replace(hash); + + // Restore scroll events and create a new history entry to be overridden + // if the initial target lacks a TOC entry to highlight. + passScrollEvents(); + history.pushState(null, '', hash); }); } diff --git a/main/.vuepress/styles/index.styl b/main/.vuepress/styles/index.styl index 3ffd2974d..bf1b89c5f 100644 --- a/main/.vuepress/styles/index.styl +++ b/main/.vuepress/styles/index.styl @@ -70,6 +70,10 @@ } } +:root.scrollingToTarget { + scroll-padding-top: $navbarHeight; +} + .ag-btn background-color $accentColor color $white From 0c225e55f4e78a149ae84c79bf90769a2d6c5448 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 18:37:48 -0500 Subject: [PATCH 03/36] refactor(zoe-data-types): Define Keyword and KeywordRecord --- main/glossary/README.md | 18 ++++--- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/README.md | 2 +- main/reference/zoe-api/zcfmint.md | 4 +- main/reference/zoe-api/zcfseat.md | 4 +- main/reference/zoe-api/zoe-data-types.md | 63 +++++++++++------------- main/reference/zoe-api/zoe-helpers.md | 8 +-- 7 files changed, 50 insertions(+), 51 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 104a7d2d5..d03dd6dcd 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -337,10 +337,9 @@ Keys can be used as elements of CopySets and CopyBags and as keys of CopyMaps (s ## Keyword -A keyword is a property name string that is a valid -[identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier), -starts with an upper case letter, and contains no non-ASCII characters. -A KeywordRecord is a CopyRecord in which every property name is a keyword. +A *Keyword* is a string that is a valid ASCII identifier +and starts with an upper case letter. +See **[Zoe Data Types](/reference/zoe-api/zoe-data-types.md#keyword)**. ## Mint @@ -424,9 +423,14 @@ can immediately cause the [seat](#seat) to exit, getting back the amount it offe ## Passable -A *passable* is something that can be marshalled (see the -[Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence)) -and sent to and from remote objects. +A *passable* is something that can be sent to and from remote objects. +Passables include pass-by-copy primitive values such as numbers and strings and +pass-by-reference values such as Remotables and Promises. +Passables also include hardened acyclic pass-by-copy containers that recursively terminate +in non-container passables, such as CopyArrays like `harden(['foo', 'bar'])` and +CopyRecords like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`. +See the +[Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence). ## Payment diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 518318829..a3f21774f 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -54,7 +54,7 @@ intrinsic value. `payments` hold actual digital assets. ## Escrowed Payments -Using the same keywords as your `proposal`, you must specify a `PaymentKeywordRecord`. +Using the same keywords as your `proposal`, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord). This is a record with the keywords as keys, and `payments` containing digital assets as values. Zoe escrows these `payments` on behalf of this offer until the offer is completed or rejected or the assets are reassigned to another offer. diff --git a/main/reference/zoe-api/README.md b/main/reference/zoe-api/README.md index c3a16a42b..6c264933b 100644 --- a/main/reference/zoe-api/README.md +++ b/main/reference/zoe-api/README.md @@ -36,7 +36,7 @@ The Zoe API introduces and uses the following data types: | Data Type | Description | | --- | --- | | [Allocation](./zoe-data-types.md#allocation) | The **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)** to be paid out to each seat upon exiting an **Offer**. | -| [AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord) | A record in which the property names are **Keywords** and the values are **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)**. | +| [AmountKeywordRecord](./zoe-data-types.md#keywordrecord) | A record in which the property names are **Keywords** and the values are **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)**. | | [Handle](./zoe-data-types.md#handle) | A **Far** object without any methods whose only useful property is its unique identity. | | [Instance](./zoe-data-types.md#instance) | A handle to an opaque object that represents a contract instance. | | [Invitation](./zoe-data-types.md#invitation) | A non-fungible eright that can be held in **[Payments](/reference/ertp-api/payment.md)** or **[Purses](/reference/ertp-api/purse.md)**, just like any other eright. | diff --git a/main/reference/zoe-api/zcfmint.md b/main/reference/zoe-api/zcfmint.md index 6bc1dc038..778b0a6f8 100644 --- a/main/reference/zoe-api/zcfmint.md +++ b/main/reference/zoe-api/zcfmint.md @@ -13,7 +13,7 @@ Returns an **IssuerRecord** containing the **[Issuer](/reference/ertp-api/issuer **[Brand](/reference/ertp-api/brand.md)** associated with the **zcfMint**. ## aZCFMint.mintGains(gains, zcfSeat?) - - **gains**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** + - **gains**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional. - Returns: **ZCFSeat** @@ -24,7 +24,7 @@ that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**. If a **seat** it is returned. Otherwise a new **seat** is returned. ## aZCFMint.burnLosses(losses, zcfSeat?) - - **losses**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** + - **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional. - Returns: None diff --git a/main/reference/zoe-api/zcfseat.md b/main/reference/zoe-api/zcfseat.md index 7d83792d5..fbadda17f 100644 --- a/main/reference/zoe-api/zcfseat.md +++ b/main/reference/zoe-api/zcfseat.md @@ -144,7 +144,7 @@ and **reallocate()** have not. Otherwise returns **false**. ::: warning DEPRECATED ## aZCFSeat.incrementBy(amountKeywordRecord) - - **amountKeywordRecord**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** + - **amountKeywordRecord**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Returns: **AmountKeyRecord** Adds the **amountKeywordRecord** argument to the **ZCFseat**'s staged allocation and returns the @@ -173,7 +173,7 @@ allocation in the same way. ::: warning DEPRECATED ## aZCFSeat.decrementBy(amountKeywordRecord) - - **amountKeywordRecord**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** + - **amountKeywordRecord**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Returns: **AmountKeywordRecord** Subtracts the **amountKeywordRecord** argument from the **ZCFseat**'s staged allocation and returns the diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 80308ab16..fe66e8897 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -16,34 +16,6 @@ For example, if a seat expected to be paid 5 *Quatloos* and 3 *Widgets* after su } ``` -## AmountKeywordRecord - -**AmountKeywordRecords** are records in which the property names are **[Keywords](#keyword)**, and -the values are **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)**. **Keywords** are -unique identifiers per contract -that tie together the **proposal**, **payments** to be escrowed, and **payouts** -to the user. In the below example, **Asset** and **Price** are **Keywords**. - -Users should submit their **payments** using **Keywords**: -```js -const payments = { Asset: quatloosPayment }; -``` - -Users will receive their **payouts** with **Keywords** as the keys of a **payout**: -```js -quatloosPurse.deposit(payout.Asset); -``` - -For example: -```js -const quatloos5 = AmountMath.make(quatloosBrand, 5n); -const quatloos9 = AmountMath.make(quatloosBrand, 9n); -const myAmountKeywordRecord = -{ - Asset: quatloos5, - Price: quatloos9 -} -``` ## Handle **Handles** are **Far** objects without any methods whose only useful property are their @@ -83,11 +55,34 @@ is exclusively yours and no one else has access to it. ## Keyword -An ASCII identifier string that must begin with an upper case letter -in order to avoid collisions with JavaScript properties such as `toString`. +A **Keyword** is a unique identifier string within a contract for tying together its +**proposals**, **payments**, and **payouts**. +It must be a valid ASCII [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) +and start with an upper case letter in order to avoid collisions with JavaScript properties +such as `toString` when used as a property name in a record. (For more detail, see [Why do Zoe keywords have to start with a capital letter? #8241](https://github.com/Agoric/agoric-sdk/discussions/8241).) `NaN` and `Infinity` are also not allowed as keywords. +<a name="amountkeywordrecord"></a> +## KeywordRecord + +A **KeywordRecord** is a [CopyRecord](/glossary/#passable) in which every property name +is a **[Keyword](#keyword)**, such as `harden({ Currency: quatloosBrand, CurrencyUnit: 100n })`. +Subtypes further constrain property values (for example, an +**AmountKeywordRecord** is a **KeywordRecord** in which every value is an +**[Amount](/reference/ertp-api/ertp-data-types.md#amount)** and a +**PaymentKeywordRecord** is a **KeywordRecord** in which every value is a +**[Payment](/reference/ertp-api/payment.md)**). + +Users submit their **payments** and receive their **payouts** as **KeywordRecords**: +```js +quatloosPurse.deposit(payouts.Asset); +const quatloos5 = AmountMath.make(quatloosBrand, 5n); +const payments = { + Asset: quatloosPurse.withdraw(quatloos5), +}; +``` + ## MutableQuote A **MutableQuote** represents a statement from a **[PriceAuthority](./price-authority.md)** as to the @@ -148,10 +143,10 @@ represents one or two **[Allocation](#allocation)** changes among existing **[ZCFSeats](./zcfseat.md)**. Each **TransferPart** consists of 4 elements, each of which can be elided in some cases: -* **fromSeat**?: **ZCFSeat** - The seat from which an **[Amount](/reference/ertp-api/ertp-data-types.md#amount)** is being taken. -* **toSeat**?: **ZCFSeat** - The seat to which an **[Amount](/reference/ertp-api/ertp-data-types.md#amount)** is being given. -* **fromAmounts**?: **[AmountKeywordRecord](#amountkeywordrecord)** - The **AmountKeywordRecord** which will be taken from the *fromSeat*. -* **toAmounts**?: **AmountKeywordRecord** - The **AmountKeywordRecord** which will be given to the *toSeat*. +* **fromSeat**?: **ZCFSeat** - The seat from which **amounts** are being taken. +* **toSeat**?: **ZCFSeat** - The seat to which **amounts** are being given. +* **fromAmounts**?: **[AmountKeywordRecord](#keywordrecord)** - The **amounts** which will be taken from the *fromSeat*. +* **toAmounts**?: **AmountKeywordRecord** - The **amounts** which will be given to the *toSeat*. If a *fromSeat* is specified, then a *fromAmounts* is required. When you specify a *toSeat* without specifying a *toAmounts*, it means that the *fromAmount* will be taken from *fromSeat* and given to diff --git a/main/reference/zoe-api/zoe-helpers.md b/main/reference/zoe-api/zoe-helpers.md index 6023a5389..6ffe7ebb6 100644 --- a/main/reference/zoe-api/zoe-helpers.md +++ b/main/reference/zoe-api/zoe-helpers.md @@ -47,7 +47,7 @@ transfers that only include one seat, you can use the helper functions ## fromOnly(fromSeat, fromAmounts) - **fromSeat**: **[ZCFSeat](./zcfseat.md)** -- **fromAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** +- **fromAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Returns: **[TransferPart](./zoe-data-types.md#transferpart)** Returns a **TransferPart** which only takes **fromAmounts** from *fromSeat*. **TransferParts** are used @@ -56,7 +56,7 @@ function. ## toOnly(toSeat, toAmounts) - **toSeat**: **[ZCFSeat](./zcfseat.md)** -- **toAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** +- **toAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Returns: **[TransferPart](./zoe-data-types.md#transferpart)** Returns a **TransferPart** which only gives **toAmount** to *toSeat*. **TransferParts** are used as part @@ -66,7 +66,7 @@ of the *transfer* argument of the **[atomicRearrange()](#atomicrearrange-zcf-tra - **zcf**: **[ZoeContractFacet](./zoe-contract-facet.md)** - **fromSeat**: **[ZCFSeat](./zcfseat.md)** - Optional. - **toSeat**: **ZCFSeat** - Optional. -- **fromAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** - Optional. +- **fromAmounts**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. - **toAmounts**: **AmountKeywordRecord** - Optional, defaults to **fromAmounts**. - Returns: None. @@ -113,7 +113,7 @@ assertIssuerKeywords(zcf, harden(['Asset', 'Price'])); ## satisfies(zcf, seat, update) - **zcf**: **[ZoeContractFacet](./zoe-contract-facet.md)** - **seat**: **[ZCFSeat](./zcfseat.md)** -- **update**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)** +- **update**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - Returns: **Boolean** Returns **true** if an update to a **seat**'s **currentAllocation** satisfies its From 8bc2424fafeee0fedbda5aaee08a2e90fe396b9a Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 18:54:04 -0500 Subject: [PATCH 04/36] fix: Document offerArgs for `E(zoe).offer` and for `zcf.makeInvitation` offerHandler --- main/guides/zoe/proposal.md | 18 ++++++++++++++++-- main/reference/zoe-api/zoe-contract-facet.md | 9 +++++++-- main/reference/zoe-api/zoe.md | 10 +++++----- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index a3f21774f..7a1ad0559 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -4,10 +4,11 @@ ## Making An offer -To make an offer, you use [`E(zoe).offer()`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), which takes three arguments: +To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), which takes up to four arguments: - An **invitation** to participate in this contract instance. - A **proposal** stating your offer conditions. -- The **payments** escrowed for the offer, each in association with a `proposal`-specified keyword. +- The **payments** escrowed for the offer, each corresponding with a **give** [Keyword](/reference/zoe-api/zoe-data-types.md#keyword) in **proposal**. +- **offerArgs** expressing additional arguments for the **offerHandler** associated with the invitation by [`zcf.makeInvitation(...)`](/reference/zoe-api/zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). ## Invitations @@ -64,6 +65,19 @@ const paymentKeywordRecord = { 'Price' : moolaPayment }; ``` + +## Offer Arguments + +To pass additional arguments to the **offerHandler** contract code associated with the +invitation, send them in an **offerArgs** record. +Each contract can define the properties it supports and which are required, and +is responsible for handling any unexpected or missing arguments. + +::: danger +Contract code should be careful interacting with **offerArgs**. These values need input validation +before being used since they are coming directly from the user and may have malicious behavior. +::: + ## Returned Value `offer()` returns a `UserSeat` object. Its name comes from the concept of "having a seat at the table" diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 0733f3df3..3e9d1be17 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -71,7 +71,7 @@ await zcf.saveIssuer(secondaryIssuer, keyword); ``` ## zcf.makeInvitation(offerHandler, description, customProperties?, proposalShape?) -- **offerHandler**: **ZCFSeat => Object** +- **offerHandler**: **(seat: ZCFSeat, offerArgs?: CopyRecord) => any** - **description**: **String** - **customProperties**: **Object** - Optional. - **proposalShape**: **Pattern** - Optional. @@ -88,7 +88,12 @@ The **Invitation**'s - The Zoe **installation**. - A unique **[Handle](./zoe-data-types.md#handle)**. -The second argument is a required *description* for the **Invitation**, +**offerHandler** is a required function accepting a **ZCFSeat** and **offerArgs** +(which will be present if and only if provided to +[`E(Zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs)) +and returning arbitrary offer results. + +**description** is a required string describing the **Invitation**, and should include whatever information is needed for a potential recipient of the **Invitation** to know what they are getting in the optional *customProperties* argument, which is put in the **Invitation**'s **value**. diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index b564bb576..75fba0e57 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -286,11 +286,11 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta ``` -## E(Zoe).offer(invitation, proposal?, paymentKeywordRecord?, offerArgs) -- **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise<Invitation>** -- **proposal**: **Proposal** - Optional. -- **paymentKeywordRecord**: **PaymentKeywordRecord** - Optional. -- **offerArgs**: **Object** +## E(Zoe).offer(invitation, proposal?, paymentKeywordRecord?, offerArgs?) +- **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise<[Invitation](./zoe-data-types.md#invitation)>** +- **proposal**: **[Proposal](/glossary/#proposal)** - Optional. +- **paymentKeywordRecord**: **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. +- **offerArgs**: **[CopyRecord](/glossary/#passable)** - Optional. - Returns: **Promise<[UserSeat](./user-seat.md)>** Used to make an offer to the contract that created the **Invitation** that is From 45035c279b5d44c557223f5818dc0c970283649b Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:13:58 -0500 Subject: [PATCH 05/36] refactor: Use better sections for `E(zoe).offer` ...and link to them from the Zoe Offers guide and the Glossary --- main/glossary/README.md | 28 ++++++------ main/guides/zoe/proposal.md | 70 ++++++++++++++-------------- main/reference/zoe-api/zoe.md | 86 ++++++++++++++++------------------- 3 files changed, 88 insertions(+), 96 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index d03dd6dcd..4f6bccd21 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -230,10 +230,8 @@ See [`E()`](#e) above. ## Exit Rule -Part of an [offer](#offer) specifying how the offer can be cancelled/exited. There are three values: -- `onDemand: null`: (Default) The offering party can cancel on demand. -- `waived: null`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. -- `afterDeadline: {…}`: The offer is automatically cancelled after a deadline, as determined by its `timer` and `deadline` properties. See [Proposals and payments](/reference/zoe-api/zoe.md#proposals-and-payments). +An object specifying how an [offer](#offer) can be cancelled, such as on demand or by a deadline. +For details, see [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#proposals). ## Facet @@ -412,7 +410,7 @@ to the amount in the proposal they're willing to give. The payments are automati according to the contract code. An offer gets a [payout](#payout) of some combination of what the party originally contributed and what others have contributed. The specific payout is determined by the contract code. -See [`E(Zoe).offer(invitation, proposal, paymentKeywordRecord, offerArgs)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs). +See [Offers](/guides/zoe/proposal.md). ## Offer Safety @@ -463,18 +461,20 @@ For more information, see the [JavaScript Distributed Programming Guide](/guides ## Proposal -Proposals are records with `give`, `want`, and `exit` properties. [Offers](#offer) must include a proposal, which states -what asset you want, what asset you will give for it, and how/when the offer maker can cancel the offer -(see [Exit Rule](#exit-rule) for details on the last). For example: +Proposals are records with `give`, `want`, and/or `exit` properties respectively +expressing [offer](#offer) conditions regarding what assets will be given, what +must be received in exchange, and an [exit rule](#exit-rule) defining how/when +the offer can be canceled. For example: ```js const myProposal = harden({ - give: { Asset: AmountMath.make(quatloosBrand, 4)}, - want: { Price: AmountMath.make(moolaBrand, 15) }, - exit: { onDemand: null } -}) + give: { Asset: AmountMath.make(quatloosBrand, 4n) }, + want: { Price: AmountMath.make(moolaBrand, 15n) }, + exit: { onDemand: null }, +}); ``` -`give` and `want` use [keywords](#keyword) defined by the contract. Each specifies via an [amount](#amount) a description of what -they are willing to give or want to get. +`give` and `want` each associate [Keywords](#keyword) defined by the contract with corresponding [Amounts](#amount) describing what will be respectively given or received. + +See [Offers](/guides/zoe/proposal.md). ## Purse diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 7a1ad0559..d328a0916 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -23,46 +23,50 @@ There are two main ways for contract users to get an `invitation`: ## Proposals -Proposals are records with **give**, **want**, and **exit** keys. +Proposals are records with **give**, **want**, and/or **exit** keys. ```js const myProposal = harden({ - give: { Asset: AmountMath.make(quatloosBrand, 4n)}, + give: { Asset: AmountMath.make(quatloosBrand, 4n) }, want: { Price: AmountMath.make(moolaBrand, 15n) }, exit: { onDemand: null }, -}) +}); ``` -**give** and **want** use keywords defined by the contract. -Keywords are unique identifiers per contract, that tie together the proposal, -payments to be escrowed, and payouts to the user. -In the example above, **Asset** and **Price** are the keywords. However, in an auction contract, -the keywords might be **Asset** and **Bid**. - -The `AmountMath.make(quatloosBrand, 4n)` is just making an ERTP `amount`, or description of digital assets. -In this case, 4 of our imaginary Quatloos currency. `AmountMath.make(moolaBrand, 15n)` is making -an `amount` of 15 of our imaginary Moola currency. (The appended "n" indicates that the numbers are -represented as `BigInts` rather than `Numbers`) - -**Note**: It's important to understand that `amounts` are just descriptions of assets with no -intrinsic value. `payments` hold actual digital assets. - -`exit` determines how an offer can be can cancelled: -- `onDemand: null`: (Default) The offering party can cancel on demand. -- `waived: null`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. -- `afterDeadline: {…}`: The offer is automatically cancelled after a deadline, - as determined by its `timer` and `deadline` properties. See - [Proposals and payments](/reference/zoe-api/zoe.md#proposals-and-payments). +**give** and **want** use [Keywords](/reference/zoe-api/zoe-data-types.md#keyword) defined by the contract. +Keywords are unique identifiers per contract, that tie together proposals, +payments to be escrowed, and payouts to users. +In the example above, "Asset" and "Price" are the Keywords. However, in an auction contract, +the Keywords might be "Asset" and "Bid". + +Each `AmountMath.make` call above is just making an ERTP [Amount](/reference/ertp-api/ertp-data-types.html#amount), or description of digital assets. +In this case, `AmountMath.make(quatloosBrand, 4n)` creates a description of 4 units +of our imaginary Quatloos currency and `AmountMath.make(moolaBrand, 15n)` creates a description +of 15 units of our imaginary Moola currency. (The "n" appended after each number indicates that +it is represented as a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) +rather than a [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)) + +::: warning Note +It's important to understand that Amounts are just descriptions of assets with no +intrinsic value. [Payments](/reference/ertp-api/payment.html) hold actual digital assets. +::: + +**exit** specifies how the offer can be can cancelled. It must conform to one of three shapes: +- `{ onDemand: null }`: (Default) The offering party can cancel on demand. +- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. +- `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, + as determined by its `timer` and `deadline` properties. + +For more details, see [Proposals](/reference/zoe-api/zoe.md#proposals). ## Escrowed Payments -Using the same keywords as your `proposal`, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord). -This is a record with the keywords as keys, and `payments` containing digital assets as -values. Zoe escrows these `payments` on behalf of this offer until the offer is completed -or rejected or the assets are reassigned to another offer. +Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord) containing [Payments](/reference/ertp-api/payment.html) of the corresponding digital assets. +Zoe escrows these payments on behalf of your offer until it is completed +or rejected or the assets are reassigned to another offer. ```js -const paymentKeywordRecord = { - 'Asset' : quatloosPayment, - 'Price' : moolaPayment +const payments = { + Asset: quatloosPayment, + Price: moolaPayment, }; ``` @@ -80,7 +84,5 @@ before being used since they are coming directly from the user and may have mali ## Returned Value -`offer()` returns a `UserSeat` object. Its name comes from the concept of "having a seat at the table" -for the contract's execution. - - +`E(zoe).offer(...)` returns a promise for a `UserSeat` object. Its name comes from the concept of +"having a seat at the table" for the contract's execution. diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 75fba0e57..ac2c30311 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -293,66 +293,56 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta - **offerArgs**: **[CopyRecord](/glossary/#passable)** - Optional. - Returns: **Promise<[UserSeat](./user-seat.md)>** -Used to make an offer to the contract that created the **Invitation** that is -provided as the first argument. +Used to make an offer to the contract that created the **invitation**. -### Proposals and Payments +<a name="proposals-and-payments"></a> +### Proposals -The invocation normally includes a **proposal** (the -rules under which they want to exercise the offer) and **payments** that correspond -to the **give** property of the **proposal**. The payments will be escrowed by Zoe. If -either the **proposal** or **payments** are empty, indicate this by -omitting that argument or passing **undefined**, instead of passing an -empty record. - -The optional **exit**'s value should be an **exitRule**, an object with three possible keys for -key:value pairs: - -- **onDemand: null**: (Default) The offering party can cancel on demand. -- **waived: null**: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. -- **afterDeadline**: The offer is automatically cancelled after a deadline, as determined - by its **timer** and **deadline** properties. - **timer** must be a timer, and **deadline** must be a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value interpreted with respect to the timer. - Some example timers use Unix epoch time, while others count block height. +**proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties +respectively expressing conditions regarding what assets will be given, what must be +received in exchange, and an exit rule defining how/when the offer can be canceled. ```js const myProposal = harden({ - give: { Asset: quatloos(4n)}, - want: { Price: moola(15n) }, - exit: { afterDeadline: { - timer, - deadline: 100n - }} -}) + give: { Asset: AmountMath.make(quatloosBrand, 4n) }, + want: { Price: AmountMath.make(moolaBrand, 15n) }, + exit: { onDemand: null }, +}); ``` -**paymentKeywordRecord** is a record with **[Keywords](./zoe-data-types.md#keyword)** as keys and with - values of the actual **payments** to be escrowed. A **payment** is - expected for every entry under **give**. +**give** and **want** use **[Keywords](./zoe-data-types.md#keyword)** defined by the contract. +In the example above, "Asset" and "Price" are the Keywords. However, in an auction contract, +the Keywords might be "Asset" and "Bid". - **offer()** returns a promise for a **UserSeat**. - -```js -const paymentKeywordRecord = { - Asset : quatloosPayment, - Price : moolaPayment -}; -``` +**exit** specifies how the offer can be can cancelled. It must conform to one of three shapes: +- `{ onDemand: null }`: (Default) The offering party can cancel on demand. +- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. +- `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, + as determined by its **timer** and **deadline** properties. + **timer** must be a timer, and **deadline** must be a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value interpreted with respect to the timer. + Some timers use Unix epoch time, while others count block height. + For more details, see [Timer Services](/reference/repl/timerServices.md). + +### Payments -### OfferArgs +**paymentKeywordRecord** must be either `undefined` or a **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** +containing the actual **payments** to be escrowed by Zoe. +Every **Keyword** in **give** must also have a corresponding **payment**. -*offerArgs* is an object that can be used to pass -additional arguments to the **offerHandler** contract code associated -with the invitation. Which arguments should be included within *offerArgs* is determined by the -contract in question; each contract can define whatever additional arguments it requires. If no -additional arguments are defined for a particular contract, then the *offerArgs* argument can be -omitted entirely. It is up to the contract code how it chooses to handle any unexpected or missing -arguments within *offerArgs*. +```js +const paymentKeywordRecord = harden({ + Asset: quatloosPayment, + Price: moolaPayment, +}); +``` +<a href="offerargs"></a> +### Offer Arguments -Contract code should be careful interacting with *offerArgs*. These values need input validation -before being used by the contract code since they are coming directly from the user and may -have malicious behavior. +**offerArgs** is an object that can be used to pass additional arguments to the +**offerHandler** contract code associated with the invitation by +[`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). +Each contract can define the properties it supports and which are required. ## E(Zoe).installBundleID(bundleId) - bundleId: **BundleId** From 9e00cdd65af9b0ae1efc496cf94286f5aa37d0cf Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:18:04 -0500 Subject: [PATCH 06/36] fix(UserSeat): Clarify that offer results must be passable Also adds cross references. --- main/reference/zoe-api/user-seat.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index e09f7f6e1..c5d87401f 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -76,14 +76,14 @@ This promise will be resolved when the seat exits. ## E(UserSeat).getOfferResult() - Returns: **Promise<OfferResult>** -Returns a **Promise** for an **OfferResult**. The **OfferResult** can be literally anything. -For example, in tests for the Automated Refund Dapp, it's the string "The offer was accepted". In -the Covered Call example, it's a call option, which is an assayable **[Invitation](./zoe-data-types.md#invitation)** +Returns a **Promise** for an **OfferResult**. The **OfferResult** can be any **[Passable](/glossary/#passable)**. +For example, in the [Automatic Refund](/guides/zoe/contracts/automatic-refund.md) example, it's the string "The offer was accepted". +In the [Covered Call](/guides/zoe/contracts/covered-call.md) example, it's a call option, which is an assayable **[Invitation](./zoe-data-types.md#invitation)** to buy the underlying asset. Strings and invitations are the most common things returned. -The value is set by the returned result of the **offerHandlers** function passed -as an argument to **[zcf.makeInvitation()](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape)**. +The value is the result returned by the **offerHandler** function passed +in the first argument to [`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). -Since the contract can return whatever it wants as an offerResult, there is no guarantee that the +Since the contract can return whatever it wants as an offer result, there is no guarantee that the promise will resolve promptly. ## E(UserSeat).hasExited() From 7398612831084d25005f3158e7d87662f624d555 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:24:33 -0500 Subject: [PATCH 07/36] refactor: Cross-reference more ERTP/Zoe data types --- main/guides/zoe/proposal.md | 16 ++++++++-------- main/reference/zoe-api/zoe-contract-facet.md | 10 +++------- main/reference/zoe-api/zoe-data-types.md | 5 ++--- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index d328a0916..886463fc8 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -12,12 +12,12 @@ To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe- ## Invitations -`Invitations` are a special case of ERTP `payments`. They are linked to a specific contract `instance`, and -having one gives you the right to participate in that contract `instance`, for example, by making offers in it. +An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special case of ERTP [Payment](/reference/ertp-api/payment.md). Each is linked to a specific contract [Instance](/reference/zoe-api/zoe-data-types.md#instance), and +having one gives you the right to participate in that contract instance, for example, by making offers in it. -There are two main ways for contract users to get an `invitation`: -- If you create the contract `instance`, you get a special creator `invitation`. -- Someone (possibly you) who holds the right objects has created an `invitation` for a contract `instance` and gives it to +There are two main ways for contract users to get an invitation: +- If you create the contract instance, you get a special creator invitation. +- Someone (possibly you) who holds the right objects has created an invitation for a contract instance and gives it to you in some way. This could've been by sending it to you, posting it on a public online location, etc. It doesn't matter (nor does Zoe specify or have any requirements) how or why it got to you, only that you have it. @@ -38,7 +38,7 @@ payments to be escrowed, and payouts to users. In the example above, "Asset" and "Price" are the Keywords. However, in an auction contract, the Keywords might be "Asset" and "Bid". -Each `AmountMath.make` call above is just making an ERTP [Amount](/reference/ertp-api/ertp-data-types.html#amount), or description of digital assets. +Each `AmountMath.make` call above is just making an ERTP [Amount](/reference/ertp-api/ertp-data-types.md#amount), or description of digital assets. In this case, `AmountMath.make(quatloosBrand, 4n)` creates a description of 4 units of our imaginary Quatloos currency and `AmountMath.make(moolaBrand, 15n)` creates a description of 15 units of our imaginary Moola currency. (The "n" appended after each number indicates that @@ -47,7 +47,7 @@ rather than a [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/R ::: warning Note It's important to understand that Amounts are just descriptions of assets with no -intrinsic value. [Payments](/reference/ertp-api/payment.html) hold actual digital assets. +intrinsic value. [Payments](/reference/ertp-api/payment.md) hold actual digital assets. ::: **exit** specifies how the offer can be can cancelled. It must conform to one of three shapes: @@ -60,7 +60,7 @@ For more details, see [Proposals](/reference/zoe-api/zoe.md#proposals). ## Escrowed Payments -Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord) containing [Payments](/reference/ertp-api/payment.html) of the corresponding digital assets. +Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord) containing [Payments](/reference/ertp-api/payment.md) of the corresponding digital assets. Zoe escrows these payments on behalf of your offer until it is completed or rejected or the assets are reassigned to another offer. ```js diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 3e9d1be17..4acee566d 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -77,13 +77,9 @@ await zcf.saveIssuer(secondaryIssuer, keyword); - **proposalShape**: **Pattern** - Optional. - Returns: **Promise<[Invitation](./zoe-data-types.md#invitation)>** -Makes a credible Zoe **Invitation** for a smart contract. Note that **Invitations** are a special case -of an ERTP **payment**. They are associated with the **invitationIssuer** and its **mint**, which -validate and mint **Invitations**. **zcf.makeInvitation()** serves as an interface to -the **invitation** **mint**. - -The **Invitation**'s -**value** specifies: +Uses the Zoe **[InvitationIssuer](./zoe-data-types.md#invitationissuer)** to _mint_ +a credible **Invitation** for a smart contract. +The returned **Invitation**'s **value** specifies: - The specific contract **instance**. - The Zoe **installation**. - A unique **[Handle](./zoe-data-types.md#handle)**. diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index fe66e8897..735dda2d7 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -35,9 +35,8 @@ You can get information about the contract instance via these methods: ## Invitation -An **Invitation** is a kind of **[Payment](/reference/ertp-api/payment.md)**. It's a non-fungible eright -that can be held in **Payments** or **[Purses](/reference/ertp-api/purse.md)**, just like any other -eright. An **Invitation** **Payment** is a **Payment** holding an **Invitation**. +An **Invitation** is a **[Payment](/reference/ertp-api/payment.md)** holding a non-fungible eright created by an **[InvitationIssuer](#invitationissuer)**. +An **Invitation Payment** is a **Payment** holding an **Invitation**. ## InvitationIssuer From 822cd1f51deb2c4b6330f74f769b1fb37ff03617 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:25:38 -0500 Subject: [PATCH 08/36] chore: Indicate multi-argument zoe methods when linking to them --- main/glossary/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 4f6bccd21..eba63b6e9 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -159,7 +159,7 @@ If they have ten houses for sale, they have ten different contract instances. ## Creator Invitation -An [invitation](#invitation) optionally returned by [`startInstance()`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance +An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance creator can use. It is usually used in contracts where the creator immediately sells something (auctions, swaps, etc.). @@ -286,7 +286,7 @@ For more details, see [What developers need to know about inter-blockchain commu A [payment](#payment) whose amount represents (and is required for) participation in a contract instance. Contracts often return a creator invitation on their instantiation, in case the contract instantiator wants to immediately participate. Otherwise, the contract instance must create any additional invitations. -Every [offer](#offer) to participate in a contract instance must include an invitation to that instance in the first argument to [`E(Zoe).offer()`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), and any wallet receiving one will validate it via the [InvitationIssuer](#invitationissuer). +Every [offer](#offer) to participate in a contract instance must include an invitation to that instance in the first argument to [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), and any wallet receiving one will validate it via the [InvitationIssuer](#invitationissuer). An invitation's [amount](#amount) includes the following properties: - The contract's installation in Zoe, including access to its source code. From 40cd9c764a4dfa0d31cf8c2c55c3f69838c4c93a Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Mon, 20 Nov 2023 19:26:09 -0500 Subject: [PATCH 09/36] chore: Clean up inconsistent formatting --- main/reference/zoe-api/zoe-contract-facet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 4acee566d..b6f7a761f 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -91,7 +91,7 @@ and returning arbitrary offer results. **description** is a required string describing the **Invitation**, and should include whatever information is needed for a potential recipient of the **Invitation** -to know what they are getting in the optional *customProperties* argument, which is +to know what they are getting in the optional **customProperties** argument, which is put in the **Invitation**'s **value**. ```js From 076b57d5fd7ee99ad49e46aa275dbe6f360be40a Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 03:01:55 -0500 Subject: [PATCH 10/36] chore: Apply suggested rewordings from code review Co-authored-by: Dan Connolly <connolly@agoric.com> Co-authored-by: Chris Hibbert <Chris-Hibbert@users.noreply.github.com> --- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/zoe-data-types.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 886463fc8..ef001c8ec 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -79,7 +79,7 @@ is responsible for handling any unexpected or missing arguments. ::: danger Contract code should be careful interacting with **offerArgs**. These values need input validation -before being used since they are coming directly from the user and may have malicious behavior. +before being used since they are coming directly from the caller and may have malicious behavior. ::: ## Returned Value diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 735dda2d7..03d946ac5 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -54,8 +54,8 @@ is exclusively yours and no one else has access to it. ## Keyword -A **Keyword** is a unique identifier string within a contract for tying together its -**proposals**, **payments**, and **payouts**. +A **Keyword** is a unique identifier string within a contract for tying together the +**issuers** in its **proposals**, **payments**, and **payouts**. It must be a valid ASCII [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) and start with an upper case letter in order to avoid collisions with JavaScript properties such as `toString` when used as a property name in a record. From 072e8f00b7f35d4a8bc0befad95791b81117eb3e Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 11:17:55 -0500 Subject: [PATCH 11/36] refactor: Fix HTML anchor links The "name" attribute has been deprecated for a long time; use "id" instead. --- main/reference/zoe-api/zoe-data-types.md | 2 +- main/reference/zoe-api/zoe.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 03d946ac5..1910dd976 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -62,7 +62,7 @@ such as `toString` when used as a property name in a record. (For more detail, see [Why do Zoe keywords have to start with a capital letter? #8241](https://github.com/Agoric/agoric-sdk/discussions/8241).) `NaN` and `Infinity` are also not allowed as keywords. -<a name="amountkeywordrecord"></a> +<a id="amountkeywordrecord"></a> ## KeywordRecord A **KeywordRecord** is a [CopyRecord](/glossary/#passable) in which every property name diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index ac2c30311..2fe5aa029 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -295,7 +295,7 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta Used to make an offer to the contract that created the **invitation**. -<a name="proposals-and-payments"></a> +<a id="proposals-and-payments"></a> ### Proposals **proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties From d6f01e5be91335f2ad8fab70178806bf54308d9b Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 12:24:48 -0500 Subject: [PATCH 12/36] refactor: Describe CopyArray/CopyRecord/etc. and add links and glossary entries --- main/glossary/README.md | 24 +++++++++-- main/guides/js-programming/far.md | 54 +++++++++++++++--------- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/zoe-data-types.md | 2 +- main/reference/zoe-api/zoe.md | 2 +- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index eba63b6e9..0a9537e11 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -157,6 +157,21 @@ code defining how that agreement works. When the realtor has a new house to sell they instantiate a new instance of their standard contract for that specific property. If they have ten houses for sale, they have ten different contract instances. +## CopyArray + +A [hardened](#harden) acyclic array in which each element is [passable](#passable), such as +`harden(['foo', 'bar'])`. +For more information, see the +[Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence). + +## CopyRecord + +A [hardened](#harden) acyclic plain object [dictionary](https://en.wikipedia.org/wiki/Associative_array) +in which each key is a string and each value is [passable](#passable), such as +`harden({ keys: [0, 1], values: ['foo', 'bar'] })`. +For more information, see the +[Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence). + ## Creator Invitation An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance @@ -424,10 +439,11 @@ can immediately cause the [seat](#seat) to exit, getting back the amount it offe A *passable* is something that can be sent to and from remote objects. Passables include pass-by-copy primitive values such as numbers and strings and pass-by-reference values such as Remotables and Promises. -Passables also include hardened acyclic pass-by-copy containers that recursively terminate -in non-container passables, such as CopyArrays like `harden(['foo', 'bar'])` and -CopyRecords like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`. -See the +Passables also include [hardened](#harden) acyclic pass-by-copy containers that +recursively terminate in non-container passables, such as +[CopyArrays](#copyarray) and [CopyRecords](#copyrecord). + +For more information, see the [Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence). ## Payment diff --git a/main/guides/js-programming/far.md b/main/guides/js-programming/far.md index 39d3cb813..d452eefb4 100644 --- a/main/guides/js-programming/far.md +++ b/main/guides/js-programming/far.md @@ -28,17 +28,28 @@ Another vat can then make and use the exported counters: ## Pass Styles and harden Calls to remote presences must only contain _passable_ arguments and return _passable_ results. -There are three kinds of passables: - -- Remotables: objects with methods that can be called using `E()` eventual send notation. -- Pass-by-copy data, such as numbers or hardened structures. -- Promises for passables. +A Passable is a [hardened](/glossary/#harden) value that can be marshalled. +There are four broad kinds of Passable: + +- Pass-by-copy **primitive** values: `undefined`, `null`, booleans `true` and `false`, numbers, + [BigInts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), + strings, and symbols that are either + [well-known](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#well-known_symbols) or + [registered](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry). +- Acyclic pass-by-copy **containers** that recursively terminate in non-container passables, such as + _CopyArrays_ like `harden(['foo', 'bar'])` and + _CopyRecords_ like `harden({ keys: [0, 1], values: ['foo', 'bar'] })` and + _CopyTaggeds_ representing higher-order types like CopySet, CopyBag, and CopyMap. +- Pass-by-reference **_Remotables_**: objects that can be shared with remote systems which can then + invoke methods using e.g. `E()` eventual send notation. Remotables are created by [`Far()`](#far-api) + and related functions. +- Pass-by-reference **Promises** for Passables. Every object exported from a smart contract, such as `publicFacet` or `creatorFacet`, must be passable. All objects used in your contract's external API must -be passable. All passables must be hardened. +be passable. -Consider what might happen if we had a remote `item` and we did not harden +All Passables must be hardened. Consider what might happen if we had a remote `item` and we did not harden some pass-by-copy data that we passed to it: ```js @@ -56,18 +67,19 @@ data leads to behavior across vats that is straightforward to reason about. <<< @/snippets/test-distributed-programming.js#import-pass-style -`passStyleOf(passable)` +`passStyleOf(passable)` returns a `PassStyle` string that categorizes `passable`. - `passable` `{Passable}` - Returns: `{PassStyle}` -A Passable is a hardened value that may be marshalled. -It is classified as one of the following `PassStyle` values: +`PassStyle` values correspond with the different kinds of Passable: +- Pass-by-copy **primitive** values: `"undefined"`, `"null"`, `"boolean"`, `"number"`, `"bigint"`, `"string"`, or `"symbol"`. +- Pass-by-copy **containers**: `"copyArray"`, `"copyRecord"`, or `"copyTagged"`. +- So-called `PassableCap` pass-by-reference leafs (**Remotables** and **Promises**): `"remotable"` or `"promise"`. +- Special cases, which also contain other Passables: `"error"`. -- Atomic pass-by-copy primitives (`"undefined" | "null" | "boolean" | "number" | "bigint" | "string" | "symbol"`). -- Pass-by-copy containers that contain other Passables (`"copyArray" | "copyRecord"`). -- Special cases, which also contain other Passables (`"error"`). -- So-called `PassableCap` leafs (`"remotable" | "promise"`). +If `passable` is not passable (for example, because it has not been hardened or has +a non-trivial prototype chain), then `passStyleOf` will throw an error. ::: tip Check `passStyleOf` when handling untrusted structured data Just as you would use `typeof` to check that an argument is @@ -79,24 +91,24 @@ this prevents malicious clients from playing tricks with cyclic data etc. <<< @/snippets/test-distributed-programming.js#importFar -`Far(farName, object-with-methods)` +`Far(farName, objectWithMethods)` marks an object as Remotable. - `farName` `{ String }` -- `object-with-methods` `{ Object }` `[remotable={}]` +- `objectWithMethods` `{ Object }` `[remotable={}]` - Returns: A `Remotable` object. The `farName` parameter gives the `Remotable` an _interface name_ for debugging purposes, which only shows up when logged through the `console`, for example with `console.log`. -The `object-with-methods` parameter should be an object whose properties are the functions serving +The `objectWithMethods` parameter should be an object whose properties are the functions serving as the object's methods. -The `Far()` function marks an object as remotable. `Far()` also: +Before succeeding, the `Far()` function: -- Hardens the object. -- Checks that all property values are functions and throws an error otherwise. +- Checks that each of the object's property values are functions and throws an error otherwise. - Accessors (i.e., `get()` and `set()`) are not allowed. -- Records the object's interface name. +- Records the interface name in the object. +- Hardens the object. ::: tip Avoid accidental exports If an object should never be exposed to other vats, you should make it diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index ef001c8ec..e621f78d4 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -73,7 +73,7 @@ const payments = { ## Offer Arguments To pass additional arguments to the **offerHandler** contract code associated with the -invitation, send them in an **offerArgs** record. +invitation, send them in an **offerArgs** [CopyRecord](/glossary/#copyrecord). Each contract can define the properties it supports and which are required, and is responsible for handling any unexpected or missing arguments. diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 1910dd976..63dc69e17 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -65,7 +65,7 @@ such as `toString` when used as a property name in a record. <a id="amountkeywordrecord"></a> ## KeywordRecord -A **KeywordRecord** is a [CopyRecord](/glossary/#passable) in which every property name +A **KeywordRecord** is a [CopyRecord](/glossary/#copyrecord) in which every property name is a **[Keyword](#keyword)**, such as `harden({ Currency: quatloosBrand, CurrencyUnit: 100n })`. Subtypes further constrain property values (for example, an **AmountKeywordRecord** is a **KeywordRecord** in which every value is an diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 2fe5aa029..b64374520 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -290,7 +290,7 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta - **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise<[Invitation](./zoe-data-types.md#invitation)>** - **proposal**: **[Proposal](/glossary/#proposal)** - Optional. - **paymentKeywordRecord**: **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. -- **offerArgs**: **[CopyRecord](/glossary/#passable)** - Optional. +- **offerArgs**: **[CopyRecord](/glossary/#copyrecord)** - Optional. - Returns: **Promise<[UserSeat](./user-seat.md)>** Used to make an offer to the contract that created the **invitation**. From b527d24b1b9743e6d10b3efe3c202bd5dbc698d2 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 12:25:50 -0500 Subject: [PATCH 13/36] chore: Clarify "Keyword" --- main/glossary/README.md | 2 +- main/reference/zoe-api/zoe-data-types.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 0a9537e11..74814fbc9 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -350,7 +350,7 @@ Keys can be used as elements of CopySets and CopyBags and as keys of CopyMaps (s ## Keyword -A *Keyword* is a string that is a valid ASCII identifier +A *Keyword* is a string that is an ASCII-only [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) and starts with an upper case letter. See **[Zoe Data Types](/reference/zoe-api/zoe-data-types.md#keyword)**. diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 63dc69e17..d4f1a5809 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -56,7 +56,7 @@ is exclusively yours and no one else has access to it. A **Keyword** is a unique identifier string within a contract for tying together the **issuers** in its **proposals**, **payments**, and **payouts**. -It must be a valid ASCII [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) +It must be an ASCII-only [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) and start with an upper case letter in order to avoid collisions with JavaScript properties such as `toString` when used as a property name in a record. (For more detail, see [Why do Zoe keywords have to start with a capital letter? #8241](https://github.com/Agoric/agoric-sdk/discussions/8241).) From 99dc32ea0a9faed51bda1f6e5a3ad33a291238d9 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 12:27:42 -0500 Subject: [PATCH 14/36] chore: Improve descriptions per code review --- main/glossary/README.md | 7 ++++--- main/guides/zoe/proposal.md | 8 ++++---- main/reference/zoe-api/zoe-data-types.md | 6 +++--- main/reference/zoe-api/zoe.md | 14 +++++++++----- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 74814fbc9..e8d5dcfcf 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -478,9 +478,10 @@ For more information, see the [JavaScript Distributed Programming Guide](/guides ## Proposal Proposals are records with `give`, `want`, and/or `exit` properties respectively -expressing [offer](#offer) conditions regarding what assets will be given, what -must be received in exchange, and an [exit rule](#exit-rule) defining how/when -the offer can be canceled. For example: +expressing [offer](#offer) conditions regarding what assets will be given, +what must be received in exchange to satisfy offer safety, and +an [exit rule](#exit-rule) defining how/when the offer can be canceled. +For example: ```js const myProposal = harden({ give: { Asset: AmountMath.make(quatloosBrand, 4n) }, diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index e621f78d4..b6bf261ce 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -16,7 +16,7 @@ An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special ca having one gives you the right to participate in that contract instance, for example, by making offers in it. There are two main ways for contract users to get an invitation: -- If you create the contract instance, you get a special creator invitation. +- If you create the contract instance, the contract might supply a special creator invitation. - Someone (possibly you) who holds the right objects has created an invitation for a contract instance and gives it to you in some way. This could've been by sending it to you, posting it on a public online location, etc. It doesn't matter (nor does Zoe specify or have any requirements) how or why it got to you, only that you have it. @@ -46,11 +46,11 @@ it is represented as a [BigInt](https://developer.mozilla.org/en-US/docs/Web/Jav rather than a [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)) ::: warning Note -It's important to understand that Amounts are just descriptions of assets with no -intrinsic value. [Payments](/reference/ertp-api/payment.md) hold actual digital assets. +Amounts are just _descriptions_ of assets, and have no intrinsic value of their own. +In contrast, [Payments](/reference/ertp-api/payment.md) hold actual digital assets. ::: -**exit** specifies how the offer can be can cancelled. It must conform to one of three shapes: +**exit** specifies how the offer can be cancelled. It must conform to one of three shapes: - `{ onDemand: null }`: (Default) The offering party can cancel on demand. - `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. - `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index d4f1a5809..9153a40c8 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -35,13 +35,13 @@ You can get information about the contract instance via these methods: ## Invitation -An **Invitation** is a **[Payment](/reference/ertp-api/payment.md)** holding a non-fungible eright created by an **[InvitationIssuer](#invitationissuer)**. +An **Invitation** is a **[Payment](/reference/ertp-api/payment.md)** holding a non-fungible eright created by the **[InvitationIssuer](#invitationissuer)**. An **Invitation Payment** is a **Payment** holding an **Invitation**. ## InvitationIssuer -The **InvitationIssuer** is a special type of **[Issuer](/reference/ertp-api/issuer.md)**. The single Zoe -instance has an **InvitationIssuer** for the entirety of its lifetime. All **Invitations** come from the +The **InvitationIssuer** is a special type of **[Issuer](/reference/ertp-api/issuer.md)**. +Zoe has a single **InvitationIssuer** for its entire lifetime. All **Invitations** come from the **[Mint](/reference/ertp-api/mint.md)** associated with the Zoe instance's **InvitationIssuer**. **InvitationIssuer** has all the methods of regular **Issuers**, but the two methods that are most diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index b64374520..4b4fa6799 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -299,8 +299,12 @@ Used to make an offer to the contract that created the **invitation**. ### Proposals **proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties -respectively expressing conditions regarding what assets will be given, what must be -received in exchange, and an exit rule defining how/when the offer can be canceled. +respectively expressing conditions regarding what is being given, +what must be received in exchange to satisfy offer safety, and +an exit rule defining how/when the offer can be canceled. +Note that the contract is not obligated to accept the proposal; +it may inspect it and reject it for any reason +(in which case all payments will be returned promptly). ```js const myProposal = harden({ @@ -314,13 +318,13 @@ const myProposal = harden({ In the example above, "Asset" and "Price" are the Keywords. However, in an auction contract, the Keywords might be "Asset" and "Bid". -**exit** specifies how the offer can be can cancelled. It must conform to one of three shapes: +**exit** specifies how the offer can be cancelled. It must conform to one of three shapes: - `{ onDemand: null }`: (Default) The offering party can cancel on demand. - `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. - `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, as determined by its **timer** and **deadline** properties. - **timer** must be a timer, and **deadline** must be a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) value interpreted with respect to the timer. - Some timers use Unix epoch time, while others count block height. + **timer** must be a timer, and **deadline** must be timestamp understood by it. + (Some timers use Unix epoch time, while others count block height.) For more details, see [Timer Services](/reference/repl/timerServices.md). ### Payments From c107f41b2f2671eda7df2a650f48f3ccb24d31c4 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 12:29:35 -0500 Subject: [PATCH 15/36] chore: Fix bad formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently, "(:)" renders as "(😃" because all characters are secretly emoji. --- main/reference/zoe-api/zoe-contract-facet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index b6f7a761f..7929e3526 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -236,7 +236,7 @@ zcf.assertUniqueKeyword(keyword); - Returns: None. Prohibit invocation of invitatations whose description include any of the strings. -Any of the strings that end with a colon (:) will be treated as a prefix, +Any of the strings that end with a colon (`:`) will be treated as a prefix, and invitations whose description string begins with the string (including the colon) will be burned and not processed if passed to **E(Zoe).offer()**. From 2c4cdd581527c3cb7cb4ae9ce8e9b389d4c64077 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 13:53:13 -0500 Subject: [PATCH 16/36] refactor: Update the KeywordRecord example to use homogeneous value types --- main/reference/zoe-api/zoe-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 9153a40c8..0a0457e9c 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -66,7 +66,7 @@ such as `toString` when used as a property name in a record. ## KeywordRecord A **KeywordRecord** is a [CopyRecord](/glossary/#copyrecord) in which every property name -is a **[Keyword](#keyword)**, such as `harden({ Currency: quatloosBrand, CurrencyUnit: 100n })`. +is a **[Keyword](#keyword)**, such as `harden({ Asset: moolaIssuer, Bid: simoleanIssuer })`. Subtypes further constrain property values (for example, an **AmountKeywordRecord** is a **KeywordRecord** in which every value is an **[Amount](/reference/ertp-api/ertp-data-types.md#amount)** and a From 0343c544225c4ceeb1fd44a66080057f872c8b25 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 16:47:59 -0500 Subject: [PATCH 17/36] refactor(zoe-data-types): Update the KeywordRecord specialization example PaymentKeywordRecord isn't actually used, so replace it with BrandKeywordRecord Co-authored-by: Chris Hibbert <Chris-Hibbert@users.noreply.github.com> --- main/reference/zoe-api/zoe-data-types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 0a0457e9c..3c39ad45b 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -70,8 +70,8 @@ is a **[Keyword](#keyword)**, such as `harden({ Asset: moolaIssuer, Bid: simolea Subtypes further constrain property values (for example, an **AmountKeywordRecord** is a **KeywordRecord** in which every value is an **[Amount](/reference/ertp-api/ertp-data-types.md#amount)** and a -**PaymentKeywordRecord** is a **KeywordRecord** in which every value is a -**[Payment](/reference/ertp-api/payment.md)**). +**BrandKeywordRecord** is a **KeywordRecord** in which every value is a +**[Brand](/guides/ertp/#brand)**). Users submit their **payments** and receive their **payouts** as **KeywordRecords**: ```js From a55b75d0d7a551c96ab8332fd851f4f37c17dae6 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 16:57:09 -0500 Subject: [PATCH 18/36] chore: Replace PaymentKeywordRecord with PaymentPKeywordRecord Per @dckc and @Chris-Hibbert, APIs deal with KeywordRecord<ERef<Payment>> rather than KeywordRecord<Payment> --- main/guides/getting-started/contract-rpc.md | 2 +- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/user-seat.md | 2 +- main/reference/zoe-api/zoe-data-types.md | 4 ++-- main/reference/zoe-api/zoe-helpers.md | 8 ++++---- main/reference/zoe-api/zoe.md | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/main/guides/getting-started/contract-rpc.md b/main/guides/getting-started/contract-rpc.md index 9d4b767f3..b50e335cc 100644 --- a/main/guides/getting-started/contract-rpc.md +++ b/main/guides/getting-started/contract-rpc.md @@ -112,7 +112,7 @@ The [vstorage-viewer](https://github.com/p2p-org/p2p-agoric-vstorage-viewer) con ## Specifying Offers Recall that for an agent within the JavaScript VM, -[E(zoe).offer(...)](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want }`, a `PaymentKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts). +[E(zoe).offer(...)](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want }`, a `PaymentPKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts).  diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index b6bf261ce..444bcfb7f 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -60,7 +60,7 @@ For more details, see [Proposals](/reference/zoe-api/zoe.md#proposals). ## Escrowed Payments -Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord) containing [Payments](/reference/ertp-api/payment.md) of the corresponding digital assets. +Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentPKeywordRecord](/reference/zoe-api/zoe-data-types.md#keywordrecord) containing [Payments](/reference/ertp-api/payment.md) of the corresponding digital assets. Zoe escrows these payments on behalf of your offer until it is completed or rejected or the assets are reassigned to another offer. ```js diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index c5d87401f..343718d25 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -45,7 +45,7 @@ const { want, give, exit } = sellerSeat.getProposal(); ``` ## E(UserSeat).getPayouts() - - Returns: **Promise<PaymentKeywordRecord>** + - Returns: **Promise<PaymentPKeywordRecord>** A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a party in a successful transaction, redirecting escrowed assets in accordance with the result of the transaction. Returns a **Promise** for a record diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 3c39ad45b..c046fdbe1 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -70,8 +70,8 @@ is a **[Keyword](#keyword)**, such as `harden({ Asset: moolaIssuer, Bid: simolea Subtypes further constrain property values (for example, an **AmountKeywordRecord** is a **KeywordRecord** in which every value is an **[Amount](/reference/ertp-api/ertp-data-types.md#amount)** and a -**BrandKeywordRecord** is a **KeywordRecord** in which every value is a -**[Brand](/guides/ertp/#brand)**). +**PaymentPKeywordRecord** is a **KeywordRecord** in which every value is either a +**[Payment](/reference/ertp-api/payment.md)** or a Promise for a Payment). Users submit their **payments** and receive their **payouts** as **KeywordRecords**: ```js diff --git a/main/reference/zoe-api/zoe-helpers.md b/main/reference/zoe-api/zoe-helpers.md index 6ffe7ebb6..1e7797cc1 100644 --- a/main/reference/zoe-api/zoe-helpers.md +++ b/main/reference/zoe-api/zoe-helpers.md @@ -268,7 +268,7 @@ assertNatAssetKind(zcf, quatloosBrand); - **zcf**: **[ZoeContractFacet](./zoe-contract-facet.md)** - **recipientSeat**: **[ZCFSeat](./zcfseat.md)** - **amounts**: **[AmountKeywordRecord](./zoe-data-types.md#allocation)** -- **payments**: **PaymentKeywordRecord** +- **payments**: **PaymentPKeywordRecord** - Returns: **Promise<String>** Deposits payments such that their amounts are reallocated to a seat. @@ -290,7 +290,7 @@ await depositToSeat(zcf, zcfSeat, { Dep: quatloos(2n) }, { Dep: quatloosPayment - **zcf**: **[ZoeContractFacet](./zoe-contract-facet.md)** - **seat**: **[ZCFSeat](./zcfseat.md)** - **amounts**: **[AmountKeywordRecord](./zoe-data-types.md#allocation)** -- Returns: **Promise<PaymentKeywordRecord>** +- Returns: **Promise<PaymentPKeywordRecord>** Withdraws payments from a seat. Note that withdrawing the amounts of the payments must not and cannot violate offer safety for the seat. The @@ -298,7 +298,7 @@ the payments must not and cannot violate offer safety for the seat. The If the seat has exited, aborts with the message **The seat cannot have exited.** -Unlike **depositToSeat()**, a **PaymentKeywordRecord** is returned, not a success message. +Unlike **depositToSeat()**, a **PaymentPKeywordRecord** is returned, not a success message. ```js import { withdrawFromSeat @@ -309,7 +309,7 @@ const paymentKeywordRecord = await withdrawFromSeat(zcf, zcfSeat, { With: quatlo ## saveAllIssuers(zcf, issuerKeywordRecord) - **zcf**: **[ZoeContractFacet](./zoe-contract-facet.md)** - **issuerKeywordRecord**: **IssuerKeywordRecord** -- Returns: **Promise<PaymentKeywordRecord>** +- Returns: **Promise<PaymentPKeywordRecord>** Saves all of the issuers in an **IssuersKeywordRecord** to ZCF, using the method [**zcf.saveIssuer()**](./zoe-contract-facet.md#zcf-saveissuer-issuer-keyword). diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 4b4fa6799..216f1d9d4 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -289,7 +289,7 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta ## E(Zoe).offer(invitation, proposal?, paymentKeywordRecord?, offerArgs?) - **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise<[Invitation](./zoe-data-types.md#invitation)>** - **proposal**: **[Proposal](/glossary/#proposal)** - Optional. -- **paymentKeywordRecord**: **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. +- **paymentKeywordRecord**: **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. - **offerArgs**: **[CopyRecord](/glossary/#copyrecord)** - Optional. - Returns: **Promise<[UserSeat](./user-seat.md)>** @@ -329,7 +329,7 @@ the Keywords might be "Asset" and "Bid". ### Payments -**paymentKeywordRecord** must be either `undefined` or a **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** +**paymentKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** containing the actual **payments** to be escrowed by Zoe. Every **Keyword** in **give** must also have a corresponding **payment**. From cb6a8517bad66cd27fb59a545f95fb84cc4f4f82 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Wed, 29 Nov 2023 23:10:37 -0500 Subject: [PATCH 19/36] chore: Improve descriptions per code review --- main/glossary/README.md | 15 ++++++++------- main/guides/getting-started/contract-rpc.md | 2 +- main/guides/js-programming/far.md | 10 +++++----- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/user-seat.md | 2 +- main/reference/zoe-api/zcfmint.md | 2 +- main/reference/zoe-api/zoe-contract-facet.md | 6 ++++-- main/reference/zoe-api/zoe.md | 2 +- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index e8d5dcfcf..3fa829608 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -439,9 +439,9 @@ can immediately cause the [seat](#seat) to exit, getting back the amount it offe A *passable* is something that can be sent to and from remote objects. Passables include pass-by-copy primitive values such as numbers and strings and pass-by-reference values such as Remotables and Promises. -Passables also include [hardened](#harden) acyclic pass-by-copy containers that -recursively terminate in non-container passables, such as -[CopyArrays](#copyarray) and [CopyRecords](#copyrecord). +Passables also include [CopyArrays](#copyarray) and [CopyRecords](#copyrecord), which are +[hardened](#harden) acyclic pass-by-copy containers that +recursively terminate in non-container passables. For more information, see the [Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence). @@ -459,8 +459,9 @@ and the [ERTP API's Payments section](/reference/ertp-api/payment.md). The assets paid out to a user when an [seat](#seat) exits, either successfully or not. The payout is always what the seat's current [allocation](#allocation) is. -If there was a previous reallocation, the payout is different than what the user escrowed. If there is no reallocation -before the seat exits, the payout is the same as what they escrowed. +If there was a reallocation, the payout may be different than what the user escrowed +(but still constrained by [offer safety](#offer-safety)). +Otherwise, the payout is the same as what they escrowed. ## Petname @@ -479,7 +480,7 @@ For more information, see the [JavaScript Distributed Programming Guide](/guides Proposals are records with `give`, `want`, and/or `exit` properties respectively expressing [offer](#offer) conditions regarding what assets will be given, -what must be received in exchange to satisfy offer safety, and +what is expected in exchange (protected by [offer safety](#offer-safety)), and an [exit rule](#exit-rule) defining how/when the offer can be canceled. For example: ```js @@ -489,7 +490,7 @@ const myProposal = harden({ exit: { onDemand: null }, }); ``` -`give` and `want` each associate [Keywords](#keyword) defined by the contract with corresponding [Amounts](#amount) describing what will be respectively given or received. +`give` and `want` each associate [Keywords](#keyword) defined by the contract with corresponding [Amounts](#amount) describing respectively what will be given and what is being requested in exchange. See [Offers](/guides/zoe/proposal.md). diff --git a/main/guides/getting-started/contract-rpc.md b/main/guides/getting-started/contract-rpc.md index b50e335cc..b527700be 100644 --- a/main/guides/getting-started/contract-rpc.md +++ b/main/guides/getting-started/contract-rpc.md @@ -112,7 +112,7 @@ The [vstorage-viewer](https://github.com/p2p-org/p2p-agoric-vstorage-viewer) con ## Specifying Offers Recall that for an agent within the JavaScript VM, -[E(zoe).offer(...)](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want }`, a `PaymentPKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts). +[E(zoe).offer(...)](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want, exit }`, a `PaymentPKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts).  diff --git a/main/guides/js-programming/far.md b/main/guides/js-programming/far.md index d452eefb4..127741309 100644 --- a/main/guides/js-programming/far.md +++ b/main/guides/js-programming/far.md @@ -36,9 +36,9 @@ There are four broad kinds of Passable: strings, and symbols that are either [well-known](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#well-known_symbols) or [registered](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry). -- Acyclic pass-by-copy **containers** that recursively terminate in non-container passables, such as - _CopyArrays_ like `harden(['foo', 'bar'])` and - _CopyRecords_ like `harden({ keys: [0, 1], values: ['foo', 'bar'] })` and +- Acyclic pass-by-copy **containers** that recursively terminate in non-container passables. + Such containers include _CopyArrays_ like `harden(['foo', 'bar'])`, + _CopyRecords_ like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`, and _CopyTaggeds_ representing higher-order types like CopySet, CopyBag, and CopyMap. - Pass-by-reference **_Remotables_**: objects that can be shared with remote systems which can then invoke methods using e.g. `E()` eventual send notation. Remotables are created by [`Far()`](#far-api) @@ -94,7 +94,7 @@ this prevents malicious clients from playing tricks with cyclic data etc. `Far(farName, objectWithMethods)` marks an object as Remotable. - `farName` `{ String }` -- `objectWithMethods` `{ Object }` `[remotable={}]` +- `objectWithMethods` `{ Object }` - Optional. - Returns: A `Remotable` object. The `farName` parameter gives the `Remotable` an _interface name_ for debugging purposes, which only shows @@ -112,6 +112,6 @@ Before succeeding, the `Far()` function: ::: tip Avoid accidental exports If an object should never be exposed to other vats, you should make it -a point **not** to use `Far()` on it. If an object is not marked as a remotable but is accidentally +a point **not** to use `Far()` on it. If an object is not marked as a Remotable but is accidentally exposed, an error is thrown. This prevents any vulnerability from such accidental exposure. ::: diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 444bcfb7f..f04b01b24 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -13,7 +13,7 @@ To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe- ## Invitations An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special case of ERTP [Payment](/reference/ertp-api/payment.md). Each is linked to a specific contract [Instance](/reference/zoe-api/zoe-data-types.md#instance), and -having one gives you the right to participate in that contract instance, for example, by making offers in it. +having one gives you the right to participate in that contract instance by making offers in it. There are two main ways for contract users to get an invitation: - If you create the contract instance, the contract might supply a special creator invitation. diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index 343718d25..761365eeb 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -49,7 +49,7 @@ const { want, give, exit } = sellerSeat.getProposal(); A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a party in a successful transaction, redirecting escrowed assets in accordance with the result of the transaction. Returns a **Promise** for a record -containing all the **Payout** **Payments** associated with the **seat**'s offers. +containing **Promises** for all the **Payout** **Payments** associated with the **seat**'s offers. ```js diff --git a/main/reference/zoe-api/zcfmint.md b/main/reference/zoe-api/zcfmint.md index 778b0a6f8..ffc37bdc1 100644 --- a/main/reference/zoe-api/zcfmint.md +++ b/main/reference/zoe-api/zcfmint.md @@ -25,7 +25,7 @@ it is returned. Otherwise a new **seat** is returned. ## aZCFMint.burnLosses(losses, zcfSeat?) - **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional. + - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Returns: None All **amounts** in *losses* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)**. diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 7929e3526..d3c29137f 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -79,7 +79,7 @@ await zcf.saveIssuer(secondaryIssuer, keyword); Uses the Zoe **[InvitationIssuer](./zoe-data-types.md#invitationissuer)** to _mint_ a credible **Invitation** for a smart contract. -The returned **Invitation**'s **value** specifies: +The returned **Invitation**'s **amount** specifies: - The specific contract **instance**. - The Zoe **installation**. - A unique **[Handle](./zoe-data-types.md#handle)**. @@ -92,7 +92,9 @@ and returning arbitrary offer results. **description** is a required string describing the **Invitation**, and should include whatever information is needed for a potential recipient of the **Invitation** to know what they are getting in the optional **customProperties** argument, which is -put in the **Invitation**'s **value**. +put in the **Invitation**'s **amount**. +Each one should be a string literal that is unique within its contract and +used only as the argument to make invitations of a particular kind. ```js const creatorInvitation = zcf.makeInvitation(makeCallOption, 'makeCallOption') diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 216f1d9d4..a5c9d6c2a 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -300,7 +300,7 @@ Used to make an offer to the contract that created the **invitation**. **proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties respectively expressing conditions regarding what is being given, -what must be received in exchange to satisfy offer safety, and +what is expected in exchange (protected by offer safety), and an exit rule defining how/when the offer can be canceled. Note that the contract is not obligated to accept the proposal; it may inspect it and reject it for any reason From 04f2983a7f60ec8ed9cb4b6fa1e43ce0b4323aba Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 19:32:00 -0500 Subject: [PATCH 20/36] chore: Apply suggestions from code review Co-authored-by: Mark S. Miller <erights@users.noreply.github.com> --- main/guides/zoe/proposal.md | 6 +++--- main/reference/zoe-api/zcfmint.md | 2 +- main/reference/zoe-api/zoe.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index f04b01b24..37ea5f025 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -13,9 +13,9 @@ To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe- ## Invitations An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special case of ERTP [Payment](/reference/ertp-api/payment.md). Each is linked to a specific contract [Instance](/reference/zoe-api/zoe-data-types.md#instance), and -having one gives you the right to participate in that contract instance by making offers in it. +having one gives you the right to participate in that contract instance by making offers with it. -There are two main ways for contract users to get an invitation: +There are two ways for contract users to get an invitation: - If you create the contract instance, the contract might supply a special creator invitation. - Someone (possibly you) who holds the right objects has created an invitation for a contract instance and gives it to you in some way. This could've been by sending it to you, posting it on a public online location, etc. It @@ -52,7 +52,7 @@ In contrast, [Payments](/reference/ertp-api/payment.md) hold actual digital asse **exit** specifies how the offer can be cancelled. It must conform to one of three shapes: - `{ onDemand: null }`: (Default) The offering party can cancel on demand. -- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. +- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to complete (finish or fail) their offer. - `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, as determined by its `timer` and `deadline` properties. diff --git a/main/reference/zoe-api/zcfmint.md b/main/reference/zoe-api/zcfmint.md index ffc37bdc1..133bec9e8 100644 --- a/main/reference/zoe-api/zcfmint.md +++ b/main/reference/zoe-api/zcfmint.md @@ -23,7 +23,7 @@ Mint the *gains* **Amount** of assets and add them to that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**. If a **seat** is provided, it is returned. Otherwise a new **seat** is returned. -## aZCFMint.burnLosses(losses, zcfSeat?) +## aZCFMint.burnLosses(losses, zcfSeat) - **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Returns: None diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index a5c9d6c2a..f32eb4256 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -320,7 +320,7 @@ the Keywords might be "Asset" and "Bid". **exit** specifies how the offer can be cancelled. It must conform to one of three shapes: - `{ onDemand: null }`: (Default) The offering party can cancel on demand. -- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to promptly finish their offer. +- `{ waived: null }`: The offering party can't cancel and relies entirely on the smart contract to complete (finish or fail) their offer. - `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, as determined by its **timer** and **deadline** properties. **timer** must be a timer, and **deadline** must be timestamp understood by it. @@ -343,7 +343,7 @@ const paymentKeywordRecord = harden({ <a href="offerargs"></a> ### Offer Arguments -**offerArgs** is an object that can be used to pass additional arguments to the +**offerArgs** is an optional CopyRecord that can be used to pass additional arguments to the **offerHandler** contract code associated with the invitation by [`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). Each contract can define the properties it supports and which are required. From a68b8d12e8a1921203b8b421e1ab822040561c97 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 19:20:33 -0500 Subject: [PATCH 21/36] refactor(zoe): Improve code examples --- main/reference/zoe-api/user-seat.md | 10 ---------- main/reference/zoe-api/zoe-data-types.md | 9 ++++----- main/reference/zoe-api/zoe.md | 5 +---- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index 761365eeb..629138706 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -51,16 +51,6 @@ A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a p escrowed assets in accordance with the result of the transaction. Returns a **Promise** for a record containing **Promises** for all the **Payout** **Payments** associated with the **seat**'s offers. - -```js -// Record example -const paymentKeywordRecord = { - FirstPayment: quatloosPayment, - SecondPayment: moolaPayment, - //etc. -}; -``` - This promise will be resolved when the seat exits. ## E(UserSeat).getPayout(keyword) diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index c046fdbe1..a8c724090 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -73,12 +73,11 @@ Subtypes further constrain property values (for example, an **PaymentPKeywordRecord** is a **KeywordRecord** in which every value is either a **[Payment](/reference/ertp-api/payment.md)** or a Promise for a Payment). -Users submit their **payments** and receive their **payouts** as **KeywordRecords**: +Users submit their **payments** as **KeywordRecords**: ```js -quatloosPurse.deposit(payouts.Asset); -const quatloos5 = AmountMath.make(quatloosBrand, 5n); -const payments = { - Asset: quatloosPurse.withdraw(quatloos5), +const aFistfulOfQuatloos = AmountMath.make(quatloosBrand, 1000n); +const paymentKeywordRecord = { + Asset: quatloosPurse.withdraw(aFistfulOfQuatloos), }; ``` diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index f32eb4256..7dc333fa8 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -334,10 +334,7 @@ containing the actual **payments** to be escrowed by Zoe. Every **Keyword** in **give** must also have a corresponding **payment**. ```js -const paymentKeywordRecord = harden({ - Asset: quatloosPayment, - Price: moolaPayment, -}); +const paymentKeywordRecord = harden({ Asset: quatloosPayment }); ``` <a href="offerargs"></a> From 1b2636f174db5e8ebccb580b9868fca6fb619ded Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 19:36:05 -0500 Subject: [PATCH 22/36] refactor(zoe): An Invitation can be _held_ in a Payment, but cannot _be_ a Payment --- main/reference/zoe-api/zoe-data-types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index a8c724090..b4afa6fd3 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -35,8 +35,8 @@ You can get information about the contract instance via these methods: ## Invitation -An **Invitation** is a **[Payment](/reference/ertp-api/payment.md)** holding a non-fungible eright created by the **[InvitationIssuer](#invitationissuer)**. -An **Invitation Payment** is a **Payment** holding an **Invitation**. +An **Invitation** is a non-fungible asset created by the **[InvitationIssuer](#invitationissuer)**. +An **Invitation Payment** is a **[Payment](/reference/ertp-api/payment.md)** holding an **Invitation**. ## InvitationIssuer From 86eddccd2702ecb7100e77e0d08e6c7abb7ce3e2 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 19:40:35 -0500 Subject: [PATCH 23/36] refactor(far): Be consistent about the categories of Passable --- main/guides/js-programming/far.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/main/guides/js-programming/far.md b/main/guides/js-programming/far.md index 127741309..b20157434 100644 --- a/main/guides/js-programming/far.md +++ b/main/guides/js-programming/far.md @@ -39,11 +39,15 @@ There are four broad kinds of Passable: - Acyclic pass-by-copy **containers** that recursively terminate in non-container passables. Such containers include _CopyArrays_ like `harden(['foo', 'bar'])`, _CopyRecords_ like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`, and - _CopyTaggeds_ representing higher-order types like CopySet, CopyBag, and CopyMap. -- Pass-by-reference **_Remotables_**: objects that can be shared with remote systems which can then - invoke methods using e.g. `E()` eventual send notation. Remotables are created by [`Far()`](#far-api) - and related functions. -- Pass-by-reference **Promises** for Passables. + _CopyTaggeds_ representing types like CopySet, CopyBag, and CopyMap + (which extend the `passStyleOf` level of abstraction with + [tag-specific shapes and semantics](https://github.com/endojs/endo/blob/master/packages/patterns/docs/marshal-vs-patterns-level.md#kindof-vs-passstyleof)) +- Pass-by-reference "**PassableCaps**": + - _Remotables_: objects that can be shared with remote systems which can then + invoke methods using e.g. `E()` eventual send notation. Remotables are created by [`Far()`](#far-api) + and related functions. + - _Promises_ for Passables. +- As a special case, **Errors** are treated as pass-by-copy data that can also contain other Passables. Every object exported from a smart contract, such as `publicFacet` or `creatorFacet`, must be passable. All objects used in your contract's external API must @@ -75,8 +79,8 @@ data leads to behavior across vats that is straightforward to reason about. `PassStyle` values correspond with the different kinds of Passable: - Pass-by-copy **primitive** values: `"undefined"`, `"null"`, `"boolean"`, `"number"`, `"bigint"`, `"string"`, or `"symbol"`. - Pass-by-copy **containers**: `"copyArray"`, `"copyRecord"`, or `"copyTagged"`. -- So-called `PassableCap` pass-by-reference leafs (**Remotables** and **Promises**): `"remotable"` or `"promise"`. -- Special cases, which also contain other Passables: `"error"`. +- Pass-by-reference **PassableCaps**: `"remotable"` or `"promise"`. +- Pass-by-copy **Errors**: `"error"`. If `passable` is not passable (for example, because it has not been hardened or has a non-trivial prototype chain), then `passStyleOf` will throw an error. From 6079c5ce8a591f4fd1cd2052024e1c73245e47cd Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 20:35:33 -0500 Subject: [PATCH 24/36] style(UserSeat): Use consistent patterns for documenting methods --- main/reference/zoe-api/user-seat.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index 629138706..851b98030 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -45,23 +45,23 @@ const { want, give, exit } = sellerSeat.getProposal(); ``` ## E(UserSeat).getPayouts() - - Returns: **Promise<PaymentPKeywordRecord>** + - Returns: **Promise<[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)>** -A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a party in a successful transaction, redirecting -escrowed assets in accordance with the result of the transaction. Returns a **Promise** for a record -containing **Promises** for all the **Payout** **Payments** associated with the **seat**'s offers. +Returns a **Promise** for a [KeywordRecord](./zoe-data-types.md#keywordrecord) containing **Promises** for all the **Payouts** associated with the **seat**'s offers. +A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a party in a successful transaction, +redirecting escrowed assets in accordance with the result of the transaction. -This promise will be resolved when the seat exits. +The promise will be resolved promptly once the seat exits. ## E(UserSeat).getPayout(keyword) -- **keyword**: **[Keyword](./zoe-data-types.md#keyword)** -- Returns: **Promise<[Payment](/reference/ertp-api/payment.md)>** + - **keyword**: **[Keyword](./zoe-data-types.md#keyword)** + - Returns: **Promise<[Payment](/reference/ertp-api/payment.md)>** -A **Payout** is a **Payment** that goes to a party in a successful transaction, redirecting -escrowed assets in accordance with the result of the transaction. Returns a **Promise** for the **Payout** -**Payment** associated with the *keyword* argument. +Returns a **Promise** for the **Payout** associated with the *keyword* argument. +A **Payout** is a **[Payment](/reference/ertp-api/payment.md)** that goes to a party in a successful transaction, +redirecting escrowed assets in accordance with the result of the transaction. -This promise will be resolved when the seat exits. +The promise will be resolved promptly once the seat exits. ## E(UserSeat).getOfferResult() - Returns: **Promise<OfferResult>** From 95f4e80efdb222e0f283a5965a9d194a8c50bfe8 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 20:57:26 -0500 Subject: [PATCH 25/36] refactor: Rename E(Zoe).offer argument `paymentKeywordRecord` to `paymentPKeywordRecord` --- main/glossary/README.md | 2 +- main/guides/getting-started/contract-rpc.md | 2 +- main/guides/zoe/proposal.md | 2 +- main/reference/zoe-api/zcfseat.md | 2 +- main/reference/zoe-api/zoe-contract-facet.md | 2 +- main/reference/zoe-api/zoe.md | 7 ++++--- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 3fa829608..7712dc76c 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -301,7 +301,7 @@ For more details, see [What developers need to know about inter-blockchain commu A [payment](#payment) whose amount represents (and is required for) participation in a contract instance. Contracts often return a creator invitation on their instantiation, in case the contract instantiator wants to immediately participate. Otherwise, the contract instance must create any additional invitations. -Every [offer](#offer) to participate in a contract instance must include an invitation to that instance in the first argument to [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), and any wallet receiving one will validate it via the [InvitationIssuer](#invitationissuer). +Every [offer](#offer) to participate in a contract instance must include an invitation to that instance in the first argument to [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentpkeywordrecord-offerargs), and any wallet receiving one will validate it via the [InvitationIssuer](#invitationissuer). An invitation's [amount](#amount) includes the following properties: - The contract's installation in Zoe, including access to its source code. diff --git a/main/guides/getting-started/contract-rpc.md b/main/guides/getting-started/contract-rpc.md index b527700be..44737e8ce 100644 --- a/main/guides/getting-started/contract-rpc.md +++ b/main/guides/getting-started/contract-rpc.md @@ -112,7 +112,7 @@ The [vstorage-viewer](https://github.com/p2p-org/p2p-agoric-vstorage-viewer) con ## Specifying Offers Recall that for an agent within the JavaScript VM, -[E(zoe).offer(...)](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want, exit }`, a `PaymentPKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts). +[`E(zoe).offer(...)`](../../reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentpkeywordrecord-offerargs) takes an `Invitation` and optionally a `Proposal` with `{ give, want, exit }`, a `PaymentPKeywordRecord`, and `offerArgs`; it returns a `UserSeat` from which we can [getPayouts()](../../reference/zoe-api/user-seat.md#e-userseat-getpayouts).  diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 37ea5f025..d24a92098 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -4,7 +4,7 @@ ## Making An offer -To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs), which takes up to four arguments: +To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentpkeywordrecord-offerargs), which takes up to four arguments: - An **invitation** to participate in this contract instance. - A **proposal** stating your offer conditions. - The **payments** escrowed for the offer, each corresponding with a **give** [Keyword](/reference/zoe-api/zoe-data-types.md#keyword) in **proposal**. diff --git a/main/reference/zoe-api/zcfseat.md b/main/reference/zoe-api/zcfseat.md index fbadda17f..37cc69df4 100644 --- a/main/reference/zoe-api/zcfseat.md +++ b/main/reference/zoe-api/zcfseat.md @@ -25,7 +25,7 @@ to get back from Zoe. It has keys **give**, **want**, and **exit**. **give** and **want** are records with **[Keywords](./zoe-data-types.md#keyword)** as keys and **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)** as values. The **proposal** is a user's understanding of the contract that they are entering when they make an offer. See -[**E(zoe).offer()**](./zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs) for full details. +[`E(zoe).offer(...)`](./zoe.md#e-zoe-offer-invitation-proposal-paymentpkeywordrecord-offerargs) for full details. - Example: ```js diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index d3c29137f..1fd42259a 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -86,7 +86,7 @@ The returned **Invitation**'s **amount** specifies: **offerHandler** is a required function accepting a **ZCFSeat** and **offerArgs** (which will be present if and only if provided to -[`E(Zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs)) +[`E(Zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe-offer-invitation-proposal-paymentpkeywordrecord-offerargs)) and returning arbitrary offer results. **description** is a required string describing the **Invitation**, diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 7dc333fa8..2ebf2b70d 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -285,11 +285,12 @@ const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInsta installation, issuerKeywordRecord, terms); ``` +<a id="e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs"></a> -## E(Zoe).offer(invitation, proposal?, paymentKeywordRecord?, offerArgs?) +## E(Zoe).offer(invitation, proposal?, paymentPKeywordRecord?, offerArgs?) - **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise<[Invitation](./zoe-data-types.md#invitation)>** - **proposal**: **[Proposal](/glossary/#proposal)** - Optional. -- **paymentKeywordRecord**: **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. +- **paymentPKeywordRecord**: **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional. - **offerArgs**: **[CopyRecord](/glossary/#copyrecord)** - Optional. - Returns: **Promise<[UserSeat](./user-seat.md)>** @@ -329,7 +330,7 @@ the Keywords might be "Asset" and "Bid". ### Payments -**paymentKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** +**paymentPKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** containing the actual **payments** to be escrowed by Zoe. Every **Keyword** in **give** must also have a corresponding **payment**. From 2b28ec84c40de2dd1ab7cf26adf43cce0306fb70 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 21:54:18 -0500 Subject: [PATCH 26/36] chore: Apply suggestions from code review --- main/glossary/README.md | 4 ++-- main/guides/js-programming/far.md | 6 ++++-- main/reference/zoe-api/zcfmint.md | 17 ++++++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 7712dc76c..573873f87 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -350,8 +350,8 @@ Keys can be used as elements of CopySets and CopyBags and as keys of CopyMaps (s ## Keyword -A *Keyword* is a string that is an ASCII-only [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier) -and starts with an upper case letter. +A *Keyword* is a string that is an ASCII-only [identifier](https://developer.mozilla.org/en-US/docs/Glossary/Identifier), +starts with an upper case letter, and is not equal to "NaN" or "Infinity". See **[Zoe Data Types](/reference/zoe-api/zoe-data-types.md#keyword)**. ## Mint diff --git a/main/guides/js-programming/far.md b/main/guides/js-programming/far.md index b20157434..688cd8c7b 100644 --- a/main/guides/js-programming/far.md +++ b/main/guides/js-programming/far.md @@ -104,8 +104,10 @@ this prevents malicious clients from playing tricks with cyclic data etc. The `farName` parameter gives the `Remotable` an _interface name_ for debugging purposes, which only shows up when logged through the `console`, for example with `console.log`. -The `objectWithMethods` parameter should be an object whose properties are the functions serving -as the object's methods. +The optional `objectWithMethods` parameter should be an object +whose properties are the functions serving as the object's methods. +It MUST NOT already be hardened or even frozen (though `Far()` will harden it before returning successfully). +If not provided, a new empty object will be used. Before succeeding, the `Far()` function: diff --git a/main/reference/zoe-api/zcfmint.md b/main/reference/zoe-api/zcfmint.md index 133bec9e8..9d0e73e61 100644 --- a/main/reference/zoe-api/zcfmint.md +++ b/main/reference/zoe-api/zcfmint.md @@ -17,21 +17,20 @@ Returns an **IssuerRecord** containing the **[Issuer](/reference/ertp-api/issuer - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional. - Returns: **ZCFSeat** -All **amounts** in *gains* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)**. -The *gains*' **[Keywords](./zoe-data-types.md#keyword)** are in that **seat**'s namespace. -Mint the *gains* **Amount** of assets and add them to -that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**. If a **seat** is provided, -it is returned. Otherwise a new **seat** is returned. +All **amounts** in *gains* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)** +and the *gains*' **[Keywords](./zoe-data-types.md#keyword)** should be defined by the contract instance in which *zcfSeat* is participating. +If *zcfSeat* is not provided, a new **seat** is used. +Mints the *gains* **Amount** of assets and adds them to *zcfSeat*'s **[Allocation](./zoe-data-types.md#allocation)**, then returns *zcfSeat*. ## aZCFMint.burnLosses(losses, zcfSeat) - **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)** - **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Returns: None -All **amounts** in *losses* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)**. -The *losses*' **[Keywords](./zoe-data-types.md#keyword)** are in that **seat**'s namespace. -Subtract *losses* from that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**, then -burn that **amount** of assets from the pooled **[Purse](/reference/ertp-api/purse.md)**. +All **amounts** in *losses* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)** +and the *losses*' **[Keywords](./zoe-data-types.md#keyword)** must be defined by the contract instance in which *zcfSeat* is participating. +Subtracts *losses* from *zcfSeat*'s **[Allocation](./zoe-data-types.md#allocation)**, then +burns that **amount** of assets from the pooled **[Purse](/reference/ertp-api/purse.md)**. From 115c03e8165904dd8cec3619b444cc2e4716cb82 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Fri, 1 Dec 2023 18:44:37 -0500 Subject: [PATCH 27/36] chore: Improve descriptions per code review --- main/glossary/README.md | 2 +- main/guides/zoe/contract-requirements.md | 2 +- main/guides/zoe/proposal.md | 5 +++-- main/reference/zoe-api/user-seat.md | 2 +- main/reference/zoe-api/zcfmint.md | 2 +- main/reference/zoe-api/zoe-contract-facet.md | 17 ++++++++++------- main/reference/zoe-api/zoe-data-types.md | 10 +++++++--- main/reference/zoe-api/zoe.md | 6 +++--- 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 573873f87..2411a5ce3 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -480,7 +480,7 @@ For more information, see the [JavaScript Distributed Programming Guide](/guides Proposals are records with `give`, `want`, and/or `exit` properties respectively expressing [offer](#offer) conditions regarding what assets will be given, -what is expected in exchange (protected by [offer safety](#offer-safety)), and +what is desired in exchange (protected by [offer safety](#offer-safety)), and an [exit rule](#exit-rule) defining how/when the offer can be canceled. For example: ```js diff --git a/main/guides/zoe/contract-requirements.md b/main/guides/zoe/contract-requirements.md index baee593d8..069dba000 100644 --- a/main/guides/zoe/contract-requirements.md +++ b/main/guides/zoe/contract-requirements.md @@ -131,7 +131,7 @@ between multiple offers, or create new assets to order. ## Making an Invitation To create an invitation in the contract, use the Zoe Contract -Facet method [`zcf.makeInvitation`](/reference/zoe-api/zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). +Facet method [`zcf.makeInvitation(...)`](/reference/zoe-api/zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customdetails-proposalshape). ## Using bundleSource diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index d24a92098..265240773 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -8,12 +8,13 @@ To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#e-zoe- - An **invitation** to participate in this contract instance. - A **proposal** stating your offer conditions. - The **payments** escrowed for the offer, each corresponding with a **give** [Keyword](/reference/zoe-api/zoe-data-types.md#keyword) in **proposal**. -- **offerArgs** expressing additional arguments for the **offerHandler** associated with the invitation by [`zcf.makeInvitation(...)`](/reference/zoe-api/zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). +- **offerArgs** expressing additional arguments for the **offerHandler** associated with the invitation by [`zcf.makeInvitation(...)`](/reference/zoe-api/zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customdetails-proposalshape). ## Invitations An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special case of ERTP [Payment](/reference/ertp-api/payment.md). Each is linked to a specific contract [Instance](/reference/zoe-api/zoe-data-types.md#instance), and -having one gives you the right to participate in that contract instance by making offers with it. +having one gives you the right to participate in that contract instance +by using that invitation as the first argument to `E(zoe).offer(...)`. There are two ways for contract users to get an invitation: - If you create the contract instance, the contract might supply a special creator invitation. diff --git a/main/reference/zoe-api/user-seat.md b/main/reference/zoe-api/user-seat.md index 851b98030..a75d85553 100644 --- a/main/reference/zoe-api/user-seat.md +++ b/main/reference/zoe-api/user-seat.md @@ -71,7 +71,7 @@ For example, in the [Automatic Refund](/guides/zoe/contracts/automatic-refund.md In the [Covered Call](/guides/zoe/contracts/covered-call.md) example, it's a call option, which is an assayable **[Invitation](./zoe-data-types.md#invitation)** to buy the underlying asset. Strings and invitations are the most common things returned. The value is the result returned by the **offerHandler** function passed -in the first argument to [`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). +in the first argument to [`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customdetails-proposalshape). Since the contract can return whatever it wants as an offer result, there is no guarantee that the promise will resolve promptly. diff --git a/main/reference/zoe-api/zcfmint.md b/main/reference/zoe-api/zcfmint.md index 9d0e73e61..d89d6423e 100644 --- a/main/reference/zoe-api/zcfmint.md +++ b/main/reference/zoe-api/zcfmint.md @@ -30,7 +30,7 @@ Mints the *gains* **Amount** of assets and adds them to *zcfSeat*'s **[Allocatio All **amounts** in *losses* must be of this **ZCFMint**'s **[Brand](/reference/ertp-api/brand.md)** and the *losses*' **[Keywords](./zoe-data-types.md#keyword)** must be defined by the contract instance in which *zcfSeat* is participating. Subtracts *losses* from *zcfSeat*'s **[Allocation](./zoe-data-types.md#allocation)**, then -burns that **amount** of assets from the pooled **[Purse](/reference/ertp-api/purse.md)**. +burns that **amount** from the assets escrowed by Zoe for this contract instance. diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 1fd42259a..448153b82 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -70,10 +70,11 @@ associated with the **Issuer** value of the record: await zcf.saveIssuer(secondaryIssuer, keyword); ``` -## zcf.makeInvitation(offerHandler, description, customProperties?, proposalShape?) +<a id="zcf-makeinvitation-offerhandler-description-customproperties-proposalshape"></a> +## zcf.makeInvitation(offerHandler, description, customDetails?, proposalShape?) - **offerHandler**: **(seat: ZCFSeat, offerArgs?: CopyRecord) => any** - **description**: **String** -- **customProperties**: **Object** - Optional. +- **customDetails**: **Object** - Optional. - **proposalShape**: **Pattern** - Optional. - Returns: **Promise<[Invitation](./zoe-data-types.md#invitation)>** @@ -91,10 +92,12 @@ and returning arbitrary offer results. **description** is a required string describing the **Invitation**, and should include whatever information is needed for a potential recipient of the **Invitation** -to know what they are getting in the optional **customProperties** argument, which is -put in the **Invitation**'s **amount**. -Each one should be a string literal that is unique within its contract and -used only as the argument to make invitations of a particular kind. +to distinguish among this contract's invitations. +Each description should be a string literal that is unique within its contract +and used only as the argument to make invitations of a particular kind. + +The optional **customDetails** argument is included in the **Invitation**'s +**amount** and not otherwise relied on by Zoe. ```js const creatorInvitation = zcf.makeInvitation(makeCallOption, 'makeCallOption') @@ -240,7 +243,7 @@ zcf.assertUniqueKeyword(keyword); Prohibit invocation of invitatations whose description include any of the strings. Any of the strings that end with a colon (`:`) will be treated as a prefix, and invitations whose description string begins with the string (including the colon) -will be burned and not processed if passed to **E(Zoe).offer()**. +will not be processed if passed to **E(Zoe).offer()**. Instead, an exception will be thrown. It is expected that most contracts will never invoke this function directly. It is intended to be used by **governance** in a legible way, so that the contract's diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index b4afa6fd3..46159fad4 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -40,9 +40,13 @@ An **Invitation Payment** is a **[Payment](/reference/ertp-api/payment.md)** hol ## InvitationIssuer -The **InvitationIssuer** is a special type of **[Issuer](/reference/ertp-api/issuer.md)**. -Zoe has a single **InvitationIssuer** for its entire lifetime. All **Invitations** come from the -**[Mint](/reference/ertp-api/mint.md)** associated with the Zoe instance's **InvitationIssuer**. +The **InvitationIssuer** is an **[Issuer](/reference/ertp-api/issuer.md)** that plays a +special role throughout Zoe. Zoe has a single **InvitationIssuer** for its entire +lifetime. All **Invitations** come from the **[Mint](/reference/ertp-api/mint.md)** +associated with the Zoe instance's **InvitationIssuer**. + +The issuer is publicly available (via [`E(Zoe).getInvitationIssuer()`](./zoe-contract-facet.md#zcf-getinvitationissuer)), +so the ability to validate invitations is widely available. **InvitationIssuer** has all the methods of regular **Issuers**, but the two methods that are most often used are **[anIssuer.claim()](/reference/ertp-api/issuer.md#anissuer-claim-payment-optamount)** diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 2ebf2b70d..4613639f1 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -301,7 +301,7 @@ Used to make an offer to the contract that created the **invitation**. **proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties respectively expressing conditions regarding what is being given, -what is expected in exchange (protected by offer safety), and +what is desired in exchange (protected by offer safety), and an exit rule defining how/when the offer can be canceled. Note that the contract is not obligated to accept the proposal; it may inspect it and reject it for any reason @@ -332,7 +332,7 @@ the Keywords might be "Asset" and "Bid". **paymentPKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)** containing the actual **payments** to be escrowed by Zoe. -Every **Keyword** in **give** must also have a corresponding **payment**. +Every **Keyword** in **give** must have a corresponding **payment**. ```js const paymentKeywordRecord = harden({ Asset: quatloosPayment }); @@ -343,7 +343,7 @@ const paymentKeywordRecord = harden({ Asset: quatloosPayment }); **offerArgs** is an optional CopyRecord that can be used to pass additional arguments to the **offerHandler** contract code associated with the invitation by -[`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customproperties-proposalshape). +[`zcf.makeInvitation(...)`](./zoe-contract-facet.md#zcf-makeinvitation-offerhandler-description-customdetails-proposalshape). Each contract can define the properties it supports and which are required. ## E(Zoe).installBundleID(bundleId) From c53f09e81d57cac06505a84db1bc5ce2df9d2bb3 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Fri, 1 Dec 2023 21:13:01 -0500 Subject: [PATCH 28/36] feat: Document Patterns, specifically for zcf.makeInvitation proposalShape --- main/reference/zoe-api/zoe-contract-facet.md | 20 +++++++++++++++++--- main/reference/zoe-api/zoe-helpers.md | 2 +- main/reference/zoe-api/zoe.md | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 448153b82..9af85ee63 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -75,7 +75,7 @@ await zcf.saveIssuer(secondaryIssuer, keyword); - **offerHandler**: **(seat: ZCFSeat, offerArgs?: CopyRecord) => any** - **description**: **String** - **customDetails**: **Object** - Optional. -- **proposalShape**: **Pattern** - Optional. +- **proposalShape**: **[Pattern](https://github.com/endojs/endo/tree/master/packages/patterns#readme)** - Optional. - Returns: **Promise<[Invitation](./zoe-data-types.md#invitation)>** Uses the Zoe **[InvitationIssuer](./zoe-data-types.md#invitationissuer)** to _mint_ @@ -93,14 +93,28 @@ and returning arbitrary offer results. **description** is a required string describing the **Invitation**, and should include whatever information is needed for a potential recipient of the **Invitation** to distinguish among this contract's invitations. -Each description should be a string literal that is unique within its contract +Each description should be a string literal that is unique within the source text of its contract and used only as the argument to make invitations of a particular kind. The optional **customDetails** argument is included in the **Invitation**'s **amount** and not otherwise relied on by Zoe. +The optional **proposalShape** argument can be used to describe the required and allowed components of each proposal. +Proposals that don't match the pattern will be rejected by Zoe without even being sent to the contract. + ```js -const creatorInvitation = zcf.makeInvitation(makeCallOption, 'makeCallOption') +import { M } from "@endo/patterns"; + +const waivedExitProposalShape = M.splitRecord( + // required properties + { exit: { waived: null } }, + // optional properties + { give: M.record(), want: M.record() }, + // unknown properties + M.record(), +); +const creatorInvitation = + zcf.makeInvitation(makeCallOption, 'makeCallOption', undefined, waivedExitProposalShape); ``` ## zcf.makeEmptySeatKit() diff --git a/main/reference/zoe-api/zoe-helpers.md b/main/reference/zoe-api/zoe-helpers.md index 1e7797cc1..8f601e88b 100644 --- a/main/reference/zoe-api/zoe-helpers.md +++ b/main/reference/zoe-api/zoe-helpers.md @@ -208,7 +208,7 @@ const swapMsg = swapExact(zcf, zcfSeatA, zcfSeatB); ## fitProposalShape(seat, proposalShape) - **seat**: **[ZCFSeat](./zcfseat.md)** -- **proposalShape**: **Pattern** +- **proposalShape**: **[Pattern](https://github.com/endojs/endo/tree/master/packages/patterns#readme)** - Returns: None. Checks the seat's proposal against the *proposalShape* argument. If the proposal does not match *proposalShape*, the seat will be exited and all **[Payments](/reference/ertp-api/payment.md)** will be refunded. diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 4613639f1..411678865 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -188,7 +188,7 @@ const instance = await E(Zoe).getInstance(invitation); ## E(Zoe).getProposalShapeForInvitation(invitation) - **invitation**: **[Invitation](./zoe-data-types.md#invitation)** -- Returns: **Promise<Pattern>** +- Returns: **Promise<[Pattern](https://github.com/endojs/endo/tree/master/packages/patterns#readme)>** Returns a **Promise** for the **Pattern** that the **Invitation's** **Proposal** adheres to. From ed6608026eeb1f810b21cd77d69f28475e42c34a Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Thu, 30 Nov 2023 18:29:49 -0500 Subject: [PATCH 29/36] chore: Improve descriptions per code review --- main/glossary/README.md | 24 ++++++++++------------ main/reference/ertp-api/ertp-data-types.md | 12 +++++------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 2411a5ce3..8cbc5bbe6 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -251,12 +251,12 @@ For details, see [`E(zoe).offer(...)`](/reference/zoe-api/zoe.md#proposals). ## Facet A *facet* is an object that exposes an API or particular view of some larger entity, which may be an object itself. -You can make any number of facets of an entity. In JavaScript, you often make a facet by selecting methods from the entity, -either directly or by destructuring: +You can make any number of facets of an entity. In JavaScript, you often make a facet that forwards method calls: ```js -const facet = { - myMethod: oldObject.method, -} +import { Far } from '@endo/far'; +const facet = Far('FacetName', { + myMethod: (...args) => oldObject.method(...args), +}); ``` Two Agoric uses are: - *Deposit Facet*: A facet of a [purse](#purse). Anyone with a reference to its deposit facet object can add @@ -285,7 +285,7 @@ its [section in the JavaScript Distributed Programming Guide](https://github.com ## Hardened JavaScript (SES) Hardened JavaScript is a standards-track extension to the JavaScript standard. -Hardening JavaScript turns the sandbox into firm ground, where you can code run +Hardening JavaScript turns the sandbox into firm ground, where you can run code you don't completely trust, without being vulnerable to their bugs or bad intentions. See the [Endo and Hardened JavaScript Programming @@ -554,13 +554,11 @@ it set at $10. They can specify the instance's minimum bid amount in its terms. ## Value -Values are the part of an [amount](#amount) that describe the value of something -that can be owned or shared: How much, how many, or a description of a unique asset, such as -Pixel(3,2), $3, or “Seat J12 for the show September 27th at 9:00pm”. -[Fungible](#fungible) values are usually represented by natural numbers. -Other values may be represented as a CopySet of strings naming particular rights or -arbitrary objects representing the rights directly (usually [non-fungible](#non-fungible) assets). -Values must be [Keys](#key). +A value is the part of an [Amount](#amount) that describes the value of something +that can be owned or shared: how much, how many, or a description of a unique asset, such as +$3, Pixel(3,2), or “Seat J12 for the show September 27th at 9:00pm”. +For a [fungible](#fungible) Amount, the Value is usually a non-negative **BigInt** such as `10n` or `137n`. +For a [non-fungible](#non-fungible) Amount, the Value might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. For more information, see the [ERTP documentation's Value section](/guides/ertp/amounts.md#values). diff --git a/main/reference/ertp-api/ertp-data-types.md b/main/reference/ertp-api/ertp-data-types.md index 849253feb..edca2b55e 100644 --- a/main/reference/ertp-api/ertp-data-types.md +++ b/main/reference/ertp-api/ertp-data-types.md @@ -36,12 +36,12 @@ someAmountShape: { ## Value -**Values** describe how much of something can be owned or shared. -For fungible **[Amounts](#amount)**, **Values** are non-negative **BigInts**. -For non-fungible **Amounts**, **Values** are [copyArrays](/guides/js-programming/far.md#passstyleof-api) -(e.g., a hardened array of strings). - -Recall that **BigInt**s are written with an *n* at the end: **10n**, **137n**, etc. +A **Value** is the part of an [Amount](#amount) that describes the value of something +that can be owned or shared: how much, how many, or a description of a unique asset, such as +$3, Pixel(3,2), or “Seat J12 for the show September 27th at 9:00pm”. +For a fungible **Amount**, the **Value** is usually a non-negative **BigInt** such as `10n` or `137n`. +For a non-fungible **Amount**, the **Value** might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. +Values must be [Keys](/glossary/#key). ## AssetKind From 35c4cf062bbcfbca42a7df5c3538a530ded0150c Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Fri, 1 Dec 2023 14:37:59 -0500 Subject: [PATCH 30/36] fix(glossary): Alphabetize --- main/glossary/README.md | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 8cbc5bbe6..68a19b656 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -32,6 +32,27 @@ The contract can modify a seat's allocation as long as it never violates offer s assign assets that weren't already in some allocation and it can't assign them to more than one seat. Also, goods can't disappear from the total allocation. +## Amount + +Amounts are the canonical descriptions of tradable goods. They are manipulated +by [issuers](#issuer) and [mints](#mint), and represent the goods and currency carried by +[purses](#purse) and [payments](#payment). They represent things like currency, stock, and the +abstract right to participate in a particular exchange. + +An amount is comprised of a [brand](#brand) with a [value](#value). For example, "4 Quatloos" +is an amount with a value of "4" and a brand of the imaginary currency "Quatloos". + +**Important**: Amounts are *descriptions* of digital assets, not the actual assets. They have no +economic scarcity or intrinsic value. +For example, to make you an offer to buy a magic sword in a game, +a party sends you an amount describing the asset of 5 Quatloos they're willing to trade for your +sword. They don't send you the actual 5 Quatloos; that only happens when there is agreement on the +trade terms and they send you a payment, not an amount, of 5 Quatloos, the actual asset. Creating +a new `amount` does **not** create new assets. + +For more information, see the [ERTP documentation's Amounts section](/guides/ertp/amounts.md) +and the [ERTP API's AmountMath section](/reference/ertp-api/amount-math.md). + ## AmountMath The AmountMath library executes the logic of how [amounts](#amount) are changed when digital assets are merged, separated, @@ -60,26 +81,9 @@ five tickets is performed by set union rather than by arithmetic. For more information, see the [ERTP documentation's AmountMath section](/guides/ertp/amount-math.md) and the [ERTP API's AmountMath section](/reference/ertp-api/amount-math.md). -## Amount -Amounts are the canonical descriptions of tradable goods. They are manipulated -by [issuers](#issuer) and [mints](#mint), and represent the goods and currency carried by -[purses](#purse) and [payments](#payment). They represent things like currency, stock, and the -abstract right to participate in a particular exchange. -An amount is comprised of a [brand](#brand) with a [value](#value). For example, "4 Quatloos" -is an amount with a value of "4" and a brand of the imaginary currency "Quatloos". -**Important**: Amounts are *descriptions* of digital assets, not the actual assets. They have no -economic scarcity or intrinsic value. -For example, to make you an offer to buy a magic sword in a game, -a party sends you an amount describing the asset of 5 Quatloos they're willing to trade for your -sword. They don't send you the actual 5 Quatloos; that only happens when there is agreement on the -trade terms and they send you a payment, not an amount, of 5 Quatloos, the actual asset. Creating -a new `amount` does **not** create new assets. - -For more information, see the [ERTP documentation's Amounts section](/guides/ertp/amounts.md) -and the [ERTP API's AmountMath section](/reference/ertp-api/amount-math.md). ## AssetHolder From 4ebf6bfdc99775c9d100e5cdf5ae07097c5e4e5f Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Fri, 1 Dec 2023 16:40:02 -0500 Subject: [PATCH 31/36] style: Improve the consistency of code samples --- main/glossary/README.md | 2 +- main/guides/js-programming/notifiers.md | 4 +- main/guides/zoe/actual-contracts/PSM.md | 4 +- main/guides/zoe/contracts/barter-exchange.md | 2 +- main/guides/zoe/contracts/covered-call.md | 4 +- main/reference/ertp-api/amount-math.md | 18 ++--- main/reference/ertp-api/issuer.md | 31 +++++---- main/reference/ertp-api/mint.md | 6 +- main/reference/ertp-api/payment.md | 2 +- main/reference/ertp-api/purse.md | 7 +- main/reference/repl/board.md | 2 +- main/reference/repl/networking.md | 2 +- main/reference/zoe-api/ratio-math.md | 16 ++--- main/reference/zoe-api/zoe-helpers.md | 71 +++++++++----------- main/reference/zoe-api/zoe.md | 16 ++--- 15 files changed, 92 insertions(+), 95 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 68a19b656..5808289c0 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -124,7 +124,7 @@ Before a contract can be installed on Zoe, its source code must be bundled. This ```js import bundleSource from '@endo/bundle-source'; const atomicSwapBundle = await bundleSource( - require.resolve('@agoric/zoe/src/contracts/atomicSwap'), + require.resolve('@agoric/zoe/src/contracts/atomicSwap'), ); ``` The installation operation returns an `installation`, which is an object with a single diff --git a/main/guides/js-programming/notifiers.md b/main/guides/js-programming/notifiers.md index 19af093a2..fd2c1a658 100644 --- a/main/guides/js-programming/notifiers.md +++ b/main/guides/js-programming/notifiers.md @@ -208,7 +208,7 @@ const consume = async subscription => { } }; consume(subscription); -// eventually prints +// Eventually prints: // non-final-value a // non-final-value b // the iteration finished @@ -221,7 +221,7 @@ const observer = harden({ fail: reason => console.log('failed', reason), }); observeIteration(subscription, observer); -// eventually prints +// Eventually prints: // non-final-value a // non-final-value b // finished done diff --git a/main/guides/zoe/actual-contracts/PSM.md b/main/guides/zoe/actual-contracts/PSM.md index 2c6a44ed3..1b4b3bfbc 100644 --- a/main/guides/zoe/actual-contracts/PSM.md +++ b/main/guides/zoe/actual-contracts/PSM.md @@ -51,8 +51,8 @@ this proposal doesn’t have (or need) an exit condition. ```js const myProposal = { - give: {In: giveAnchorAmount }, - want: {Out: wantMintedAmount } + give: { In: giveAnchorAmount }, + want: { Out: wantMintedAmount } }; ``` 4. Create a payment record containing the external stable tokens you’re trading to the PSM. diff --git a/main/guides/zoe/contracts/barter-exchange.md b/main/guides/zoe/contracts/barter-exchange.md index 56563cb0d..e3d4383a6 100644 --- a/main/guides/zoe/contracts/barter-exchange.md +++ b/main/guides/zoe/contracts/barter-exchange.md @@ -19,7 +19,7 @@ keeps an order book, and each time it receives a new offer, it looks for matches throughout the order book. The Barter Exchange only accepts offers that look like -`{ give: { In: amount }, want: { Out: amount}` } +`{ give: { In: amount }, want: { Out: amount }` } The want amount will be matched, while the give amount is a maximum. Each successful trader gets their `want` and may trade with counter-parties who diff --git a/main/guides/zoe/contracts/covered-call.md b/main/guides/zoe/contracts/covered-call.md index 6da3e4fd7..523bfed54 100644 --- a/main/guides/zoe/contracts/covered-call.md +++ b/main/guides/zoe/contracts/covered-call.md @@ -50,7 +50,9 @@ with the key "afterDeadline": { give: { ... }, want: { ... }, - exit: {afterDeadline: { deadline: time, timer: chainTimer } }, + exit: { + afterDeadline: { deadline: time, timer: chainTimer }, + }, } ``` diff --git a/main/reference/ertp-api/amount-math.md b/main/reference/ertp-api/amount-math.md index e1c0d0ec1..1815ec62f 100644 --- a/main/reference/ertp-api/amount-math.md +++ b/main/reference/ertp-api/amount-math.md @@ -25,7 +25,7 @@ not equal, an error is thrown and no changes are made. Creates an **Amount** from a given **Value** and a **Brand**. ```js -//amount837 = { value: 837n, brand: quatloos } +// amount837 = { brand: quatloosBrand, value: 837n } const amount837 = AmountMath.make(quatloosBrand, 837n); ``` @@ -53,7 +53,7 @@ Returns the **Value** from the given **Amount**. ```js const quatloos123 = AmountMath.make(quatloosBrand, 123n); -// returns 123n +// Returns 123n const myValue = AmountMath.getValue(quatloosBrand, quatloos123); ``` ## AmountMath.makeEmpty(brand, assetKind) @@ -64,7 +64,7 @@ const myValue = AmountMath.getValue(quatloosBrand, quatloos123); Returns the **Amount** representing an empty **Amount** for the *brand* parameter's **Brand**. This is the identity element for **AmountMath.add()** and **AmountMath.subtract()**. The empty **Value** depends -on whether the *assetKind* is **AssetKind.NAT** (*0n*), **AssetKind.COPY_SET** (*[]*), or **AssetKind.COPY_BAG** (*[]*). +on whether the *assetKind* is **AssetKind.NAT** (`0n`), **AssetKind.COPY_SET** (`[]`), or **AssetKind.COPY_BAG** (`[]`). ```js // Returns an empty amount. @@ -81,9 +81,9 @@ Returns the **Amount** representing an empty **Amount**, using another **Amount** as the template for the **[Brand](./brand.md)** and **[Value](./ertp-data-types.md#value)**. ```js -// quatloosAmount837 = { value: 837n, brand: quatloos } +// quatloosAmount837 = { brand: quatloos, value: 837n } const quatloosAmount837 = AmountMath.make(quatloosBrand, 837n); -// Returns an amount = { value: 0n, brand: quatloos } +// Returns an amount = { brand: quatloos, value: 0n } const quatloosAmount0 = AmountMath.makeEmptyFromAmount(quatloosAmount837); ``` @@ -100,10 +100,10 @@ If the optional *brand* argument doesn't match the **Amount**'s **Brand**, an er const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); const quatloos1 = AmountMath.make(quatloosBrand, 1n); -// returns true +// Returns true const result = AmountMath.isEmpty(empty); -// returns false +// Returns false const result = AmountMath.isEmpty(quatloos1); ``` @@ -254,7 +254,7 @@ If the optional *brand* argument doesn't match the **Brand** of *x* and *y*, an const smallerAmount = AmountMath.make(quatloosBrand, 5n); const largerAmount = AmountMath.make(quatloosBrand, 10n); -//returns smallerAmount +// Returns smallerAmount const comparisonResult = AmountMath.min(smallerAmount, largerAmount); ``` @@ -274,7 +274,7 @@ If the optional *brand* argument doesn't match the **Brand** of *x* and *y*, an const smallerAmount = AmountMath.make(quatloosBrand, 5n); const largerAmount = AmountMath.make(quatloosBrand, 10n); -//returns largerAmount +// Returns largerAmount const comparisonResult = AmountMath.max(smallerAmount, largerAmount); ``` diff --git a/main/reference/ertp-api/issuer.md b/main/reference/ertp-api/issuer.md index 66ad8b126..89d1f96ba 100644 --- a/main/reference/ertp-api/issuer.md +++ b/main/reference/ertp-api/issuer.md @@ -59,13 +59,13 @@ makeIssuerKit('title', AssetKind.COPY_SET); ``` ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = - makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); // This is merely an amount, describing assets, not minting assets const quatloos2 = AmountMath.make(quatloosBrand, 2n); -const { issuer: titleIssuer, mint: titleMint, brand: titleBrand } = - makeIssuerKit('propertyTitle'); +const { issuer: titleIssuer, mint: titleMint, brand: titleBrand } = + makeIssuerKit('propertyTitle'); // These are merely amounts describing digital assets, not minting assets. const cornerProperty = AmountMath.make(propertyTitleBrand, ['1292826']); const adjacentProperty = AmountMath.make(propertyTitleBrand, ['1028393']); @@ -119,7 +119,8 @@ source cannot be trusted to provide its own true value, the **Issuer** must be u validate its **[Brand](./brand.md)** and report how much the returned **Amount** contains. ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand} = makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const quatloosPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 100n)); quatloosIssuer.getAmountOf(quatloosPayment); // returns an amount of 100 Quatloos ``` @@ -167,8 +168,8 @@ and the original **Payment** is unmodified. If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = - makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const amountToBurn = AmountMath.make(quatloosBrand, 10n); const paymentToBurn = quatloosMint.mintPayment(amountToBurn); @@ -192,7 +193,8 @@ and the original **Payment** is unmodified. If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. ```js -const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const amountExpectedToTransfer = AmountMath.make(quatloosBrand, 2n); const originalPayment = quatloosMint.mintPayment(amountExpectedToTransfer); @@ -216,14 +218,15 @@ and the original **Payment** is unmodified. Each **Payment** in *paymentsArray* must be associated with the same **[Brand](./brand.md)** as the **Issuer**. ```js -const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos'); -// create an array of 100 payments of 1 quatloo each +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); +// Create an array of 100 payments of 1 quatloo each const payments = []; for (let i = 0; i < 100; i += 1) { payments.push(quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1n))); } -// combinedpayment equals 100 +// combinedPayment equals 100 const combinedPayment = quatloosIssuer.combine(payments); ``` @@ -243,7 +246,8 @@ If *payment* is a promise, the operation proceeds after it resolves to a **Payme *payment* and *paymentAmountA* must both be associated with the same **[Brand](./brand.md)** as the **Issuer**. ```js -const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const oldPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 20n)); // After the split, paymentA has 5 quatloos and paymentB has 15. const [paymentA, paymentB] = quatloosIssuer.split(oldPayment, AmountMath.make(quatloosBrand, 5n)); @@ -265,7 +269,8 @@ If the **Amounts** in *amountArray* don't add up to the value of *payment*, the *payment* and each **Amount** in *amountArray* must be associated with the same **[Brand](./brand.md)** as **Issuer**. ```js -const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand} = makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const oldPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 100n)); const goodAmounts = Array(10).fill(AmountMath.make(quatloosBrand, 10n)); diff --git a/main/reference/ertp-api/mint.md b/main/reference/ertp-api/mint.md index 0ad9ce658..679d66092 100644 --- a/main/reference/ertp-api/mint.md +++ b/main/reference/ertp-api/mint.md @@ -18,7 +18,7 @@ in an unchangeable one-to-one relationship with a particular **Issuer**. const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit('quatloos'); const quatloosMintIssuer = quatloosMint.getIssuer(); -// returns true +// Returns true issuer === quatloosMintIssuer; ``` @@ -31,8 +31,8 @@ From its creation, a **Mint** is always in an unchangeable one-to-one relationship with a **Brand**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint - brand: quatloosBrand } = makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const quatloos1000 = amountMath.make(quatloosBrand, 1000n); // newPayment will have a balance of 1000 Quatloos diff --git a/main/reference/ertp-api/payment.md b/main/reference/ertp-api/payment.md index cd29e953f..54bf0085c 100644 --- a/main/reference/ertp-api/payment.md +++ b/main/reference/ertp-api/payment.md @@ -40,7 +40,7 @@ Any successful operation by an **Issuer** on a **Payment** verifies it. ```js const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 10n)); -//Should return 'quatloos' +// Should return 'quatloos' const allegedBrand = payment.getAllegedBrand(); ``` diff --git a/main/reference/ertp-api/purse.md b/main/reference/ertp-api/purse.md index 0ef4265f6..d15fe0301 100644 --- a/main/reference/ertp-api/purse.md +++ b/main/reference/ertp-api/purse.md @@ -18,7 +18,7 @@ method on the **[Issuer](./issuer.md)** associated with the **Brand** of assets new **Purse** to hold. ```js -const {issuer: quatloosIssuer} = makeIssuerKit{'quatloos'}; +const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); const quatloosPurse = quatloosIssuer.makeEmptyPurse(); ``` @@ -86,8 +86,8 @@ may pass them by. This is safe, as even if all the assets are withdrawn, the deposit still works on an empty **Purse**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = - makeIssuerKit('quatloos'); +const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = + makeIssuerKit('quatloos'); const quatloosPurse = quatloosIssuer.makeEmptyPurse(); const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 123n)); const quatloos123 = AmountMath.make(quatloosBrand, 123n); @@ -158,6 +158,7 @@ const depositOnlyFacet = purse.getDepositFacet(); // a payment, thus depositing the payment assets in the Purse associated with the deposit facet. depositOnlyFacet.receive(payment); ``` + Once you have created a **DepositFacet**, there is one method you can call on it, **[aDepositFacet.receive()](#adepositfacet-receive-payment-optamount)**. The **DepositFacet** takes a **Payment** and adds it to the balance of the **DepositFacet**'s associated **Purse**. The **Payment** diff --git a/main/reference/repl/board.md b/main/reference/repl/board.md index e2c62d920..a7445b869 100644 --- a/main/reference/repl/board.md +++ b/main/reference/repl/board.md @@ -61,7 +61,7 @@ Errors: ```js // Continuing from the example above in getValue(), the id returns its associated value command[3] E(home.board).getValue("1403739213") -// returns the "abc" value +// Returns the "abc" value history[3] [Alleged: presence o-102]{} ``` diff --git a/main/reference/repl/networking.md b/main/reference/repl/networking.md index def8252c8..7dbb99e03 100644 --- a/main/reference/repl/networking.md +++ b/main/reference/repl/networking.md @@ -60,7 +60,7 @@ The other side of `connect()` is a "listening port". These ports are waiting for To get a listening port, you need a `NetworkInterface` object (such as the one on your `ag-solo` under `home.network`) and ask it to `bind()` to an endpoint. You can either provide a specific port name, or allow the API to allocate a random one for you. The endpoint specifies the type of connection that this port will be able to accept (IBC, TCP, etc), and some properties of that connection. `bind()` uses a "multiaddress" to encode this information. ```js -// ask for a random allocation - ends with a slash +// Ask for a random allocation - ends with a slash E(home.network).bind('/ibc-port/') .then(port => usePort(port)); diff --git a/main/reference/zoe-api/ratio-math.md b/main/reference/zoe-api/ratio-math.md index 2b0ef16dc..852f909a6 100644 --- a/main/reference/zoe-api/ratio-math.md +++ b/main/reference/zoe-api/ratio-math.md @@ -273,11 +273,11 @@ denominator, and then the **Ratios** are added. For example: -1. Let's assume *left* = {numerator: 44n kilometers, denominator: 3n hours} and -*right* = {numerator: 25n kilometers, denominator: 2n hours}. +1. Let's assume *left* = { numerator: 44n kilometers, denominator: 3n hours } and +*right* = { numerator: 25n kilometers, denominator: 2n hours }. 2. *left* would be multiplied by 2/2, and *right* would be multiplied by 3/3, resulting in -*left* = {numerator: 88n kilometers, denominator: 6n hours} and *right* = {numerator: 75n kilometers, denominator: 6n hours} -3. *left* and *right* would then be added together, resulting in {numerator: 163n kilometers, denominator: 6n hours}. +*left* = { numerator: 88n kilometers, denominator: 6n hours } and *right* = { numerator: 75n kilometers, denominator: 6n hours } +3. *left* and *right* would then be added together, resulting in { numerator: 163n kilometers, denominator: 6n hours }. This **Ratio** would then be returned. @@ -298,11 +298,11 @@ denominator, and then *right* is subtracted from *left*. For example: -1. Let's assume *left* = {numerator: 44n kilometers, denominator: 3n hours} and -*right* = {numerator: 25n kilometers, denominator: 2n hours}. +1. Let's assume *left* = { numerator: 44n kilometers, denominator: 3n hours } and +*right* = { numerator: 25n kilometers, denominator: 2n hours }. 2. *left* would be multiplied by 2/2, and *right* would be multiplied by 3/3, resulting in -*left* = {numerator: 88n kilometers, denominator: 6n hours} and *right* = {numerator: 75n kilometers, denominator: 6n hours} -3. *right* would then be subtracted from *left* would then be added together, resulting in {numerator: 13n kilometers, denominator: 6n hours}. +*left* = { numerator: 88n kilometers, denominator: 6n hours } and *right* = { numerator: 75n kilometers, denominator: 6n hours } +3. *right* would then be subtracted from *left* would then be added together, resulting in { numerator: 13n kilometers, denominator: 6n hours }. This **Ratio** would then be returned. ## multiplyRatios(left, right) diff --git a/main/reference/zoe-api/zoe-helpers.md b/main/reference/zoe-api/zoe-helpers.md index 8f601e88b..0b4e5fd52 100644 --- a/main/reference/zoe-api/zoe-helpers.md +++ b/main/reference/zoe-api/zoe-helpers.md @@ -106,7 +106,7 @@ import { assertIssuerKeywords } from '@agoric/zoe/src/contractSupport/index.js'; -// proposals for this contract instance use keywords 'Asset' and 'Price' +// Proposals for this contract instance use keywords 'Asset' and 'Price' assertIssuerKeywords(zcf, harden(['Asset', 'Price'])); ``` @@ -131,14 +131,14 @@ It then calls **satisfiedBy()** on both orders of the two **seats**. If both sat it does a swap on them. ```js -import { - satisfies, -} from '@agoric/zoe/src/contractSupport/index.js'; +import { satisfies } from '@agoric/zoe/src/contractSupport/index.js'; const satisfiedBy = (xSeat, ySeat) => - satisfies(zcf, xSeat, ySeat.getCurrentAllocation()); + satisfies(zcf, xSeat, ySeat.getCurrentAllocation()); + if (satisfiedBy(offer, seat) && satisfiedBy(seat, offer)) { - swap(zcf, seat, offer); + swap(zcf, seat, offer); +} ``` ## swap(zcf, leftSeat, rightSeat) @@ -165,9 +165,7 @@ wants 3 Quatloos, **seat** A retains 2 Quatloos. If the swap fails, no assets transfer, and both *leftSeat* and *rightSeat* are exited. ```js -import { - swap -} from '@agoric/zoe/src/contractSupport.js'; +import { swap } from '@agoric/zoe/src/contractSupport.js'; swap(zcf, firstSeat, secondSeat); ``` @@ -199,9 +197,7 @@ Once the contract has been completed, please check your payout**. If the swap fails, no assets transfer, and both *leftSeat* and *rightSeat* are exited. ```js -import { - swapExact -} from '@agoric/zoe/src/contractSupport/index.js'; +import { swapExact } from '@agoric/zoe/src/contractSupport/index.js'; const swapMsg = swapExact(zcf, zcfSeatA, zcfSeatB); ``` @@ -231,14 +227,12 @@ and **give** should be **null**; the **exit** clause should specify a rule with these expectations, that **proposal** is rejected (and refunded). ```js -import { - assertProposalShape -} from '@agoric/zoe/src/contractSupport/index.js'; +import { assertProposalShape } from '@agoric/zoe/src/contractSupport/index.js'; const sellAssetForPrice = harden({ - give: { Asset: null }, - want: { Price: null }, - }); + give: { Asset: null }, + want: { Price: null }, +}); const sell = seat => { assertProposalShape(seat, sellAssetForPrice); buySeats = swapIfCanTradeAndUpdateBook(buySeats, sellSeats, seat); @@ -257,9 +251,7 @@ This means the corresponding **[Mint](/reference/ertp-api/mint.md)** creates fun If **false** throws with message **brand must be AssetKind.NAT**. ```js -import { - assertNatAssetKind -} from '@agoric/zoe/src/contractSupport/index.js'; +import { assertNatAssetKind } from '@agoric/zoe/src/contractSupport/index.js'; assertNatAssetKind(zcf, quatloosBrand); ``` @@ -280,9 +272,8 @@ If the seat has exited, aborts with the message **The recipientSeat cannot have On success, returns the exported and settable **depositToSeatSuccessMsg** which defaults to **Deposit and reallocation successful.** ```js -import { - depositToSeat, -} from '@agoric/zoe/src/contractSupport/index.js'; +import { depositToSeat } from '@agoric/zoe/src/contractSupport/index.js'; + await depositToSeat(zcf, zcfSeat, { Dep: quatloos(2n) }, { Dep: quatloosPayment }); ``` @@ -300,9 +291,8 @@ If the seat has exited, aborts with the message **The seat cannot have exited.** Unlike **depositToSeat()**, a **PaymentPKeywordRecord** is returned, not a success message. ```js -import { - withdrawFromSeat -} from '@agoric/zoe/src/contractSupport/index.js'; +import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/index.js'; + const paymentKeywordRecord = await withdrawFromSeat(zcf, zcfSeat, { With: quatloos(2n) }); ``` @@ -318,9 +308,8 @@ This does **not** error if any of the **[Keywords](./zoe-data-types.md#keyword)* already present, it is ignored. ```js -import { - saveAllIssuers, -} from '@agoric/zoe/src/contractSupport/index.js'; +import { saveAllIssuers } from '@agoric/zoe/src/contractSupport/index.js'; + await saveAllIssuers(zcf, { G: gIssuer, D: dIssuer, P: pIssuer }); ``` @@ -355,10 +344,10 @@ contractA reverses this mapping. It looks like this, where the **Keywords** are from the contracts indicated by using "A" or "B" in the **Keyword** name. ```js // Map the keywords in contractA to the keywords in contractB - const keywordMapping = harden({ - TokenA1: 'TokenB1', - TokenA2: 'TokenB2' - }); +const keywordMapping = harden({ + TokenA1: 'TokenB1', + TokenA2: 'TokenB2', +}); ``` *offerArgs* is an object that can be used to pass @@ -381,11 +370,11 @@ Its two properties are: - **deposited**: **Promise<AmountKeywordRecord>** ```js - const { userSeatPromise: AMMUserSeat, deposited } = zcf.offerTo( - swapInvitation, - keywordMapping, // {} - proposal, - fromSeat, - lenderSeat - ); +const { userSeatPromise: AMMUserSeat, deposited } = zcf.offerTo( + swapInvitation, + keywordMapping, // {} + proposal, + fromSeat, + lenderSeat, +); ``` diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 411678865..74faba1ec 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -34,7 +34,7 @@ and the values are the **Brands** for particular **[Issuers](/reference/ertp-api const brandKeywordRecord = { FirstCurrency: quatloosBrand, SecondCurrency: moolaBrand, - //etc. + // etc. }; ``` @@ -74,12 +74,12 @@ custom terms. The returned values look like: ```js { - //brands and issuers are keywordRecords + // Brands and issuers are keywordRecords brands: { A: moolaKit.brand, B: simoleanKit.brand }, issuers: { A: moolaKit.issuer, B: simoleanKit.issuer }, customTermA: 'something', customTermB: 'something else', - //All other customTerms + // All other customTerms }; ``` @@ -114,7 +114,7 @@ const invitationIssuer = await E(Zoe).getInvitationIssuer(); // transform the untrusted invitation to a trusted one const trustedInvitation = await invitationIssuer.claim(untrustedInvitation); const { value: invitationValue } = - await E(invitationIssuer).getAmountOf(trustedInvitation); + await E(invitationIssuer).getAmountOf(trustedInvitation); ``` ## E(Zoe).getInvitationDetails(invitation) @@ -242,7 +242,7 @@ not be in the public terms. For example, to share minting authority among multiple contracts, pass in the following as **privateArgs**: ```js -{ externalMint: myExternalMint } +const privateArgs = { externalMint: myExternalMint }; ``` It returns a **Promise** for a **StartInstanceResult** object. The object consists of: @@ -278,11 +278,11 @@ represented as a **Payment**. ```js const issuerKeywordRecord = { Asset: moolaIssuer, - Price: quatlooIssuer + Price: quatlooIssuer, }; const terms = { numBids: 3 }; -const { creatorFacet, publicFacet, creatorInvitation } = await E(Zoe).startInstance( - installation, issuerKeywordRecord, terms); +const { creatorFacet, publicFacet, creatorInvitation } = + await E(Zoe).startInstance(installation, issuerKeywordRecord, terms); ``` <a id="e-zoe-offer-invitation-proposal-paymentkeywordrecord-offerargs"></a> From 9e50cf2342a6a47278ec24b7d4e40fb210e0fa1c Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Fri, 1 Dec 2023 16:41:31 -0500 Subject: [PATCH 32/36] refactor: Consistently refer to AmountValue for values in amounts --- main/glossary/README.md | 25 +++++++++------------ main/guides/ertp/README.md | 2 +- main/guides/ertp/amounts.md | 5 +++-- main/reference/ertp-api/README.md | 2 +- main/reference/ertp-api/amount-math.md | 26 +++++++++++----------- main/reference/ertp-api/ertp-data-types.md | 19 ++++++++-------- main/reference/ertp-api/purse.md | 2 +- main/reference/zoe-api/ratio-math.md | 4 ++-- main/reference/zoe-api/zoe-data-types.md | 2 +- 9 files changed, 43 insertions(+), 44 deletions(-) diff --git a/main/glossary/README.md b/main/glossary/README.md index 5808289c0..34ed95bee 100644 --- a/main/glossary/README.md +++ b/main/glossary/README.md @@ -39,7 +39,7 @@ by [issuers](#issuer) and [mints](#mint), and represent the goods and currency c [purses](#purse) and [payments](#payment). They represent things like currency, stock, and the abstract right to participate in a particular exchange. -An amount is comprised of a [brand](#brand) with a [value](#value). For example, "4 Quatloos" +An amount is comprised of a [brand](#brand) with a [value](#amountvalue). For example, "4 Quatloos" is an amount with a value of "4" and a brand of the imaginary currency "Quatloos". **Important**: Amounts are *descriptions* of digital assets, not the actual assets. They have no @@ -71,7 +71,7 @@ five tickets is performed by set union rather than by arithmetic. - `AssetKind.COPY_SET`: Used with [non-fungible](#non-fungible) assets. Each amount value is a set of [Key](#key) values (strings, numbers, objects, etc.). - Values cannot include promises (they aren't keys), and should not + Amount values cannot include promises (they aren't keys), and should not include privileged objects such as payments and purses. - `AssetKind.COPY_BAG`: Used with [semi-fungible](#semi-fungible) assets. Each amount value is a [multiset](https://en.wikipedia.org/wiki/Multiset) @@ -81,9 +81,16 @@ five tickets is performed by set union rather than by arithmetic. For more information, see the [ERTP documentation's AmountMath section](/guides/ertp/amount-math.md) and the [ERTP API's AmountMath section](/reference/ertp-api/amount-math.md). +<a id="value"></a> +## AmountValue +An AmountValue is the part of an [Amount](#amount) that describes the value of something +that can be owned or shared: how much, how many, or a description of a unique asset, such as +$3, Pixel(3,2), or “Seat J12 for the show September 27th at 9:00pm”. +For a [fungible](#fungible) Amount, the AmountValue is usually a non-negative **BigInt** such as `10n` or `137n`. +For a [non-fungible](#non-fungible) Amount, the AmountValue might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. - +For more information, see the [ERTP documentation's AmountValue section](/guides/ertp/amounts.md#amountvalues). ## AssetHolder @@ -350,7 +357,7 @@ If either side of the comparison contains promises and/or errors, equality is in If both are fulfilled down to [presences](#presence) and local state, then either they're the same all the way down, or they represent different objects. -Keys can be used as elements of CopySets and CopyBags and as keys of CopyMaps (see [AmountMath](#amountmath)). [Values](#value) must be Keys. +Keys can be used as elements of CopySets and CopyBags and as keys of CopyMaps (see [AmountMath](#amountmath)). [AmountValues](#amountvalue) must be Keys. ## Keyword @@ -556,16 +563,6 @@ they provide terms applicable only to that instance. For some instances of the auction, they want the minimum bid set at $1000. At other instances, they'd like it set at $10. They can specify the instance's minimum bid amount in its terms. -## Value - -A value is the part of an [Amount](#amount) that describes the value of something -that can be owned or shared: how much, how many, or a description of a unique asset, such as -$3, Pixel(3,2), or “Seat J12 for the show September 27th at 9:00pm”. -For a [fungible](#fungible) Amount, the Value is usually a non-negative **BigInt** such as `10n` or `137n`. -For a [non-fungible](#non-fungible) Amount, the Value might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. - -For more information, see the [ERTP documentation's Value section](/guides/ertp/amounts.md#values). - ## Vat A vat is a unit of isolation. diff --git a/main/guides/ertp/README.md b/main/guides/ertp/README.md index cb2b3a7eb..ec28bf280 100644 --- a/main/guides/ertp/README.md +++ b/main/guides/ertp/README.md @@ -41,7 +41,7 @@ and Balcony sections, where a holder may sit in any seat of the respective secti Assets are described by **[Amount](./amounts.md)** records consisting of a `brand` and a `value`. - **[Brand](./amounts.md#brands)**: An asset's type. You can think of this as the answer to the question "What is it?" about an asset. -- **[Value](./amounts.md#values)**: An asset's size. +- **[AmountValue](./amounts.md#amountvalues)**: An asset's size. You can think of this as the answer to the questions "how many?" or "how much?" about an asset. **Important**: Amounts are *descriptions* of digital assets, not the actual assets. They have no diff --git a/main/guides/ertp/amounts.md b/main/guides/ertp/amounts.md index 9a187d33b..07e9fd2eb 100644 --- a/main/guides/ertp/amounts.md +++ b/main/guides/ertp/amounts.md @@ -84,11 +84,12 @@ return a `brand`. that it's genuine. - <<< @/snippets/ertp/guide/test-amounts.js#depositSomewhere -## Values +<a id="values"></a> +## AmountValues  -Values are the "how many" part of an `amount`. +AmountValues are the "how many" part of an `amount`. Note that number values (for fungible assets) are represented as `BigInt`s and not `Number`s. Write `10n` rather than `10`. diff --git a/main/reference/ertp-api/README.md b/main/reference/ertp-api/README.md index 6e9eafdbd..5ac6fcc2e 100644 --- a/main/reference/ertp-api/README.md +++ b/main/reference/ertp-api/README.md @@ -25,7 +25,7 @@ The ERTP API introduces and uses the following data types: | --- | --- | | [Amount](./ertp-data-types.md#amount) | Describes digital assets, specifying the number and **[Brand](./brand.md)** of assets. Note that **Amounts** can describe either fungible or non-fungible assets. | | [AmountShape](./ertp-data-types.md#amountshape) | Describes digital assets, specifying the properties and **[Brand](./brand.md)** of assets. | -| [Value](./ertp-data-types.md#value) | Describes how much of something there is. | +| [AmountValue](./ertp-data-types.md#amountvalue) | Describes how much of something there is. | | [AssetKind](./ertp-data-types.md#assetkind) | Specifies whether an **Amount** is fungible or non-fungible. | | [DisplayInfo](./ertp-data-types.md#displayinfo) | Specifies how to display a **Brand**'s **Amounts**. | diff --git a/main/reference/ertp-api/amount-math.md b/main/reference/ertp-api/amount-math.md index 1815ec62f..b14b8b0fb 100644 --- a/main/reference/ertp-api/amount-math.md +++ b/main/reference/ertp-api/amount-math.md @@ -19,10 +19,10 @@ not equal, an error is thrown and no changes are made. ## AmountMath.make(brand, allegedValue) - **brand**: **[Brand](./brand.md)** -- **allegedValue**: **[Value](./ertp-data-types.md#value)** +- **allegedValue**: **[AmountValue](./ertp-data-types.md#amountvalue)** - Returns: **[Amount](./ertp-data-types.md#amount)** -Creates an **Amount** from a given **Value** and a **Brand**. +Creates an **Amount** from a given **Brand** and **AmountValue**. ```js // amount837 = { brand: quatloosBrand, value: 837n } @@ -46,9 +46,9 @@ const verifiedAmount = AmountMath.coerce(quatloosBrand, allegedAmount); ## AmountMath.getValue(brand, amount) - **brand**: **[Brand](./brand.md)** - **amount**: **[Amount](./ertp-data-types.md#amount)** -- Returns: **[Value](./ertp-data-types.md#amount)** +- Returns: **[AmountValue](./ertp-data-types.md#amountvalue)** -Returns the **Value** from the given **Amount**. +Returns the **AmountValue** from the given **Amount**. ```js const quatloos123 = AmountMath.make(quatloosBrand, 123n); @@ -63,7 +63,7 @@ const myValue = AmountMath.getValue(quatloosBrand, quatloos123); Returns the **Amount** representing an empty **Amount** for the *brand* parameter's **Brand**. This is the identity element for **AmountMath.add()** -and **AmountMath.subtract()**. The empty **Value** depends +and **AmountMath.subtract()**. The empty **AmountValue** depends on whether the *assetKind* is **AssetKind.NAT** (`0n`), **AssetKind.COPY_SET** (`[]`), or **AssetKind.COPY_BAG** (`[]`). ```js @@ -78,7 +78,7 @@ const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); - Returns: **Amount** Returns the **Amount** representing an empty **Amount**, using another -**Amount** as the template for the **[Brand](./brand.md)** and **[Value](./ertp-data-types.md#value)**. +**Amount** as the template for the **[Brand](./brand.md)** and **[AmountValue](./ertp-data-types.md#amountvalue)**. ```js // quatloosAmount837 = { brand: quatloos, value: 837n } @@ -113,13 +113,13 @@ const result = AmountMath.isEmpty(quatloos1); - **brand**: **[Brand](./brand.md)** - Optional, defaults to **undefined**. - Returns: **Boolean** -Returns **true** if the **[Value](./ertp-data-types.md#value)** of *leftAmount* is greater than or equal to -the **Value** of *rightAmount*. Both **Amount** arguments must have the same +Returns **true** if the **[AmountValue](./ertp-data-types.md#amountvalue)** of *leftAmount* is greater than or equal to +the **AmountValue** of *rightAmount*. Both **Amount** arguments must have the same **Brand**. If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. -For non-fungible **Values**, what "greater than or equal to" is depends on the +For non-fungible **AmountValues**, what "greater than or equal to" is depends on the kind of **AmountMath**. For example, { 'seat 1', 'seat 2' } is considered greater than { 'seat 2' } because the former both contains all of the latter's content and has additional elements. @@ -147,13 +147,13 @@ AmountMath.isGTE(quatloos5, quatloos5); - **brand**: **[Brand](./brand.md)** - Optional, defaults to **undefined**. - Returns: **Boolean** -Returns **true** if the **[Value](./ertp-data-types.md#value)** of *leftAmount* is equal to -the **Value** of *rightAmount*. Both **Amount** arguments must have the same +Returns **true** if the **[AmountValue](./ertp-data-types.md#amountvalue)** of *leftAmount* is equal to +the **AmountValue** of *rightAmount*. Both **Amount** arguments must have the same **Brand**. If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. -For non-fungible **Values**, "equal to" depends on the value of the +For non-fungible **AmountValues**, "equal to" depends on the value of the **Brand's** **[AssetKind](./ertp-data-types.md#assetkind)**. For example, { 'seat 1', 'seat 2' } is considered @@ -188,7 +188,7 @@ arguments must be of the same **Brand**. If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. -For fungible **Amounts** this means adding their **[Values](./ertp-data-types.md#value)**. For non-fungible +For fungible **Amounts** this means adding their **[AmountValues](./ertp-data-types.md#amountvalue)**. For non-fungible **Amounts**, it usually means including all of the elements from *leftAmount* and *rightAmount*. diff --git a/main/reference/ertp-api/ertp-data-types.md b/main/reference/ertp-api/ertp-data-types.md index edca2b55e..ec39da884 100644 --- a/main/reference/ertp-api/ertp-data-types.md +++ b/main/reference/ertp-api/ertp-data-types.md @@ -5,7 +5,7 @@ ERTP introduces and uses several data types. ## Amount An **Amount** is a description of digital assets, answering the -questions "how much?" and "of what kind?". It is a **[Value](#value)** ("how much?") +questions "how much?" and "of what kind?". It is an **[AmountValue](#amountvalue)** ("how much?") labeled with a **[Brand](./brand.md)** ("of what kind?"). The **[AmountMath](./amount-math.md)** object introduces a library of methods that can be used to manipulate and analyze **Amounts**. @@ -34,23 +34,24 @@ someAmountShape: { } ``` -## Value +<a id="value"></a> +## AmountValue -A **Value** is the part of an [Amount](#amount) that describes the value of something +An **AmountValue** is the part of an [Amount](#amount) that describes the value of something that can be owned or shared: how much, how many, or a description of a unique asset, such as $3, Pixel(3,2), or “Seat J12 for the show September 27th at 9:00pm”. -For a fungible **Amount**, the **Value** is usually a non-negative **BigInt** such as `10n` or `137n`. -For a non-fungible **Amount**, the **Value** might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. -Values must be [Keys](/glossary/#key). +For a fungible **Amount**, the **AmountValue** is usually a non-negative **BigInt** such as `10n` or `137n`. +For a non-fungible **Amount**, the **AmountValue** might be a [CopySet](/guides/js-programming/far.md#pass-styles-and-harden) containing strings naming particular rights or objects representing the rights directly. +AmountValues must be [Keys](/glossary/#key). ## AssetKind There are several kinds of Assets. -- **AssetKind.NAT** : Used with fungible assets. **Values** are natural numbers using the JavaScript [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) type to avoid overflow risks from using the usual JavaScript **Number** type. +- **AssetKind.NAT** : Used with fungible assets. **AmountValues** are natural numbers using the JavaScript [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) type to avoid overflow risks from using the usual JavaScript **Number** type. - **AssetKind.SET** : Deprecated. -- **AssetKind.COPY_SET** : Used with non-fungible assets where there can't be duplicates (e.g., assigned seats in a stadium). **Values** are arrays of objects. -- **AssetKind.COPY_BAG** : Used with non-fungible assets where there can be duplicates. (e.g., weapons in a computer game). **Values** are arrays of objects. +- **AssetKind.COPY_SET** : Used with non-fungible assets where there can't be duplicates (e.g., assigned seats in a stadium). **AmountValues** are arrays of objects. +- **AssetKind.COPY_BAG** : Used with non-fungible assets where there can be duplicates. (e.g., weapons in a computer game). **AmountValues** are arrays of objects. Even though very different mathematical processes are performed, **[AmountMath](./amount-math.md)** methods work for all kinds of assets. diff --git a/main/reference/ertp-api/purse.md b/main/reference/ertp-api/purse.md index d15fe0301..706b4bb71 100644 --- a/main/reference/ertp-api/purse.md +++ b/main/reference/ertp-api/purse.md @@ -36,7 +36,7 @@ send the **Payment** to another party. - Returns: **[Amount](./ertp-data-types.md#amount)** Returns the **Purse**'s current balance as an **Amount**. -The returned **Amount** **[Value](./ertp-data-types.md#value)** might be empty, and might be different the next time you +The returned **Amount** **[AmountValue](./ertp-data-types.md#amountvalue)** might be empty, and might be different the next time you call **aPurse.getCurrentAmount()** on the same **Purse** if assets have been deposited or withdrawn in the interim. diff --git a/main/reference/zoe-api/ratio-math.md b/main/reference/zoe-api/ratio-math.md index 852f909a6..fdcbdbe9f 100644 --- a/main/reference/zoe-api/ratio-math.md +++ b/main/reference/zoe-api/ratio-math.md @@ -342,8 +342,8 @@ aren't identical. Returns **true** if the *left* and *right* **Ratios** are the same, **false** otherwise. Note that for the two **Ratios** to be considered the same, the -**[Value](/reference/ertp-api/ertp-data-types.md#value)** and **[Brand](/reference/ertp-api/brand.md)** -of both the *numerator* and *denominator* of one **Ratio** must be identical to the **Value** and +**[AmountValue](/reference/ertp-api/ertp-data-types.md#amountvalue)** and **[Brand](/reference/ertp-api/brand.md)** +of both the *numerator* and *denominator* of one **Ratio** must be identical to the **AmountValue** and **Brand** of the *numerator* and *denominator* of the other **Ratio**. diff --git a/main/reference/zoe-api/zoe-data-types.md b/main/reference/zoe-api/zoe-data-types.md index 46159fad4..b3e8a0ddc 100644 --- a/main/reference/zoe-api/zoe-data-types.md +++ b/main/reference/zoe-api/zoe-data-types.md @@ -127,7 +127,7 @@ const { quoteAmount, quotePayment } = priceQuote; **Ratios** are pass-by-value records that consist of a *numerator* and a *denominator*. Both of these consist of a -**[Value](/reference/ertp-api/ertp-data-types.md#value)** and a **[Brand](/reference/ertp-api/brand.md)**, +**[AmountValue](/reference/ertp-api/ertp-data-types.md#amountvalue)** and a **[Brand](/reference/ertp-api/brand.md)**, just like **[Amounts](/reference/ertp-api/ertp-data-types.md#amount)**. A **Ratio** cannot have a denominator value of 0. From 2cce5008b2de6faa5f2e65527b3cc5bed2e0e0b5 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Sun, 3 Dec 2023 11:59:33 -0500 Subject: [PATCH 33/36] chore: Alphabetize redirects --- main/.vuepress/enhanceApp.js | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/main/.vuepress/enhanceApp.js b/main/.vuepress/enhanceApp.js index 3c132ae5f..bb9af32f3 100644 --- a/main/.vuepress/enhanceApp.js +++ b/main/.vuepress/enhanceApp.js @@ -46,37 +46,37 @@ function patchRoutesToPreserveFragments(router) { export default ({ router }) => { patchRoutesToPreserveFragments(router); const redirects = [ - { path: '/wallet-api/', redirect: '/guides/wallet/' }, - { path: '/wallet-api.html', redirect: '/guides/wallet/' }, - { path: '/chainlink-integration/', redirect: '/guides/chainlink-integration/' }, { path: '/chainlink-integration.html', redirect: '/guides/chainlink-integration/' }, - { path: '/distributed-programming/', redirect: '/guides/js-programming/' }, + { path: '/chainlink-integration/', redirect: '/guides/chainlink-integration/' }, + { path: '/dapps/', redirect: '/guides/dapps/' }, { path: '/distributed-programming.html', redirect: '/guides/js-programming/' }, - { path: '/getting-started/agoric-cli-guide/', redirect: '/guides/agoric-cli/' }, + { path: '/distributed-programming/', redirect: '/guides/js-programming/' }, + { path: '/ertp/api/', redirect: '/reference/ertp-api/' }, + { path: '/ertp/api/issuer.html', redirect: '/reference/ertp-api/issuer.html' }, + { path: '/ertp/guide/', redirect: '/guides/ertp/' }, + { path: '/ertp/guide/amounts.html', redirect: '/guides/ertp/amounts.html' }, { path: '/getting-started/agoric-cli-guide.html', redirect: '/guides/agoric-cli/' }, - { path: '/guides/js-programming/ses/ses-guide.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.html' }, - { path: '/guides/js-programming/ses/ses-reference.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/reference.html' }, - { path: '/guides/js-programming/ses/lockdown.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/lockdown.html' }, + { path: '/getting-started/agoric-cli-guide/', redirect: '/guides/agoric-cli/' }, { path: '/getting-started/before-using-agoric.html', redirect: '/guides/getting-started/' }, + { path: '/getting-started/beta.html', redirect: '/guides/getting-started/' }, + { path: '/getting-started/intro-zoe.html', redirect: '/guides/zoe/offer-enforcement.html' }, { path: '/getting-started/start-a-project.html', redirect: '/guides/getting-started/start-a-project.html' }, { path: '/guides/agoric-cli/commands.html', redirect: '/guides/agoric-cli/' }, - { path: '/dapps/', redirect: '/guides/dapps/' }, - { path: '/ertp/guide/', redirect: '/guides/ertp/' }, - { path: '/ertp/guide/amounts.html', redirect: '/guides/ertp/amounts.html' }, + { path: '/guides/js-programming/ses/lockdown.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/lockdown.html' }, + { path: '/guides/js-programming/ses/ses-guide.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.html' }, + { path: '/guides/js-programming/ses/ses-reference.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/reference.html' }, + { path: '/guides/wallet/api.html', redirect: '/reference/wallet-api.html' }, { path: '/platform/', redirect: '/guides/platform/' }, - { path: '/zoe/guide/', redirect: '/guides/zoe/' }, - { path: '/getting-started/intro-zoe.html', redirect: '/guides/zoe/offer-enforcement.html' }, - { path: '/zoe/guide/offer-safety.html', redirect: '/guides/zoe/offer-safety.html' }, - { path: '/zoe/guide/contracts/', redirect: '/guides/zoe/contracts/' }, - { path: '/zoe/guide/contracts/oracle.html', redirect: '/guides/zoe/contracts/oracle.html' }, - { path: '/ertp/api/', redirect: '/reference/ertp-api/' }, - { path: '/ertp/api/issuer.html', redirect: '/reference/ertp-api/issuer.html' }, { path: '/repl/', redirect: '/reference/repl/' }, { path: '/repl/timerServices.html', redirect: '/reference/repl/timerServices.html' }, - { path: '/guides/wallet/api.html', redirect: '/reference/wallet-api.html' }, + { path: '/wallet-api.html', redirect: '/guides/wallet/' }, + { path: '/wallet-api/', redirect: '/guides/wallet/' }, { path: '/zoe/api/', redirect: '/reference/zoe-api/' }, { path: '/zoe/api/zoe.html', redirect: '/reference/zoe-api/zoe.html' }, - { path: '/getting-started/beta.html', redirect: '/guides/getting-started/' }, + { path: '/zoe/guide/', redirect: '/guides/zoe/' }, + { path: '/zoe/guide/contracts/', redirect: '/guides/zoe/contracts/' }, + { path: '/zoe/guide/contracts/oracle.html', redirect: '/guides/zoe/contracts/oracle.html' }, + { path: '/zoe/guide/offer-safety.html', redirect: '/guides/zoe/offer-safety.html' }, ]; redirects.forEach(config => router.addRoute(config)); } From a66327caa50fed65bfd0fac5bb0f80a2bc576b83 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Sun, 3 Dec 2023 14:08:47 -0500 Subject: [PATCH 34/36] fix: Manually implement external redirects --- main/.vuepress/enhanceApp.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/main/.vuepress/enhanceApp.js b/main/.vuepress/enhanceApp.js index bb9af32f3..c9e00aab1 100644 --- a/main/.vuepress/enhanceApp.js +++ b/main/.vuepress/enhanceApp.js @@ -45,6 +45,16 @@ function patchRoutesToPreserveFragments(router) { export default ({ router }) => { patchRoutesToPreserveFragments(router); + // The router assumes everything is site-local, so manually implement external redirection + // to avoid Not Found URLs like 'https://docs.agoric.com/https:/github.com/...'. + // cf. https://github.com/vuejs/vue-router/issues/1280 and + // https://stackoverflow.com/questions/62254666/use-vue-router-for-redirecting-to-absolute-path + const makeExternalRedirect = target => { + const externalRedirect = () => { + location.assign(target); + }; + return externalRedirect; + }; const redirects = [ { path: '/chainlink-integration.html', redirect: '/guides/chainlink-integration/' }, { path: '/chainlink-integration/', redirect: '/guides/chainlink-integration/' }, @@ -62,9 +72,9 @@ export default ({ router }) => { { path: '/getting-started/intro-zoe.html', redirect: '/guides/zoe/offer-enforcement.html' }, { path: '/getting-started/start-a-project.html', redirect: '/guides/getting-started/start-a-project.html' }, { path: '/guides/agoric-cli/commands.html', redirect: '/guides/agoric-cli/' }, - { path: '/guides/js-programming/ses/lockdown.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/lockdown.html' }, - { path: '/guides/js-programming/ses/ses-guide.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.html' }, - { path: '/guides/js-programming/ses/ses-reference.html', redirect: 'https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/reference.html' }, + { path: '/guides/js-programming/ses/lockdown.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md') }, + { path: '/guides/js-programming/ses/ses-guide.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/guide.md') }, + { path: '/guides/js-programming/ses/ses-reference.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/reference.md') }, { path: '/guides/wallet/api.html', redirect: '/reference/wallet-api.html' }, { path: '/platform/', redirect: '/guides/platform/' }, { path: '/repl/', redirect: '/reference/repl/' }, From a0bba25401375a0702ae6eff0ae42f4831b27967 Mon Sep 17 00:00:00 2001 From: Richard Gibson <richard.gibson@gmail.com> Date: Sun, 3 Dec 2023 16:58:55 -0500 Subject: [PATCH 35/36] fix: Handle redirects as prefixes --- main/.vuepress/enhanceApp.js | 124 ++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/main/.vuepress/enhanceApp.js b/main/.vuepress/enhanceApp.js index c9e00aab1..41f2d513a 100644 --- a/main/.vuepress/enhanceApp.js +++ b/main/.vuepress/enhanceApp.js @@ -43,50 +43,86 @@ function patchRoutesToPreserveFragments(router) { }); } +// The router assumes everything is site-local, so manually implement external redirection +// to avoid Not Found URLs like 'https://docs.agoric.com/https:/github.com/...'. +// cf. https://github.com/vuejs/vue-router/issues/1280 and +// https://stackoverflow.com/questions/62254666/use-vue-router-for-redirecting-to-absolute-path +const makeExternalRedirect = target => { + const externalRedirect = () => { + location.assign(target); + }; + return externalRedirect; +}; + +const isPathPrefix = (prefix, fullPath) => { + const trimmedPrefix = prefix.replace(/\/+$/, ''); + if (!fullPath.startsWith(trimmedPrefix)) { + return false; + } + if (fullPath.length === prefix.length || fullPath[trimmedPrefix.length] === '/') { + return true; + } + // As a special case, allow /path/to/resource to match /path/to/resource.html + return fullPath.slice(prefix.length).toLowerCase() === '.html'; +}; + export default ({ router }) => { patchRoutesToPreserveFragments(router); - // The router assumes everything is site-local, so manually implement external redirection - // to avoid Not Found URLs like 'https://docs.agoric.com/https:/github.com/...'. - // cf. https://github.com/vuejs/vue-router/issues/1280 and - // https://stackoverflow.com/questions/62254666/use-vue-router-for-redirecting-to-absolute-path - const makeExternalRedirect = target => { - const externalRedirect = () => { - location.assign(target); - }; - return externalRedirect; - }; + const redirects = [ - { path: '/chainlink-integration.html', redirect: '/guides/chainlink-integration/' }, - { path: '/chainlink-integration/', redirect: '/guides/chainlink-integration/' }, - { path: '/dapps/', redirect: '/guides/dapps/' }, - { path: '/distributed-programming.html', redirect: '/guides/js-programming/' }, - { path: '/distributed-programming/', redirect: '/guides/js-programming/' }, - { path: '/ertp/api/', redirect: '/reference/ertp-api/' }, - { path: '/ertp/api/issuer.html', redirect: '/reference/ertp-api/issuer.html' }, - { path: '/ertp/guide/', redirect: '/guides/ertp/' }, - { path: '/ertp/guide/amounts.html', redirect: '/guides/ertp/amounts.html' }, - { path: '/getting-started/agoric-cli-guide.html', redirect: '/guides/agoric-cli/' }, - { path: '/getting-started/agoric-cli-guide/', redirect: '/guides/agoric-cli/' }, - { path: '/getting-started/before-using-agoric.html', redirect: '/guides/getting-started/' }, - { path: '/getting-started/beta.html', redirect: '/guides/getting-started/' }, - { path: '/getting-started/intro-zoe.html', redirect: '/guides/zoe/offer-enforcement.html' }, - { path: '/getting-started/start-a-project.html', redirect: '/guides/getting-started/start-a-project.html' }, - { path: '/guides/agoric-cli/commands.html', redirect: '/guides/agoric-cli/' }, - { path: '/guides/js-programming/ses/lockdown.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md') }, - { path: '/guides/js-programming/ses/ses-guide.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/guide.md') }, - { path: '/guides/js-programming/ses/ses-reference.html', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/reference.md') }, - { path: '/guides/wallet/api.html', redirect: '/reference/wallet-api.html' }, - { path: '/platform/', redirect: '/guides/platform/' }, - { path: '/repl/', redirect: '/reference/repl/' }, - { path: '/repl/timerServices.html', redirect: '/reference/repl/timerServices.html' }, - { path: '/wallet-api.html', redirect: '/guides/wallet/' }, - { path: '/wallet-api/', redirect: '/guides/wallet/' }, - { path: '/zoe/api/', redirect: '/reference/zoe-api/' }, - { path: '/zoe/api/zoe.html', redirect: '/reference/zoe-api/zoe.html' }, - { path: '/zoe/guide/', redirect: '/guides/zoe/' }, - { path: '/zoe/guide/contracts/', redirect: '/guides/zoe/contracts/' }, - { path: '/zoe/guide/contracts/oracle.html', redirect: '/guides/zoe/contracts/oracle.html' }, - { path: '/zoe/guide/offer-safety.html', redirect: '/guides/zoe/offer-safety.html' }, - ]; - redirects.forEach(config => router.addRoute(config)); -} + { path: '/chainlink-integration', redirect: '/guides/chainlink-integration/' }, + { path: '/dapps', redirect: '/guides/dapps/' }, + { path: '/distributed-programming', redirect: '/guides/js-programming/' }, + { path: '/ertp/api', redirect: '/reference/ertp-api/' }, + { path: '/ertp/guide', redirect: '/guides/ertp/' }, + { path: '/getting-started/agoric-cli-guide', redirect: '/guides/agoric-cli/' }, + { path: '/getting-started/before-using-agoric', redirect: '/guides/getting-started/' }, + { path: '/getting-started/beta', redirect: '/guides/getting-started/' }, + { path: '/getting-started/intro-zoe', redirect: '/guides/zoe/offer-enforcement/' }, + { path: '/getting-started/start-a-project', redirect: '/guides/getting-started/start-a-project/' }, + { path: '/guides/agoric-cli/commands', redirect: '/guides/agoric-cli/' }, + { path: '/guides/js-programming/ses/lockdown', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/lockdown.md') }, + { path: '/guides/js-programming/ses/ses-guide', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/guide.md') }, + { path: '/guides/js-programming/ses/ses-reference', redirect: makeExternalRedirect('https://github.com/endojs/endo/blob/master/packages/ses/docs/reference.md') }, + { path: '/guides/wallet/api', redirect: '/reference/wallet-api/' }, + { path: '/platform', redirect: '/guides/platform/' }, + { path: '/repl', redirect: '/reference/repl/' }, + { path: '/wallet-api', redirect: '/guides/wallet/' }, + { path: '/zoe/api', redirect: '/reference/zoe-api/' }, + { path: '/zoe/guide', redirect: '/guides/zoe/' }, + ].map(redirect => ({ ...redirect, path: redirect.path.replace(/\.html$/i, '') })); + + // Define exact-match redirect routes. + redirects.forEach(redirect => { + router.addRoute(redirect); + }); + + // Also redirect subpaths. + router.beforeEach((to, from, next) => { + const done = (...args) => { next(...args); }; + const target = to.path; + const prefixRedirects = redirects.filter(redirect => isPathPrefix(redirect.path, target)); + if (prefixRedirects.length === 0) { + // There is no covering redirect. + return done(); + } else if (prefixRedirects.some(redirect => redirect.path === target)) { + // There is an exact-match covering redirect. + return done(); + } + // Apply the longest-path covering redirect. + prefixRedirects.sort((a, b) => b.path.length - a.path.length); + const match = prefixRedirects[0]; + if (!target.startsWith(match.path)) { + console.error('unexpected covering redirect', { to, redirect }); + return done(); + } + if (typeof match.redirect === 'function') { + return done(match.redirect(to)); + } + const trimmedPrefix = match.path.replace(/\/+$/, ''); + const trimmedReplacementPrefix = match.redirect.replace(/\/+$/, ''); + const targetSuffix = target.slice(trimmedPrefix.length).replace(/\.html$/i, '/'); + const newPath = trimmedReplacementPrefix + targetSuffix; + return done({ ...to, path: newPath }); + }); +} From 296b4ff4ca8b4bb4a452e6abfa4ab8de6dc891bb Mon Sep 17 00:00:00 2001 From: Chris Hibbert <Chris-Hibbert@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:41:45 -0800 Subject: [PATCH 36/36] Refer to PatternMatcher API doc from makeInvitation (#890) * Refer to PatternMatcher API doc from makeInvitation Adding a link to the newly generated do in @endojs, and a tiny bit of explanation. * Update main/reference/zoe-api/zoe-contract-facet.md Co-authored-by: Richard Gibson <richard.gibson@gmail.com> --------- Co-authored-by: Richard Gibson <richard.gibson@gmail.com> --- main/reference/zoe-api/zoe-contract-facet.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/main/reference/zoe-api/zoe-contract-facet.md b/main/reference/zoe-api/zoe-contract-facet.md index 9af85ee63..45fb354a0 100644 --- a/main/reference/zoe-api/zoe-contract-facet.md +++ b/main/reference/zoe-api/zoe-contract-facet.md @@ -102,6 +102,21 @@ The optional **customDetails** argument is included in the **Invitation**'s The optional **proposalShape** argument can be used to describe the required and allowed components of each proposal. Proposals that don't match the pattern will be rejected by Zoe without even being sent to the contract. +Patterns are constructed using the +**[M](https://endojs.github.io/endo/interfaces/_endo_patterns.PatternMatchers.html)** (for '**M**atcher') object. +**proposalShape**s are usually built from [`M.splitRecord(required, optional, rest)`](https://endojs.github.io/endo/interfaces/_endo_patterns.PatternMatchers.html#splitRecord). + +``` + M.splitRecord({ + give: { + Collateral: makeNatAmountShape(collateralBrand), + }, + want: { + Minted: makeNatAmountShape(debtBrand), + }, + }), +``` + ```js import { M } from "@endo/patterns";