From 159b0a46704764c4a5f3126cc2826df159db0607 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 27 Nov 2024 15:46:42 -0800 Subject: [PATCH 1/6] docs: durable contract details collected in one place --- main/.vitepress/config.mjs | 4 + main/guides/zoe/contract-details.md | 122 ++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 main/guides/zoe/contract-details.md diff --git a/main/.vitepress/config.mjs b/main/.vitepress/config.mjs index b797ad72a..02289f3ad 100644 --- a/main/.vitepress/config.mjs +++ b/main/.vitepress/config.mjs @@ -216,6 +216,10 @@ export default defineConfig({ text: 'Complete Contract Walk-Through', link: '/guides/zoe/contract-walkthru', }, + { + text: 'Durable Contract Details', + link: '/guides/zoe/contract-details', + }, { text: 'Contract Upgrade', link: '/guides/zoe/contract-upgrade', diff --git a/main/guides/zoe/contract-details.md b/main/guides/zoe/contract-details.md new file mode 100644 index 000000000..3f3dfa25d --- /dev/null +++ b/main/guides/zoe/contract-details.md @@ -0,0 +1,122 @@ +# Durable Contract Details + +Zoe allows you to write smart contracts that manage interactions between cooperative, but possibly untrusting, +parties. Some contracts perform a single simple task like trading one good for another, and then are +done. Others stay around and manage assets and interactions over time. The first kind don't need persistence +or the ability to upgrade, while the second kind need to make use of more sophisticated functionality. + +When a contract is intended to continue running and serving many customers over a long time, its objects and +data need to be persistent, its owners or managers may need to be able to adjust parameters or perform other +governance actions, and it needs to be upgradeable so that the code can adapt over time. + +## Durable Objects + +The first step toward contracts that can be upgraded is storing all the data that a later incarnation will +need. This means putting relevant state in +[Baggage](http://localhost:5173/guides/zoe/contract-upgrade.html#baggage), and ensuring that reachable objects +that will be accessible to users have an identity that can be maintained as the behavior changes with contract +upgrades. + +We use zone.exo(), zone.exoClass(), and zone.exoClassKit() to define durable objects. + +[Zone](http://localhost:5173/glossary/#zone) provides an interface for defining objects and classes that +supports both ephemeral objects (allocated on the heap), and durable objects that can persist and that +SwingSet will page in or out on demand. + +Our persistent objects are designed to encapsulate their state, and can present different facets to different +clients to distinguish different aspects of authority. `zone.exoClass()` defines a kind with a single facet, +while `zone.exoClassKit()` defines a kind with multiple facets. (Here are some relevant [naming +conventions](https://docs.agoric.com/guides/ertp/#method-naming-structure).) + +``` +zone.exoClassKit(tag, guard, init, methodKit, options) +zone.exoClass(tag, guard, init, methods, options) +zone.exo(tag, guard, methods, options) +``` + +The next several sub-sections explain how the parameters to those functions are used. + +### Tag: naming kinds of objects + +The `tag` provides the identity of the kind of object, which is associated with the defined behavior. When a +contract (or other vat) is restarted or upgraded, SwingSet requires that all kinds that were previously +defined in a vat be defined again. With an upgrade, the behavior can be changed. We use the term "null +upgrade" to refer to upgrades that don't change the behavior. + +### Init: specifying state + +The `init` parameter defines a function that is used to define the state associated with each instance of an +object. Notice that `exo()` doesn't take `init` as a parameter; this limits the defined (singleton) object to +referencing values defined in the enclosing scope. Classes can also refer to variables in their defining +scope, but any values inherited from the scope will be accessible to all instances of that type. The `init` +function's parameters become the parameters of the maker function returned by `exoClass()` and +`exoClassKit()`. `init`'s return value is the state that will be preserved by SwingSet for each +object. `exo()` doesn't have an init parameter, so it creates and returns the singleton immediately rather +than returning a maker. + +The Exo objects (or just "Exos") defined by these functions are both persistent and virtualizable. SwingSet +knows their complete state, so it can page them out when space is tight, and page them back in when they are +referenced again. + +Fields of the object returned by the `init` function become fields of the persistent state. (These cannot +currently be changed on upgrade, though we're considering relaxing that restriction.) Within methods they can +each be accessed as fields of `this.state`. Our convention is to extract the fields that will be used in a +method on its first line, like `const { a, b } = this.state;` Once that has been done, those variable can be +read or written as normal javascript variables, and the values will persist. (For more details, see [the note +here](https://docs.agoric.com/guides/zoe/contract-upgrade.html#kinds)). + +### Methods: defining behavior + +The methods argument of `exoClass()` is a bag of methods, written in [concise method +syntax](https://github.com/Agoric/agoric-sdk/wiki/Arrow-Function-Style#far-classes-do-not-use-arrow-function-style). +`exoClass()` defines a single facet. + +The methodKit parameter to `exoClassKit` is a record of labelled bags of methods. Each label defines a facet +of the object. All facets of each object share access to the same state, but each facet is a separate +capability. Within the methods, other facets can be reached by name within `this.facets`. The maker you get +from `exoClassKit()` builds a new object each time it is called, and return all the facets. The caller can +decide which of the facets to pass to each recipient. + +### Guards: defensive methods + +These objects and facets are designed to be durable and shareable across address space boundaries. Since code +in different vats might not be mutually trusting, code needs to be defensive about parameters received from +remote callers. Interface Guards let us express in code what parameters each method expects and can handle +safely. If a caller provides a parameter that doesn't match the template specified in the guard, SwingSet +returns an exception to the caller without notifying the receiver. If the return value doesn't match, the +function returns an exception to the caller. + +`exoClass()` takes a guard for a single interface, defined by + +``` +M.interface('name', { + methodA: M.call(paramsAShape).returns(resultAShape), + methodB: M.callWhen(M.await(paramsBShape)).returns(resultBShape), +} +``` + +`M.call()` verifies that all parameters match the guard before passing them through to the +method. `M.callWhen(M.await(paramsBGuard))` awaits the resolution of the parameter, and then verifies that the +result matches before invoking the method. When a guard is written this latter way, the method doesn't have to +be `async`. In both cases, the method doesn't have to check for compliance with the guard. + +[Shapes can specify](https://endojs.github.io/endo/interfaces/_endo_patterns.PatternMatchers.html) simple +types like `M.string()`, `M.remotable()`, and `M.number()`, as well as complex structures of records and +arrays. The list of parameters can specify required and optional parameters, as well as allowing unspecified +rest parameters. + +If you want to make use of the power of this type-checking within methods, you can call `mustMatch(specimen, +pattern)` or `matches(specimen, pattern)` directly. The former throws if the pattern doesn't match, while the +latter returns a boolean. + +### Options: finish and stateShape + +All the type definers can also take an [options +argument](https://endojs.github.io/endo/types/_endo_exo.FarClassOptions.html) at the end, which is commonly +used for a `finish()` function to complete initialization, or a stateShape, which can enforce invariants on +the state values. + +`finish()`, if provided, is called after instances have been created but before they are returned to the +caller. They can be used to send an initial state update, or to complete initialization which couldn't be done +in `init`. `finish` has access to state and facets if needed. + From f47fd29baddd7b05439d0db5285b3c36a6da6fe3 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 3 Dec 2024 14:12:11 -0800 Subject: [PATCH 2/6] docs: more detail and more cross links --- main/guides/zoe/contract-upgrade.md | 57 ++++++++++++++------------- main/reference/zoe-api/zoe.md | 32 ++++++++++++++- snippets/zoe/src/02b-state-durable.js | 8 ++-- 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index 793a19ef1..d0b930a4a 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -1,8 +1,12 @@ # Contract Upgrade -The result of starting a contract includes the right to upgrade the contract instance. A call to [E(zoe).startInstance(...)](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) returns a record of several objects that represent different levels of access. -The `publicFacet` and `creatorFacet` are defined by the contract. -The `adminFacet` is defined by Zoe and includes methods to upgrade the contract. +The return value when starting a contract includes a capability that conveys the right to upgrade +the contract instance. A call to +[E(zoe).startInstance(...)](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) +returns a record of several objects that carry different powers. The `publicFacet` and +`creatorFacet` are defined by the contract. The +[`adminFacet`](/reference/zoe-api/zoe.html#adminFacet) is defined by Zoe and includes methods to +upgrade the contract. ::: tip Upgrade Governance @@ -60,16 +64,27 @@ There are a few requirements for the contract that differ from non-upgradable co ### Upgradable Declaration -The new code bundle declares that it supports upgrade by exporting a `prepare` function in place of `start`. +The new code bundle declares that it supports upgrade by including a `meta` record in addition to +`start`. (We used to indicate upgradability by using `prepare` instead of `start`, but that +approach is deprecated.)` -<<< @/../snippets/zoe/src/02b-state-durable.js#export-prepare +`meta` is a record with any or all of `upgradability`, `customTermsShape`, and `privateArgsShape` +defined. The latter two are optional +[Patterns](https://endojs.github.io/endo/modules/_endo_patterns.html) restricting respectively +acceptable `terms`, and `privateArgs`. `upgradability` can be `none` (the contract is not +upgradable), `canUpgrade` (this code can perform an upgrade), or `canBeUpgraded` (the contract +stores kinds durably such that the next version can upgrade). + +<<< @/../snippets/zoe/src/02b-state-durable.js#export-start ### Durability -The 3rd argument, `baggage`, of the `prepare` function is a `MapStore` -that provides a way to preserve state and behavior of objects -between incarnations in a way that preserves identity of objects -as seen from other vats: + + +The 3rd argument, `baggage`, of the `start` function is a `MapStore` that is saved by the kernel +across restarts of the contract. It provides a way to preserve state and behavior of objects between +incarnations in a way that also maintains the identity of objects as seen from other [vats](/glossary/#vat). + ```js let rooms; @@ -83,7 +98,7 @@ if (!baggage.has('rooms')) { } ``` -The `provide` function supports a concise idiom for this find-or-create pattern: +The `provide` function supports a concise idiom for this get-or-create pattern: ```js import { provide } from '@agoric/vat-data'; @@ -113,7 +128,8 @@ When the contract instance is restarted, its [vat](../js-programming/#vats-the-u ### Kinds -Use `zone.exoClass()` to define state and methods of kinds of durable objects such as `Room`: +Use [`zone.exoClass()`](./contract-details.md#durable-objects) to define state and methods of kinds +of durable objects such as `Room`: <<< @/../snippets/zoe/src/02b-state-durable.js#exoclass @@ -141,8 +157,9 @@ const makeRoom = zone.exoClass('Room', RoomI, id => ({ id, value: 0 }), { }); ``` -The interface guard also needs updating. -_See [@endo/patterns](https://endojs.github.io/endo/modules/_endo_patterns.html) for more on interface guards._ +The interface guard also needs updating. _[The Durable +objects](./contract-details.md#guards-defensive-methods) section has more on interface +guards._ ```js const RoomI = M.interface('Room', { @@ -175,20 +192,6 @@ Define all exo classes/kits before any incoming method calls from other vats -- ::: -### Baggage - -baggage is a MapStore that provides a way to preserve the state and behavior of objects between [smart contract upgrades](/guides/zoe/contract-upgrade) in a way that preserves the identity of objects as seen from other [vats](#vat). In the provided contract, baggage is used to ensure that the state of various components is maintained even after the contract is upgraded. - -```js -export const start = async (zcf, privateArgs, baggage) => { - // ... - const { accountsStorageNode } = await provideAll(baggage, { - accountsStorageNode: () => E(storageNode).makeChildNode('accounts') - }); - // ... -}; -``` - ### Exo An Exo object is an exposed Remotable object with methods (aka a [`Far`](/guides/js-programming/far) object) which is diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index fd2c8b255..0f913c7f2 100644 --- a/main/reference/zoe-api/zoe.md +++ b/main/reference/zoe-api/zoe.md @@ -269,24 +269,54 @@ It returns a **Promise** for a **StartInstanceResult** object. The object consis - **instance**: **Instance** - **creatorInvitation**: **Payment | undefined** -The **adminFacet** has one method: + + +The **adminFacet** has four methods: - **getVatShutdownPromise()** - Returns a promise that resolves to reason (the value passed to **fail(reason)**) or completion (the value passed to **exit(completion)**) when this newly started instance terminates. +- **restartContract(newPrivateArgs?)** + - **newPrivateArgs**: **any** - Optional + - returns VatUpgradeResults (a record with one field: incarnationNumber) + + Restarts the contract without changing the contract bundle + +- **upgradeContract(contractBundleId, newPrivateArgs)** + - **contractBundleId**: **string** + - **newPrivateArgs**: **any** - Optional + + - returns VatUpgradeResults (a record with one field: incarnationNumber) + + Upgrades the contract to use source code from a new bundle. + + See [Contract Upgrade](/guides/zoe/contract-upgrade) for a description the + process of upgrading contracts. + +- **terminateContract(reason)** + - **reason**: **Error** + + terminates the contract. `reason` will be provided as the failure reason. + + + A **publicFacet** is an object available via Zoe to anyone knowing the instance they are associated with. The **publicFacet** is used for general queries and actions, such as getting a current price or creating public **[Invitations](./zoe-data-types#invitation)**. Since a facet is defined just as any other object, the contract developer can add methods to them just like they would any object. + + The **creatorFacet** is only available in this return value (i.e. only when starting a contract instance). The contract designer should use it to encapsulate things that the contract runner might not want to share, or might want to control the distribution of. The party who starts the contract should carefully consider the impact before sharing access to the **creatorFacet**. + + **creatorInvitation** is an **Invitation** that the contract instance creator can use. It is usually used in contracts where the creator immediately sells something (auctions, swaps, etc.), so it's helpful for the creator to have diff --git a/snippets/zoe/src/02b-state-durable.js b/snippets/zoe/src/02b-state-durable.js index 7571510a9..dc5083da3 100644 --- a/snippets/zoe/src/02b-state-durable.js +++ b/snippets/zoe/src/02b-state-durable.js @@ -17,9 +17,11 @@ const RoomMakerI = M.interface('RoomMaker', { }); // #endregion interface-guard -// #region export-prepare -export const prepare = (_zcf, _privateArgs, baggage) => { - // #endregion export-prepare +// #region export-start +export const meta = { upgradability: 'canUpgrade' }; + +export const start = (_zcf, _privateArgs, baggage) => { + // #endregion export-start // #region zone1 const zone = makeDurableZone(baggage); const rooms = zone.mapStore('rooms'); From 5a72a8c0b929e4fcb234b1b228988ec4ae44cd04 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 3 Dec 2024 15:00:08 -0800 Subject: [PATCH 3/6] chore: prettier's suggestions --- main/guides/zoe/contract-details.md | 7 +++---- main/guides/zoe/contract-upgrade.md | 21 ++++++++++----------- main/reference/zoe-api/zoe.md | 14 +++++++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/main/guides/zoe/contract-details.md b/main/guides/zoe/contract-details.md index 3f3dfa25d..9be5c3d2a 100644 --- a/main/guides/zoe/contract-details.md +++ b/main/guides/zoe/contract-details.md @@ -17,7 +17,7 @@ need. This means putting relevant state in that will be accessible to users have an identity that can be maintained as the behavior changes with contract upgrades. -We use zone.exo(), zone.exoClass(), and zone.exoClassKit() to define durable objects. +We use zone.exo(), zone.exoClass(), and zone.exoClassKit() to define durable objects. [Zone](http://localhost:5173/glossary/#zone) provides an interface for defining objects and classes that supports both ephemeral objects (allocated on the heap), and durable objects that can persist and that @@ -50,7 +50,7 @@ object. Notice that `exo()` doesn't take `init` as a parameter; this limits the referencing values defined in the enclosing scope. Classes can also refer to variables in their defining scope, but any values inherited from the scope will be accessible to all instances of that type. The `init` function's parameters become the parameters of the maker function returned by `exoClass()` and -`exoClassKit()`. `init`'s return value is the state that will be preserved by SwingSet for each +`exoClassKit()`. `init`'s return value is the state that will be preserved by SwingSet for each object. `exo()` doesn't have an init parameter, so it creates and returns the singleton immediately rather than returning a maker. @@ -98,7 +98,7 @@ M.interface('name', { `M.call()` verifies that all parameters match the guard before passing them through to the method. `M.callWhen(M.await(paramsBGuard))` awaits the resolution of the parameter, and then verifies that the result matches before invoking the method. When a guard is written this latter way, the method doesn't have to -be `async`. In both cases, the method doesn't have to check for compliance with the guard. +be `async`. In both cases, the method doesn't have to check for compliance with the guard. [Shapes can specify](https://endojs.github.io/endo/interfaces/_endo_patterns.PatternMatchers.html) simple types like `M.string()`, `M.remotable()`, and `M.number()`, as well as complex structures of records and @@ -119,4 +119,3 @@ the state values. `finish()`, if provided, is called after instances have been created but before they are returned to the caller. They can be used to send an initial state update, or to complete initialization which couldn't be done in `init`. `finish` has access to state and facets if needed. - diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index d0b930a4a..aecc5d8cb 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -4,7 +4,7 @@ The return value when starting a contract includes a capability that conveys the the contract instance. A call to [E(zoe).startInstance(...)](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) returns a record of several objects that carry different powers. The `publicFacet` and -`creatorFacet` are defined by the contract. The +`creatorFacet` are defined by the contract. The [`adminFacet`](/reference/zoe-api/zoe.html#adminFacet) is defined by Zoe and includes methods to upgrade the contract. @@ -85,7 +85,6 @@ The 3rd argument, `baggage`, of the `start` function is a `MapStore` that is sav across restarts of the contract. It provides a way to preserve state and behavior of objects between incarnations in a way that also maintains the identity of objects as seen from other [vats](/glossary/#vat). - ```js let rooms; if (!baggage.has('rooms')) { @@ -104,7 +103,7 @@ The `provide` function supports a concise idiom for this get-or-create pattern: import { provide } from '@agoric/vat-data'; const rooms = provide(baggage, 'rooms', () => - makeScalarBigMapStore('rooms', { durable: true }) + makeScalarBigMapStore('rooms', { durable: true }), ); ``` @@ -153,18 +152,18 @@ const makeRoom = zone.exoClass('Room', RoomI, id => ({ id, value: 0 }), { // ... clear(delta) { this.state.value = 0; - } + }, }); ``` -The interface guard also needs updating. _[The Durable +The interface guard also needs updating. _[The Durable objects](./contract-details.md#guards-defensive-methods) section has more on interface guards._ ```js const RoomI = M.interface('Room', { // ... - clear: M.call().returns() + clear: M.call().returns(), }); ``` @@ -206,7 +205,7 @@ const publicFacet = zone.exo( 'StakeAtom', M.interface('StakeAtomI', { makeAccount: M.callWhen().returns(M.remotable('ChainAccount')), - makeAccountInvitationMaker: M.callWhen().returns(InvitationShape) + makeAccountInvitationMaker: M.callWhen().returns(InvitationShape), }), { async makeAccount() { @@ -221,8 +220,8 @@ const publicFacet = zone.exo( const holder = await makeAccountKit(); return holder.asContinuingOffer(); }, 'wantStakingAccount'); - } - } + }, + }, ); ``` @@ -259,13 +258,13 @@ const makeLocalOrchestrationAccountKit = prepareLocalChainAccountKit( zcf, privateArgs.timerService, vowTools, - makeChainHub(privateArgs.agoricNames) + makeChainHub(privateArgs.agoricNames), ); // ... const makeCosmosOrchestrationAccount = prepareCosmosOrchestrationAccount( zone, makeRecorderKit, vowTools, - zcf + zcf, ); ``` diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index 0f913c7f2..e8b6a7763 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 // Record example const brandKeywordRecord = { FirstCurrency: quatloosBrand, - SecondCurrency: moolaBrand + SecondCurrency: moolaBrand, // etc. }; ``` @@ -58,7 +58,7 @@ and the values are **Issuers**. // Record example const issuerKeywordRecord = { FirstCurrency: quatloosIssuer, - SecondCurrency: moolaIssuer + SecondCurrency: moolaIssuer, }; ``` @@ -274,16 +274,19 @@ It returns a **Promise** for a **StartInstanceResult** object. The object consis The **adminFacet** has four methods: - **getVatShutdownPromise()** + - Returns a promise that resolves to reason (the value passed to **fail(reason)**) or completion (the value passed to **exit(completion)**) when this newly started instance terminates. - **restartContract(newPrivateArgs?)** + - **newPrivateArgs**: **any** - Optional - returns VatUpgradeResults (a record with one field: incarnationNumber) Restarts the contract without changing the contract bundle - **upgradeContract(contractBundleId, newPrivateArgs)** + - **contractBundleId**: **string** - **newPrivateArgs**: **any** - Optional @@ -295,6 +298,7 @@ The **adminFacet** has four methods: process of upgrading contracts. - **terminateContract(reason)** + - **reason**: **Error** terminates the contract. `reason` will be provided as the failure reason. @@ -326,11 +330,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 + Zoe, ).startInstance(installation, issuerKeywordRecord, terms); ``` @@ -362,7 +366,7 @@ it may inspect it and reject it for any reason const myProposal = harden({ give: { Asset: AmountMath.make(quatloosBrand, 4n) }, want: { Price: AmountMath.make(moolaBrand, 15n) }, - exit: { onDemand: null } + exit: { onDemand: null }, }); ``` From 8368811f958aeca41a3316aa4d43fe7edebbc4c5 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 4 Dec 2024 16:55:42 -0800 Subject: [PATCH 4/6] chore: clean up links and improve wording Thanks, Dan! --- main/guides/zoe/contract-details.md | 36 ++++++++++++++--------------- main/guides/zoe/contract-upgrade.md | 14 +++++------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/main/guides/zoe/contract-details.md b/main/guides/zoe/contract-details.md index 9be5c3d2a..fc6113e14 100644 --- a/main/guides/zoe/contract-details.md +++ b/main/guides/zoe/contract-details.md @@ -7,26 +7,25 @@ or the ability to upgrade, while the second kind need to make use of more sophis When a contract is intended to continue running and serving many customers over a long time, its objects and data need to be persistent, its owners or managers may need to be able to adjust parameters or perform other -governance actions, and it needs to be upgradeable so that the code can adapt over time. +governance actions, and they may want it to be upgradeable so that the code can adapt over time. ## Durable Objects The first step toward contracts that can be upgraded is storing all the data that a later incarnation will -need. This means putting relevant state in -[Baggage](http://localhost:5173/guides/zoe/contract-upgrade.html#baggage), and ensuring that reachable objects -that will be accessible to users have an identity that can be maintained as the behavior changes with contract -upgrades. +need. This means putting relevant state in [Baggage](/guides/zoe/contract-upgrade#baggage), and ensuring that +reachable objects that will be accessible to clients have an identity that can be maintained as the behavior +changes with contract upgrades. We use zone.exo(), zone.exoClass(), and zone.exoClassKit() to define durable objects. -[Zone](http://localhost:5173/glossary/#zone) provides an interface for defining objects and classes that -supports both ephemeral objects (allocated on the heap), and durable objects that can persist and that -SwingSet will page in or out on demand. +[Zone](/glossary/#zone) provides an interface for defining objects and classes that supports both ephemeral +objects (allocated on the heap), and durable objects that can persist and that +[SwingSet](/guides/platform/#swingset) will page in or out on demand. Our persistent objects are designed to encapsulate their state, and can present different facets to different clients to distinguish different aspects of authority. `zone.exoClass()` defines a kind with a single facet, while `zone.exoClassKit()` defines a kind with multiple facets. (Here are some relevant [naming -conventions](https://docs.agoric.com/guides/ertp/#method-naming-structure).) +conventions](/guides/ertp/#method-naming-structure).) ``` zone.exoClassKit(tag, guard, init, methodKit, options) @@ -58,24 +57,25 @@ The Exo objects (or just "Exos") defined by these functions are both persistent knows their complete state, so it can page them out when space is tight, and page them back in when they are referenced again. -Fields of the object returned by the `init` function become fields of the persistent state. (These cannot -currently be changed on upgrade, though we're considering relaxing that restriction.) Within methods they can +Fields of the object returned by the `init` function become fields of the persistent state. (_These cannot +currently be changed on upgrade, though we're considering relaxing that restriction._) Within methods they can each be accessed as fields of `this.state`. Our convention is to extract the fields that will be used in a method on its first line, like `const { a, b } = this.state;` Once that has been done, those variable can be read or written as normal javascript variables, and the values will persist. (For more details, see [the note -here](https://docs.agoric.com/guides/zoe/contract-upgrade.html#kinds)). +here](/guides/zoe/contract-upgrade.html#kinds)). ### Methods: defining behavior -The methods argument of `exoClass()` is a bag of methods, written in [concise method +The methods argument of `exoClass()` is a record of methods, written in [concise method syntax](https://github.com/Agoric/agoric-sdk/wiki/Arrow-Function-Style#far-classes-do-not-use-arrow-function-style). `exoClass()` defines a single facet. -The methodKit parameter to `exoClassKit` is a record of labelled bags of methods. Each label defines a facet -of the object. All facets of each object share access to the same state, but each facet is a separate -capability. Within the methods, other facets can be reached by name within `this.facets`. The maker you get -from `exoClassKit()` builds a new object each time it is called, and return all the facets. The caller can -decide which of the facets to pass to each recipient. +The methodKit parameter to `exoClassKit` is a record that can define multiple facets. The keys give the names +of the facets, and each value defines the methods of the corresponding facet. All facets of each object share +access to the entire state defined in `init`, but each facet is a separate capability. Within the methods, +other facets can be reached by name within `this.facets`. The maker returned by `exoClassKit()` builds a new +object each time it is called, and returns all the facets. The caller can decide which of the facets to hold +or to pass to separate recipients. ### Guards: defensive methods diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index aecc5d8cb..758bfae0c 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -1,10 +1,10 @@ # Contract Upgrade -The return value when starting a contract includes a capability that conveys the right to upgrade -the contract instance. A call to +The return value when starting a contract includes a capability to upgrade the contract instance. A call to [E(zoe).startInstance(...)](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) -returns a record of several objects that carry different powers. The `publicFacet` and -`creatorFacet` are defined by the contract. The +returns a [kit](/guides/ertp/#method-naming-structure) of [facets](/glossary#facet); that is a +record of several objects that represent different ways to access the contract instance. The +`publicFacet` and `creatorFacet` are defined by the contract. The [`adminFacet`](/reference/zoe-api/zoe.html#adminFacet) is defined by Zoe and includes methods to upgrade the contract. @@ -65,8 +65,8 @@ There are a few requirements for the contract that differ from non-upgradable co ### Upgradable Declaration The new code bundle declares that it supports upgrade by including a `meta` record in addition to -`start`. (We used to indicate upgradability by using `prepare` instead of `start`, but that -approach is deprecated.)` +`start`. (_We used to indicate upgradability by using `prepare` instead of `start`, but that +approach is deprecated._) `meta` is a record with any or all of `upgradability`, `customTermsShape`, and `privateArgsShape` defined. The latter two are optional @@ -97,7 +97,7 @@ if (!baggage.has('rooms')) { } ``` -The `provide` function supports a concise idiom for this get-or-create pattern: +The `provide` function supports a concise idiom for this find-or-create pattern: ```js import { provide } from '@agoric/vat-data'; From c80699b62d854f233d05e4338e70132b012abfc6 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Thu, 5 Dec 2024 09:16:10 -0800 Subject: [PATCH 5/6] chore: cleanup with yarn format --- main/guides/zoe/contract-upgrade.md | 16 ++++++++-------- main/reference/zoe-api/zoe.md | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index 758bfae0c..37887ddc6 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -103,7 +103,7 @@ The `provide` function supports a concise idiom for this find-or-create pattern: import { provide } from '@agoric/vat-data'; const rooms = provide(baggage, 'rooms', () => - makeScalarBigMapStore('rooms', { durable: true }), + makeScalarBigMapStore('rooms', { durable: true }) ); ``` @@ -152,7 +152,7 @@ const makeRoom = zone.exoClass('Room', RoomI, id => ({ id, value: 0 }), { // ... clear(delta) { this.state.value = 0; - }, + } }); ``` @@ -163,7 +163,7 @@ guards._ ```js const RoomI = M.interface('Room', { // ... - clear: M.call().returns(), + clear: M.call().returns() }); ``` @@ -205,7 +205,7 @@ const publicFacet = zone.exo( 'StakeAtom', M.interface('StakeAtomI', { makeAccount: M.callWhen().returns(M.remotable('ChainAccount')), - makeAccountInvitationMaker: M.callWhen().returns(InvitationShape), + makeAccountInvitationMaker: M.callWhen().returns(InvitationShape) }), { async makeAccount() { @@ -220,8 +220,8 @@ const publicFacet = zone.exo( const holder = await makeAccountKit(); return holder.asContinuingOffer(); }, 'wantStakingAccount'); - }, - }, + } + } ); ``` @@ -258,13 +258,13 @@ const makeLocalOrchestrationAccountKit = prepareLocalChainAccountKit( zcf, privateArgs.timerService, vowTools, - makeChainHub(privateArgs.agoricNames), + makeChainHub(privateArgs.agoricNames) ); // ... const makeCosmosOrchestrationAccount = prepareCosmosOrchestrationAccount( zone, makeRecorderKit, vowTools, - zcf, + zcf ); ``` diff --git a/main/reference/zoe-api/zoe.md b/main/reference/zoe-api/zoe.md index e8b6a7763..787ff4ecb 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 // Record example const brandKeywordRecord = { FirstCurrency: quatloosBrand, - SecondCurrency: moolaBrand, + SecondCurrency: moolaBrand // etc. }; ``` @@ -58,7 +58,7 @@ and the values are **Issuers**. // Record example const issuerKeywordRecord = { FirstCurrency: quatloosIssuer, - SecondCurrency: moolaIssuer, + SecondCurrency: moolaIssuer }; ``` @@ -330,11 +330,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, + Zoe ).startInstance(installation, issuerKeywordRecord, terms); ``` @@ -366,7 +366,7 @@ it may inspect it and reject it for any reason const myProposal = harden({ give: { Asset: AmountMath.make(quatloosBrand, 4n) }, want: { Price: AmountMath.make(moolaBrand, 15n) }, - exit: { onDemand: null }, + exit: { onDemand: null } }); ``` From 0335f869205b63156355fccf935517d4d545631f Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Thu, 5 Dec 2024 13:17:35 -0800 Subject: [PATCH 6/6] chore: better format for glossary link --- main/guides/zoe/contract-upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index 37887ddc6..5a8b0ad59 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -2,7 +2,7 @@ The return value when starting a contract includes a capability to upgrade the contract instance. A call to [E(zoe).startInstance(...)](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) -returns a [kit](/guides/ertp/#method-naming-structure) of [facets](/glossary#facet); that is a +returns a [kit](/guides/ertp/#method-naming-structure) of [facets](/glossary/#facet); that is a record of several objects that represent different ways to access the contract instance. The `publicFacet` and `creatorFacet` are defined by the contract. The [`adminFacet`](/reference/zoe-api/zoe.html#adminFacet) is defined by Zoe and includes methods to