Skip to content

Commit

Permalink
fix: Improve offer documentation
Browse files Browse the repository at this point in the history
Merge pull request #876 from Agoric/gibson-2023-11-improve-offer-documentation
  • Loading branch information
gibson042 authored Dec 3, 2023
2 parents 8fe8467 + c53f09e commit 88cbbec
Show file tree
Hide file tree
Showing 13 changed files with 309 additions and 254 deletions.
72 changes: 47 additions & 25 deletions main/glossary/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,24 @@ 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 [`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.).

Expand Down Expand Up @@ -230,10 +245,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

Expand Down Expand Up @@ -288,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.
Expand Down Expand Up @@ -337,10 +350,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 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

Expand Down Expand Up @@ -413,7 +425,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

Expand All @@ -424,9 +436,15 @@ 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 [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).

## Payment

Expand All @@ -441,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

Expand All @@ -459,18 +478,21 @@ 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 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
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 respectively what will be given and what is being requested in exchange.

See [Offers](/guides/zoe/proposal.md).

## Purse

Expand Down
2 changes: 1 addition & 1 deletion main/guides/getting-started/contract-rpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-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).

![Zoe API diagram, simplified](./assets/zoe-simp.svg)

Expand Down
64 changes: 41 additions & 23 deletions main/guides/js-programming/far.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,32 @@ 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 containers include _CopyArrays_ like `harden(['foo', 'bar'])`,
_CopyRecords_ like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`, and
_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
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
Expand All @@ -56,18 +71,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"`.
- Pass-by-reference **PassableCaps**: `"remotable"` or `"promise"`.
- Pass-by-copy **Errors**: `"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
Expand All @@ -79,27 +95,29 @@ 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 }` - Optional.
- 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
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.

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
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.
:::
2 changes: 1 addition & 1 deletion main/guides/zoe/contract-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading

0 comments on commit 88cbbec

Please sign in to comment.