From f920af26fc5c7a3f18334611a32c1de376cb7c11 Mon Sep 17 00:00:00 2001 From: Mudassir Shabbir Date: Wed, 11 Sep 2024 13:16:19 +0500 Subject: [PATCH 1/6] docs: adding how--=orch-works page --- main/guides/orchestration/how-orch-works.md | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 main/guides/orchestration/how-orch-works.md diff --git a/main/guides/orchestration/how-orch-works.md b/main/guides/orchestration/how-orch-works.md new file mode 100644 index 000000000..1258f7f12 --- /dev/null +++ b/main/guides/orchestration/how-orch-works.md @@ -0,0 +1,38 @@ +# How Orchestration Works +Blockchain orchestration fundamentally relies on protocols and mechanisms that enable blockchains to communicate and transact with each other securely and efficiently. The primary goals of blockchain orchestration are: + +- **Interoperability:** Allowing different blockchain networks to interact and transact with each other. +- **Scalability:** Enabling multiple blockchains to work together without compromising performance. +- **Security:** Ensuring that cross-chain transactions are secure and trustworthy. + +To achieve these goals, several foundational technologies and protocols have been developed, with the [Inter-Blockchain Communication (IBC) protocol](https://ibcprotocol.org/) being one of the most prominent. + +### Inter-Blockchain Communication (IBC) + +The [Inter-Blockchain Communication (IBC) protocol](https://ibcprotocol.org/) can be thought of as the TCP/IP of the blockchain world. Just like TCP/IP allows different computer networks to communicate over the internet, IBC enables different blockchains to communicate with each other. + +#### How IBC Works + +IBC operates on a simple premise: by adhering to a common set of communication protocols, blockchains can securely transfer data and tokens between one another. Here's a high-level overview of how IBC achieves this: + +- **Light Client Verification:** Each blockchain maintains a light client of the other blockchain. A light client is a simplified version of a blockchain client that only retains enough information to verify transactions and proofs, without needing to store the entire blockchain history. +- **Relayer:** A [relayer](https://medium.com/@cosmos/relayer-in-blockchain-ecosystem-5f8b5b9b8b5e) is an off-chain process or entity that listens for transactions on one blockchain and relays them to another. The relayer facilitates communication between blockchains but does not have any special permissions or abilities; it merely passes messages between chains. +- **IBC Handshake:** Before two blockchains can communicate, they must perform a handshake, establishing a trusted channel between them. This involves verifying each other's consensus state through light clients. +- **Packet Transfer:** Once the connection is established, IBC allows the transfer of packets of data. These packets can represent tokens, smart contract commands, or any other type of data. The receiving blockchain uses the light client verification to ensure that the data packet is valid and hasn't been tampered with. +- **Finality and Acknowledgement:** After a packet is successfully received and processed by the receiving blockchain, an acknowledgment is sent back to the originating blockchain, confirming the completion of the transaction. + +The IBC protocol is highly modular, meaning it can be extended and adapted for various use cases and blockchain types. This modularity is what makes IBC a powerful tool for blockchain orchestration, allowing diverse blockchains to participate in a common ecosystem. + +### Interchain Accounts (ICA) + +[Interchain Accounts (ICA)](https://cosmos.network/learn/interchain-accounts) is a feature built on top of IBC that allows one blockchain to control an account on another blockchain. This is akin to having a remote account that can be operated from a different blockchain. ICA is a critical component of blockchain orchestration, as it enables seamless cross-chain operations and automation. + +#### How ICA Works + +- **Account Creation:** One blockchain (let's call it Chain A) creates an account on another blockchain (Chain B) using the IBC protocol. This account is fully owned and controlled by Chain A. +- **Transaction Execution:** Chain A can then send IBC messages to execute transactions on Chain B as if it were a local user. This could include transferring tokens, interacting with smart contracts, or any other blockchain operation. +- **Automation:** By leveraging ICA, Chain A can automate operations on Chain B, creating complex workflows that span multiple blockchains. For example, Chain A could automatically execute a smart contract on Chain B when certain conditions are met. + +ICA greatly enhances the flexibility and capability of blockchain orchestration by enabling direct, programmable interactions between blockchains. This opens up a wide range of possibilities for cross-chain applications, from decentralized finance (DeFi) to supply chain management. + +For more information, you can read about [blockchain scalability](https://www.investopedia.com/terms/b/blockchain-scalability.asp) and [cross-chain communication](https://www.coindesk.com/learn/what-is-cross-chain-communication/). From 20c9b314aaf14e112c15a6c2aa8175ad3a6fb366 Mon Sep 17 00:00:00 2001 From: Mudassir Shabbir Date: Thu, 12 Sep 2024 08:50:41 +0500 Subject: [PATCH 2/6] fixup: external links --- main/guides/orchestration/how-orch-works.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/main/guides/orchestration/how-orch-works.md b/main/guides/orchestration/how-orch-works.md index 1258f7f12..2da7c40da 100644 --- a/main/guides/orchestration/how-orch-works.md +++ b/main/guides/orchestration/how-orch-works.md @@ -15,8 +15,8 @@ The [Inter-Blockchain Communication (IBC) protocol](https://ibcprotocol.org/) ca IBC operates on a simple premise: by adhering to a common set of communication protocols, blockchains can securely transfer data and tokens between one another. Here's a high-level overview of how IBC achieves this: -- **Light Client Verification:** Each blockchain maintains a light client of the other blockchain. A light client is a simplified version of a blockchain client that only retains enough information to verify transactions and proofs, without needing to store the entire blockchain history. -- **Relayer:** A [relayer](https://medium.com/@cosmos/relayer-in-blockchain-ecosystem-5f8b5b9b8b5e) is an off-chain process or entity that listens for transactions on one blockchain and relays them to another. The relayer facilitates communication between blockchains but does not have any special permissions or abilities; it merely passes messages between chains. +- **Light Client Verification:** Each blockchain maintains a [light client](https://github.com/cosmos/ibc-go/blob/34628eb0c1ca0ca9721c6e3923cf048e1172b8b0/docs/docs/03-light-clients/01-developer-guide/01-overview.md) of the other blockchain. A light client is a simplified version of a blockchain client that only retains enough information to verify transactions and proofs, without needing to store the entire blockchain history. +- **Relayer:** A [relayer](https://github.com/cosmos/relayer) is an off-chain process or entity that listens for transactions on one blockchain and relays them to another. The relayer facilitates communication between blockchains but does not have any special permissions or abilities; it merely passes messages between chains. - **IBC Handshake:** Before two blockchains can communicate, they must perform a handshake, establishing a trusted channel between them. This involves verifying each other's consensus state through light clients. - **Packet Transfer:** Once the connection is established, IBC allows the transfer of packets of data. These packets can represent tokens, smart contract commands, or any other type of data. The receiving blockchain uses the light client verification to ensure that the data packet is valid and hasn't been tampered with. - **Finality and Acknowledgement:** After a packet is successfully received and processed by the receiving blockchain, an acknowledgment is sent back to the originating blockchain, confirming the completion of the transaction. @@ -25,7 +25,7 @@ The IBC protocol is highly modular, meaning it can be extended and adapted for v ### Interchain Accounts (ICA) -[Interchain Accounts (ICA)](https://cosmos.network/learn/interchain-accounts) is a feature built on top of IBC that allows one blockchain to control an account on another blockchain. This is akin to having a remote account that can be operated from a different blockchain. ICA is a critical component of blockchain orchestration, as it enables seamless cross-chain operations and automation. +[Interchain Accounts (ICA)](https://github.com/cosmos/ibc/blob/main/spec/app/ics-027-interchain-accounts/README.md) is a feature built on top of IBC that allows one blockchain to control an account on another blockchain. This is akin to having a remote account that can be operated from a different blockchain. ICA is a critical component of blockchain orchestration, as it enables seamless cross-chain operations and automation. #### How ICA Works @@ -35,4 +35,3 @@ The IBC protocol is highly modular, meaning it can be extended and adapted for v ICA greatly enhances the flexibility and capability of blockchain orchestration by enabling direct, programmable interactions between blockchains. This opens up a wide range of possibilities for cross-chain applications, from decentralized finance (DeFi) to supply chain management. -For more information, you can read about [blockchain scalability](https://www.investopedia.com/terms/b/blockchain-scalability.asp) and [cross-chain communication](https://www.coindesk.com/learn/what-is-cross-chain-communication/). From 1fc4e5047aeb93a3b6e495d73f9d5831edf8fd95 Mon Sep 17 00:00:00 2001 From: Mujahid Khan <106528609+mujahidkay@users.noreply.github.com> Date: Fri, 13 Sep 2024 01:36:39 +0500 Subject: [PATCH 3/6] lint: add prettier config --- .prettierrc.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..95d6e1268 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,21 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "proseWrap": "preserve", + "trailingComma": "none", + "bracketSpacing": true, + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.md", + "options": { + "parser": "markdown", + "printWidth": 80, + "proseWrap": "preserve" + } + } + ] + } From ba8648112bd67c4960ddd7a61e2f708a9aa8c631 Mon Sep 17 00:00:00 2001 From: Mujahid Khan <106528609+mujahidkay@users.noreply.github.com> Date: Fri, 13 Sep 2024 01:37:07 +0500 Subject: [PATCH 4/6] chore: update package.json --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index e14919ad1..99e39b693 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "test": "ava", "lint-fix": "yarn lint --fix", "lint": "eslint 'snippets/**/*.js'", + "format": "prettier --write '**/*.md' --config .prettierrc.json", + "lint:format": "prettier --check '**/*.md' --config .prettierrc.json", "build": "exit 0" }, "packageManager": "yarn@4.4.0", From d461e4b284bd98f146fd9185199bddf768e8364d Mon Sep 17 00:00:00 2001 From: Mujahid Khan <106528609+mujahidkay@users.noreply.github.com> Date: Fri, 13 Sep 2024 01:42:09 +0500 Subject: [PATCH 5/6] docs: run formatter on md files --- CONTRIBUTING.md | 86 ++++-- README.md | 25 +- main/e2e-testing.md | 36 +-- main/glossary/index.md | 47 ++- .../guides/UIComponentLibrary/assets/asset.md | 1 - main/guides/UIComponentLibrary/index.md | 40 +-- main/guides/agoric-cli/agd-query-tx.md | 1 + main/guides/agoric-cli/index.md | 1 + main/guides/coreeval/permissions.md | 10 +- main/guides/coreeval/proposal.md | 70 ++--- main/guides/dapps/index.md | 58 ++-- main/guides/dapps/starting-multiuser-dapps.md | 101 ++++--- main/guides/ertp/amount-math.md | 31 +- main/guides/ertp/amounts.md | 47 +-- main/guides/ertp/index.md | 80 ++--- main/guides/ertp/issuers-and-mints.md | 46 ++- main/guides/ertp/purses-and-payments.md | 34 ++- main/guides/getting-started/deploying.md | 69 +++-- .../explainer-deploying-a-smart-contact.md | 5 + .../explainer-how-to-make-an-offer.md | 2 + .../explainer-how-to-start-a-local-chain.md | 3 + main/guides/getting-started/index.md | 22 +- ...sell-concert-tickets-contract-explainer.md | 74 +++-- .../swaparoo-how-to-swap-assets-explainer.md | 83 +++--- .../swaparoo-making-a-payment-explainer.md | 18 +- .../tutorial-dapp-agoric-basics.md | 15 +- .../ui-tutorial/agoric-provider.md | 24 +- .../ui-tutorial/connect-wallet.md | 34 +-- .../ui-tutorial/making-an-offer.md | 50 ++-- .../ui-tutorial/querying-vstorage.md | 18 +- .../getting-started/ui-tutorial/starting.md | 20 +- main/guides/governance/index.md | 6 +- main/guides/index.md | 2 +- main/guides/integration/chain-integration.md | 34 ++- main/guides/integration/name-services.md | 37 +-- main/guides/js-programming/far.md | 7 +- main/guides/js-programming/hardened-js.md | 108 +++---- main/guides/js-programming/index.md | 8 +- main/guides/js-programming/notifiers.md | 112 ++++--- .../orchestration/getting-started/api.md | 23 +- .../contract-walkthrough/cross-chain-swap.md | 124 ++++---- .../cross-chain-unbond.md | 60 ++-- .../orchestration-basics.md | 4 +- .../getting-started/contract-walkthroughs.md | 5 +- .../getting-started/key-concepts.md | 20 +- main/guides/orchestration/index.md | 9 +- main/guides/platform/index.md | 12 +- main/guides/subquery-indexing.md | 21 +- main/guides/wallet/index.md | 111 ++++--- main/guides/wallet/ui.md | 2 - main/guides/zoe/actual-contracts/PSM.md | 139 +++++---- main/guides/zoe/contract-access-control.md | 13 +- main/guides/zoe/contract-basics.md | 6 +- main/guides/zoe/contract-hello.md | 7 +- main/guides/zoe/contract-requirements.md | 51 ++-- main/guides/zoe/contract-state.md | 6 +- main/guides/zoe/contract-upgrade.md | 56 ++-- main/guides/zoe/contract-walkthru.md | 4 +- main/guides/zoe/contracts/atomic-swap.md | 79 ++--- main/guides/zoe/contracts/automatic-refund.md | 1 + main/guides/zoe/contracts/barter-exchange.md | 1 + .../zoe/contracts/constantProductAMM.md | 93 +++--- main/guides/zoe/contracts/covered-call.md | 101 +++---- main/guides/zoe/contracts/escrow-to-vote.md | 1 + main/guides/zoe/contracts/fundedCallSpread.md | 41 +-- main/guides/zoe/contracts/index.md | 58 ++-- main/guides/zoe/contracts/loan.md | 53 ++-- .../zoe/contracts/mint-and-sell-nfts.md | 2 + main/guides/zoe/contracts/mint-payments.md | 1 + main/guides/zoe/contracts/oracle.md | 5 +- main/guides/zoe/contracts/otc-desk.md | 15 +- main/guides/zoe/contracts/pricedCallSpread.md | 41 +-- .../zoe/contracts/second-price-auction.md | 95 +++--- main/guides/zoe/contracts/sell-items.md | 1 + main/guides/zoe/contracts/simple-exchange.md | 79 ++--- main/guides/zoe/contracts/use-obj-example.md | 1 + main/guides/zoe/contracts/vault.md | 8 +- main/guides/zoe/offer-enforcement.md | 53 ++-- main/guides/zoe/offer-safety.md | 17 +- main/guides/zoe/price-authority.md | 4 +- main/guides/zoe/proposal.md | 13 +- main/guides/zoe/pub-to-storage.md | 18 +- main/reference/ertp-api/amount-math.md | 166 ++++++----- main/reference/ertp-api/brand.md | 59 ++-- main/reference/ertp-api/ertp-data-types.md | 17 +- main/reference/ertp-api/index.md | 36 +-- main/reference/ertp-api/issuer.md | 268 ++++++++++------- main/reference/ertp-api/mint.md | 23 +- main/reference/ertp-api/payment.md | 46 +-- main/reference/ertp-api/purse.md | 132 +++++---- main/reference/repl/index.md | 67 +++-- main/reference/repl/networking.md | 60 ++-- main/reference/repl/scratch.md | 11 +- main/reference/repl/timerServices.md | 2 +- main/reference/vstorage-ref.md | 10 +- main/reference/wallet-api/index.md | 10 +- main/reference/wallet-api/wallet-bridge.md | 18 +- main/reference/wallet-api/wallet-commands.md | 16 +- main/reference/zoe-api/mutable-quote.md | 14 +- main/reference/zoe-api/price-authority.md | 52 ++-- main/reference/zoe-api/ratio-math.md | 276 ++++++++++-------- main/reference/zoe-api/user-seat.md | 37 ++- main/reference/zoe-api/zcfmint.md | 34 +-- main/reference/zoe-api/zcfseat.md | 130 +++++---- main/reference/zoe-api/zoe-contract-facet.md | 46 ++- main/reference/zoe-api/zoe-data-types.md | 10 +- main/reference/zoe-api/zoe-helpers.md | 64 ++-- main/reference/zoe-api/zoe.md | 60 ++-- 108 files changed, 2515 insertions(+), 2068 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee7d7cb25..b01b2bf3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,7 @@ sidebar: auto Agoric's public-facing technical documentation is mostly in the [Agoric Documentation GitHub repo](https://github.com/Agoric/documentation). The complete documentation set also includes external items such as papers, presentations, videos, etc. Our document process is: + 1. Write docs in the repo in Markdown. Image files are usually in `.svg` format and also stored in the repo. 2. Proofread your docs. However, be aware that everyone is their own worst proofreader and this is especially true if you try to do it immediately or very soon after you finish writing it. Given our frequent time pressure, while @@ -29,9 +30,10 @@ process is: 9. [VitePress](https://vitepress.dev/guide/what-is-vitepress) automatically processes any new or changed files for display. 10. The [Agoric website's Documentation Section](https://agoric.com/documentation/) displays - the VitePress processed files, which have been converted to HTML. + the VitePress processed files, which have been converted to HTML. This doc explains: + - The overall documentation structure. - Our preferred way of writing links. - What happens when you make a PR. @@ -88,14 +90,17 @@ on one page and that they aren't too long. Otherwise the sidebar menu for the pa Individual pages do not automatically display a sidebar menu for their headers without the use of a plugin. To force an individual page sidebar menu, add the following YAML at the top of a page's source file (this file has this YAML at the top): + ```js --- sidebar: auto --- ``` + Other ways of activating this are: Turn it on for the whole site: + ```js // .vitepress/config.js module.exports = { @@ -106,23 +111,24 @@ module.exports = { ``` Or, add a config entry, either as part of a group or as an individual page. + ```js // .vitepress/config.js module.exports = { themeConfig: { sidebar: [ { - title: 'Group 1', // required - link: '/foo/', // optional, link of the title, which should be an absolute path and must exist + title: 'Group 1', // required + link: '/foo/', // optional, link of the title, which should be an absolute path and must exist collapsable: false, // optional, defaults to true - sidebarDepth: 1, // optional, defaults to 1 - items: [ - { text: '', link: '/' }, - ] + sidebarDepth: 1, // optional, defaults to 1 + items: [{ text: '', link: '/' }] }, { title: 'Group 2', - items: [ /* ... */ ], + items: [ + /* ... */ + ], initialOpenGroupIndex: -1 // optional, defaults to 0, defines the index of initially opened subgroup } ] @@ -152,7 +158,7 @@ by just linking to `(/glossary/#allocation)`; its path starting at `main`. Any p at `main`. These links also open in the same browser tab. VitePress turns every header in a Markdown file into an HTML anchor you can link to, so clicking such a link takes you directly to -that file location (called *slugifying* by WordPress and other blogging platforms). A header link consists of its file +that file location (called _slugifying_ by WordPress and other blogging platforms). A header link consists of its file name, with an appended `#` and appended altered header text. The header text in a link has been converted to to lower case and all non-alphanumerics, including spaces, have been replaced by hyphens. The two exceptions to the latter are, first, all consecutive non-alphanumbers are converted to a single hyphen; i.e. "Foo&$ Bar" is converted to "foo-bar". @@ -223,11 +229,13 @@ displayed in a doc. You can make an entire code file, or any part of it, into a snippet (each of which can be used multiple times in the docs). Just surround the part you want to be a snippet with `#region` and `#endregion` comments: + ```js // #region regionName ... // #endregion regionName ``` + `regionName` in the above is any name you want to give this snippet. If you want the whole file to be a snippet, just put the `#region` / `#endregion` @@ -248,6 +256,7 @@ the file. The tests should be in the snippets directory. Actually the snippet files and the test files ended up being the same file because that was the cleanest way to go. The snippet files should all be named test-original-filename.js where original-filename is the markdown filename, like amounts of ertp/guide/amounts.md To test your snippets files while writing your docs: + 1. Write tests using AVA. They should be in the appropriate file in the snippets directory, with files named `test-original-filename.js` `original-filename` is the Markdown filename. For example, `test-amounts.js` for `ertp/guide/amounts.md` See [this Snippets file](/snippets/ertp/guide/test-amounts.js) 2. Run the tests with `yarn test` (run from anywhere, but usually from the root of the repo). @@ -266,43 +275,53 @@ broken links, and what file and line number they're at. ## Local Install, Build, and Run 1. **Clone**: Clone the Documentation repo to your local machine. We suggest using -Sourcetree to manage your local and remote copies and the various commits -and pull requests you'll make while debugging. The following steps should all -be run from the directory you cloned the repo into. + Sourcetree to manage your local and remote copies and the various commits + and pull requests you'll make while debugging. The following steps should all + be run from the directory you cloned the repo into. 2. **Install**: To ensure using the latest agoric-sdk -version when running code snippets, from a shell, run + version when running code snippets, from a shell, run + ```shell agoric install ``` + 3. **Build**: To build the site as it will be built for production, run: + ```shell yarn docs:build ``` + The resulting build assets can be found in `/dist` in the project root. 4. **Run**: To run a local server and see your changes in real time, run: + ```shell yarn docs:dev ``` + Most edit changes are immediately reflected in the browser, but applying site config changes may require stopping and restarting this program. View your local documentation site at `localhost:5173` 5. **Preview**: To preview a production build, run: + ```shell yarn docs:preview ``` + View your local documentation site at `localhost:4173` ## Updating Zoe Version and DocsUpdated In `[/.vitepress/config.js](/.vitepress/config.js)`, find the lines + ``` zoeVersion: 'Beta Release v1.0.0', zoeDocsUpdated: 'Apr 7, 2021' ``` + Edit the values to be current. The current Zoe version is the "version" field of [Zoe's package.json](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/package.json), normally on line 3. @@ -325,18 +344,22 @@ But if you're viewing "Introduction to Zoe" itself, you'll always see the Gettin no way to have it sometimes (appropriately) display the Zoe sidebar menu instead. ### Configuration and navigation + All configuration is handled in [`/main/.vitepress/config.js`](/.vitepress/config.js). Here you can: + - Set and modify the website title and description. - Configure the top navigation bar. - Configure the various sidebar menus #### Configuring the top menubar + Go to `[main/.vitepress/themeConfig/nav.js](/.vitepress/themeConfig/nav.js)` to configure the top navigation bar. `/main/.vitepress/config.js`, the overall VitePress configuration file, imports `nav.js`. Below is an abridged configuration of the top navigation bar showing an array of only two entries, Getting Started and Learn More. Each entry is an object with three or four properties: + - `text`: The text shown in the nav bar. - `ariaLabel`: Labels this page element. Used to access it if the text is not visible. - `link`: Optional. Link to where the browser goes if you click the top menubar item itself, instead of a @@ -349,6 +372,7 @@ Each entry is an object with three or four properties: To add an entry to the top menubar, just add a menu item object to the array. We suggest copying a similar one, adding the copy, and editing the copy's property values to be those of the new item and its submenus. To delete an entry, just remove its object from the menubar item array. + ```js module.exports = [ { @@ -378,11 +402,13 @@ module.exports = [ }, ] ``` + #### Configuring the top menubar submenus A top menubar item without a submenu, such as Glossary, has no `items` property and must have a `link` property (otherwise there's nothing to click, so it's really not a good navigation menu item). + ```js { text: 'Glossary', @@ -400,6 +426,7 @@ link value is `'/getting-started/ertp-introduction/'` and not `'/getting-started To add a submenu item, just copy an appropriate one, add it to the `items` array, and edit its property values to be what you want for the new item. To delete a submenu item, just remove its entry from the `items` array. + ```js { text: 'ERTP', @@ -426,11 +453,13 @@ entry from the `items` array. ``` #### Configuring sidebar menus. + Sidebar menus are configured in [`/.vitepress/config.js`](/.vitepress/config.js). There, sidebars are configured where it starts: `sidebar: {`. Here's an abridged version of the overall sidebar configuration, only showing the Getting Started and ERTP sidebars, and leaving out their specific items: + ```js sidebar: { '/getting-started/': [ @@ -451,7 +480,9 @@ sidebar: { ], } ``` + Below is an abridged version of the ERTP sidebar. Each item entry has five properties: + - `title`: The string that appears in the sidebar menu for this item. - `path`: Where you go if you click on this menu item. As usual, the leading `/` denotes a path starting at `main`. Note the full file name is given, including the `.md` suffix (which VitePress @@ -492,6 +523,7 @@ Below is an abridged version of the ERTP sidebar. Each item entry has five prope }, ], ``` + When viewing a page, VitePress has automatically constructed a sidebar menu entry for that page consisting of all `h1`, `h2`, and `h3` header titles on the page. @@ -505,21 +537,39 @@ If you need to redirect to an **external** website, this will be accomplished at Go to (or create if not there) `documentation/main/.vitepress/enhanceApp.js` As of March 2021, ours looks like this: + ```js export default ({ router }) => { router.addRoutes([ { path: '/wallet-api/', redirect: '/guides/wallet/' }, { path: '/wallet-api.html', redirect: '/guides/wallet/' }, - { path: '/chainlink-integration/', redirect: '/guides/chainlink-integration.md' }, - { path: '/chainlink-integration.html', redirect: '/guides/chainlink-integration.md' }, + { + path: '/chainlink-integration/', + redirect: '/guides/chainlink-integration.md' + }, + { + path: '/chainlink-integration.html', + redirect: '/guides/chainlink-integration.md' + }, { path: '/distributed-programming/', redirect: '/guides/js-programming/' }, - { path: '/distributed-programming.html', redirect: '/guides/js-programming/' }, - { path: '/getting-started/agoric-cli-guide/', redirect: '/guides/agoric-cli/' }, - { path: '/getting-started/agoric-cli-guide.html', redirect: '/guides/agoric-cli/' }, + { + path: '/distributed-programming.html', + redirect: '/guides/js-programming/' + }, + { + path: '/getting-started/agoric-cli-guide/', + redirect: '/guides/agoric-cli/' + }, + { + path: '/getting-started/agoric-cli-guide.html', + redirect: '/guides/agoric-cli/' + } ]) } ``` + The general format should be self-explanatory. However, there are two things you need to know that aren't apparent + - VitePress treats `main` as the root of the folders. So all of the addresses start with `/` to represent `/main/`. - You'll notice there are two entries for every redirect, one where the redirected address ends with `.html` and one where it ends with `/`. For each individual file that is not a `index.md`, there are two ways to access it. diff --git a/README.md b/README.md index 76b3e6603..91534a2ca 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,17 @@ This repository contains the raw documentation files for the [Agoric documentation website](https://agoric.com/documentation/). -* [Learn how to mint new tokens of various kinds in our ERTP (Electronic -Rights Transfer -Protocol)](https://agoric.com/documentation/ertp/guide/) +- [Learn how to mint new tokens of various kinds in our ERTP (Electronic + Rights Transfer + Protocol)](https://agoric.com/documentation/ertp/guide/) +- Want to write smart contracts where the worst thing that can happen to + your users is they get their money back? [Check out how we enforce + "offer safety" in smart contracts on + Zoe](https://agoric.com/documentation/zoe/guide/) -* Want to write smart contracts where the worst thing that can happen to -your users is they get their money back? [Check out how we enforce -"offer safety" in smart contracts on -Zoe](https://agoric.com/documentation/zoe/guide/) +- Wondering about IBC? [Agoric has been hard at work with Tendermint Inc + and the Interchain Foundation](https://cosmos.network/ibc) - -* Wondering about IBC? [Agoric has been hard at work with Tendermint Inc -and the Interchain Foundation](https://cosmos.network/ibc) - - -* Want to run the full Agoric vm? You can [get started -here](https://agoric.com/documentation/getting-started/#overview) +- Want to run the full Agoric vm? You can [get started + here](https://agoric.com/documentation/getting-started/#overview) diff --git a/main/e2e-testing.md b/main/e2e-testing.md index fb1b73894..6871f2821 100644 --- a/main/e2e-testing.md +++ b/main/e2e-testing.md @@ -40,16 +40,16 @@ Before you start writing your E2E tests, you'll need to create a configuration f Inside `synpress.config.js`, you'll set the `baseUrl` property within the e2e configuration. This tells Cypress where to find your DApp during testing. Here's an example configuration: ```js -const baseConfig = require('@agoric/synpress/synpress.config'); -const { defineConfig } = require('cypress'); +const baseConfig = require('@agoric/synpress/synpress.config') +const { defineConfig } = require('cypress') module.exports = defineConfig({ ...baseConfig, e2e: { ...baseConfig.e2e, - baseUrl: 'http://localhost:5173', - }, -}); + baseUrl: 'http://localhost:5173' + } +}) ``` In this example, `baseUrl` is set to `http://localhost:5173`. Make sure to replace this with the actual URL where your DApp is running. @@ -69,7 +69,7 @@ Navigate to your project's `tests/e2e` directory and create a new file named `su After creating your `support.js` file, make sure to include the following import statement: ```js -import '@agoric/synpress/support/index'; +import '@agoric/synpress/support/index' ``` This import is essential because it brings in the necessary functionalities from `@agoric/synpress` to interact with the Keplr wallet within your e2e tests. Without it, your tests won't be able to leverage the features provided by `@agoric/synpress` for Keplr integration. @@ -86,8 +86,8 @@ You use `describe` blocks to group related tests together, and `it` blocks to de describe('User Login', () => { it('should login with valid credentials', () => { // Test steps for login functionality - }); -}); + }) +}) ``` ### Test 1: Setting Up Keplr Wallet @@ -95,10 +95,10 @@ describe('User Login', () => { ```js it('should setup a Keplr wallet', () => { cy.setupWallet({ - secretWords: 'KEPLR_MNEMONIC', - }); - cy.visit('/'); -}); + secretWords: 'KEPLR_MNEMONIC' + }) + cy.visit('/') +}) ``` This test case simulates setting up a Keplr wallet for your tests, using the `cy.setupWallet` method. Make sure to replace `KEPLR_MNEMONIC` with a 24-word mnemonic phrase. The `setupWallet` method creates a wallet based on the provided mnemonic phrase, which can then be used throughout your test suite. @@ -109,9 +109,9 @@ After setting up the wallet, we visit the root path (`/`) of the DApp using `cy. ```js it('should accept connection with wallet', () => { - cy.contains('Connect Wallet').click(); - cy.acceptAccess(); -}); + cy.contains('Connect Wallet').click() + cy.acceptAccess() +}) ``` This test simulates a user connecting their Keplr wallet to your DApp. `cy.contains('Connect Wallet')` searches for an element containing the text `Connect Wallet` on the webpage and triggers a click event. `cy.acceptAccess` simulates accepting Keplr wallet access for your DApp. @@ -120,9 +120,9 @@ This test simulates a user connecting their Keplr wallet to your DApp. `cy.conta ```js it('should confirm make an offer transaction', () => { - cy.contains('Make an Offer').click(); - cy.confirmTransaction(); -}); + cy.contains('Make an Offer').click() + cy.confirmTransaction() +}) ``` This test simulates transaction Signing on your DApp. `cy.contains('Make an Offer')` searches for an element containing the text `Make an Offer` and triggers a click event. `cy.confirmTransaction` simulates confirming a transaction. diff --git a/main/glossary/index.md b/main/glossary/index.md index 7eb6ca94e..94eaffb0c 100644 --- a/main/glossary/index.md +++ b/main/glossary/index.md @@ -141,10 +141,10 @@ and the [ERTP API's Brand section](/reference/ertp-api/brand). Before a contract can be installed on Zoe, its source code must be bundled. This is done by: ```js -import bundleSource from '@endo/bundle-source'; +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 @@ -153,7 +153,7 @@ In most cases, the bundle contains a base64-encoded zip file that you can extract for review. ```js -const { endoZipBase64 } = await E(installation).getBundle(); +const { endoZipBase64 } = await E(installation).getBundle() ``` ```sh @@ -282,13 +282,13 @@ For details, see [`E(zoe).offer(...)`](/reference/zoe-api/zoe#proposals). ## Exo -An Exo object is an exposed Remotable object with methods (aka a [`Far`](/guides/js-programming/far) object) which is +An Exo object is an exposed Remotable object with methods (aka a [`Far`](/guides/js-programming/far) object) which is normally defined with an `InterfaceGuard` as a protective outer layer, providing the first - layer of defensiveness. +layer of defensiveness. -This [`@endo/exo` package](https://github.com/endojs/endo/tree/master/packages/exo) defines +This [`@endo/exo` package](https://github.com/endojs/endo/tree/master/packages/exo) defines the APIs for making Exo objects, and for defining ExoClasses and ExoClassKits for making Exo - objects. +objects. ## Facet @@ -296,10 +296,10 @@ A _facet_ is an object that exposes an API or particular view of some larger ent You can make any number of facets of an entity. In JavaScript, you often make a facet that forwards method calls: ```js -import { Far } from '@endo/far'; +import { Far } from '@endo/far' const facet = Far('FacetName', { - myMethod: (...args) => oldObject.method(...args), -}); + myMethod: (...args) => oldObject.method(...args) +}) ``` Two Agoric uses are: @@ -341,8 +341,8 @@ Guide](https://github.com/endojs/endo/blob/HEAD/packages/ses/docs/guide.md) for 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). - ## Interchain Account (ICA) + Interchain Accounts are an [IBC](#ibc) feature used in Agoric's [Orchestration API](#orchestration) to enable an Agoric smart contract to control an account on another blockchain within the Cosmos ecosystem. This feature leverages the [Inter-Blockchain Communication (IBC)](#ibc) protocol to facilitate interactions and transactions across different blockchains seamlessly. ## Invitation @@ -485,15 +485,15 @@ the user either gets what they said they wanted, or gets back what they original escrowed (a refund). One reason this is possible is if a [proposal](#proposal) doesn't match what the contract expects to do, it can immediately cause the [seat](#seat) to exit, getting back the amount it offered. -## Orchestration +## Orchestration Orchestration API is a tool to help developers build seamless applications out of disparate interoperable chains and services. This composability allows for the development of user-centric applications - that leverage the unique strengths of different blockchain ecosystems. +that leverage the unique strengths of different blockchain ecosystems. Orchestration integrates with existing Agoric components ([SwingSet](/guides/platform/#swingset), Cosmos modules) and introduces - vat-orchestration. This [vat](/glossary/#vat) manages [Inter-Chain Account (ICA)](#interchain-account-ica) identities and connections to host - chains, ensuring proper transaction authorization. - For more information, see the [Orchestration API](/guides/orchestration/). +vat-orchestration. This [vat](/glossary/#vat) manages [Inter-Chain Account (ICA)](#interchain-account-ica) identities and connections to host +chains, ensuring proper transaction authorization. +For more information, see the [Orchestration API](/guides/orchestration/). ## Passable @@ -549,8 +549,8 @@ For example: const myProposal = harden({ give: { Asset: AmountMath.make(quatloosBrand, 4n) }, want: { Price: AmountMath.make(moolaBrand, 15n) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) ``` `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. @@ -608,7 +608,7 @@ An imaginary currency Agoric documentation uses in examples. ## Smart Contract -A smart contract is a contract-​like arrangement expressed in code, where the behavior of the +A smart contract is a contract-​like arrangement expressed in code, where the behavior of the program enforces the terms of the contract. In the context of the Agoric blockchain, smart contracts are written using JavaScript and leverage @@ -635,11 +635,9 @@ For more information, see the [Vat section in the Distributed JS Programming doc The concept of a vat is metaphorically inspired by the philosophical experiment known as “Brain in a Vat.” This thought experiment, explored in philosophy, posits a scenario in which a brain is sustained in a vat and connected to a computer that simulates reality, raising questions about knowledge, reality, and perception. Similarly, in the context of distributed systems, a vat isolates and encapsulates its contents, maintaining strict boundaries on synchronous and asynchronous communication, much like the hypothetical brain’s isolated and controlled environment. For more details, see the Wikipedia page on [Brain in a Vat](https://en.wikipedia.org/wiki/Brain_in_a_vat). - ## Vow -Vows are objects that represent promises that can be stored durably. Native promises are not compatible with Agoric's durable stores, which means that on the Agoric platform, such promises disconnect their clients when their creator vat is upgraded. - +Vows are objects that represent promises that can be stored durably. Native promises are not compatible with Agoric's durable stores, which means that on the Agoric platform, such promises disconnect their clients when their creator vat is upgraded. ## Wallet @@ -671,7 +669,6 @@ A set of API methods for deploying and working with smart contracts. See [Zoe Se ## Zone -Each Zone provides an API that allows the allocation of [Exo objects](#exo) and [Stores (object collections)](https://github.com/Agoric/agoric-sdk/tree/master/packages/store/README.md) which use the same underlying persistence mechanism. This allows library code to be agnostic to whether its objects are backed purely by the JS heap (ephemeral), pageable out to disk (virtual) or can be revived after a vat upgrade (durable). +Each Zone provides an API that allows the allocation of [Exo objects](#exo) and [Stores (object collections)](https://github.com/Agoric/agoric-sdk/tree/master/packages/store/README.md) which use the same underlying persistence mechanism. This allows library code to be agnostic to whether its objects are backed purely by the JS heap (ephemeral), pageable out to disk (virtual) or can be revived after a vat upgrade (durable). See [SwingSet vat upgrade documentation](https://github.com/Agoric/agoric-sdk/tree/master/packages/SwingSet/docs/vat-upgrade.md) for more example use of the zone API. - diff --git a/main/guides/UIComponentLibrary/assets/asset.md b/main/guides/UIComponentLibrary/assets/asset.md index 8b1378917..e69de29bb 100644 --- a/main/guides/UIComponentLibrary/assets/asset.md +++ b/main/guides/UIComponentLibrary/assets/asset.md @@ -1 +0,0 @@ - diff --git a/main/guides/UIComponentLibrary/index.md b/main/guides/UIComponentLibrary/index.md index 928c551ce..bedb02f00 100644 --- a/main/guides/UIComponentLibrary/index.md +++ b/main/guides/UIComponentLibrary/index.md @@ -7,7 +7,7 @@ Utilization of these building blocks ensures best practices in design and access See [Introduction to Agoric UI Kit](https://a0a31cba.documentation-7tp.pages.dev/guides/getting-started/how-to-use-ui-kit#introduction-to-agoric-ui-kit) for installation and setup how-to. -Once complete you'll need to run this yarn command: +Once complete you'll need to run this yarn command: ```sh yarn add @agoric/react-components @@ -30,22 +30,22 @@ These React UI components can be immediately used to streamline your Agoric Dapp alt="Screenshot: Connect Wallet" src="./assets/connectwallet.png" /> - Screenshot: Wallet Address - Screenshot: Select Wallet - [Connecting with Wallet Connect Button](https://github.com/Agoric/ui-kit/tree/main/packages/react-components#integrating) -- [Connecting without Wallet Connect Button](https://github.com/Agoric/ui-kit/tree/main/packages/react-components#connecting-without-connectwalletbutton) +- [Connecting without Wallet Connect Button](https://github.com/Agoric/ui-kit/tree/main/packages/react-components#connecting-without-connectwalletbutton) - [Using a Custom Chain Provider](https://github.com/Agoric/ui-kit/tree/main/packages/react-components#using-a-custom-chainprovider) Customizable Parameters | Parameter | Type | Description | |----------|----------|----------| -| ClassName | string | CSS class name for the underlying ` - ); + ) } ``` @@ -281,4 +281,4 @@ solution for this example, check out the [checkpoint-5](https://github.com/agori ### Result -Curious to know how it looks after implementation? Check out our [guide](https://docs.agoric.com/guides/getting-started/explainer-how-to-make-an-offer.html) for the result. \ No newline at end of file +Curious to know how it looks after implementation? Check out our [guide](https://docs.agoric.com/guides/getting-started/explainer-how-to-make-an-offer.html) for the result. diff --git a/main/guides/getting-started/ui-tutorial/querying-vstorage.md b/main/guides/getting-started/ui-tutorial/querying-vstorage.md index e06ddb3f3..1d2f99523 100644 --- a/main/guides/getting-started/ui-tutorial/querying-vstorage.md +++ b/main/guides/getting-started/ui-tutorial/querying-vstorage.md @@ -14,7 +14,7 @@ to use the RPC endpoints we added earlier. Example: ```ts -const { chainStorageWatcher } = useAgoric(); +const { chainStorageWatcher } = useAgoric() ``` ## Querying Vstorage @@ -29,10 +29,10 @@ Create a new file, `src/Trade.tsx`: const Trade = () => { return (
TODO - Create inputs for submitting an offer.
- ); -}; + ) +} -export default Trade; +export default Trade ``` And add some styling for it in `App.css` while we're at it: @@ -120,18 +120,18 @@ and emits updates when the data on-chain changes. For more details about vstorag Next, go ahead and add this hook to the `Trade` component you made before this: ```tsx -import { useContract } from './hooks'; +import { useContract } from './hooks' const Trade = () => { // Don't do anything with brands or instances yet. - useContract(); + useContract() return (
TODO - Create inputs for submitting an offer.
- ); -}; + ) +} -export default Trade; +export default Trade ``` You should now see the `brands` and `instances` being logged to the console. See if you diff --git a/main/guides/getting-started/ui-tutorial/starting.md b/main/guides/getting-started/ui-tutorial/starting.md index 71babe44e..7755a5c5e 100644 --- a/main/guides/getting-started/ui-tutorial/starting.md +++ b/main/guides/getting-started/ui-tutorial/starting.md @@ -35,30 +35,30 @@ yarn add -D buffer Now, create a new file `src/installSesLockdown.ts`: ```typescript -import 'ses'; // adds lockdown, harden, and Compartment -import '@endo/eventual-send/shim.js'; // adds support needed by E -import { Buffer } from 'buffer'; +import 'ses' // adds lockdown, harden, and Compartment +import '@endo/eventual-send/shim.js' // adds support needed by E +import { Buffer } from 'buffer' -const consoleTaming = import.meta.env.DEV ? 'unsafe' : 'safe'; +const consoleTaming = import.meta.env.DEV ? 'unsafe' : 'safe' lockdown({ errorTaming: 'unsafe', overrideTaming: 'severe', - consoleTaming, -}); + consoleTaming +}) -Error.stackTraceLimit = Infinity; +Error.stackTraceLimit = Infinity -globalThis.Buffer = Buffer; +globalThis.Buffer = Buffer // @ts-expect-error Add process to context for cosmos-kit -globalThis.process = { env: import.meta.env }; +globalThis.process = { env: import.meta.env } ``` And at the top of `src/main.tsx` import the new file: ```typescript -import './installSesLockdown.ts'; +import './installSesLockdown.ts' ``` Restart your app and it should load as before without errors. Now, the app is running with Hardened JS enabled and we're ready to continue. diff --git a/main/guides/governance/index.md b/main/guides/governance/index.md index 1a0e65cce..27797e817 100644 --- a/main/guides/governance/index.md +++ b/main/guides/governance/index.md @@ -25,9 +25,9 @@ swaparoo contract has a governed `Fee` amount parameter: ```js const paramTypes = harden( /** @type {const} */ ({ - Fee: ParamTypes.AMOUNT, - }), -); + Fee: ParamTypes.AMOUNT + }) +) ``` ## Reusing Contracts for Electorate, Election Manager diff --git a/main/guides/index.md b/main/guides/index.md index 774ee88f7..9c48d72e8 100644 --- a/main/guides/index.md +++ b/main/guides/index.md @@ -1 +1 @@ -This is the non-API section of the Agoric documentation. \ No newline at end of file +This is the non-API section of the Agoric documentation. diff --git a/main/guides/integration/chain-integration.md b/main/guides/integration/chain-integration.md index 6a64ce0bb..2ce8e962c 100644 --- a/main/guides/integration/chain-integration.md +++ b/main/guides/integration/chain-integration.md @@ -1,34 +1,36 @@ # Integrating with Agoric Network -The Agoric network builds a blockchain for smart contracts in JavaScript using the `cosmos-sdk`. Cosmos-sdk is software that provides the widely-used Tendermint/CometBFT consensus and best-in-class support for chain operations like staking and governance. For simplicity of chain integration, the Agoric Network works identically to the Cosmos Hub, except using different parameters (e.g., `ubld` instead of `uatom`). - +The Agoric network builds a blockchain for smart contracts in JavaScript using the `cosmos-sdk`. Cosmos-sdk is software that provides the widely-used Tendermint/CometBFT consensus and best-in-class support for chain operations like staking and governance. For simplicity of chain integration, the Agoric Network works identically to the Cosmos Hub, except using different parameters (e.g., `ubld` instead of `uatom`). ## TL;DR for Cosmos-experienced This section points at relevant reference documentation for the underlying `cosmos-sdk` and CometBFT/Tendermint consensus engine, and summarizes the differences. -The Agoric Network currently uses `cosmos-sdk` v0.45. The general Cosmos documentation for this version can be [found here](https://docs.cosmos.network/v0.45/), including structure and`golang` documentation, and REST API documentation. - -Use the [v0.45.1 version of the REST API](https://v1.cosmos.network/rpc/v0.45.1) for accessing the chain. To use the "Try it out" functionality, change the Base URL to `agoric-api.polkachu.com`: +The Agoric Network currently uses `cosmos-sdk` v0.45. The general Cosmos documentation for this version can be [found here](https://docs.cosmos.network/v0.45/), including structure and`golang` documentation, and REST API documentation. +Use the [v0.45.1 version of the REST API](https://v1.cosmos.network/rpc/v0.45.1) for accessing the chain. To use the "Try it out" functionality, change the Base URL to `agoric-api.polkachu.com`: | ![Alt name of image](./assets/cosmos-api.png) | -|-| +| --------------------------------------------- | The chain can also be accessed via JavaScript using the [`cosmjs` library](https://github.com/cosmos/cosmjs) (and [associated tutorials](https://tutorials.cosmos.network/tutorials/7-cosmjs/1-cosmjs-intro.html)), or using [CosmosKit](https://cosmoskit.com/). ## Chain resources -- The base network entry points for the Agoric chain are specified in the [network config](https://main.agoric.net/network-config). +- The base network entry points for the Agoric chain are specified in the [network config](https://main.agoric.net/network-config). - Additional chain information, including tokens and their logos, gas fee information for wallets, additional entry points, and explorers is maintained in the Cosmos [Chain Registry](https://github.com/cosmos/chain-registry/tree/master/agoric). -- The source code for the Agoric Network runtime and contracts is in [the Agoric open source repository](https://github.com/Agoric/agoric-sdk) on GitHub. +- The source code for the Agoric Network runtime and contracts is in [the Agoric open source repository](https://github.com/Agoric/agoric-sdk) on GitHub. - The base unit for staking is `ubld` (corresponding to `uatom` for Cosmos Hub) -- The command utility of the agoric chain is `agd` (corresponding to [`simd` for the Cosmos Hub](https://docs.cosmos.network/v0.45/run-node/interact-node.html)). +- The command utility of the agoric chain is `agd` (corresponding to [`simd` for the Cosmos Hub](https://docs.cosmos.network/v0.45/run-node/interact-node.html)). + --- + # Tools + ## Building `agd` The `agd` command line tool can be built as described in the Agoric [getting-started documentation](https://docs.agoric.com/guides/getting-started#build-the-cosmic-swingset-package). The linked step builds `agd`. To confirm that `agd` is in your `$PATH`, execute + ``` agd version --long ``` @@ -36,15 +38,15 @@ agd version --long # FAQ - How are transactions encoded? -[Cosmos SDK v0.45 Docs - Encoding](https://docs.cosmos.network/v0.45/core/encoding.html) + [Cosmos SDK v0.45 Docs - Encoding](https://docs.cosmos.network/v0.45/core/encoding.html) - What data is needed to create a transaction (last block hash, nonce, sender public key, etc.)? -[Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) + [Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) - What data is signed and how is that data obtained (for example truncated SHA256 of transaction data)? -[Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) + [Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) - Do transactions expire? -Transaction do not expire unless you specify --timeout-height: [Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) -However they do have a sequence number and may be invalidated if another transaction with the same sequence number is processed by the chain + Transaction do not expire unless you specify --timeout-height: [Cosmos SDK v0.45 Docs - Transaction Generation](https://docs.cosmos.network/v0.45/core/transactions.html#transaction-generation) + However they do have a sequence number and may be invalidated if another transaction with the same sequence number is processed by the chain - How are addresses generated? -[Cosmos SDK v0.45 Docs - Accounts](https://docs.cosmos.network/v0.45/basics/accounts.html) + [Cosmos SDK v0.45 Docs - Accounts](https://docs.cosmos.network/v0.45/basics/accounts.html) - How is the blockchain queried? -JSON-RPC, gRPC, REST [Cosmos SDK v0.45 Docs - Interact with Node](https://docs.cosmos.network/v0.45/run-node/interact-node.html) \ No newline at end of file + JSON-RPC, gRPC, REST [Cosmos SDK v0.45 Docs - Interact with Node](https://docs.cosmos.network/v0.45/run-node/interact-node.html) diff --git a/main/guides/integration/name-services.md b/main/guides/integration/name-services.md index 588c63fe8..30de12b67 100644 --- a/main/guides/integration/name-services.md +++ b/main/guides/integration/name-services.md @@ -1,9 +1,10 @@ # Name Services The Agoric chain has a few name services: - - `agoricNames` for well-known names controlled by governance - - `namesByAddress` - a namespace for each provisioned account - - `board` - to map objects to arbitrary names and back + +- `agoricNames` for well-known names controlled by governance +- `namesByAddress` - a namespace for each provisioned account +- `board` - to map objects to arbitrary names and back ## agoricNames / agoricNamesAdmin - well known names @@ -12,14 +13,14 @@ Well-known names are chosen by [BLD staker governance](https://community.agoric. To look up well-known objects, such as the BLD brand: ```js -const brandHub = E(agoricNames).lookup('brand'); -const bldBrand = await E(brandHub).lookup('BLD'); +const brandHub = E(agoricNames).lookup('brand') +const bldBrand = await E(brandHub).lookup('BLD') ``` or, equivalently: ```js -const bldBrand = await E(agoricNames).lookup('brand', 'BLD'); +const bldBrand = await E(agoricNames).lookup('brand', 'BLD') ``` `agoricNames` is a _NameHub_. In general, `E(hub).lookup(key1, key2, ...rest)` is equivalent @@ -27,21 +28,24 @@ to `E(E(hub).lookup(key1)).lookup(key2, ...rest)`. The NameHub interface also in methods `has`, `entries`, `keys`, and `values`. The keys of `agoricNames` include: - - `brand` - IST, BLD, Invitation (Zoe invitation brand), timer (a TimerBrand, not an ERTP brand) - - `issuer` - IST, BLD, Invitation, ... - - `vbankAsset` - IST, BLD, USDC, ATOM, ... - including info about corresponding cosmos denom - - `oracleBrand` - USD, ATOM - - `installation` - psm, reserve, priceAuthority, ... (see [deployed contracts](../zoe/actual-contracts/)) - - `instance` - reserve, one for each psm, one for each priceAuthority, ... (see [deployed contracts](../zoe/actual-contracts/)) + +- `brand` - IST, BLD, Invitation (Zoe invitation brand), timer (a TimerBrand, not an ERTP brand) +- `issuer` - IST, BLD, Invitation, ... +- `vbankAsset` - IST, BLD, USDC, ATOM, ... - including info about corresponding cosmos denom +- `oracleBrand` - USD, ATOM +- `installation` - psm, reserve, priceAuthority, ... (see [deployed contracts](../zoe/actual-contracts/)) +- `instance` - reserve, one for each psm, one for each priceAuthority, ... (see [deployed contracts](../zoe/actual-contracts/)) Adding or updating an entry requires access to the corresponding _NameAdmin_ facet: `agoricNamesAdmin` or one of its descendants - most likely as part of [permissioned contract deployment](../coreeval/). For example: ```js -const { instance } = await E(zoe).startInstance(lemonadeStand); -const { brands: { Lemonade: lemonadeBrand } } = await E(zoe).getTerms(instance); -const brandAdmin = E(agoricNamesAdmin).lookupAdmin('brand'); -await E(brandAdmin).update('Lemonade', lemonadeBrand); +const { instance } = await E(zoe).startInstance(lemonadeStand) +const { + brands: { Lemonade: lemonadeBrand } +} = await E(zoe).getTerms(instance) +const brandAdmin = E(agoricNamesAdmin).lookupAdmin('brand') +await E(brandAdmin).update('Lemonade', lemonadeBrand) ``` ### agoricNames in vstorage @@ -53,7 +57,6 @@ The entries for `instance` and the other keys of `agoricNames` are likewise refl See [marshalling amounts and instance](../getting-started/contract-rpc#marshalling-amounts-and-instances) for details on the format of the data stored in vstorage. - ## namesByAddress / namesByAddressAdmin, and depositFacet - per account namespace Each time a smart wallet is provisioned for address `a`, a NameHub / NameAdmin pair is diff --git a/main/guides/js-programming/far.md b/main/guides/js-programming/far.md index d9453aa44..853b9af4d 100644 --- a/main/guides/js-programming/far.md +++ b/main/guides/js-programming/far.md @@ -57,9 +57,9 @@ All Passables must be hardened. Consider what might happen if we had a remote `i some pass-by-copy data that we passed to it: ```js -let amount1 = { brand: brand1, value: 10n }; -await E(item).setPrice(amount1); // Throws an error, but let's imagine it doesn't. -amount1.value = 20n; +let amount1 = { brand: brand1, value: 10n } +await E(item).setPrice(amount1) // Throws an error, but let's imagine it doesn't. +amount1.value = 20n ``` Now `amount1` is supposedly both in the local and the remote vat, but the `value` @@ -77,6 +77,7 @@ data leads to behavior across vats that is straightforward to reason about. - Returns: `{PassStyle}` `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"`. diff --git a/main/guides/js-programming/hardened-js.md b/main/guides/js-programming/hardened-js.md index 7e5280047..8092d5c4a 100644 --- a/main/guides/js-programming/hardened-js.md +++ b/main/guides/js-programming/hardened-js.md @@ -10,7 +10,6 @@ The last 10 minutes are Q&A._ ::: - ## Example Hardened JavaScript Code The example below demonstrates several features of Hardened JavaScript. @@ -20,15 +19,15 @@ The example below demonstrates several features of Hardened JavaScript. We'll unpack this a bit [below](#objects-and-the-maker-pattern), but for now please note the use of functions and records: - - `makeCounter` is a function. - - Each call to `makeCounter` creates a new instance: - - a new record with two properties, `incr` and `decr`, and - - a new `count` variable. - - The `incr` and `decr` properties are visible from - outside the object. - - The `count` variable is encapsulated; only the - `incr` and `decr` methods can access it. - - Each of these instances is isolated from each other. +- `makeCounter` is a function. +- Each call to `makeCounter` creates a new instance: + - a new record with two properties, `incr` and `decr`, and + - a new `count` variable. +- The `incr` and `decr` properties are visible from + outside the object. +- The `count` variable is encapsulated; only the + `incr` and `decr` methods can access it. +- Each of these instances is isolated from each other. ## Separation of Duties @@ -81,7 +80,7 @@ e.g., only giving the `entryGuard` the ability to increment the counter. This limits the damage that can happen if there is an exploitable bug. ::: tip Watch: Navigating the Attack Surface -to achieve a *multiplicative* reduction in risk. _15 min_
+to achieve a _multiplicative_ reduction in risk. _15 min_
@@ -194,6 +193,7 @@ across a trust boundary. It's important to `harden()` an object before exposing Note that hardening a class instance also hardens the class. For more details, see [harden API in the `ses` package](https://github.com/endojs/endo/blob/HEAD/packages/ses/README.md#harden) ::: + ## Objects with State Now let's review the `makeCounter` example: @@ -249,6 +249,7 @@ may fail in Hardened JavaScript. The [SES wiki](https://github.com/endojs/endo/wiki) tracks compatibility reports for NPM packages, including potential workarounds. ::: + ## Hardening JavaScript: Limiting Globals with Compartments A globally available function such as `fetch` means that every object, @@ -261,9 +262,9 @@ Hardened JavaScript includes a `Compartment` API for enforcing OCap discipline. Only the [standard, built-in objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) such as `Object`, `Array`, and `Promise` are globally available by default (with -an option for carefully controlled exceptions such as `console.log`). With the +an option for carefully controlled exceptions such as `console.log`). With the default `Compartment` options, the non-deterministic `Math.random` and -`Date.now()` are not available. (Earlier versions of Hardened JavaScript +`Date.now()` are not available. (Earlier versions of Hardened JavaScript provided `Compartment` with a `Date.now()` that always returned `NaN`.) Almost all existing JS code was written to run under Node.js or inside a browser, @@ -275,22 +276,22 @@ The conventional globals defined by browser or Node.js hosts are not available by default in a `Compartment`, whether authority-bearing or not: - - authority-bearing: - - `window`, `document`, `process`, `console` - - `setImmediate`, `clearImmediate`, `setTimeout` - - but `Promise` is available, so sometimes - `Promise.resolve().then(_ => fn())` suffices - - see also [Timer Service](/reference/repl/timerServices) - - `require` (Use `import` module syntax instead.) - - `localStorage` - - [SwingSet](../platform/#swingset) orthogonal persistence means state lives indefinitely in ordinary variables and data structures and need not be explicitly written to storage. - - For high cardinality data, see [the `@agoric/store` package](https://github.com/Agoric/agoric-sdk/tree/master/packages/store). - - `global` (Use `globalThis` instead.) - - authority-free but host-defined: - - `Buffer` - - `URL` and `URLSearchParams` - - `TextEncoder`, `TextDecoder` - - `WebAssembly` +- authority-bearing: + - `window`, `document`, `process`, `console` + - `setImmediate`, `clearImmediate`, `setTimeout` + - but `Promise` is available, so sometimes + `Promise.resolve().then(_ => fn())` suffices + - see also [Timer Service](/reference/repl/timerServices) + - `require` (Use `import` module syntax instead.) + - `localStorage` + - [SwingSet](../platform/#swingset) orthogonal persistence means state lives indefinitely in ordinary variables and data structures and need not be explicitly written to storage. + - For high cardinality data, see [the `@agoric/store` package](https://github.com/Agoric/agoric-sdk/tree/master/packages/store). + - `global` (Use `globalThis` instead.) +- authority-free but host-defined: + - `Buffer` + - `URL` and `URLSearchParams` + - `TextEncoder`, `TextDecoder` + - `WebAssembly` In compartments used to load Agoric smart contracts, `globalThis` is hardened, following OCap discipline. @@ -316,14 +317,14 @@ are only for lint tools and do not have any effect at runtime: /** @param {number} init */ const makeCounter = init => { - let value = init; + let value = init return { incr: () => { - value += 1; - return value; - }, - }; -}; + value += 1 + return value + } + } +} ``` If we're not careful, our clients can cause us to misbehave: @@ -382,14 +383,13 @@ in [Higher-order Smart Contracts across Chains](https://www.youtube.com/watch?v= ](https://youtube.com/watch?v=iyuo0ymTt4g&t=1525&list=PLzDw4TTug5O1oHRbp2HkcvKABAY9FKsmG) ::: - ```js const makeMint = () => { - const ledger = makeWeakMap(); + const ledger = makeWeakMap() const issuer = harden({ - makeEmptyPurse: () => mint.makePurse(0), - }); + makeEmptyPurse: () => mint.makePurse(0) + }) const mint = harden({ makePurse: initialBalance => { @@ -398,21 +398,21 @@ const makeMint = () => { getBalance: () => ledger.get(purse), deposit: (amount, src) => { - Nat(ledger.get(purse) + Nat(amount)); - ledger.set(src, Nat(ledger.get(src) - amount)); - ledger.set(purse, ledger.get(purse) + amount); + Nat(ledger.get(purse) + Nat(amount)) + ledger.set(src, Nat(ledger.get(src) - amount)) + ledger.set(purse, ledger.get(purse) + amount) }, withdraw: amount => { - const newPurse = issuer.makeEmptyPurse(); - newPurse.deposit(amount, purse); - return newPurse; - }, - }); - ledger.set(purse, initialBalance); - return purse; - }, - }); - - return mint; -}; + const newPurse = issuer.makeEmptyPurse() + newPurse.deposit(amount, purse) + return newPurse + } + }) + ledger.set(purse, initialBalance) + return purse + } + }) + + return mint +} ``` diff --git a/main/guides/js-programming/index.md b/main/guides/js-programming/index.md index cb1303c8f..f6ea6d76c 100644 --- a/main/guides/js-programming/index.md +++ b/main/guides/js-programming/index.md @@ -10,6 +10,7 @@ of short talks on the Agoric Architecture that overlap substantially with the ma the sections below.
+ ::: @@ -33,6 +34,7 @@ Vats may be on remote machines, including massively replicated machines such as The framework includes: - **[Hardened JavaScript](./hardened-js)** + - Hardened JavaScript provides a platform for making objects that can interact with code you don't completely trust, without being vulnerable to bugs or bad intentions. @@ -40,14 +42,16 @@ The framework includes: to apply the [principle of least authority](./hardened-js#the-principle-of-least-authority-pola). - **[`E()` for Eventual Send to Remote Presences](./eventual-send)** + - The `E()` wrapper function lets you invoke methods within or between vats. - Given a local representative (a *presence*) for a remote object, + Given a local representative (a _presence_) for a remote object, it sends messages to the origin of the presence. `E(obj).myMethod(...args)` is an asynchronous form of `obj.myMethod(...args)`. - **[`Far()`, Remoteable Objects, and Marshaling](./far)** - - Objects used across vats are called *remotables*. + + - Objects used across vats are called _remotables_. To mark an object for exporting from a vat, use the `Far()` function. - **[Notifiers and Subscriptions](./notifiers)** diff --git a/main/guides/js-programming/notifiers.md b/main/guides/js-programming/notifiers.md index 9c69e5d42..a91d6b043 100644 --- a/main/guides/js-programming/notifiers.md +++ b/main/guides/js-programming/notifiers.md @@ -1,6 +1,6 @@ # Notifiers and Subscriptions -*Notifiers* and *subscriptions* both let a service notify clients of state changes. +_Notifiers_ and _subscriptions_ both let a service notify clients of state changes. Specifically, both are abstractions for producing and consuming asynchronous value sequences. They rely on promises to deliver a stream of messages allowing many clients to receive notifications without the originator having to track a subscription list. @@ -11,17 +11,17 @@ In JavaScript, async iterations are manipulated by `AsyncGenerators`, `AsyncIter ## Distributed Asynchronous Iteration -An *async iteration* is an abstract sequence of values. It consists of zero or -more *non-final values* in a fully ordered sequence, revealed asynchronously +An _async iteration_ is an abstract sequence of values. It consists of zero or +more _non-final values_ in a fully ordered sequence, revealed asynchronously over time. In other words, the values have a full ordering, and all consumers see the whole sequence, or a subset of it, in the same order. The sequence may continue indefinitely or terminate in one of two ways: -- *Finish*: The async iteration successfully completes and reports any JavaScript - value as a final completion. -- *Fail*: The async iteration fails and gives a reported final reason. This should be an - error object, but can be any JavaScript value. +- _Finish_: The async iteration successfully completes and reports any JavaScript + value as a final completion. +- _Fail_: The async iteration fails and gives a reported final reason. This should be an + error object, but can be any JavaScript value. `Finish` and `Fail` are final values. To avoid confusion, for iteration values in this doc, "final" and "non-final" merely refer to position in an iteration, and not @@ -33,19 +33,21 @@ this doc, "final" and "non-final" merely refer to position in an iteration, and makes a similar` {publication, subscription}` pair. Each pair’s first element (i.e., `updater` or `publication`) produces the async iteration which is then consumed using each pair’s second element (i.e., `notifier` or `subscription`). + ```js -import { makeNotifierKit } from '@agoric/notifier'; -import { makeSubscriptionKit } from '@agoric/notifier'; -const { updater, notifier } = makeNotifierKit(); -const { publication, subscription } = makeSubscriptionKit(); +import { makeNotifierKit } from '@agoric/notifier' +import { makeSubscriptionKit } from '@agoric/notifier' +const { updater, notifier } = makeNotifierKit() +const { publication, subscription } = makeSubscriptionKit() ``` The key difference between the two is + - `notifiers` are lossy. - - While the sequence is ordered, the consumer requests only the current value and - so may never see any values that happened between requests. + - While the sequence is ordered, the consumer requests only the current value and + so may never see any values that happened between requests. - `subscriptions` are lossless. - - The consumer will see every value in the sequence. + - The consumer will see every value in the sequence. If your consumers only care about more recent states, use `makeNotifierKit()`. Notifiers are often appropriate when the iteration represents a changing quantity, like a purse @@ -63,6 +65,7 @@ A NotifierKit producer produces iteration values with the `updater` using the using the `AsyncIterable` API. Each NotifierKit consumer iteration is a lossy sampling subset of the iteration produced by the producer. Different consumers may see different sampling subsets. The following properties hold for every sampling subset: + - Any non-final value from the producer may be missing from the sampling subset. - Every non-final value in the sampling subset is a non-final value from the producer (e.g., if "7" is in the subset, then it was in the original producer iteration). @@ -110,9 +113,10 @@ position. ## Methods The `updater` and `publication` both have the same three methods: + - `updateState(state)` - Supplies and sends out a new state to consumers. All active Promises - produced by `getUpdateSince()` are resolved to the next record. + produced by `getUpdateSince()` are resolved to the next record. - `finish(finalState)` - Closes the stream of state changes and supplies a final state value to consumers. @@ -123,6 +127,7 @@ The `updater` and `publication` both have the same three methods: signalling that the monitored object encountered an error condition. The `notifier` has an additional method that the `subscription` does not: + - `getUpdateSince(previousUpdateCount)` - Returns a promise for the next published value as a `{ value, updateCount }` record, using an optional `previousUpdateCount` to communicate the last obtained value. @@ -156,21 +161,21 @@ Individual contracts can use notifiers and subscriptions to provide updates givi The following methods use or return notifiers. - [aPurse.getCurrentAmountNotifier()](/reference/ertp-api/purse#apurse-getcurrentamountnotifier) - - Part of the ERTP API. Returns a lossy notifier for changes to this purse's balance. + - Part of the ERTP API. Returns a lossy notifier for changes to this purse's balance. - [getPursesNotifier()](/reference/wallet-api/wallet-bridge#getpursesnotifier) - - Part of the Wallet API. It returns a notifier that follows changes in the purses in the Wallet. + - Part of the Wallet API. It returns a notifier that follows changes in the purses in the Wallet. - [getOffersNotifier()](/reference/wallet-api/wallet-bridge#getoffersnotifier) - - Part of the Wallet API. It returns a notifier that follows changes to the offers received by the Wallet. + - Part of the Wallet API. It returns a notifier that follows changes to the offers received by the Wallet. - [makeQuoteNotifier(amountIn,brandOut)](/reference/repl/priceAuthority#makequotenotifier-amountin-brandout) - - Part of the PriceAuthority API. Notifies the latest `PriceQuotes` for the given `amountIn`. + - Part of the PriceAuthority API. Notifies the latest `PriceQuotes` for the given `amountIn`. - [getPriceNotifier(brandIn, brandOut)](/reference/repl/priceAuthority#getpricenotifier-brandin-brandout) - - Part of the PriceAuthority API. Returns a notifier for the specified brands. Different PriceAuthorities may issue these at very - different rates. + - Part of the PriceAuthority API. Returns a notifier for the specified brands. Different PriceAuthorities may issue these at very + different rates. - [E(home.localTimerService).makeNotifier(delay, interval) and E(home.chainTimerService).makeNotifier(delay, interval)](/reference/repl/timerServices#e-home-chain-or-local-timerservice-makenotifier-delay-interval) - - Part of the REPL's TimerService API. It creates and returns a `Notifier` object - that repeatedly delivers updates at times that are a multiple of the provided `interval` value, - with the first update happening after the provided `delay` value. + - Part of the REPL's TimerService API. It creates and returns a `Notifier` object + that repeatedly delivers updates at times that are a multiple of the provided `interval` value, + with the first update happening after the provided `delay` value. ## Examples @@ -179,13 +184,15 @@ The following methods use or return notifiers. Let’s look at a subscription example. We have three characters: Paula the publisher, and Alice and Bob the subscribers. While Alice and Bob both consume Paula's published iteration, they use different tools to do so. First we create a publication/subscription pair with `makeSubscriptionKit()`. Paula publishes an iteration with the non-final sequence 'a', 'b' and 'done' as its completion value. + ```js -const { publication, subscription } = makeSubscriptionKit(); +const { publication, subscription } = makeSubscriptionKit() // Paula the publisher says -publication.updateState('a'); -publication.updateState('b'); -publication.finish('done'); +publication.updateState('a') +publication.updateState('b') +publication.finish('done') ``` + Remember, a `SubscriptionKit` is lossless. It conveys all of an async iteration’s non-final values, as well as the final value. You can use the JavaScript `AsyncIterable` API directly, but both the JavaScript for-await-of syntax and the `observeIteration` adaptor are more convenient. Here, @@ -196,44 +203,50 @@ the non-final values and whether the iteration completes or fails. She can see a failure reason, but the for-await-of syntax does not let her see the completion value 'done'. She can write code that only executes after the loop finishes, but the code won’t know what the completion value actually was “done”, “completed”, or something else. This is a limitation of JavaScript's iteration, whether asynchronous or synchronous (as consumed by a for-of loop). + ```js const consume = async subscription => { try { for await (const val of subscription) { - console.log('non-final-value', val); + console.log('non-final-value', val) } - console.log('the iteration finished'); + console.log('the iteration finished') } catch (reason) { - console.log('the iteration failed', reason); + console.log('the iteration failed', reason) } -}; -consume(subscription); +} +consume(subscription) // Eventually prints: // non-final-value a // non-final-value b // the iteration finished ``` + Subscriber Bob consumes using the `(observeIteration(asyncIterableP, iterationObserver)` adaptor. + ```js const observer = harden({ updateState: val => console.log('non-final-value', val), finish: completion => console.log('finished', completion), - fail: reason => console.log('failed', reason), -}); -observeIteration(subscription, observer); + fail: reason => console.log('failed', reason) +}) +observeIteration(subscription, observer) // Eventually prints: // non-final-value a // non-final-value b // finished done ``` + ### Notifier Example A `NotifierKit` is a lossy conveyor of non-final values, but does losslessly convey termination. Let's say the subscription example above started with the following instead of `makeSubscriptionKit()`. + ```js -const { updater, notifier } = makeNotifierKit(); +const { updater, notifier } = makeNotifierKit() ``` + If we then renamed `publication` to `updater` and `subscription` to `notifier` in the rest of the example, the code would still be correct and work. However, when using a notifier, either Alice or Bob may have missed either or both of the @@ -249,7 +262,7 @@ producing values from making progress. The consumers cannot cause each other to hang or miss values. For distributed operations, all the iteration values—non-final values, -successful completion value, failure reason—must be *Passable*, which means they're values that +successful completion value, failure reason—must be _Passable_, which means they're values that can somehow be passed between [vats](../../glossary/index#vat). The rest of this doc assumes all these values are Passable. @@ -277,13 +290,16 @@ for-await-of loop which requires a local `AsyncIterable`. It cannot handle a remote reference to an `AsyncIterable` at Paula's site. Alice has to make an `AsyncIterable` at her site by using `getSharableSubsciptionInternals()`. She can replace her call to `consume(subscription)` with: + ```js -import { makeSubscription } from '@agoric/notifier'; +import { makeSubscription } from '@agoric/notifier' -const localSubscription = - makeSubscription(E(subscription).getSharableSubsciptionInternals()); - consume(localSubscription); +const localSubscription = makeSubscription( + E(subscription).getSharableSubsciptionInternals() +) +consume(localSubscription) ``` + The code above uses a SubscriptionKit. NotifierKits have a similar pair of a `getSharableNotifierInternals()` method and a `makeNotifier`. However, this technique requires that Alice know what kind of a possibly remote `AsyncIterable` @@ -291,14 +307,14 @@ she has, and she must have the required making function code locally available. Alternatively, Alice can generically mirror any possibly remote `AsyncIterable` by making a new local pair and plugging them together with `observeIteration`. + ```js -const { - publication: adapterPublication, - subscription: adapterSubscription -} = makeSubscriptionKit(); -observeIteration(subscription, adapterPublication); -consume(adapterSubscription); +const { publication: adapterPublication, subscription: adapterSubscription } = + makeSubscriptionKit() +observeIteration(subscription, adapterPublication) +consume(adapterSubscription) ``` + This works when subscription is a reference to a `AsyncIterable`. If Alice only needs to consume in a lossy manner, she can use the `makeNotifierKit()` method instead, which still works independently of what kind of `AsyncIterable` subscription is a diff --git a/main/guides/orchestration/getting-started/api.md b/main/guides/orchestration/getting-started/api.md index 17c336cb0..1a1cc0502 100644 --- a/main/guides/orchestration/getting-started/api.md +++ b/main/guides/orchestration/getting-started/api.md @@ -13,14 +13,15 @@ The [`Orchestrator`](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestrati Retrieves the chain information and provides access to chain-specific methods. See [getChain](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.Orchestrator#getChain). ```javascript -const chain = await orchestrator.getChain('chainName'); +const chain = await orchestrator.getChain('chainName') ``` ### makeLocalAccount + Creates a new `LocalChainAccount`. See [makeLocalAccount](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.Orchestrator#makeLocalAccount). ```javascript -const localAccount = await orchestrator.makeLocalAccount(); +const localAccount = await orchestrator.makeLocalAccount() ``` ### getBrandInfo @@ -28,7 +29,7 @@ const localAccount = await orchestrator.makeLocalAccount(); Returns information about a `denom`, including the equivalent local Brand, the chain where the denom is held, and the chain that issues the corresponding asset. See [getBrandInfo](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.Orchestrator#getBrandInfo). ```javascript -const brandInfo = orchestrator.getBrandInfo('denom'); +const brandInfo = orchestrator.getBrandInfo('denom') ``` ### asAmount @@ -36,7 +37,7 @@ const brandInfo = orchestrator.getBrandInfo('denom'); Converts a denom amount to an `Amount` with a brand. See [asAmount](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.Orchestrator#asAmount). ```javascript -const amount = orchestrator.asAmount({ denom: 'uatom', value: 1000n }); +const amount = orchestrator.asAmount({ denom: 'uatom', value: 1000n }) ``` ## OrchestrationAccount @@ -48,7 +49,7 @@ An [`OrchestrationAccount`](https://agoric-sdk.pages.dev/types/_agoric_orchestra Retrieves the address of the account on the remote chain. See [getAddress](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#getAddress). ```javascript -const address = await orchestrationAccount.getAddress(); +const address = await orchestrationAccount.getAddress() ``` ### getBalances @@ -56,7 +57,7 @@ const address = await orchestrationAccount.getAddress(); Returns an array of amounts for every balance in the account. See [getBalances](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#getBalances). ```javascript -const balances = await orchestrationAccount.getBalances(); +const balances = await orchestrationAccount.getBalances() ``` ### getBalance @@ -64,7 +65,7 @@ const balances = await orchestrationAccount.getBalances(); Retrieves the balance of a specific denom for the account. See [getBalance](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#getBalance). ```javascript -const balance = await orchestrationAccount.getBalance('uatom'); +const balance = await orchestrationAccount.getBalance('uatom') ``` ### send @@ -72,7 +73,7 @@ const balance = await orchestrationAccount.getBalance('uatom'); Transfers an amount to another account on the same chain. The promise settles when the transfer is complete. See [send](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#send). ```javascript -await orchestrationAccount.send(receiverAddress, amount); +await orchestrationAccount.send(receiverAddress, amount) ``` ### transfer @@ -80,7 +81,7 @@ await orchestrationAccount.send(receiverAddress, amount); Transfers an amount to another account, typically on another chain. The promise settles when the transfer is complete. See [transfer](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#transfer). ```javascript -await orchestrationAccount.transfer(amount, destinationAddress); +await orchestrationAccount.transfer(amount, destinationAddress) ``` ### transferSteps @@ -88,7 +89,7 @@ await orchestrationAccount.transfer(amount, destinationAddress); Transfers an amount to another account in multiple steps. The promise settles when the entire path of the transfer is complete. See [transferSteps](https://agoric-sdk.pages.dev/interfaces/_agoric_orchestration.OrchestrationAccountI#transferSteps). ```javascript -await orchestrationAccount.transferSteps(amount, transferMsg); +await orchestrationAccount.transferSteps(amount, transferMsg) ``` ### deposit @@ -96,5 +97,5 @@ await orchestrationAccount.transferSteps(amount, transferMsg); Deposits payment from Zoe to the account. For remote accounts, an IBC Transfer will be executed to transfer funds there. ```javascript -await orchestrationAccount.deposit(payment); +await orchestrationAccount.deposit(payment) ``` diff --git a/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-swap.md b/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-swap.md index 732fe6f0d..d0ed83ce6 100644 --- a/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-swap.md +++ b/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-swap.md @@ -1,22 +1,25 @@ # Cross-Chain Swap Contract ## Overview Diagram +

## Imports + ```javascript -import { StorageNodeShape } from '@agoric/internal'; -import { TimerServiceShape } from '@agoric/time'; -import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js'; -import { deeplyFulfilled } from '@endo/marshal'; -import { M, objectMap } from '@endo/patterns'; -import { orcUtils } from '../utils/orc.js'; -import { withOrchestration } from '../utils/start-helper.js'; +import { StorageNodeShape } from '@agoric/internal' +import { TimerServiceShape } from '@agoric/time' +import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js' +import { deeplyFulfilled } from '@endo/marshal' +import { M, objectMap } from '@endo/patterns' +import { orcUtils } from '../utils/orc.js' +import { withOrchestration } from '../utils/start-helper.js' ``` Importing Shapes and Utilities: + - `StorageNodeShape` and `TimerServiceShape` are imported for validating the `privateArgs`. - `withdrawFromSeat` is a helper function from Zoe to withdraw funds from a seat. - `deeplyFulfilled` is a function that ensures that all promises within an object are resolved. @@ -25,6 +28,7 @@ Importing Shapes and Utilities: - `withOrchestration` is a function that sets up orchestration. ## Type Imports + ```javascript /** * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' @@ -40,7 +44,7 @@ Importing Shapes and Utilities: This includes type information to help with TypeScript or JSDoc annotations, which are useful for understanding the types used throughout the contract. -## `stakeAndSwapFn` Offer Handler +## `stakeAndSwapFn` Offer Handler ```javascript /** @@ -57,35 +61,36 @@ const stakeAndSwapFn = async (orch, { zcf }, seat, offerArgs) => { ``` Function Parameters: + - `orch`: The orchestrator object to manage interactions with chains/accounts. - `ctx`: Context object containing zcf. - `seat`: The seat representing the contract's position in the offer. - `offerArgs`: Arguments provided with the offer, including staked amount and validator address. ```javascript -const { give } = seat.getProposal(); +const { give } = seat.getProposal() ``` Extracts the `give` part of the proposal from the seat. This includes what the user is offering to the contract. ```javascript -const omni = await orch.getChain('omniflixhub'); -const agoric = await orch.getChain('agoric'); +const omni = await orch.getChain('omniflixhub') +const agoric = await orch.getChain('agoric') ``` Retrieves chain objects for omniflixhub (a remote chain) and agoric (the local chain) chains using the orchestrator. ```javascript const [omniAccount, localAccount] = await Promise.all([ - omni.makeAccount(), - agoric.makeAccount(), -]); + omni.makeAccount(), + agoric.makeAccount() +]) ``` Creates accounts on both omniflixhub and agoric chains concurrently. ```javascript -const omniAddress = omniAccount.getAddress(); +const omniAddress = omniAccount.getAddress() ``` Retrieves the address of the omniAccount. @@ -94,22 +99,23 @@ Retrieves the address of the omniAccount. ```javascript // deposit funds from user seat to LocalChainAccount -const payments = await withdrawFromSeat(zcf, seat, give); +const payments = await withdrawFromSeat(zcf, seat, give) await deeplyFulfilled( - objectMap(payments, payment => - localAccount.deposit(payment), - ), -); -seat.exit(); + objectMap(payments, payment => localAccount.deposit(payment)) +) +seat.exit() ``` ### Withdraw Funds + Withdraws the funds specified in the give part of the proposal from the seat. -### Deposit Funds +### Deposit Funds + Deposits the withdrawn payments into the local account. ### Exit Seat + The seat exits the offer, completing the offer being handled. ## Building and Executing Swap Instructions @@ -117,26 +123,27 @@ The seat exits the offer, completing the offer being handled. ```javascript // build swap instructions with orcUtils library const transferMsg = orcUtils.makeOsmosisSwap({ - destChain: 'omniflixhub', - destAddress: omniAddress, - amountIn: give.Stable, - brandOut: '...', - slippage: 0.03, -}); + destChain: 'omniflixhub', + destAddress: omniAddress, + amountIn: give.Stable, + brandOut: '...', + slippage: 0.03 +}) ``` -Parameters include destination chain, destination address, input amount, output brand, and slippage tolerance. In the `give` keyword record, the `Stable` keyword is expected to have the assets to trade. +Parameters include destination chain, destination address, input amount, output brand, and slippage tolerance. In the `give` keyword record, the `Stable` keyword is expected to have the assets to trade. ### Executing the `Swap` Instructions & Delegate -Carries out the swap instructions using the results of `orcUtils.makeOsmosisSwap` above. + +Carries out the swap instructions using the results of `orcUtils.makeOsmosisSwap` above. ```javascript await localAccount -.transferSteps(give.Stable, transferMsg) -.then(_txResult => - omniAccount.delegate(offerArgs.validator, offerArgs.staked), -) -.catch(e => console.error(e)); + .transferSteps(give.Stable, transferMsg) + .then(_txResult => + omniAccount.delegate(offerArgs.validator, offerArgs.staked) + ) + .catch(e => console.error(e)) ``` Transfers the stablecoins according to the swap instructions. On `transferSteps` being resolves, we delegate the staked amount to the specified validator on the omniflixhub chain. @@ -154,28 +161,30 @@ export const meta = { orchestrationService: M.or(M.remotable('orchestration'), null), storageNode: StorageNodeShape, marshaller: M.remotable('marshaller'), - timerService: M.or(TimerServiceShape, null), + timerService: M.or(TimerServiceShape, null) }, - upgradability: 'canUpgrade', -}; -harden(meta); + upgradability: 'canUpgrade' +} +harden(meta) ``` This defines the shape of private arguments and the contract’s upgradability, and `harden` ensures that the metadata object is immutable. ## `makeNatAmountShape` function + ```javascript /** * @param {Brand} brand must be a 'nat' brand, not checked * @param {NatValue} [min] */ export const makeNatAmountShape = (brand, min) => - harden({ brand, value: min ? M.gte(min) : M.nat() }); + harden({ brand, value: min ? M.gte(min) : M.nat() }) ``` Utility function to create a shape for amounts of the specified fungible brand. If a minimum value is provided, ensures the amount is greater than or equal to it. ## `contract` Function + The `contract` function when wrapped inside `withOrchestration` defines the [`start` function](#start-function) which is the entry point of the contract. The contract exports a `start` function [below](#start-function). It is merely a convention/convenience that we define a more abstract `contract` function here and pass it to `withOrchestration`. The arguments of this function are `zcf`, `privateAge`, `zone`, and `tools` for orchestration. ```javascript @@ -198,8 +207,9 @@ const contract = async (zcf, privateArgs, zone, { orchestrate }) => { ``` ## Getting brands from Contract Terms + ```javascript -const { brands } = zcf.getTerms(); +const { brands } = zcf.getTerms() ``` This retrieves the brands specified in the contract terms. @@ -207,19 +217,20 @@ This retrieves the brands specified in the contract terms. ## Handler for swap and stake offers ```javascript - /** deprecated historical example */ - /** - * @type {OfferHandler< - * unknown, - * { staked: Amount<'nat'>; validator: CosmosValidatorAddress } - * >} - */ - const swapAndStakeHandler = orchestrate('LSTTia', { zcf }, stakeAndSwapFn); +/** deprecated historical example */ +/** + * @type {OfferHandler< + * unknown, + * { staked: Amount<'nat'>; validator: CosmosValidatorAddress } + * >} + */ +const swapAndStakeHandler = orchestrate('LSTTia', { zcf }, stakeAndSwapFn) ``` `swapAndStakeHandler` defines the offer handler for the swap and stake operation using [`stakeAndSwapFn` function](#stakeandswapfn-offer-handler). ## Make Invitation and Create `publicFacet` + ```javascript const publicFacet = zone.exo('publicFacet', undefined, { makeSwapAndStakeInvitation() { @@ -230,18 +241,19 @@ const publicFacet = zone.exo('publicFacet', undefined, { harden({ give: { Stable: makeNatAmountShape(brands.Stable, 1n) }, want: {}, // XXX ChainAccount Ownable? - exit: M.any(), - }), - ); - }, -}); + exit: M.any() + }) + ) + } +}) ``` Defines the `publicFacet` for the contract, which includes the method to make an `invitation` for users to swap stablecoins for TIA and stake, and returns the hardened public facet. Defining `publicFacet` with `zone.exo` makes it [remotely accessible](/glossary/#exo) and persistent through contract upgrades with a [durable `zone`](/glossary/#zone). ## `start` Function + ```javascript -export const start = withOrchestration(contract); +export const start = withOrchestration(contract) ``` -Defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup. \ No newline at end of file +Defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup. diff --git a/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-unbond.md b/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-unbond.md index 73c8dc61e..a3f34e830 100644 --- a/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-unbond.md +++ b/main/guides/orchestration/getting-started/contract-walkthrough/cross-chain-unbond.md @@ -1,23 +1,26 @@ # Cross-Chain Unbond Contract ## Overview Diagram +

## Imports + ```javascript -import { M } from '@endo/patterns'; -import { withOrchestration } from '../utils/start-helper.js'; +import { M } from '@endo/patterns' +import { withOrchestration } from '../utils/start-helper.js' ``` - `M`: Imported from @endo/patterns, provides pattern-matching utilities. - `withOrchestration`: Imported from a utility module, used to set up and provide access to orchestration tools. ## JSDoc Annotations for Type Information + ```javascript /** - * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' + * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' * @import {TimerService} from '@agoric/time'; * @import {Baggage} from '@agoric/vat-data'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; @@ -32,6 +35,7 @@ import { withOrchestration } from '../utils/start-helper.js'; This includes type information annotations to help with TypeScript or JSDoc, making it easier to understand the types used throughout the contract. ## `unbondAndLiquidStakeFn` Function + ```javascript /** * @param {Orchestrator} orch @@ -45,36 +49,44 @@ const unbondAndLiquidStakeFn = async (orch, { zcf }, _seat, _offerArgs) => { ``` ### Function Parameters + - `orch`: The orchestrator object to manage interactions with chains/accounts. - `ctx`: Context object containing zcf. - `_seat`: The seat representing the user’s position in the contract (not used in this function, hence `_` prefix). - `_offerArgs`: Arguments provided with the offer (not used in this function, hence `_` prefix). ## Interacting with Chains + ```javascript -const omni = await orch.getChain('omniflixhub'); -const omniAccount = await omni.makeAccount(); +const omni = await orch.getChain('omniflixhub') +const omniAccount = await omni.makeAccount() ``` ### Get Chain + Retrieves the omniflixhub chain object using the orchestrator. ### Make Account + Creates an account on the omniflixhub chain. ## Interaction with Stride Chain + ```javascript -const stride = await orch.getChain('stride'); -const strideAccount = await stride.makeAccount(); +const stride = await orch.getChain('stride') +const strideAccount = await stride.makeAccount() ``` ### Get Chain + Retrieves the stride chain object using the orchestrator. ### Make Account + Creates an account on the stride chain. ## `contract` Function + The `contract` function when wrapped inside `withOrchestration` defines the [`start` function](#start-function) which is the entry point of the contract. The contract exports a `start` function [below](#start-function). It is merely a convention/convenience that we define a more abstract `contract` function here and pass it to `withOrchestration`. The arguments of this function are `zcf`, `privateAge`, `zone`, and `tools` for orchestration. ```javascript @@ -94,27 +106,32 @@ The `contract` function when wrapped inside `withOrchestration` defines the [`st * @param {OrchestrationTools} tools */ const contract = async (zcf, privateArgs, zone, { orchestrate }) => { - ``` - ### `contract` Function Parameters: +``` + +### `contract` Function Parameters: + - `zcf`: Zoe Contract Facet. - `privateArgs`: Object containing remote references to various services. - `zone`: A `Zone` object with access to storage for persistent data. - `OrchestrationTools`: A set of orchestration related tools needed by the contract. ## Offer Handler for Unbond and Liquid Stake + ```javascript /** @type {OfferHandler} */ const unbondAndLiquidStake = orchestrate( - 'LSTTia', - { zcf }, - unbondAndLiquidStakeFn, -); + 'LSTTia', + { zcf }, + unbondAndLiquidStakeFn +) ``` ### Offer Handler + Defines the offer handler for the unbond and liquid stake operation using [`unbondAndLiquidStakeFn`](#unbondandliquidstakefn-function). ## Make Invitation and Create `publicFacet` + ```javascript const publicFacet = zone.exo('publicFacet', undefined, { makeUnbondAndLiquidStakeInvitation() { @@ -126,20 +143,21 @@ const publicFacet = zone.exo('publicFacet', undefined, { // Nothing to give; the funds come from undelegating give: {}, want: {}, // XXX ChainAccount Ownable? - exit: M.any(), - }), - ); - }, -}); + exit: M.any() + }) + ) + } +}) -return harden({ publicFacet }); +return harden({ publicFacet }) ``` Defines the `publicFacet` for the contract, which includes the method to make an `invitation`, and returns the hardened public facet. Defining `publicFacet` with `zone.exo` makes it [remotely accessible](/glossary/#exo) and persistent through contract upgrades with a [durable `zone`](/glossary/#zone). ## `start` Function + ```javascript -export const start = withOrchestration(contract); +export const start = withOrchestration(contract) ``` -Defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup. \ No newline at end of file +Defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup. diff --git a/main/guides/orchestration/getting-started/contract-walkthrough/orchestration-basics.md b/main/guides/orchestration/getting-started/contract-walkthrough/orchestration-basics.md index 3585791c1..d4ab4683f 100644 --- a/main/guides/orchestration/getting-started/contract-walkthrough/orchestration-basics.md +++ b/main/guides/orchestration/getting-started/contract-walkthrough/orchestration-basics.md @@ -1,5 +1,5 @@ # dApp Orchestration Basics -To get started with developing using the Orchestration API, developers can make use of our [dapp-orchestration-basics](https://github.com/Agoric/dapp-orchestration-basics) template. -Following the dApp pattern of our existing dapp templates, `dapp-orchestration-basics` contains both ui & contract folders within a single yarn workspace. +To get started with developing using the Orchestration API, developers can make use of our [dapp-orchestration-basics](https://github.com/Agoric/dapp-orchestration-basics) template. +Following the dApp pattern of our existing dapp templates, `dapp-orchestration-basics` contains both ui & contract folders within a single yarn workspace. diff --git a/main/guides/orchestration/getting-started/contract-walkthroughs.md b/main/guides/orchestration/getting-started/contract-walkthroughs.md index a6c3a753d..c7d8da8da 100644 --- a/main/guides/orchestration/getting-started/contract-walkthroughs.md +++ b/main/guides/orchestration/getting-started/contract-walkthroughs.md @@ -1,12 +1,12 @@ # Contract Walkthroughs -This section is designed to provide detailed explanations and insights into example orchestration smart contracts. +This section is designed to provide detailed explanations and insights into example orchestration smart contracts. In this section, we will cover three primary contracts: 1. `swapExample.contract.js`: A comprehensive guide to the process of swapping assets between different chains using the Agoric orchestration library. 2. `unbondExample.contract.js`: A detailed walkthrough of the unbonding and liquid staking process, highlighting the steps involved in managing cross-chain operations. -3. `orca.contract.js`: A dapp template serving as an introduction to the foundational concepts and implementation of basic orchestration within an Agoric dApp (currently under active development). +3. `orca.contract.js`: A dapp template serving as an introduction to the foundational concepts and implementation of basic orchestration within an Agoric dApp (currently under active development). Each walkthrough will include line-by-line explanations of the contract code, providng insights into the mechanics and best practices of smart contract development on the Agoric platform. By the end of these walkthroughs, you should have a solid understanding of how to utilize Agoric’s tools and libraries to create robust and efficient cross-chain smart contracts. @@ -31,7 +31,6 @@ The Unbond Contract focuses on the process of unbonding staked assets and perfor [See Contract Overview](/guides/orchestration/getting-started/contract-walkthrough/cross-chain-unbond) - ## Dapp Orchestration Basics The Agoric Dapp Orchestration Basics walkthrough (currently under development) will provide an introduction to the core concepts and basic implementation of orchestrtion within an Agoric dApp. This guide aims to: diff --git a/main/guides/orchestration/getting-started/key-concepts.md b/main/guides/orchestration/getting-started/key-concepts.md index bd4f0ad4a..222c9e7c3 100644 --- a/main/guides/orchestration/getting-started/key-concepts.md +++ b/main/guides/orchestration/getting-started/key-concepts.md @@ -54,17 +54,17 @@ It simplifies accessing and interacting with multiple chains, providing a unifie ChainHub also allows dynamic registration and use of chain and connection information. ```javascript -const chainHub = makeChainHub(remotePowers.agoricNames); +const chainHub = makeChainHub(remotePowers.agoricNames) // Register a new chain with its information -chainHub.registerChain(chainKey, chainInfo); +chainHub.registerChain(chainKey, chainInfo) // Register a connection between the Agoric chain and the new chain chainHub.registerConnection( agoricChainInfo.chainId, chainInfo.chainId, - connectionInfo, -); + connectionInfo +) ``` In this example, `chainHub` is used to register a new chain and establish a connection between the Agoric chain and the newly registered chain. @@ -78,7 +78,7 @@ Orchestration accounts are a key concept in the Agoric Orchestration API, repres - `getAddress` retrieves the address of the account on the remote chain. ```javascript -const address = await orchestrationAccount.getAddress(); +const address = await orchestrationAccount.getAddress() ``` **2. Balance Management** @@ -87,8 +87,8 @@ const address = await orchestrationAccount.getAddress(); - `getBalance` retrieves the balance of a specific denom for the account. ```javascript -const balances = await orchestrationAccount.getBalances(); -const balance = await orchestrationAccount.getBalance('uatom'); +const balances = await orchestrationAccount.getBalances() +const balance = await orchestrationAccount.getBalance('uatom') ``` **3. Funds Transfer** @@ -98,9 +98,9 @@ const balance = await orchestrationAccount.getBalance('uatom'); - `transferSteps` transfers an amount in multiple steps, handling complex transfer paths. ```javascript -await orchestrationAccount.send(receiverAddress, amount); -await orchestrationAccount.transfer(amount, destinationAddress); -await orchestrationAccount.transferSteps(amount, transferMsg); +await orchestrationAccount.send(receiverAddress, amount) +await orchestrationAccount.transfer(amount, destinationAddress) +await orchestrationAccount.transferSteps(amount, transferMsg) ``` To see the function the Orchestration API exposes, see [Orchestration API](/guides/orchestration/getting-started/api.html) diff --git a/main/guides/orchestration/index.md b/main/guides/orchestration/index.md index fcaa35848..b0a880472 100644 --- a/main/guides/orchestration/index.md +++ b/main/guides/orchestration/index.md @@ -1,21 +1,20 @@ # Orchestration Overview + Agoric's Orchestration API is a tool to help developers build seamless applications out of disparate interoperable chains and services. This composability allows for the development of user-centric applications that leverage the unique strengths of different blockchain ecosystems. The Agoric Orchestration API simplifies interactions between multiple networks, particularly those -using the [Inter-Blockchain Communication (IBC)](/glossary/#ibc) protocol within Cosmos. The API acts as an +using the [Inter-Blockchain Communication (IBC)](/glossary/#ibc) protocol within Cosmos. The API acts as an abstraction layer, streamlining multi-step processes. -Orchestration integrates with existing Agoric components ([SwingSet](/guides/platform/#swingset), Cosmos modules) and introduces vat-orchestration. This [vat](/glossary/#vat) manages Inter-Chain Account (ICA) identities and connections to host chains, ensuring proper transaction authorization. +Orchestration integrates with existing Agoric components ([SwingSet](/guides/platform/#swingset), Cosmos modules) and introduces vat-orchestration. This [vat](/glossary/#vat) manages Inter-Chain Account (ICA) identities and connections to host chains, ensuring proper transaction authorization. The Orchestration API handles asynchronous tasks and complex workflows, including those spanning multiple chains. This empowers smart contracts for actions like inter-chain staking and multi-hop transfers, facilitated by notifications from the transfer vat and IBC middleware updates. Orchestration simplifies complex cross-chain interactions within a secure and user-controlled environment on the Agoric platform. - # Introduction to Orchestration API Flow The following sequence diagram provides a comprehensive overview of the orchestration process within the Agoric platform. This example illustrates the interaction between various components, highlighting how the orchestration library (`OrchLib`) facilitates cross-chain operations. This is a good first example to understand the flow of the Orchestration API, showing the steps involved in creating and managing cross-chain transactions. -
-
\ No newline at end of file +
diff --git a/main/guides/platform/index.md b/main/guides/platform/index.md index dd4c43649..bac48b870 100644 --- a/main/guides/platform/index.md +++ b/main/guides/platform/index.md @@ -5,7 +5,7 @@ This document focuses on the layers beneath Zoe and ERTP, what we call the Agoric Platform. This includes "SwingSet", which can be thought of as our VM providing a distributed Javascript environment, as well as -the Cosmos SDK and IBC. +the Cosmos SDK and IBC. ## SwingSet @@ -14,8 +14,8 @@ it's very important to ensure that one user cannot prevent another user's code from executing and that the way in which code is interleaved doesn't open up hazards such as reentrancy. SwingSet solves that problem by dividing up the execution environment into -*vats*. A [vat](../js-programming/#vats-the-unit-of-synchrony) is a *unit -of synchrony*. This means that within a JavaScript vat, objects and +_vats_. A [vat](../js-programming/#vats-the-unit-of-synchrony) is a _unit +of synchrony_. This means that within a JavaScript vat, objects and functions can communicate with one another synchronously. Between vats, objects and functions communicate asynchronously, by design. @@ -32,14 +32,14 @@ a part of the state that is intended to serve as an outbox. On a non-blockchain machine, this might mean sending a message to a remote machine. -SwingSet provides [orthogonal persistence](https://en.wikipedia.org/wiki/Persistence_(computer_science)#Orthogonal_or_transparent_persistence). +SwingSet provides [orthogonal persistence](). ## Cosmos SDK Our testnet has a single SwingSet instance with multiple vats running on top of Cosmos SDK. SwingSet and most of our code is written in JavaScript, so we currently have a complicated process that starts up -the JavaScript environment, starts a SwingSet instance, and then +the JavaScript environment, starts a SwingSet instance, and then connects through Go to the Cosmos SDK modules, the consensus algorithm in Tendermint, and back again. @@ -55,7 +55,7 @@ protocol without needing a platform upgrade or chain governance vote. In essence, dIBC is the idea of using a smart contract or VM platform to deploy new contracts that support new protocols, all on an existing -chain without having to wait for chain upgrades. +chain without having to wait for chain upgrades. For more information, check out [a recent article on dIBC](https://medium.com/agoric/the-road-to-dynamic-ibc-4a43bc964bca). diff --git a/main/guides/subquery-indexing.md b/main/guides/subquery-indexing.md index c6203a534..3a7aff523 100644 --- a/main/guides/subquery-indexing.md +++ b/main/guides/subquery-indexing.md @@ -11,6 +11,7 @@ SubQuery is a leading blockchain data indexer that provides developers with fast Features include multiple RPC endpoint configurations, multi-worker capabilities and a configurable caching architecture. To find out more, visit our [documentation](https://academy.subquery.network/). ## Getting started + Take a look at this [SubQuery Starter Project](https://github.com/subquery/cosmos-subql-starter/tree/main/Agoric/agoric-starter) that introduces SubQuery's Agoric support by indexing all transfer events and messages on the Agoric network. You can also follow along this [step by step guide](https://academy.subquery.network/quickstart/quickstart_chains/cosmos-agoric.html) to get familiar with SubQuery or check out the [Agoric x SubQuery workshop](https://www.youtube.com/watch?v=QC5wQOcWynU) to see an actual demo. @@ -19,17 +20,19 @@ You can also follow along this [step by step guide](https://academy.subquery.net SubQuery is [open-source](https://opensource.org/osd/), licensed under the [GNU GENERAL PUBLIC LICENSE](https://github.com/subquery/subql/blob/main/LICENSE), meaning you have the freedom to run it in the following three ways: -* Locally on your own computer, or a cloud provider of your choosing. View the [instructions on how to run SubQuery locally](https://academy.subquery.network/run_publish/run.html). +- Locally on your own computer, or a cloud provider of your choosing. View the [instructions on how to run SubQuery locally](https://academy.subquery.network/run_publish/run.html). -* You can publish it to SubQuery's [Managed Service](https://managedservice.subquery.network/login), where SubQuery will host projects on your behalf. There is also a free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html). +- You can publish it to SubQuery's [Managed Service](https://managedservice.subquery.network/login), where SubQuery will host projects on your behalf. There is also a free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html). -* You can publish it to the [decentralised SubQuery Network](https://kepler.subquery.network/dashboard). The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way and supports Agoric from launch. +- You can publish it to the [decentralised SubQuery Network](https://kepler.subquery.network/dashboard). The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way and supports Agoric from launch. ## Resources + Here are some additional resources to help you get started using SubQuery with Agoric: -* [SubQuery Website](https://subquery.network/?utm_source=agoric&utm_medium=partner-docs) -* [Documentation](https://academy.subquery.network/?utm_source=agoric&utm_medium=partner-docs) -* [SubQuery Agoric Support Announcement](https://subquery.medium.com/subquery-now-supports-builders-on-agoric-with-fast-data-indexing-27da34a9050c?utm_source=agoric&utm_medium=partner-docs) -* [Agoric Quick Start Guide](https://academy.subquery.network/quickstart/quickstart_chains/cosmos-agoric.html?utm_source=agoric&utm_medium=partner-docs) -* [Agoric Starter Project](https://github.com/subquery/cosmos-subql-starter/tree/main/Agoric/agoric-starter?utm_source=agoric&utm_medium=partner-docs) -* [Discord Support](https://discord.com/invite/subquery/?utm_source=agoric&utm_medium=partner-docs) \ No newline at end of file + +- [SubQuery Website](https://subquery.network/?utm_source=agoric&utm_medium=partner-docs) +- [Documentation](https://academy.subquery.network/?utm_source=agoric&utm_medium=partner-docs) +- [SubQuery Agoric Support Announcement](https://subquery.medium.com/subquery-now-supports-builders-on-agoric-with-fast-data-indexing-27da34a9050c?utm_source=agoric&utm_medium=partner-docs) +- [Agoric Quick Start Guide](https://academy.subquery.network/quickstart/quickstart_chains/cosmos-agoric.html?utm_source=agoric&utm_medium=partner-docs) +- [Agoric Starter Project](https://github.com/subquery/cosmos-subql-starter/tree/main/Agoric/agoric-starter?utm_source=agoric&utm_medium=partner-docs) +- [Discord Support](https://discord.com/invite/subquery/?utm_source=agoric&utm_medium=partner-docs) diff --git a/main/guides/wallet/index.md b/main/guides/wallet/index.md index e7ca9a0c5..ecbc0fb5e 100644 --- a/main/guides/wallet/index.md +++ b/main/guides/wallet/index.md @@ -1,51 +1,51 @@ # Agoric Wallet -This page documents the *Agoric Wallet*, including its use of *petnames* and its place in the Agoric Platform +This page documents the _Agoric Wallet_, including its use of _petnames_ and its place in the Agoric Platform architecture. See also [tour of the Wallet UI](./ui), [Wallet API reference](/reference/wallet-api/). ## Wallet and Agoric Architecture -The Agoric System consists of interconnected Agoric VMs. Some are -on the blockchain, some are local. The Wallet is a user's trusted +The Agoric System consists of interconnected Agoric VMs. Some are +on the blockchain, some are local. The Wallet is a user's trusted agent for interacting with the Agoric VM network. -We also have Dapps (*Decentralized applications*), which are Web UIs +We also have Dapps (_Decentralized applications_), which are Web UIs that interact with Agoric VMs. Dapps have their own agendas...which -may include wanting to steal assets from Wallets. +may include wanting to steal assets from Wallets. -An *Ag-Solo* is a single off-chain Agoric VM. They have their own UI +An _Ag-Solo_ is a single off-chain Agoric VM. They have their own UI and way of communicating with chains (including multiple chains and network connections). They serve as entry points into the Agoric System. -When you run `agoric start`, you get a private ag-solo that runs your -private wallet. The wallet is a user's *trusted agent*. It lets you +When you run `agoric start`, you get a private ag-solo that runs your +private wallet. The wallet is a user's _trusted agent_. It lets you enable or disable inbound connections from Dapps and approve or decline -proposals from those Dapps you enabled. The Wallet is visible +proposals from those Dapps you enabled. The Wallet is visible when you run `agoric open`. -The way this works in the Wallet's UI is via the *proposals* that are -part of a Zoe *offer*; a Dapp says it wants the user to offer something. +The way this works in the Wallet's UI is via the _proposals_ that are +part of a Zoe _offer_; a Dapp says it wants the user to offer something. The wallet expresses that request/offer in a popup, and the user indicates -if they want to enact or decline it. +if they want to enact or decline it. -Dapps can be anywhere; they can be web apps interacting with wallets, +Dapps can be anywhere; they can be web apps interacting with wallets, usually because they want your money and/or help you exchange something -with someone else. They may even want to give you something for free. +with someone else. They may even want to give you something for free. But a Dapp's main use is exchanging something on the chain, in addition to controlling what access they have and managing the proposals. ## Wallet Bridge Protocol -The *wallet bridge* is a web page with direct access to an Agoric Wallet. It provides +The _wallet bridge_ is a web page with direct access to an Agoric Wallet. It provides the Dapp with a facet of an API. Dapps never talk directly to a Wallet, only to this bridge that knows where the Wallet is. So, for example, if a Dapp is running in -your browser at `https://treasury.agoric.app/` and the Wallet is running locally, -they don't communicate directly. They do so by sending JSON-encoded messages through +your browser at `https://treasury.agoric.app/` and the Wallet is running locally, +they don't communicate directly. They do so by sending JSON-encoded messages through the wallet bridge. ## Petnames and Paths -Before we get into the Wallet itself, you should know about *petnames*, +Before we get into the Wallet itself, you should know about _petnames_, which are your personal names for objects. No one else can see or modify a petname without your permission. You can think of them as your phone's contacts list. The actual phone number is what your phone @@ -55,64 +55,63 @@ Grandpa, Kate S., etc. Different people can have different petnames for different objects. For example, the same person is "Mom" to you, "Mimi" to her granddaughter, and "Mrs. Watson" to many others. -Your Wallet manages your petnames for Dapps, asset types, issuers, etc. +Your Wallet manages your petnames for Dapps, asset types, issuers, etc. -The wallet bridge protocol is migrating petnames to *paths*. All former petnames -are now either a *path* or still a plain string. A path is an array of strings +The wallet bridge protocol is migrating petnames to _paths_. All former petnames +are now either a _path_ or still a plain string. A path is an array of strings whose first element is the user's petname for a Dapp. Dapps must be able to -work with either plain string petnames or array-of-strings paths. +work with either plain string petnames or array-of-strings paths. They can do this via `JSON.stringify(petnameOrPath)` before using the `petnameOrPath` in -a programmatic string-only context (such as a key in a Map or Set, or an HTML element's -attribute value, such as an ID). When displaying a path to users, you should join its -elements with `'.'`. If in a UI, you should ideally color the first element -differently from the dots and other elements. The first element is a trusted, -user-assigned petname for the Dapp, while the other elements were automatically +a programmatic string-only context (such as a key in a Map or Set, or an HTML element's +attribute value, such as an ID). When displaying a path to users, you should join its +elements with `'.'`. If in a UI, you should ideally color the first element +differently from the dots and other elements. The first element is a trusted, +user-assigned petname for the Dapp, while the other elements were automatically generated by the Dapp or wallet. Thus, they have no special relationship to the user. ### Dapp-Specific Path Suggestions Your Dapp should suggest names for any Installations, Instances, or Issuers wallet users -will interact with. When a wallet accepts them, it returns them to the Dapp as paths (arrays +will interact with. When a wallet accepts them, it returns them to the Dapp as paths (arrays of strings) that start with the user's petname for the Dapp. -For example, here are [the messages that the Fungible Faucet Dapp -sends](https://github.com/Agoric/dapp-fungible-faucet/blob/6092d6648a7a773d299c79fecd44bb650f6cfa06/ui/public/src/main.js#L145) +For example, here are [the messages that the Fungible Faucet Dapp +sends](https://github.com/Agoric/dapp-fungible-faucet/blob/6092d6648a7a773d299c79fecd44bb650f6cfa06/ui/public/src/main.js#L145) over the wallet bridge: ```js - // Our issuer will default to something like `FungibleFaucet.Installation`. - walletSend({ - type: 'walletSuggestInstallation', - petname: 'Installation', - boardId: INSTALLATION_BOARD_ID, - }); - // Our issuer will default to something like `FungibleFaucet.Instance`. - walletSend({ - type: 'walletSuggestInstance', - petname: 'Instance', - boardId: INSTANCE_BOARD_ID, - }); - // Our issuer will default to something like `FungibleFaucet.Token`. - walletSend({ - type: 'walletSuggestIssuer', - petname: 'Token', - boardId: TOKEN_ISSUER_BOARD_ID, - }); - ``` +// Our issuer will default to something like `FungibleFaucet.Installation`. +walletSend({ + type: 'walletSuggestInstallation', + petname: 'Installation', + boardId: INSTALLATION_BOARD_ID +}) +// Our issuer will default to something like `FungibleFaucet.Instance`. +walletSend({ + type: 'walletSuggestInstance', + petname: 'Instance', + boardId: INSTANCE_BOARD_ID +}) +// Our issuer will default to something like `FungibleFaucet.Token`. +walletSend({ + type: 'walletSuggestIssuer', + petname: 'Token', + boardId: TOKEN_ISSUER_BOARD_ID +}) +``` ## The Agoric Board -Several Wallet API methods use *Agoric's Board*, a key-value "bulletin board" that -lets users make data generally available. Users can obtain an Id by posting a value and -others can get the value just by knowing the Id. You can make Id(s) known by any -communication method you like; private email, an email blast to a mailing list -or many individuals, buying an ad on a website, tv program, or newspaper, +Several Wallet API methods use _Agoric's Board_, a key-value "bulletin board" that +lets users make data generally available. Users can obtain an Id by posting a value and +others can get the value just by knowing the Id. You can make Id(s) known by any +communication method you like; private email, an email blast to a mailing list +or many individuals, buying an ad on a website, tv program, or newspaper, listing it on your website, etc. <<< @/../snippets/ertp/guide/test-readme.js#getValue To get an object, such as a depositFacet, using the Board, first you have to be told what Board Id is associated with it. Using the `getValue()` method, -you retrieve the reference to the depositFacet and can deposit payments into it. - +you retrieve the reference to the depositFacet and can deposit payments into it. diff --git a/main/guides/wallet/ui.md b/main/guides/wallet/ui.md index 947a305f6..67800f739 100644 --- a/main/guides/wallet/ui.md +++ b/main/guides/wallet/ui.md @@ -1,4 +1,3 @@ - # Wallet UI From a shell window, run `agoric open` to open the Wallet UI in a browser tab. @@ -58,4 +57,3 @@ Tokens can be freely sent between purses within the same wallet. To send tokens Then, a user can select the "Irrevocable one-way" transfer option to send their tokens to another wallet in their contacts: Transfer - diff --git a/main/guides/zoe/actual-contracts/PSM.md b/main/guides/zoe/actual-contracts/PSM.md index 1b4b3bfbc..39107af07 100644 --- a/main/guides/zoe/actual-contracts/PSM.md +++ b/main/guides/zoe/actual-contracts/PSM.md @@ -10,8 +10,8 @@ to external stable tokens at a specified fixed ratio, and vice versa. IST is an evolving, fully collateralized, cryptocurrency-backed decentralized stable token for the interchain ecosystem on the Agoric chain. IST is designed to maintain parity with the US dollar (USD) for broad accessibility and provides Agoric and the interchain -ecosystem users an asset with minimum price volatility. In addition, IST is the native -fee token for the Agoric platform and provides some of the core functionality and stability +ecosystem users an asset with minimum price volatility. In addition, IST is the native +fee token for the Agoric platform and provides some of the core functionality and stability for the Agoric cryptoeconomy. Currently the PSM is the only minter of IST. Which external stable tokens are supported is determined by governance in the form of a @@ -28,85 +28,82 @@ multiple tokens, instantiate the PSM contract once for each. The PSM contract supports 2 different offer types: swapping external stable tokens for IST tokens, and swapping IST tokens for external stable tokens. For both offer types only one user is required for a successful offer; in both cases the PSM itself acts as the other trading party. - + ### Swapping External Stable Tokens for IST Tokens To create an offer to swap external stable tokens for IST tokens, do the following: -1. Create an invitation using the makeWantMintedInvitation method. - ```js - const myInvitation = E(publicFacet).makeWantMintedInvitation(); - ``` -2. Create Amounts for the external stable tokens you want to trade and for the IST tokens -you want to receive. - - ```js - const giveAnchorAmount = AmountMath.make(anchorBrand, 200_000_000n); - const wantMintedAmount = AmountMath.make(istBrand, 200_000_000n); - ``` -3. Create a proposal. Use the keywords **In** and **Out**, where **In** is the amount of -external stable tokens you’re offering, and **Out** is the amount of IST tokens you expect -to receive. Note that because the PSM will always be able to act as the other trading partner, -this proposal doesn’t have (or need) an exit condition. - - ```js - const myProposal = { - give: { In: giveAnchorAmount }, - want: { Out: wantMintedAmount } - }; - ``` -4. Create a payment record containing the external stable tokens you’re trading to the PSM. - - ```js - const myPaymentRecord = { In: anchorPayment }; - ``` -5. Create the offer, remembering to harden the proposal & payment record. - - ```js - const seat = E(zoe).offer( - myInvitation, - harden(myProposal), - harden(myPaymentRecord) - ); - ``` +1. Create an invitation using the makeWantMintedInvitation method. + ```js + const myInvitation = E(publicFacet).makeWantMintedInvitation() + ``` +2. Create Amounts for the external stable tokens you want to trade and for the IST tokens + you want to receive. + + ```js + const giveAnchorAmount = AmountMath.make(anchorBrand, 200_000_000n); + const wantMintedAmount = AmountMath.make(istBrand, 200_000_000n); + ``` + +3. Create a proposal. Use the keywords **In** and **Out**, where **In** is the amount of + external stable tokens you’re offering, and **Out** is the amount of IST tokens you expect + to receive. Note that because the PSM will always be able to act as the other trading partner, + this proposal doesn’t have (or need) an exit condition. + + ```js + const myProposal = { + give: { In: giveAnchorAmount }, + want: { Out: wantMintedAmount } + }; + ``` + +4. Create a payment record containing the external stable tokens you’re trading to the PSM. + + ```js + const myPaymentRecord = { In: anchorPayment } + ``` + +5. Create the offer, remembering to harden the proposal & payment record. + + ```js + const seat = E(zoe).offer( + myInvitation, + harden(myProposal), + harden(myPaymentRecord) + ) + ``` ### Swapping IST Tokens for External Stable Tokens + To create an offer to swap IST tokens for external stable tokens, do the following: 1. Create an invitation using the makeGiveMintedInvitation method. - ```js - const myInvitation = E(publicFacet).makeGiveMintedInvitation(); - ``` -2. Create Amounts for the IST tokens you want to trade and for the external stable -tokens you want to receive. - ```js - const giveMintedAmount = AmountMath.make(istBrand, 200_000_000n); - const wantAnchorAmount = AmountMath.make(anchorBrand, 200_000_000n); - ``` + ```js + const myInvitation = E(publicFacet).makeGiveMintedInvitation() + ``` + +2. Create Amounts for the IST tokens you want to trade and for the external stable + tokens you want to receive. + `js +const giveMintedAmount = AmountMath.make(istBrand, 200_000_000n); +const wantAnchorAmount = AmountMath.make(anchorBrand, 200_000_000n); +` 3. Create and harden a proposal. Use the keywords **In** and **Out**, where **In** is the amount -of IST tokens you’re offering, and **Out** is the amount of external stable tokens you -expect to receive. Note that because the PSM will always be able to act as the other -trading partner, this proposal doesn’t have (or need) an exit condition. - ```js - const myProposal = harden({ - give: { In: giveMintedAmount }, - want: { Out: wantAnchorAmount }, - }); - ``` + of IST tokens you’re offering, and **Out** is the amount of external stable tokens you + expect to receive. Note that because the PSM will always be able to act as the other + trading partner, this proposal doesn’t have (or need) an exit condition. + `js +const myProposal = harden({ + give: { In: giveMintedAmount }, + want: { Out: wantAnchorAmount }, + }); +` 4. Create and harden a payment record containing the IST tokens you’re trading to the PSM. - ```js - const myPaymentRecord = harden({ In: mintedPayment }); - ``` + ```js + const myPaymentRecord = harden({ In: mintedPayment }) + ``` 5. Create the offer. - ```js - const seat = E(zoe).offer( - myInvitation, - myProposal, - myPaymentRecord, - ); - ``` - - - - + ```js + const seat = E(zoe).offer(myInvitation, myProposal, myPaymentRecord) + ``` diff --git a/main/guides/zoe/contract-access-control.md b/main/guides/zoe/contract-access-control.md index 83d98f44c..dbfae187f 100644 --- a/main/guides/zoe/contract-access-control.md +++ b/main/guides/zoe/contract-access-control.md @@ -1,12 +1,11 @@ - # Access Control with Objects -In our third smart contract, we will demostrate how to control access to different functions of a smart contract. So far, we have only used `publicFacet` to expose all functions. There is an other facet, called `creatorFacet` that is provided only to the caller who creates the contract instance. -In this smart contract, we -limit the `publicFacet` API to a read-only function `get()`, and use `creatorFacet` API to expose the `set()` method to the caller who creates the contract instanace. +In our third smart contract, we will demostrate how to control access to different functions of a smart contract. So far, we have only used `publicFacet` to expose all functions. There is an other facet, called `creatorFacet` that is provided only to the caller who creates the contract instance. +In this smart contract, we +limit the `publicFacet` API to a read-only function `get()`, and use `creatorFacet` API to expose the `set()` method to the caller who creates the contract instanace. Here is the complete code for `03-access.js` smart contract: - + <<< @/../snippets/zoe/src/03-access.js#access-contract We can write a simple test as below to make sure that trying to `set` using the `publicFacet` throws an exception, but using the `creatorFacet` works: @@ -15,7 +14,6 @@ We can write a simple test as below to make sure that trying to `set` using the Note that the `set()` method has no access check inside it. Access control is based on separation of powers between the `publicFacet`, which is expected to be shared widely, and the `creatorFacet`, which is closely held. _We'll discuss this [object capabilities](../js-programming/hardened-js#object-capabilities-ocaps) approach more later._ If you're having trouble, check out the [`tut-03-access`](https://github.com/Agoric/dapp-offer-up/tree/tut-03-access) branch in the example repo. - ## Object Access Rules The object access rules include introduction, parenthood, endowment, and initial conditions, which help manage and control access to objects within the contract: @@ -25,7 +23,6 @@ The object access rules include introduction, parenthood, endowment, and initial - **Endowment**: Objects can be endowed with certain capabilities or resources upon creation. This allows the contract to control what actions an object can perform based on its endowments. - **Initial Conditions**: Objects are initialized with certain conditions or states. These initial conditions define the starting point for the object’s behavior and interactions. -Also see [Object Capability Model](https://en.wikipedia.org/wiki/Object-capability_model) - +Also see [Object Capability Model](https://en.wikipedia.org/wiki/Object-capability_model) Next, let's look at minting and trading assets with [Zoe](../zoe/). diff --git a/main/guides/zoe/contract-basics.md b/main/guides/zoe/contract-basics.md index 4c1c98a30..14f04ad11 100644 --- a/main/guides/zoe/contract-basics.md +++ b/main/guides/zoe/contract-basics.md @@ -1,20 +1,22 @@ # Smart Contract Basics -This guide is designed to help developers understand how to write smart contracts efficiently and securely. Here, you will find detailed examples that demonstrate different functionalities and use-cases within the context of smart contracts starting from the very basics. To follow along, verify your work, or to get help if you get stuck, you can use the https://github.com/Agoric/dapp-offer-up/ repo as a reference. Each section of the tutorial has an associated branch in the repo to act as a checkpoint. +This guide is designed to help developers understand how to write smart contracts efficiently and securely. Here, you will find detailed examples that demonstrate different functionalities and use-cases within the context of smart contracts starting from the very basics. To follow along, verify your work, or to get help if you get stuck, you can use the https://github.com/Agoric/dapp-offer-up/ repo as a reference. Each section of the tutorial has an associated branch in the repo to act as a checkpoint. ## Examples We provide three core examples to illustrate how to implement various smart contract functionalities: ### 1. Hello World Contract + The **Hello World Contract** demonstrates how to create a simple contract that greets the caller. This example is perfect for understanding the basic structure and syntax of smart contracts. The relevant code is available in [`tut-01-hello` branch](https://github.com/Agoric/dapp-offer-up/tree/tut-01-hello). ### 2. State Contract + The **State Contract** shows how to maintain a state or a variable within a smart contract. This is useful for contracts that need to store data or state across transactions. The relevant code is available in [`tut-02-state` branch](https://github.com/Agoric/dapp-offer-up/tree/tut-02-state). ### 3. Access-Control Contract -The **Access-Control Contract** provides an example of how to implement access control, ensuring that only authorized users can call certain functions within the smart contract. The relevant code is available in [`tut-03-access` branch](https://github.com/Agoric/dapp-offer-up/tree/tut-03-access). +The **Access-Control Contract** provides an example of how to implement access control, ensuring that only authorized users can call certain functions within the smart contract. The relevant code is available in [`tut-03-access` branch](https://github.com/Agoric/dapp-offer-up/tree/tut-03-access). Let us get started! diff --git a/main/guides/zoe/contract-hello.md b/main/guides/zoe/contract-hello.md index 2b86c211d..0233702b9 100644 --- a/main/guides/zoe/contract-hello.md +++ b/main/guides/zoe/contract-hello.md @@ -1,7 +1,7 @@ # Hello World Smart Contract Before we look at how to make a contract such as the one in [the -basic dapp](../getting-started/) in the previous section, let's cover some basics by writing a simple contract that returns a greeting message. We will simply call it _hello-world smart contract_. +basic dapp](../getting-started/) in the previous section, let's cover some basics by writing a simple contract that returns a greeting message. We will simply call it _hello-world smart contract_. A contract is defined by a JavaScript module that exports a `start` function. For our hello-world smart contract, the declaration of `start` function looks like this: @@ -22,7 +22,7 @@ Putting it all together: <<< @/../snippets/zoe/src/01-hello.js#contract -Let us save this code to a file named `01-hello.js` inside `src` directory. +Let us save this code to a file named `01-hello.js` inside `src` directory. ## Testing a contract @@ -37,10 +37,13 @@ Let's save this code in a file named `test-01-hello.js` in a `test` directory. B ```sh yarn ava --match="contract greets by name" ``` + You should see the following line towards the end of the output: + ``` 1 test passed ``` + Congratulations! You have written and tested your first smart contract. Our next goal is to learn about the state of a smart contract. If you're having trouble, check out the [`tut-01-hello`](https://github.com/Agoric/dapp-offer-up/tree/tut-01-hello) branch in the example repo. diff --git a/main/guides/zoe/contract-requirements.md b/main/guides/zoe/contract-requirements.md index dd13be991..ea3598d07 100644 --- a/main/guides/zoe/contract-requirements.md +++ b/main/guides/zoe/contract-requirements.md @@ -5,17 +5,17 @@ When writing a smart contract to run on Zoe, you need to know the proper format and other expectations. -A Zoe smart contract is a JavaScript module that exports a `start` function +A Zoe smart contract is a JavaScript module that exports a `start` function and may import other code, including: -* [@endo/harden](https://www.npmjs.com/package/@endo/harden): A package for recursively deep-freezing. -* [@endo/nat](https://www.npmjs.com/package/@endo/nat): A package +- [@endo/harden](https://www.npmjs.com/package/@endo/harden): A package for recursively deep-freezing. +- [@endo/nat](https://www.npmjs.com/package/@endo/nat): A package for testing whether something is a natural number (natural numbers are recommended for currency-related programming in order to avoid rounding issues) and throwing an error if not. -* [@agoric/notifier](https://www.npmjs.com/package/@agoric/zoe): A package that provides updates through +- [@agoric/notifier](https://www.npmjs.com/package/@agoric/zoe): A package that provides updates through smartly resolving promises rather than polling. -* [@agoric/zoe](https://www.npmjs.com/package/@agoric/zoe): Zoe has +- [@agoric/zoe](https://www.npmjs.com/package/@agoric/zoe): Zoe has helpers that contracts can use by importing `@agoric/zoe/src/contractSupport/zoeHelpers.js`. @@ -37,7 +37,8 @@ Put it right before the start of your contract code. /** * @type {ContractStartFn} */ - ``` +``` + Your contract code must export a function `start` as a non-default export. `zcf` is the [Zoe Contract Facet](/reference/zoe-api/zoe-contract-facet) and is the first argument provided to the contract. @@ -57,17 +58,18 @@ export { start }; ``` The contract must return a record with any (or none) of the following: + - **creatorFacet**: An object, usually with admin authority. It is only given to the entity -that calls `E(zoe).startInstance()`; i.e. the party that was the creator of the current -contract `instance`. It might create `invitations` for other parties, or take actions that -are unrelated to making offers. + that calls `E(zoe).startInstance()`; i.e. the party that was the creator of the current + contract `instance`. It might create `invitations` for other parties, or take actions that + are unrelated to making offers. - **creatorInvitation**: A Zoe `invitation` only given to the entity that -calls `E(zoe).startInstance()`; i.e. the party that was the creator of the current -contract `instance`. This is usually used when a party has to make an offer first, -such as escrowing the underlying good for sale in an auction or covered call. + calls `E(zoe).startInstance()`; i.e. the party that was the creator of the current + contract `instance`. This is usually used when a party has to make an offer first, + such as escrowing the underlying good for sale in an auction or covered call. - **publicFacet**: An object available through Zoe to anyone who knows the contract `instance`. -Use the `publicFacet` for general queries and actions, such as getting the current price -or creating public `invitations`. + Use the `publicFacet` for general queries and actions, such as getting the current price + or creating public `invitations`. The contract can contain arbitrary JavaScript code, but there are a few things you'll want to do in order to act as a contract, and interact with Zoe and zcf (the internal contract @@ -87,8 +89,8 @@ Use `zcf.makeInvitation()` to create the first party's `invitation`: ```js const creatorInvitation = zcf.makeInvitation( makeMatchingInvitation, - 'firstOffer', -); + 'firstOffer' +) ``` `makeMatchingInvitation()` creates the second `invitation`. @@ -99,9 +101,9 @@ const matchingSeatInvitation = zcf.makeInvitation( 'matchOffer', { asset: give.Asset, - price: want.Price, - }, -); + price: want.Price + } +) ``` The third argument (which is optional and wasn't needed for the first `invitation`) says @@ -117,17 +119,16 @@ match, they each get back what they brought to the exchange, and it's still over ```js const matchingSeatOfferHandler = matchingSeat => { - const swapResult = swap(zcf, firstSeat, matchingSeat); - zcf.shutdown(); - return swapResult; -}; + const swapResult = swap(zcf, firstSeat, matchingSeat) + zcf.shutdown() + return swapResult +} ``` If you study other contracts, you'll see they all have this basic format. Depending on their goals, they may do additional bookkeeping, or try to find compatible terms between multiple offers, or create new assets to order. - ## Making an Invitation To create an invitation in the contract, use the Zoe Contract @@ -158,7 +159,7 @@ These modules are built out of native code (C++), not plain JS. None of these built-in modules are available to vat code. `require` or `import` can be used on pure JS modules, but not on modules including native code. For a vat to exercise authority -from a built-in module, you have to write a *device* with an endowment with the built-in +from a built-in module, you have to write a _device_ with an endowment with the built-in module's functions, then have the vat send messages to the device. ## Library Compatibility diff --git a/main/guides/zoe/contract-state.md b/main/guides/zoe/contract-state.md index 93c207d40..1502bf234 100644 --- a/main/guides/zoe/contract-state.md +++ b/main/guides/zoe/contract-state.md @@ -1,6 +1,6 @@ # State Smart Contract -In our first `hello-world` smart contract, we created a `greet` function and exposed it using `publicFacet` so that it can be remotely called. However, if you notice, there is no state in our smart contract that is preserved between calls. Contracts can use ordinary variables and data structures for state. +In our first `hello-world` smart contract, we created a `greet` function and exposed it using `publicFacet` so that it can be remotely called. However, if you notice, there is no state in our smart contract that is preserved between calls. Contracts can use ordinary variables and data structures for state. In our second example smart contract, we will manage a list of rooms. We want everyone with access to `publicFacet` to be able to create a new room, and also get current count of rooms. We maintain state using `Map` data structure as below: @@ -18,7 +18,7 @@ Putting it all together: <<< @/../snippets/zoe/src/02-state.js#state-contract -Let us save this contract as `02-state.js` and creating a simple test to validate its functionality: +Let us save this contract as `02-state.js` and creating a simple test to validate its functionality: <<< @/../snippets/zoe/contracts/test-zoe-hello.js#test-state @@ -32,4 +32,4 @@ We'll discuss more explicit state management for large numbers of objects (_virtual objects_) and objects that last across upgrades ([durable objects](./contract-upgrade#durability)) later. -::: \ No newline at end of file +::: diff --git a/main/guides/zoe/contract-upgrade.md b/main/guides/zoe/contract-upgrade.md index a3e1b5bc9..dd7936612 100644 --- a/main/guides/zoe/contract-upgrade.md +++ b/main/guides/zoe/contract-upgrade.md @@ -72,25 +72,25 @@ between incarnations in a way that preserves identity of objects as seen from other vats: ```js -let rooms; +let rooms if (!baggage.has('rooms')) { // initial incarnation: create the object - rooms = makeScalarBigMapStore('rooms', { durable: true }); - baggage.init('rooms', rooms); + rooms = makeScalarBigMapStore('rooms', { durable: true }) + baggage.init('rooms', rooms) } else { // subsequent incarnation: use the object from the initial incarnation - rooms = baggage.get('rooms'); + rooms = baggage.get('rooms') } ``` The `provide` function supports a concise idiom for this find-or-create pattern: ```js -import { provide } from '@agoric/vat-data'; +import { provide } from '@agoric/vat-data' const rooms = provide(baggage, 'rooms', () => - makeScalarBigMapStore('rooms', { durable: true }), -); + makeScalarBigMapStore('rooms', { durable: true }) +) ``` The `zone` API is a convenient way to manage durability. Its store methods integrate the `provide` pattern: @@ -175,8 +175,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](https://docs.agoric.com/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. @@ -191,8 +189,8 @@ export const start = async (zcf, privateArgs, baggage) => { } ``` - ### Exo + An Exo object is an exposed Remotable object with methods (aka a [Far](/glossary/#zone) object), which is normally defined with an [InterfaceGuard](#todo-interface-guard) as a protective outer layer, providing the first layer of defensiveness. This [@endo/exo](https://github.com/endojs/endo/tree/master/packages/exo) package defines the APIs for making Exo objects, and for defining ExoClasses and ExoClassKits for making Exo objects. @@ -202,34 +200,29 @@ 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() { - trace('makeAccount'); - const holder = await makeAccountKit(); - return holder; + trace('makeAccount') + const holder = await makeAccountKit() + return holder }, makeAccountInvitationMaker() { - trace('makeCreateAccountInvitation'); - return zcf.makeInvitation( - async seat => { - seat.exit(); - const holder = await makeAccountKit(); - return holder.asContinuingOffer(); - }, - 'wantStakingAccount', - ); - }, - }, -); + trace('makeCreateAccountInvitation') + return zcf.makeInvitation(async seat => { + seat.exit() + const holder = await makeAccountKit() + return holder.asContinuingOffer() + }, 'wantStakingAccount') + } + } +) ``` - - ### Zones -Each [Zone](/glossary/#zone) provides an API that allows the allocation of [Exo objects](#exo) and Stores [(object collections)](https://github.com/Agoric/agoric-sdk/tree/master/packages/store/README.md) which use the same underlying persistence mechanism. This allows library code to be agnostic to whether its objects are backed purely by the JS heap (ephemeral), pageable out to disk (virtual), or can be revived after a vat upgrade (durable). +Each [Zone](/glossary/#zone) provides an API that allows the allocation of [Exo objects](#exo) and Stores [(object collections)](https://github.com/Agoric/agoric-sdk/tree/master/packages/store/README.md) which use the same underlying persistence mechanism. This allows library code to be agnostic to whether its objects are backed purely by the JS heap (ephemeral), pageable out to disk (virtual), or can be revived after a vat upgrade (durable). See [SwingSet vat upgrade documentation](https://github.com/Agoric/agoric-sdk/tree/master/packages/SwingSet/docs/vat-upgrade.md) for more example use of the zone API. @@ -242,12 +235,11 @@ zone.subZone('vows') ### Durable Zone A zone specifically designed for durability, allowing the contract to persist its state across upgrades. This is critical for maintaining the continuity and reliability of the contract’s operations. + ```javascript -const zone = makeDurableZone(baggage); +const zone = makeDurableZone(baggage) ``` - - ### Vow Tools See [Vow](/glossary/#vow); These tools handle promises and asynchronous operations within the contract. `prepareVowTools` prepares the necessary utilities to manage these asynchronous tasks, ensuring that the contract can handle complex workflows that involve waiting for events or responses from other chains. diff --git a/main/guides/zoe/contract-walkthru.md b/main/guides/zoe/contract-walkthru.md index 9eaa4c6df..a14634464 100644 --- a/main/guides/zoe/contract-walkthru.md +++ b/main/guides/zoe/contract-walkthru.md @@ -80,7 +80,7 @@ The test starts by using `makeZoeKitForTest` to set up zoe for testing: <<< @/../snippets/zoe/contracts/test-bundle-source.js#importZoeForTest ```js -const { zoeService: zoe } = makeZoeKitForTest(); +const { zoeService: zoe } = makeZoeKitForTest() ``` ::: @@ -199,7 +199,7 @@ alicePurse.deposit(moneyPayment); Then we pass the contract instance and the purse to our code for `alice`: ```js -await alice(t, zoe, instance, alicePurse); +await alice(t, zoe, instance, alicePurse) ``` Alice starts by using the `instance` to get the contract's `publicFacet` and `terms` from Zoe: diff --git a/main/guides/zoe/contracts/atomic-swap.md b/main/guides/zoe/contracts/atomic-swap.md index 0010c5bba..4d392abc5 100644 --- a/main/guides/zoe/contracts/atomic-swap.md +++ b/main/guides/zoe/contracts/atomic-swap.md @@ -2,8 +2,8 @@ - ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/f29591519809dbadf19db0a26f38704d87429b89/packages/zoe/src/contracts/atomicSwap.js) (Last updated: Sep 12, 2020) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) If I want to trade one kind of asset for another kind, I could send @@ -28,10 +28,12 @@ can create a swap instance for this particular transaction. ```js const issuerKeywordRecord = harden({ Asset: moolaIssuer, - Price: simoleanIssuer, -}); -const { creatorInvitation } = - await E(zoe).startInstance(atomicSwapInstallation, issuerKeywordRecord); + Price: simoleanIssuer +}) +const { creatorInvitation } = await E(zoe).startInstance( + atomicSwapInstallation, + issuerKeywordRecord +) ``` Then Alice escrows her offer with Zoe. She passes in two @@ -41,6 +43,7 @@ smart contract (which may have been written by someone else) and other participants. A proposal has three parts: + - `give`: What this party will give to the swap. Used by Zoe to enforce offer safety (Alice will get back what she gave or what she wanted). - `want`: What this party wants to get from the swap. Used by Zoe to enforce offer safety (Alice will get back what she gave or what she wanted). - `exit`: How this party can exit from the contract instance. Used by Zoe to enforce payout liveness (Alice will be able to get a payout according to the exit rule she specifies) @@ -49,14 +52,14 @@ In this case, Alice's exit rule is `onDemand`, meaning she can exit the contract instance at any time. ```js -const threeMoola = AmountMath.make(moolaBrand, 3); +const threeMoola = AmountMath.make(moolaBrand, 3) const aliceProposal = harden({ give: { Asset: threeMoola }, want: { Price: AmountMath.make(simoleanBrand, 7) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) -const alicePayment = await E(aliceMoolaPurse).withdraw(threeMoola); +const alicePayment = await E(aliceMoolaPurse).withdraw(threeMoola) ``` For Alice to escrow with Zoe, she needs to use her invitation. @@ -68,35 +71,41 @@ const aliceSeat = await E(zoe).offer( creatorInvitation, aliceProposal, harden({ Asset: alicePayment }) -); +) ``` This first offer's outcome is an invitation Alice can send to anyone she wants. In this example, she sends it to Bob. ```js -const invitationP = aliceSeat.getOfferResult(); +const invitationP = aliceSeat.getOfferResult() ``` Bob examines the invitation's details to see if they match Alice's claims about it. ```js secondary style2 -const { - installation: bobInstallation, - instance, -} = E(zoe).getInvitationDetails(invitationP); -const bobIssuers = E(zoe).getIssuers(instance); +const { installation: bobInstallation, instance } = + E(zoe).getInvitationDetails(invitationP) +const bobIssuers = E(zoe).getIssuers(instance) -const bobExclusiveInvitation = await invitationIssuer.claim(invitationP); -const bobInvitationValue = await E(zoe).getInvitationDetails(bobExclusiveInvitation); +const bobExclusiveInvitation = await invitationIssuer.claim(invitationP) +const bobInvitationValue = await E(zoe).getInvitationDetails( + bobExclusiveInvitation +) // Bob verifies the invitation. -assert(bobInstallation === atomicSwapInstallation, details`wrong contract`); -assert(bobIssuers.Asset === moolaIssuer, details`unexpected Asset issuer`); -assert(bobIssuers.Price === simoleanIssuer, details`unexpected Price issuer`); -assert(AmountMath.isEqual(bobInvitationValue.asset, moola(3)), details`wrong asset`); -assert(AmountMath.isEqual(bobInvitationValue.price, simoleans(7)), details`wrong price`); +assert(bobInstallation === atomicSwapInstallation, details`wrong contract`) +assert(bobIssuers.Asset === moolaIssuer, details`unexpected Asset issuer`) +assert(bobIssuers.Price === simoleanIssuer, details`unexpected Price issuer`) +assert( + AmountMath.isEqual(bobInvitationValue.asset, moola(3)), + details`wrong asset` +) +assert( + AmountMath.isEqual(bobInvitationValue.price, simoleans(7)), + details`wrong price` +) ``` Bob decides to exercise the invitation, and to escrow his payments. He then @@ -105,20 +114,20 @@ But Bob has written his proposal to match Alice's (notice that the `give` and `want` clauses are reversed from Alice's proposal): ```js secondary style2 -const sevenSimoleans = AmountMath.make(simoleanBrand, 7n); +const sevenSimoleans = AmountMath.make(simoleanBrand, 7n) const bobProposal = harden({ want: { Asset: AmountMath.make(moolaBrand, 3n) }, give: { Price: sevenSimoleans }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) -const bobPayment = await E(bobSimoleansPurse).withdraw(sevenSimoleans); +const bobPayment = await E(bobSimoleansPurse).withdraw(sevenSimoleans) // Bob escrows with zoe and makes an offer const bobSeat = await E(zoe).offer( bobExclusiveInvitation, bobProposal, - harden({ Price: bobPayment }), -); + harden({ Price: bobPayment }) +) ``` Bob has made his offer, so the contract executes. Since Alice @@ -127,16 +136,16 @@ and Bob's offers match, Alice's payouts resolve. She uses her payout to find out if Zoe returned some of it. ```js -const aliceAssetPayout = await aliceSeat.getPayout('Asset'); -const alicePricePayout = await aliceSeat.getPayout('Price'); -const moolaRefundAmount = aliceMoolaPurse.deposit(aliceAssetPayout); -const simoleanGainAmount = aliceSimoleansPurse.deposit(alicePricePayout); +const aliceAssetPayout = await aliceSeat.getPayout('Asset') +const alicePricePayout = await aliceSeat.getPayout('Price') +const moolaRefundAmount = aliceMoolaPurse.deposit(aliceAssetPayout) +const simoleanGainAmount = aliceSimoleansPurse.deposit(alicePricePayout) ``` Bob's payout is also available. Since he already knows what Alice's offer was, he doesn't need to look for a simolean refund. ```js secondary style2 -const bobAssetPayout = await bobSeat.getPayout('Asset'); -const bobMoolaGainAmount = bobMoolaPurse.deposit(bobAssetPayout); +const bobAssetPayout = await bobSeat.getPayout('Asset') +const bobMoolaGainAmount = bobMoolaPurse.deposit(bobAssetPayout) ``` diff --git a/main/guides/zoe/contracts/automatic-refund.md b/main/guides/zoe/contracts/automatic-refund.md index 260d9c6a8..e9f74810c 100644 --- a/main/guides/zoe/contracts/automatic-refund.md +++ b/main/guides/zoe/contracts/automatic-refund.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/automaticRefund.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This is a very trivial contract to explain and test Zoe. diff --git a/main/guides/zoe/contracts/barter-exchange.md b/main/guides/zoe/contracts/barter-exchange.md index e3d4383a6..121f17b9c 100644 --- a/main/guides/zoe/contracts/barter-exchange.md +++ b/main/guides/zoe/contracts/barter-exchange.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/a564c6081976d7b66b3cdf54e0ba8903c8f1ee6d/packages/zoe/src/contracts/barterExchange.js) (Last updated: Sep 14, 2020) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) Barter Exchange takes offers for trading arbitrary goods for one another. diff --git a/main/guides/zoe/contracts/constantProductAMM.md b/main/guides/zoe/contracts/constantProductAMM.md index 34add6658..326f13941 100644 --- a/main/guides/zoe/contracts/constantProductAMM.md +++ b/main/guides/zoe/contracts/constantProductAMM.md @@ -3,8 +3,8 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/7d141a47b311363f099f496d4ed9b4d0f28c8fff/packages/inter-protocol/src/vpool-xyk-amm/multipoolMarketMaker.js) (Last updated: Aug 15, 2022) -##### [View contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) +##### [View contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) The Constant Product AMM is an automated market maker (AMM) that supports multiple liquidity pools and direct exchanges across pools. It's called the "Constant @@ -24,7 +24,7 @@ pools between two secondary tokens. There should only need to be one instance of this contract, so liquidity can be shared as much as possible. Each secondary currency has a separate pool of liquidity. -When the contract is instantiated, the terms specify the central token. Invitations +When the contract is instantiated, the terms specify the central token. Invitations for adding and removing liquidity and for making trades are available by calling methods on the publicFacet. Other publicFacet operations support querying prices and the sizes of pools. Create new pools with `addPool()`. @@ -32,12 +32,12 @@ the sizes of pools. Create new pools with `addPool()`. When making trades or requesting prices, the caller must specify that either the input price (swapIn, getInputPrice) or the output price (swapOut, getOutputPrice) is fixed. For swaps, the required keywords are `In` for the trader's `give` amount, and -`Out` for the trader's `want` amount. `getInputPrice()` and `getOutputPrice()` each +`Out` for the trader's `want` amount. `getInputPrice()` and `getOutputPrice()` each take two amounts. When `getInputPrice()` or `swapIn()` is called, the `amountOut` parameter indicated the desired `amountOut`; if `amountIn` is insufficient to provide that much, the result indicates that no trade will take place. (The returned amountIn and amountOut will both be empty amounts.) Similarly, when `swapIn()` or -`getOutputPrice()` is called, `amountIn` is treated as a maximum. If it would take a +`getOutputPrice()` is called, `amountIn` is treated as a maximum. If it would take a greater amount to get the specified `amountOut`, the result indicates no trade. When adding and removing liquidity, the keywords are `Central`, `Secondary`, and @@ -68,9 +68,9 @@ amountOut of the result.) ```js const quote = E(publicFacet).getOutputPrice( AmountMath.make(BLDBrand, 275n), - AmountMath.makeEmpty(ATMBrand), -); - ``` + AmountMath.makeEmpty(ATMBrand) +) +``` Let's assume the quote says she needs to provide 216 ATM. Sara believes the price is somewhat volatile, and she doesn't want to make repeated calls, so she pads @@ -84,15 +84,16 @@ back. ```js const saraProposal = harden({ want: { Out: AmountMath.make(BLDBrand, 275n) }, - give: { In: AmountMath.make(atmBrand, 220n) }, -}); + give: { In: AmountMath.make(atmBrand, 220n) } +}) -const swapInvitation = await E(publicFacet).makeSwapOutInvitation(); -const atmPayment = - harden({ In: saraAtmPurse.withdraw(AmountMath.make(atmBrand, 220n)) }); +const swapInvitation = await E(publicFacet).makeSwapOutInvitation() +const atmPayment = harden({ + In: saraAtmPurse.withdraw(AmountMath.make(atmBrand, 220n)) +}) -const saraSeat = await E(zoe).offer(swapInvitation, saraProposal, atmPayment); -const saraResult = await saraSeat.getOfferResult(); +const saraSeat = await E(zoe).offer(swapInvitation, saraProposal, atmPayment) +const saraResult = await saraSeat.getOfferResult() ``` If the result is `Swap successfully completed.`, she got the BLD for 220 ATM @@ -100,23 +101,23 @@ or less (she'll want to deposit any refund). Otherwise the market price moved ag her, and she'll have to check the price again and make another offer. ```js -const BLDProceeds = await E(saraSeat).getPayout('In'); -const atmRefund = await E(saraSeat).getPayout('Out'); +const BLDProceeds = await E(saraSeat).getPayout('In') +const atmRefund = await E(saraSeat).getPayout('Out') -const BLDProceedsAmount = E(saraBLDPurse).deposit(BLDProceeds); -E(saraAtmPurse).deposit(atmRefund); +const BLDProceedsAmount = E(saraBLDPurse).deposit(BLDProceeds) +E(saraAtmPurse).deposit(atmRefund) ``` -### Creating a New Pool +### Creating a New Pool When the contract is first instantiated, there won't be any pools ready for -trading. `addPool()` adds a new currency, which can then be funded. (All +trading. `addPool()` adds a new currency, which can then be funded. (All currencies must be fungible.) When a pool is first funded, there's no other basis on which to decide how much liquidity to create, so the liquidity amount equals the amount of the central token in the offer. ```js -const BLDLiquidityIssuer = await E(publicFacet).addPool(BLDIssuer, 'BLD'); +const BLDLiquidityIssuer = await E(publicFacet).addPool(BLDIssuer, 'BLD') ``` Alice sees that the current rate in the external market is 2 BLD for each @@ -127,20 +128,20 @@ const aliceProposal = harden({ want: { Liquidity: BLDLiquidity(50n) }, give: { Secondary: AmountMath.make(BLDBrand, 100n), - Central: AmountMath.make(ISTBrand, 50n), - }, -}); + Central: AmountMath.make(ISTBrand, 50n) + } +}) const alicePayments = { Secondary: aliceBLDPayment, - Central: aliceISTPayment, -}; + Central: aliceISTPayment +} -const aliceAddLiquidityInvitation = E(publicFacet).makeAddLiquidityInvitation(); +const aliceAddLiquidityInvitation = E(publicFacet).makeAddLiquidityInvitation() const addLiquiditySeat = await E(zoe).offer( aliceAddLiquidityInvitation, aliceProposal, - alicePayments, -); + alicePayments +) ``` ### Adding Liquidity to an Existing Pool @@ -148,7 +149,7 @@ const addLiquiditySeat = await E(zoe).offer( When adding or removing liquidity to pools that have already been established, the amounts deposited must be in proportion to the current balances in the pool. The calculation is based on the amount of the `Central` asset. The `Secondary` assets -must be added in proportion. If less `Secondary` is provided than required, the +must be added in proportion. If less `Secondary` is provided than required, the offer is exited with no trade. If more of the secondary is provided than is required, the excess is returned. @@ -156,12 +157,12 @@ Bob calls `getPoolAllocation()` to find the relative levels. Let's say the answe that the current ratio is 1234 BLD to 1718 IST. ```js -const BLDPoolAlloc = E(publicFacet).getPoolAllocation(BLDBrand); -const ISTValue = BLDPoolAlloc.Central.value; -const BLDValue = BLDPoolAlloc.secondary.value; +const BLDPoolAlloc = E(publicFacet).getPoolAllocation(BLDBrand) +const ISTValue = BLDPoolAlloc.Central.value +const BLDValue = BLDPoolAlloc.secondary.value ``` -Now he can add liquidity. The price ratio changes when anyone trades with the pool, +Now he can add liquidity. The price ratio changes when anyone trades with the pool, so he should leave some flexibility in the proposal. The pool calculates the amount of `secondary` currency required based on the amount of `central` currency provided. Bob bumps up the amount of BLD he'll contribute by a little. If he was concerned @@ -172,18 +173,18 @@ figure, but there's no need in this case. const bobProposal = harden({ give: { Central: AmountMath.make(ISTBrand, 1800n), - Secondary: AmountMath.make(BLDBrand, 1200n), + Secondary: AmountMath.make(BLDBrand, 1200n) }, want: { Liquidity: AmountMath.make(liquidityBrand, 0n) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) const bobPayments = { Central: bobISTPayment, - Secondary: bobBLDPayment, + Secondary: bobBLDPayment } -const seat = await E(zoe).offer(addLiquidityInvite, bobProposal, bobPayments); +const seat = await E(zoe).offer(addLiquidityInvite, bobProposal, bobPayments) ``` ## Governance @@ -196,10 +197,10 @@ An instance of the ConstantProduct AMM is managed by a contractGovernor, which controls the ability to change contract parameters and add new types of collateral. The contractGovernor adds these four methods to the contract's publicFacet: -* `getSubscription()`: get a [Subscription](/guides/js-programming/notifiers) that - updates when votes are called. -* `getContractGovernor()`: returns the contractGovernor for verification. -* `getGovernedParamsValues()`: returns a structure showing the current values of - the two parameters. -* `getParamValue('PoolFee')`: gets a description of the current value of - either parameter. Note the initial capital letter. +- `getSubscription()`: get a [Subscription](/guides/js-programming/notifiers) that + updates when votes are called. +- `getContractGovernor()`: returns the contractGovernor for verification. +- `getGovernedParamsValues()`: returns a structure showing the current values of + the two parameters. +- `getParamValue('PoolFee')`: gets a description of the current value of + either parameter. Note the initial capital letter. diff --git a/main/guides/zoe/contracts/covered-call.md b/main/guides/zoe/contracts/covered-call.md index 523bfed54..6b7413fa1 100644 --- a/main/guides/zoe/contracts/covered-call.md +++ b/main/guides/zoe/contracts/covered-call.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/f29591519809dbadf19db0a26f38704d87429b89/packages/zoe/src/contracts/coveredCall.js) (Last updated: Sep 12, 2020) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) The owner of an asset can use a covered call to give someone else the right @@ -46,7 +47,7 @@ underlying assets. The proposal to escrow assets can have any `give` and escrowed under different keywords. The proposal must have an exit condition with the key "afterDeadline": -``` js +```js { give: { ... }, want: { ... }, @@ -84,7 +85,6 @@ covered call option can use whatever keywords they wish, as long as they specify that they `give` the strike price as specified in the invitation value, and `want` the underlying assets exactly. - ## Making A Call Option Let's say Alice wants to create a covered call. She creates the first proposal @@ -94,26 +94,26 @@ issuerKeywordRecord to specify the issuers to be used with each keyword. ```js const issuerKeywordRecord = harden({ UnderlyingAsset: moolaIssuer, - StrikePrice: simoleanIssuer, -}); + StrikePrice: simoleanIssuer +}) const { creatorInvitation } = await E(zoe).startInstance( coveredCallInstallation, - issuerKeywordRecord, -); + issuerKeywordRecord +) ``` Then Alice creates a proposal, and escrows the funds she is depositing. ```js -const threeMoola = AmountMath.make(moolaBrand, 3n); +const threeMoola = AmountMath.make(moolaBrand, 3n) const aliceProposal = harden({ give: { UnderlyingAsset: threeMoola }, want: { StrikePrice: AmountMath.make(simoleanBrand, 7n) }, - exit: { afterDeadline: { deadline: 1599856578n, timer: chainTimer } }, -}); + exit: { afterDeadline: { deadline: 1599856578n, timer: chainTimer } } +}) -const alicePayment = { UnderlyingAsset: aliceMoolaPurse.withdraw(threeMoola) }; +const alicePayment = { UnderlyingAsset: aliceMoolaPurse.withdraw(threeMoola) } ``` Alice makes an offer and gets a seat. @@ -122,33 +122,35 @@ Alice makes an offer and gets a seat. const aliceSeat = await E(zoe).offer( creatorInvitation, aliceProposal, - alicePayment, -); + alicePayment +) const coveredCall = aliceSeat.getOfferResult() ``` The offerResult obtained from the seat is a zoe invitation that serves as the -covered call she wants. This invitation is a full ERTP payment and can be +covered call she wants. This invitation is a full ERTP payment and can be escrowed and used in other contracts. For instance, Alice can send it to Bob, who can either exercise the call option or sell it in another contract, say, an atomic swap: ```js -const invitationIssuer = E(zoe).getInvitationIssuer(); -const bobExclOption = await invitationIssuer.claim(coveredCall); +const invitationIssuer = E(zoe).getInvitationIssuer() +const bobExclOption = await invitationIssuer.claim(coveredCall) ``` -Let's imagine that Bob wants to sell the invitation. He can start a swap +Let's imagine that Bob wants to sell the invitation. He can start a swap instance to trade this invitation for bucks. ```js const swapIssuerKeywordRecord = harden({ Asset: invitationIssuer, - Price: bucksR.issuer, -}); -const bobSwapSeat = - await E(zoe).startInstance(swapInstallation, swapIssuerKeywordRecord); + Price: bucksR.issuer +}) +const bobSwapSeat = await E(zoe).startInstance( + swapInstallation, + swapIssuerKeywordRecord +) ``` Bob specifies that he wants to swap the invitation for 1 buck, and escrows @@ -158,13 +160,17 @@ share. ```js const bobProposalSwap = harden({ give: { Asset: invitationIssuer.getAmountOf(bobExclOption) }, - want: { Price: bucks(1) }, -}); + want: { Price: bucks(1) } +}) -const bobPayments = harden({ Asset: bobExclOption }); -const bobSwapSeat = await E(zoe).offer(bobSwapInvitation, bobProposalSwap, bobPayments); +const bobPayments = harden({ Asset: bobExclOption }) +const bobSwapSeat = await E(zoe).offer( + bobSwapInvitation, + bobProposalSwap, + bobPayments +) -const daveSwapInvitation = bobSwapSeat.getOfferResult(); +const daveSwapInvitation = bobSwapSeat.getOfferResult() ``` ## Buying An Option @@ -177,16 +183,14 @@ to see what contract it is for, and any contract-provided information about what the invitation can be used for. ```js -const { - installation: daveSwapInstall, - instance, -} = await E(zoe).getInvitationDetails(daveSwapInvitation); -const daveSwapIssuers = await E(zoe).getIssuers(instance); +const { installation: daveSwapInstall, instance } = + await E(zoe).getInvitationDetails(daveSwapInvitation) +const daveSwapIssuers = await E(zoe).getIssuers(instance) // Dave does some checks -assert(daveSwapInstall === swapInstallation, details`wrong installation`); -assert(daveIssuers.Asset === moolaIssuer, details`unexpected Asset issuer`); -assert(daveIssuers.Price === simoleanIssuer, details`unexpected Price issuer`); +assert(daveSwapInstall === swapInstallation, details`wrong installation`) +assert(daveIssuers.Asset === moolaIssuer, details`unexpected Asset issuer`) +assert(daveIssuers.Price === simoleanIssuer, details`unexpected Price issuer`) ``` Dave can safely proceed with the swap because he knows that if Bob has lied @@ -196,16 +200,16 @@ Dave escrows his 1 buck with Zoe and forms his proposal. ```js const daveSwapProposal = harden({ want: { Asset: optionAmount }, - give: { Price: bucks(1) }, -}); + give: { Price: bucks(1) } +}) -const daveSwapPayments = harden({ Price: daveBucksPayment }); +const daveSwapPayments = harden({ Price: daveBucksPayment }) const daveSwapSeat = await E(zoe).offer( daveSwapInvitation, daveSwapProposal, - daveSwapPayments, -); + daveSwapPayments +) ``` ## Exercising the Option @@ -215,26 +219,23 @@ option by submitting an offer that pays the required exercise price in exchange for the underlying asset: ```js -const daveOption = await daveSwapSeat.getPayout('Asset'); +const daveOption = await daveSwapSeat.getPayout('Asset') const daveCoveredCallProposal = harden({ want: { UnderlyingAsset: AmountMath.make(moolaBrand, 3n) }, - give: { StrikePrice: AmountMath.make(simoleanBrand, 7n) }, -}); + give: { StrikePrice: AmountMath.make(simoleanBrand, 7n) } +}) const daveCoveredCallPayments = harden({ - StrikePrice: daveSimoleanPayment, -}); + StrikePrice: daveSimoleanPayment +}) const daveCallSeat = await E(zoe).offer( daveOption, daveCoveredCallProposal, - daveCoveredCallPayments, -); - - const daveMoolaPayout = await daveCallSeat.getPayout( - 'UnderlyingAsset', - ); - await daveMoolaPurse.deposit(daveMoolaPayout); + daveCoveredCallPayments +) +const daveMoolaPayout = await daveCallSeat.getPayout('UnderlyingAsset') +await daveMoolaPurse.deposit(daveMoolaPayout) ``` diff --git a/main/guides/zoe/contracts/escrow-to-vote.md b/main/guides/zoe/contracts/escrow-to-vote.md index c7850c03f..80b32dc8d 100644 --- a/main/guides/zoe/contracts/escrow-to-vote.md +++ b/main/guides/zoe/contracts/escrow-to-vote.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/test/unitTests/contracts/escrowToVote.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This contract implements coin voting. There are two roles: the diff --git a/main/guides/zoe/contracts/fundedCallSpread.md b/main/guides/zoe/contracts/fundedCallSpread.md index e2d13144b..e25b1d110 100644 --- a/main/guides/zoe/contracts/fundedCallSpread.md +++ b/main/guides/zoe/contracts/fundedCallSpread.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/callSpread/fundedCallSpread.js) (Last updated: Feb 20, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This contract implements a fully collateralized call spread. You can use a call spread as a @@ -30,34 +31,36 @@ currencies. You can have, for example, a spread based on APPL stock (`Underlying price in USD (`Strike`) where the contract pays out in JPY (`Collateral`). The issuerKeywordRecord specifies issuers for three keywords: Underlying, Strike, and Collateral. - * The asset whose eventual value determines the payouts uses `Underlying`. This is often a fungible - currency, but doesn't have to be. It would be perfectly valid to have a call spread contract on - the value of a "Superior Magic Sword", as long as there was a price oracle to determine its price - at the expiration time. - * The original deposit and the payout use the `Collateral` issuer. - * `Strike` amounts are used for the price oracle's quote as to the value of the Underlying, as - well as the strike prices in the terms. + +- The asset whose eventual value determines the payouts uses `Underlying`. This is often a fungible + currency, but doesn't have to be. It would be perfectly valid to have a call spread contract on + the value of a "Superior Magic Sword", as long as there was a price oracle to determine its price + at the expiration time. +- The original deposit and the payout use the `Collateral` issuer. +- `Strike` amounts are used for the price oracle's quote as to the value of the Underlying, as + well as the strike prices in the terms. ## Terms The terms include `{ timer, underlyingAmount, expiration, priceAuthority, strikePrice1, strikePrice2, settlementAmount }`. - * `timer` is a [timer](/reference/repl/timerServices), and must be recognized by `priceAuthority`. - * `expiration` is a time recognized by the `timer`. - * `underlyingAmount` is passed to `priceAuthority`. It could be an NFT or a fungible amount. - * `strikePrice2` must be greater than `strikePrice1`. - * `settlementAmount` is the amount deposited by the creator and split between the holders of the - options. It uses Collateral. - * `priceAuthority` is an oracle that has a timer so it can respond to requests for prices as of a - stated time. After the deadline, it will issue a PriceQuote giving the value of the underlying - asset in the strike currency. + +- `timer` is a [timer](/reference/repl/timerServices), and must be recognized by `priceAuthority`. +- `expiration` is a time recognized by the `timer`. +- `underlyingAmount` is passed to `priceAuthority`. It could be an NFT or a fungible amount. +- `strikePrice2` must be greater than `strikePrice1`. +- `settlementAmount` is the amount deposited by the creator and split between the holders of the + options. It uses Collateral. +- `priceAuthority` is an oracle that has a timer so it can respond to requests for prices as of a + stated time. After the deadline, it will issue a PriceQuote giving the value of the underlying + asset in the strike currency. <<< @/../snippets/zoe/contracts/test-callSpread.js#startInstance ## Creating the Options The terms specify all the details of the options. However, the options are not handed out until the -creator provides the collateral that will make them valuable. The creatorInvitation has +creator provides the collateral that will make them valuable. The creatorInvitation has customProperties including the amounts of the two options: `longAmount` and `shortAmount`. <<< @/../snippets/zoe/contracts/test-callSpread.js#invitationDetails @@ -73,9 +76,9 @@ keyword `Collateral`. ## Validating the Options The options returned by the contract are Zoe invitations, so their values and terms can be verified -by asking for the contract terms. This makes it possible to sell the options because a prospective +by asking for the contract terms. This makes it possible to sell the options because a prospective purchaser will be able to inspect the value. The prospective purchaser can see that the -priceAuthority is one they are willing to rely on and can verify the underlying amount. They can +priceAuthority is one they are willing to rely on and can verify the underlying amount. They can check that the expiration matches their expectations (here `3n` is a small integer suitable for a manual timer in a test; in actual use, it might represent block height or wall clock time.) The strike prices and settlement amount are likewise visible. diff --git a/main/guides/zoe/contracts/index.md b/main/guides/zoe/contracts/index.md index f091fc720..b4ce17a15 100644 --- a/main/guides/zoe/contracts/index.md +++ b/main/guides/zoe/contracts/index.md @@ -8,58 +8,58 @@ pre-built example contracts that can be imported and run on Zoe. Note that none ## Oracle Contracts -| Contract | Description | -| --- | --- | -| [Oracle Query](./oracle) | A low-level oracle contract for querying [Chainlink](https://docs.chain.link/docs/request-and-receive-data#config) or other oracles. | -| [PriceAuthority](/guides/zoe/price-authority) | To use an price oracle in your own contract, we recommend using the `priceAuthority` higher-level abstraction. | +| Contract | Description | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| [Oracle Query](./oracle) | A low-level oracle contract for querying [Chainlink](https://docs.chain.link/docs/request-and-receive-data#config) or other oracles. | +| [PriceAuthority](/guides/zoe/price-authority) | To use an price oracle in your own contract, we recommend using the `priceAuthority` higher-level abstraction. | ## DeFi Contracts These contracts create various sorts of financial instruments. -| Contract | Description | -| --- | --- | -| [Vault](./vault) | The Vault is the primary mechanism for making IST (the Agoric stable-value currency) available to participants in the economy. It does this by issuing loans against supported types of collateral. The creator of the contract can add new types of collateral. (This is expected to be under the control of on-chain governance after the initial currencies are defined when the contract starts up.) | -| [Loan](./loan) | A basic collateralized loan contract. | -| [Funded Call Spread](./fundedCallSpread) | Creates a pair of fully collateralized call spread options. They are ERTP assets and can be used as such in other contracts. This contract has two variants, which affect how invitations are created. This version is fully funded by the creator, who receives a matching pair of call spread options. They can be traded or sold separately. | -|[Priced Call Spread](./pricedCallSpread) | Creates a pair of fully collateralized call spread options. They are ERTP assets and can be used as such in other contracts. This contract has two variants, which affect how invitations are created. In this version, the creator requests a pair of invitations. Each one lets the holder obtain one of the positions by providing a started portion of the collateral. This version is useful for a market maker who finds pairs of participants with matching interests. | -| [Covered Call](./covered-call) | Creates a call option, which is the right to buy an underlying asset. | -| [OTC Desk](./otc-desk) | A contract for giving quotes that can be exercised. The quotes are guaranteed to be exercisable because they are actually options with escrowed underlying assets. | +| Contract | Description | +| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Vault](./vault) | The Vault is the primary mechanism for making IST (the Agoric stable-value currency) available to participants in the economy. It does this by issuing loans against supported types of collateral. The creator of the contract can add new types of collateral. (This is expected to be under the control of on-chain governance after the initial currencies are defined when the contract starts up.) | +| [Loan](./loan) | A basic collateralized loan contract. | +| [Funded Call Spread](./fundedCallSpread) | Creates a pair of fully collateralized call spread options. They are ERTP assets and can be used as such in other contracts. This contract has two variants, which affect how invitations are created. This version is fully funded by the creator, who receives a matching pair of call spread options. They can be traded or sold separately. | +| [Priced Call Spread](./pricedCallSpread) | Creates a pair of fully collateralized call spread options. They are ERTP assets and can be used as such in other contracts. This contract has two variants, which affect how invitations are created. In this version, the creator requests a pair of invitations. Each one lets the holder obtain one of the positions by providing a started portion of the collateral. This version is useful for a market maker who finds pairs of participants with matching interests. | +| [Covered Call](./covered-call) | Creates a call option, which is the right to buy an underlying asset. | +| [OTC Desk](./otc-desk) | A contract for giving quotes that can be exercised. The quotes are guaranteed to be exercisable because they are actually options with escrowed underlying assets. | ## AMM (Automatic Market Maker) Contract -| Contract | Description | -| --- | --- | +| Contract | Description | +| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [ConstantProduct AMM](./constantProductAMM) | An automated market maker with multiple liquidity pools that can trade between any pair of funded currencies. It charges a poolFee (added to the liquidity pools) and a protocolFee (set aside for the benefit of the Agoric economy). These fees are subject to change by votes controlled by and made visible by the governance system. | ## Generic Sales/Trading Contracts These contracts involve trading or selling ERTP digital assets. -| Contract | Description | -| --- | --- | -| [Sell Items](./sell-items) | A generic sales contract, mostly used for selling NFTs for money. | -| [Atomic Swap](./atomic-swap) | A basic trade of digital assets between two parties. | -| [Barter Exchange](./barter-exchange) | An exchange with an order book letting all kinds of goods to be offered for explicit barter swaps. | +| Contract | Description | +| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Sell Items](./sell-items) | A generic sales contract, mostly used for selling NFTs for money. | +| [Atomic Swap](./atomic-swap) | A basic trade of digital assets between two parties. | +| [Barter Exchange](./barter-exchange) | An exchange with an order book letting all kinds of goods to be offered for explicit barter swaps. | | [Second-Price Auction](./second-price-auction) | An auction in which the highest bidder wins and pays the second-highest bid. This version doesn't conceal the bids (an essential aspect of second price auctions). Therefore, **it should not be used in production**. | -| [Simple Exchange](./simple-exchange) | A basic exchange with an order book for one asset, priced in a second asset. | +| [Simple Exchange](./simple-exchange) | A basic exchange with an order book for one asset, priced in a second asset. | ## Governance Contract -| Contract | Description | -| --- | --- | +| Contract | Description | +| ---------------------------------- | ------------------------------------------------------------------------------------- | | [Escrow To Vote](./escrow-to-vote) | A coin voting contract in which votes are weighted by the escrowed governance tokens. | ## Minting Contracts -| Contract | Description | -| --- | --- | -| [Mint Payments](./mint-payments) | An example of minting fungible tokens. | +| Contract | Description | +| ------------------------------------------ | ---------------------------------------------------------------------------- | +| [Mint Payments](./mint-payments) | An example of minting fungible tokens. | | [Mint and Sell NFTs](./mint-and-sell-nfts) | A contract that mints NFTs and sells them through a separate sales contract. | ## Miscellaneous Contracts -| Contract | Description | -| --- | --- | -| [Use Object](./use-obj-example) | An example of how you might associate the ability to take an action with ownership of a particular digital asset. In this case, you can color a pixel if you own the NFT for the pixel. | -| [Automatic Refund](./automatic-refund) | A trivial contract that gives the user back what they put in. | +| Contract | Description | +| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Use Object](./use-obj-example) | An example of how you might associate the ability to take an action with ownership of a particular digital asset. In this case, you can color a pixel if you own the NFT for the pixel. | +| [Automatic Refund](./automatic-refund) | A trivial contract that gives the user back what they put in. | diff --git a/main/guides/zoe/contracts/loan.md b/main/guides/zoe/contracts/loan.md index 7e32be177..a754274b2 100644 --- a/main/guides/zoe/contracts/loan.md +++ b/main/guides/zoe/contracts/loan.md @@ -3,9 +3,10 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/loan/index.js) (Last updated: Nov 23, 2021) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) -The basic loan contract has two parties, a *lender* and a *borrower*. +The basic loan contract has two parties, a _lender_ and a _borrower_. It lets the borrower add collateral of a particular brand and get a loan of another brand. The collateral (also known as margin) must be a certain percentage of the loan value (the default is 150%). The exact @@ -22,32 +23,33 @@ Note that all collateral must be of the same brand and all of the loaned amount and interest must be of the same (separate) brand. ## Terms -* `mmr` (default = 150) - the Maintenance Margin Requirement, in - percent. The default is 150, meaning that collateral should be - worth at least 150% of the loan. If the value of the collateral - drops below `mmr`, liquidation can occur. -* [`priceAuthority`](/guides/zoe/price-authority) - used for getting the current value of - collateral and setting liquidation triggers. -* `autoswapInstance` - The running contract instance for - [AMM](./constantProductAMM) installation. The `publicFacet` - of the instance is used to make an invitation to sell the - collateral on liquidation. -* `periodNotifier` - the [notifier](/guides/js-programming/notifiers) used for notifications - that a period has passed, on which compound interest will be - calculated using the `interestRate`. -* `interestRate` - the rate in [basis points](https://www.investopedia.com/terms/b/basispoint.asp) that will be multiplied - with the debt on every period to compound interest. -* `interestPeriod` - the period at which interest will be compounded. + +- `mmr` (default = 150) - the Maintenance Margin Requirement, in + percent. The default is 150, meaning that collateral should be + worth at least 150% of the loan. If the value of the collateral + drops below `mmr`, liquidation can occur. +- [`priceAuthority`](/guides/zoe/price-authority) - used for getting the current value of + collateral and setting liquidation triggers. +- `autoswapInstance` - The running contract instance for + [AMM](./constantProductAMM) installation. The `publicFacet` + of the instance is used to make an invitation to sell the + collateral on liquidation. +- `periodNotifier` - the [notifier](/guides/js-programming/notifiers) used for notifications + that a period has passed, on which compound interest will be + calculated using the `interestRate`. +- `interestRate` - the rate in [basis points](https://www.investopedia.com/terms/b/basispoint.asp) that will be multiplied + with the debt on every period to compound interest. +- `interestPeriod` - the period at which interest will be compounded. ## IssuerKeywordRecord All keyword records use the following, regardless of their role in the contract: -* Keyword: `Collateral` - The issuer/payment for the digital assets to be - escrowed as collateral. -* Keyword: `Loan` - The issuer/payment for the digital assets to be loaned - out. +- Keyword: `Collateral` - The issuer/payment for the digital assets to be + escrowed as collateral. +- Keyword: `Loan` - The issuer/payment for the digital assets to be loaned + out. ## The Lender @@ -95,14 +97,15 @@ liquidation. ## Contract Shutdown The contract shuts down under any one of 3 conditions: + 1. The loan (plus interest) is repaid. - * The lender gets the repayment and the borrower gets - their collateral back. + - The lender gets the repayment and the borrower gets + their collateral back. 2. The value of the collateral drops and the collateral must be liquidated. - * The lender gets the outcome of the collateral sale, and the borrower keeps their loan. + - The lender gets the outcome of the collateral sale, and the borrower keeps their loan. 3. An error occurs when trying to use the priceAuthority. - * The lender gets the collateral, and the borrower keeps their loan. + - The lender gets the collateral, and the borrower keeps their loan. ## Debt and Interest Calculation diff --git a/main/guides/zoe/contracts/mint-and-sell-nfts.md b/main/guides/zoe/contracts/mint-and-sell-nfts.md index a2af73551..94a780b8d 100644 --- a/main/guides/zoe/contracts/mint-and-sell-nfts.md +++ b/main/guides/zoe/contracts/mint-and-sell-nfts.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/mintAndSellNFT.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This contract mints non-fungible tokens and creates a selling contract @@ -10,6 +11,7 @@ instance to sell the tokens in exchange for some sort of money. startInstance() returns a creatorFacet with a `.sellTokens()` method. `.sellTokens()` takes a specification of what is being sold, such as: + ``` { customValueProperties: { ...arbitrary }, diff --git a/main/guides/zoe/contracts/mint-payments.md b/main/guides/zoe/contracts/mint-payments.md index 0083434be..3b878cd34 100644 --- a/main/guides/zoe/contracts/mint-payments.md +++ b/main/guides/zoe/contracts/mint-payments.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/mintPayments.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This very simple contract shows how to create a new issuer kit and diff --git a/main/guides/zoe/contracts/oracle.md b/main/guides/zoe/contracts/oracle.md index 168f3f3ff..baecf0d60 100644 --- a/main/guides/zoe/contracts/oracle.md +++ b/main/guides/zoe/contracts/oracle.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4c4da6a7ae76aebbff2af48613008978eb04462b/packages/zoe/src/contracts/oracle.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) **NOTE: You almost certainly do not want to use this contract directly. @@ -10,13 +11,13 @@ Instead, please read the [Chainlink integration documentation](/guides/chainlink-integration)** This contract lets other contracts or users make single free or fee-based -queries to a generic oracle node (a single instance). This provides a very +queries to a generic oracle node (a single instance). This provides a very low-level API to issue single queries that an individual off-chain oracle node answers. **CAUTION: The security of oracle networks (such as Chainlink) depends upon having higher-level contracts to aggregate the results of the individual nodes -(this low-level contract). This protects against misbehaviour from an +(this low-level contract). This protects against misbehaviour from an individual node.** Relying on just a single node can be both expensive and risky. Instead, use the diff --git a/main/guides/zoe/contracts/otc-desk.md b/main/guides/zoe/contracts/otc-desk.md index 626d607ae..7db0f7641 100644 --- a/main/guides/zoe/contracts/otc-desk.md +++ b/main/guides/zoe/contracts/otc-desk.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/otcDesk.js) (Last updated: Mar 1, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) ![Building a Composable DeFi Contract](./assets/title.jpg) @@ -15,7 +16,6 @@ Us workshop](https://www.youtube.com/watch?v=e9dMkC2oFh8). workshop](https://www.youtube.com/watch?v=faxrecQgEio): [![Building a Composable DeFi Contract](./assets/play.png)](https://www.youtube.com/watch?v=faxrecQgEio) - ## Functionality The OTC Desk contract is based on an idea by Haseeb Qureshi in @@ -24,12 +24,13 @@ The OTC Desk contract is based on an idea by Haseeb Qureshi in ![OTC Desk](./assets/contract.svg) In this OTC Desk Contract: -* Trades are atomic and “trustless” -* Creator keeps all profits -* Can use any pricing mechanism -* Can stop quoting when the market is crazy -* Can trade fungible and non-fungible digital assets -* Uses another contract (the [covered call option contract](https://github.com/Agoric/agoric-sdk/blob/HEAD/packages/zoe/src/contracts/coveredCall.js)) as a reusable component + +- Trades are atomic and “trustless” +- Creator keeps all profits +- Can use any pricing mechanism +- Can stop quoting when the market is crazy +- Can trade fungible and non-fungible digital assets +- Uses another contract (the [covered call option contract](https://github.com/Agoric/agoric-sdk/blob/HEAD/packages/zoe/src/contracts/coveredCall.js)) as a reusable component ## The Dapp diff --git a/main/guides/zoe/contracts/pricedCallSpread.md b/main/guides/zoe/contracts/pricedCallSpread.md index 248059941..41717f0b5 100644 --- a/main/guides/zoe/contracts/pricedCallSpread.md +++ b/main/guides/zoe/contracts/pricedCallSpread.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/callSpread/pricedCallSpread.js) (Last updated: Feb 20, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This contract implements a fully collateralized call spread. You can use a call spread as a @@ -13,11 +14,11 @@ higher price. A call spread has two participating seats that pay out complementa on the value of some good at a known future time. This video gives a [walkthrough of the implementation](https://youtu.be/m5Pf2d1tHCs?t=3566) of the contract. -There are two variants of the callSpread. In this version, the creator requests a pair of +There are two variants of the callSpread. In this version, the creator requests a pair of invitations, each of which enables the holder to obtain one of the positions by providing a started portion of the collateral. The other is called the [fundedCallSpread](./fundedCallSpread). It is fully funded by its creator, who can then sell (or otherwise transfer) the options to other parties. -The Zoe invitations representing options are produced in pairs. The individual options are Zoe +The Zoe invitations representing options are produced in pairs. The individual options are Zoe invitations whose details are inspectable by prospective purchasers. These options are settled financially. There is no requirement that the original purchaser have @@ -31,27 +32,29 @@ currencies. You can have, for example, a spread based on APPL stock (`Underlying price in USD (`Strike`) and contract paying out in JPY (`Collateral`). The issuerKeywordRecord specifies issuers for three keywords: Underlying, Strike, and Collateral. - * The asset whose eventual value determines the payouts uses `Underlying`. This is often a fungible - currency, but doesn't have to be. It would be perfectly valid to have a call spread contract on - the value of a "Superior Magic Sword", as long as there was a price oracle to determine its price - at the expiration time. - * The original deposit and the payout use the `Collateral` issuer. - * `Strike` amounts are used for the price oracle's quote as to the value of the Underlying, as - well as the strike prices in the terms. + +- The asset whose eventual value determines the payouts uses `Underlying`. This is often a fungible + currency, but doesn't have to be. It would be perfectly valid to have a call spread contract on + the value of a "Superior Magic Sword", as long as there was a price oracle to determine its price + at the expiration time. +- The original deposit and the payout use the `Collateral` issuer. +- `Strike` amounts are used for the price oracle's quote as to the value of the Underlying, as + well as the strike prices in the terms. ## Terms The terms include `{ timer, underlyingAmount, expiration, priceAuthority, strikePrice1, strikePrice2, settlementAmount }`. - * `timer` is a [timer](/reference/repl/timerServices), and must be recognized by `priceAuthority`. - * `expiration` is a time recognized by the `timer`. - * `underlyingAmount` is passed to `priceAuthority`. It could be an NFT or a fungible amount. - * `strikePrice2` must be greater than `strikePrice1`. - * `settlementAmount` is the amount deposited by the creator and split between the holders of the - options. It uses Collateral. - * `priceAuthority` is an oracle that has a timer so it can respond to requests for prices as of a - stated time. After the deadline, it will issue a PriceQuote giving the value of the underlying - asset in the strike currency. + +- `timer` is a [timer](/reference/repl/timerServices), and must be recognized by `priceAuthority`. +- `expiration` is a time recognized by the `timer`. +- `underlyingAmount` is passed to `priceAuthority`. It could be an NFT or a fungible amount. +- `strikePrice2` must be greater than `strikePrice1`. +- `settlementAmount` is the amount deposited by the creator and split between the holders of the + options. It uses Collateral. +- `priceAuthority` is an oracle that has a timer so it can respond to requests for prices as of a + stated time. After the deadline, it will issue a PriceQuote giving the value of the underlying + asset in the strike currency. <<< @/../snippets/zoe/contracts/test-callSpread.js#startInstancePriced @@ -85,7 +88,7 @@ instance of the contract. ## Options can be Exercised Independently - The option position invitations can be exercised for free, and provide their payouts under the +The option position invitations can be exercised for free, and provide their payouts under the keyword `Collateral`. <<< @/../snippets/zoe/contracts/test-callSpread.js#bobExercise diff --git a/main/guides/zoe/contracts/second-price-auction.md b/main/guides/zoe/contracts/second-price-auction.md index 79e17e4d9..1bfe09dc4 100644 --- a/main/guides/zoe/contracts/second-price-auction.md +++ b/main/guides/zoe/contracts/second-price-auction.md @@ -3,11 +3,12 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/a564c6081976d7b66b3cdf54e0ba8903c8f1ee6d/packages/zoe/src/contracts/auction/secondPriceAuction.js) (Last updated: Sep 14, 2020) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) In a second-price auction, the winner is the participant with the highest bid, but the winner only pays the price corresponding to the second highest -bid. Second-price auctions must have sealed (i.e. private) bids to have the +bid. Second-price auctions must have sealed (i.e. private) bids to have the touted economic incentives, so this version, which is entirely public, should not be used in production for real valuables. It's a demonstration that auctions under Zoe can enforce different rules about how prices are calculated, or how winners are @@ -21,14 +22,16 @@ bid by the second highest bidder. `startInstance()` specifies the issuers and the terms. An invitation for the seller is returned as the creatorInvitation. The seller's offer should look like + ```js { give: { Asset: asset }, want: { Ask: minimumBidAmount}} ``` + The asset can be non-fungible, but the Ask amount should be of a fungible brand. Make the bidder invitations by calling `makeBidInvitation()` on the object returned from the seller's -offer. Each bidder can submit an offer: ```js { give: { Bid: null } -want: { Asset: null } }. ``` +offer. Each bidder can submit an offer: `js { give: { Bid: null } +want: { Asset: null } }. ` ## Public Second-Price Auction @@ -42,11 +45,15 @@ installation.) ```js const issuerKeywordRecord = harden({ Asset: moolaIssuer, - Bid: simoleanIssuer, -}); - -const terms = harden({ numBidsAllowed: 3 }); -const { creatorInvitation } = await E(zoe).startInstance(installation, issuerKeywordRecord, terms); + Bid: simoleanIssuer +}) + +const terms = harden({ numBidsAllowed: 3 }) +const { creatorInvitation } = await E(zoe).startInstance( + installation, + issuerKeywordRecord, + terms +) ``` She can put something up for auction by escrowing it with Zoe, so she provides a @@ -59,14 +66,18 @@ onDemand: null }`) is used. const aliceProposal = harden({ give: { Asset: AmountMath.make(moolaBrand, 1n) }, want: { Bid: AmountMath.make(simoleanBrand, 3n) }, - exit: { waived: null }, -}); - -const alicePayments = { Asset: aliceMoolaPayment }; - -const aliceSeat = await E(zoe).offer(creatorInvitation, aliceProposal, alicePayments); -const invitationMaker = await E(aliceSeat).getOfferResult(); -const bobInvitation = E(invitationMaker).makeBidInvitation(); + exit: { waived: null } +}) + +const alicePayments = { Asset: aliceMoolaPayment } + +const aliceSeat = await E(zoe).offer( + creatorInvitation, + aliceProposal, + alicePayments +) +const invitationMaker = await E(aliceSeat).getOfferResult() +const bobInvitation = E(invitationMaker).makeBidInvitation() ``` Now Alice can share the counterparty invitation with her friends and see if there are @@ -76,17 +87,19 @@ he expects. He can also check that the item up for sale is what he wants by comp the issuers. ```js -const invitationIssuer = await E(zoe).getInvitationIssuer(); -const bobExclusiveInvitation = await invitationIssuer.claim(bobInvitation); - -const { - installation: bobInstallation, - instance, -} = await E(zoe).getInvitationDetails(bobExclusiveInvitation); -const bobIssuers = await E(zoe).getIssuers(instance); - -assert(bobInstallation === secondPriceAuctionInstallation, details`wrong installation`); -assert(bobIssuers.Asset === moolaIssuer, details`wrong issuer`); +const invitationIssuer = await E(zoe).getInvitationIssuer() +const bobExclusiveInvitation = await invitationIssuer.claim(bobInvitation) + +const { installation: bobInstallation, instance } = await E( + zoe +).getInvitationDetails(bobExclusiveInvitation) +const bobIssuers = await E(zoe).getIssuers(instance) + +assert( + bobInstallation === secondPriceAuctionInstallation, + details`wrong installation` +) +assert(bobIssuers.Asset === moolaIssuer, details`wrong issuer`) ``` Bob decides to join the contract and makes an offer: @@ -94,12 +107,16 @@ Bob decides to join the contract and makes an offer: ```js const bobProposal = harden({ give: { Bid: AmountMath.make(simoleanBrand, 11n) }, - want: { Asset: AmountMath.make(moolaBrand, 1n) }, -}); + want: { Asset: AmountMath.make(moolaBrand, 1n) } +}) -const bobPayments = { Bid: bobSimoleanPayment }; +const bobPayments = { Bid: bobSimoleanPayment } -const bobSeat = await E(zoe).offer(bobExclusiveInvitation, bobProposal, bobPayments); +const bobSeat = await E(zoe).offer( + bobExclusiveInvitation, + bobProposal, + bobPayments +) ``` Since multiple parties may want to participate in the auction, let's say that Carol and Dave also decide to bid in the same way @@ -111,19 +128,19 @@ Bob gets the 1 moola that was up for auction as well as a refund of 4 simoleans (11-7), and Carol and Dave get a full refund. ```js -const aliceAssetPayout = await aliceSeat.getPayout('Asset'); -const moolaRefundAmount = aliceMoolaPurse.deposit(aliceAssetPayout); +const aliceAssetPayout = await aliceSeat.getPayout('Asset') +const moolaRefundAmount = aliceMoolaPurse.deposit(aliceAssetPayout) -const alicePricePayout = await aliceSeat.getPayout('Price'); -const simoleanGainAmount = aliceSimPurse.deposit(alicePricePayout); +const alicePricePayout = await aliceSeat.getPayout('Price') +const simoleanGainAmount = aliceSimPurse.deposit(alicePricePayout) ``` Bob's payouts are also available. ```js -const bobAssetPayout = await bobSeat.getPayout('Asset'); -const bobMoolaGainAmount = bobMoolaPurse.deposit(bobAssetPayout); +const bobAssetPayout = await bobSeat.getPayout('Asset') +const bobMoolaGainAmount = bobMoolaPurse.deposit(bobAssetPayout) -const bobPricePayout = await bobSeat.getPayout('Price'); -const bobSimoleanRefundAmount = bobSimoleanPurse.deposit(bobPricePayout); +const bobPricePayout = await bobSeat.getPayout('Price') +const bobSimoleanRefundAmount = bobSimoleanPurse.deposit(bobPricePayout) ``` diff --git a/main/guides/zoe/contracts/sell-items.md b/main/guides/zoe/contracts/sell-items.md index 4c6b8317c..86f53d62a 100644 --- a/main/guides/zoe/contracts/sell-items.md +++ b/main/guides/zoe/contracts/sell-items.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/src/contracts/sellItems.js) (Last updated: Feb 4, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) Sell items in exchange for money. Items may be fungible or diff --git a/main/guides/zoe/contracts/simple-exchange.md b/main/guides/zoe/contracts/simple-exchange.md index ed3ec1b47..eb7998c86 100644 --- a/main/guides/zoe/contracts/simple-exchange.md +++ b/main/guides/zoe/contracts/simple-exchange.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/f29591519809dbadf19db0a26f38704d87429b89/packages/zoe/src/contracts/simpleExchange.js) (Last updated: Sep 12, 2020) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) The "simple exchange" is a very basic, un-optimized exchange. It @@ -24,6 +25,7 @@ accepted in either direction. { give: { Asset: simoleans(5) }, want: { Price: quatloos(3) } } { give: { Price: quatloos(8) }, want: { Asset: simoleans(3) } } ``` + Note: Here we used a shorthand for assets whose values are 5 simoleons, 3 quatloos, 8 quatloos, and 3 simoleons. Elsewhere this might have been done by creating `amounts` inline (i.e. `AmountMath.make(quatloosBrand, 8n)`). Or by @@ -41,12 +43,12 @@ The `publicFacet` is returned when the contract is started. ```js const { publicFacet } = await E(zoe).startInstance(installation, { - Asset: moolaIssuer, - Price: simoleanIssuer, - }); -const simpleExchangeInvitation = await E(publicFacet).makeInvitation(); -const { instance } = await E(zoe).getInvitationDetails(simpleExchangeInvitation); -const aliceInvitation = await E(publicFacet).makeInvitation(); + Asset: moolaIssuer, + Price: simoleanIssuer +}) +const simpleExchangeInvitation = await E(publicFacet).makeInvitation() +const { instance } = await E(zoe).getInvitationDetails(simpleExchangeInvitation) +const aliceInvitation = await E(publicFacet).makeInvitation() ``` ## Adding an Order @@ -58,10 +60,10 @@ moola and receive at least 4 simoleans in return: const aliceSellOrderProposal = harden({ give: { Asset: AmountMath.make(moolaBrand, 3n) }, want: { Price: AmountMath.make(simoleanBrand, 4n) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) -const alicePayment = { Asset: aliceMoolaPayment }; +const alicePayment = { Asset: aliceMoolaPayment } ``` Alice escrows her payment with Zoe to add her sell order to the exchange. @@ -70,8 +72,8 @@ Alice escrows her payment with Zoe to add her sell order to the exchange. const aliceSeat = await E(zoe).offer( aliceInvitation, aliceSellOrderProposal, - alicePayment, -); + alicePayment +) ``` ## Buying an Order @@ -81,14 +83,13 @@ offer. It sounds like a good deal to him, so he checks the installation with Zoe and sees the exchange is trading what he expects: ```js -const bobInvitation = E(publicFacet).makeInvitation(); -const invitationIssuer = E(zoe).getInvitationIssuer(); -const bobExclusiveInvitation = E(invitationIssuer).claim(bobInvitation); -const { - instance, - installation, -} = await E(zoe).getInvitationDetails(bobExclusiveInvitation); -const bobIssuers = await E(zoe).getIssuers(instance); +const bobInvitation = E(publicFacet).makeInvitation() +const invitationIssuer = E(zoe).getInvitationIssuer() +const bobExclusiveInvitation = E(invitationIssuer).claim(bobInvitation) +const { instance, installation } = await E(zoe).getInvitationDetails( + bobExclusiveInvitation +) +const bobIssuers = await E(zoe).getIssuers(instance) ``` Bob verifies the information is what he expects. He compares the @@ -96,9 +97,9 @@ installation he gets from the invitation with a canonical link he found in a public directory he trusts. ```js -assert(installation === simpleExchangeInstallation, details`wrong installation`); -assert(bobIssuers.Asset === moolaIssuer, details`wrong Asset issuer`); -assert(bobIssuers.Price === simoleanIssuer, details`wrong Price issuer`); +assert(installation === simpleExchangeInstallation, details`wrong installation`) +assert(bobIssuers.Asset === moolaIssuer, details`wrong Asset issuer`) +assert(bobIssuers.Price === simoleanIssuer, details`wrong Price issuer`) ``` Bob has checked that everything is in order, so he fulfills the buy order: @@ -107,17 +108,19 @@ Bob has checked that everything is in order, so he fulfills the buy order: const bobBuyOrderProposal = harden({ give: { Price: AmountMath.make(simoleanBrand, 7n) }, want: { Asset: AmountMath.make(moolaBrand, 3n) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) -const bobSimPayment = await E(bobSimoleanPurse).withdraw(AmountMath(simoleanBrand, 7n)); -const bobPayments = { Price: bobSimPayment }; +const bobSimPayment = await E(bobSimoleanPurse).withdraw( + AmountMath(simoleanBrand, 7n) +) +const bobPayments = { Price: bobSimPayment } const bobSeat = await E(zoe).offer( bobExclusiveInvitation, bobBuyOrderProposal, - bobPayments, -); + bobPayments +) ``` ## Payout @@ -126,18 +129,20 @@ When a match is made, the payout promise from a user's seat resolves to a promise for payment. For Bob: ```js -const { Asset: bobAssetPayoutP, Price: bobPricePayoutP } = await bobSeat.getPayouts(); -const bobAssetPayout = await bobAssetPayoutP; -const bobMoolaGainAmount = await E(bobMoolaPurse).deposit(bobAssetPayout); -const bobPricePayout = await bobPricePayoutP; -const bobSimGainAmount = await E(bobSimPurse).deposit(bobPricePayout); +const { Asset: bobAssetPayoutP, Price: bobPricePayoutP } = + await bobSeat.getPayouts() +const bobAssetPayout = await bobAssetPayoutP +const bobMoolaGainAmount = await E(bobMoolaPurse).deposit(bobAssetPayout) +const bobPricePayout = await bobPricePayoutP +const bobSimGainAmount = await E(bobSimPurse).deposit(bobPricePayout) ``` + Alice gets her payouts the same way. (The choice between `getPayouts()` and `getPayout(keyword)` is based on which is more convenient in each circumstance). ```js -const aliceAssetPayout = await aliceSeat.getPayout('Asset'); -const aliceMoolaGainAmount = aliceMoolaPurse.deposit(aliceAssetPayout); -const alicePricePayout = await aliceSeat.getPayout('Price'); -const aliceSimGainAmount = aliceSimPurse.deposit(alicePricePayout); +const aliceAssetPayout = await aliceSeat.getPayout('Asset') +const aliceMoolaGainAmount = aliceMoolaPurse.deposit(aliceAssetPayout) +const alicePricePayout = await aliceSeat.getPayout('Price') +const aliceSimGainAmount = aliceSimPurse.deposit(alicePricePayout) ``` diff --git a/main/guides/zoe/contracts/use-obj-example.md b/main/guides/zoe/contracts/use-obj-example.md index 3b378496f..b2f6a5814 100644 --- a/main/guides/zoe/contracts/use-obj-example.md +++ b/main/guides/zoe/contracts/use-obj-example.md @@ -3,6 +3,7 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/4e0aece631d8310c7ab8ef3f46fad8981f64d208/packages/zoe/test/unitTests/contracts/useObjExample.js) (Last updated: Jan 31, 2022) + ##### [View all contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) This contract is an example of associating a particular ability diff --git a/main/guides/zoe/contracts/vault.md b/main/guides/zoe/contracts/vault.md index 75b7a9ab7..a873a6aab 100644 --- a/main/guides/zoe/contracts/vault.md +++ b/main/guides/zoe/contracts/vault.md @@ -3,8 +3,8 @@ ##### [View the code on Github](https://github.com/Agoric/agoric-sdk/blob/7d141a47b311363f099f496d4ed9b4d0f28c8fff/packages/inter-protocol/src/vaultFactory/vaultFactory.js) (Last updated: Aug 15, 2022) -##### [View contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) +##### [View contracts on Github](https://github.com/Agoric/agoric-sdk/tree/master/packages/zoe/src/contracts) The Vault is the primary mechanism for making `IST` (the Agoric stable-value currency) available to participants in the economy. It does this by issuing @@ -33,8 +33,8 @@ getCollateralAmount, getDebtAmount, getLiquidationSeat, getLiquidationPromise }`. An `AdjustBalancesInvitation` allows the borrower to add or remove collateral -or increase or decrease the loan balance. `CloseInvitation` allows the -borrower to close their loan and withdraw any remaining collateral. The +or increase or decrease the loan balance. `CloseInvitation` allows the +borrower to close their loan and withdraw any remaining collateral. The `liquidationPromise` allows the borrower to find out if/when the loan gets liquidated. The `liquidationSeat`'s `getPayoff()` or `getPayoffs()` allow the borrower to retrieve any proceeds above what's needed to repay the debt. @@ -71,7 +71,7 @@ over-collateralize so that price volatility and interest charges don't quickly drive their loans into default. The `loanFee` (in basis points) is charged on the amount of `IST` issued when -opening a loan or increasing the amount of a loan. The `interestRate` is an +opening a loan or increasing the amount of a loan. The `interestRate` is an annual rate. `ChargingPeriod` and `recordingPeriod` are parameters of the Vault that apply diff --git a/main/guides/zoe/offer-enforcement.md b/main/guides/zoe/offer-enforcement.md index 7bc9c0360..f250027b1 100644 --- a/main/guides/zoe/offer-enforcement.md +++ b/main/guides/zoe/offer-enforcement.md @@ -4,12 +4,12 @@ ## What is Zoe? -__For users__: Zoe guarantees that as a user of a smart contract, you +**For users**: Zoe guarantees that as a user of a smart contract, you will either get what you wanted or get a full refund, even if the smart contract is buggy or malicious. (In fact, the smart contract never has access to your digital assets.) -__For developers__: Zoe provides a safety net so you can focus on what +**For developers**: Zoe provides a safety net so you can focus on what your smart contract does best, without worrying about your users losing their assets due to a bug in the code that you wrote. Writing a smart contract on Zoe is easy: all of the Zoe smart contracts are @@ -27,14 +27,14 @@ bricks](https://en.wikipedia.org/wiki/Catan)." [Learn more about the particulars of structuring an offer proposal here](./proposal). Offers are a structured way of describing user intent. To a certain -extent, an offer's rules (called a *proposal*) are the user's -*contractual understanding* of the agreement they are entering into. +extent, an offer's rules (called a _proposal_) are the user's +_contractual understanding_ of the agreement they are entering into. You might have noticed that the offer doesn't specify the mechanism by which the exchange happens. The offer doesn't say whether the item you want is up for auction, in an exchange, or part of a private trade. The offer doesn't mention the particular mechanism because an -important part of the design of Zoe is a __separation of concerns__. +important part of the design of Zoe is a **separation of concerns**. Zoe is responsible for enforcing what we call "offer safety", and the smart contract that runs on top of Zoe is responsible for figuring out @@ -70,6 +70,7 @@ Let's look at the basic [Atomic Swap contract](/guides/zoe/contracts/atomic-swap (link includes [real contract code](https://github.com/Agoric/agoric-sdk/blob/f29591519809dbadf19db0a26f38704d87429b89/packages/zoe/src/contracts/atomicSwap.js)). Here's a high-level overview of what happens: + 1. I make an instance of the swap contract, and get an invitation to participate in the contract. 2. I make an offer through Zoe by presenting my invitation, a proposal @@ -99,23 +100,24 @@ It only does one thing, and it's pretty useless—it gives you back what you ```js const start = zcf => { const refund = seat => { - seat.exit(); - return `The offer was accepted`; - }; - const makeRefundInvitation = () => zcf.makeInvitation(refund, 'getRefund'); + seat.exit() + return `The offer was accepted` + } + const makeRefundInvitation = () => zcf.makeInvitation(refund, 'getRefund') const publicFacet = Far('publicFacet', { - makeInvitation: makeRefundInvitation, - }); + makeInvitation: makeRefundInvitation + }) - const creatorInvitation = makeRefundInvitation(); + const creatorInvitation = makeRefundInvitation() - return harden({ creatorInvitation, publicFacet }); -}; + return harden({ creatorInvitation, publicFacet }) +} -harden(start); -export { start }; +harden(start) +export { start } ``` + Whenever we create a new object or array, we recursively freeze it with `harden`. You can learn more about `harden` in the [Endo and Hardened JavaScript @@ -129,6 +131,7 @@ A smart contract on Zoe must export a function named `start` that takes a single parameter: `zcf`, which is the contract-internal API for Zoe. The `start` function must return an object with any of several optional properties: + - **creatorInvitation**: An invitation only available to the creator of the contract instance. - **creatorFacet**: An object with operations made accessible only to the creator. - **publicFacet**: An object with operations available to any client with access to the instance. @@ -142,6 +145,7 @@ The contract first confirms that `issuers` are setup for the `Asset` and `Price` The following uses the [`assertIssuerKeywords` helper function](/reference/zoe-api/zoe-helpers#assertissuerkeywords-zcf-expected). It checks properties of the running contract instance's terms. + ```js const start = zcf => { assertIssuerKeywords(zcf, harden(['Asset', 'Price'])); @@ -156,6 +160,7 @@ This contract uses the [`assertProposalShape` helper function](/reference/zoe-api/zoe-helpers#assertproposalshape-seat-expected) to check that the offer proposes the kind of trade the contract accepts. In this case, offers must have a proposal of the form: + ```js { give: { Asset: amount1 }, @@ -165,6 +170,7 @@ have a proposal of the form: `amount1` and `amount2` are amounts with the correct issuers for the keywords. The contract then uses `getProposal()` to extract the properties of the proposal for later matching. + ```js const makeMatchingInvitation = firstSeat => { assertProposalShape(firstSeat, { @@ -177,21 +183,23 @@ The contract then uses `getProposal()` to extract the properties of the proposal `makeMatchingInvitation()` then constructs a `matchingSeatOfferHandler()` handler for the second offer, with the first offer's `want` and `give` in scope. This second handler is responsible for the final step. -It uses the [`swap` helper function](/reference/zoe-api/zoe-helpers#swap-zcf-leftseat-rightseat) +It uses the [`swap` helper function](/reference/zoe-api/zoe-helpers#swap-zcf-leftseat-rightseat) to attempt asset reallocation between the two seats as described above and then (whether or not the attempt succeeds) exits both seats, making payouts available to both parties. Finally, `matchingSeatOfferHandler()` shuts down the contract. + ```js - const matchingSeatOfferHandler = matchingSeat => { - const swapResult = swap(zcf, firstSeat, matchingSeat); - zcf.shutdown(); - return swapResult; - }; +const matchingSeatOfferHandler = matchingSeat => { + const swapResult = swap(zcf, firstSeat, matchingSeat) + zcf.shutdown() + return swapResult +} ``` Now let's put it together. The final step of `makeMatchingInvitation()` is to create and return the second party's invitation, using `matchingSeatOfferHandler()` and including custom properties for the proposal of the invited offer. + ```js const matchingSeatInvitation = zcf.makeInvitation( matchingSeatOfferHandler, @@ -207,6 +215,7 @@ is to create and return the second party's invitation, using Finally, the `start` function makes an invitation for the instance's creator and returns it as `creatorInvitation`. + ```js const creatorInvitation = zcf.makeInvitation( makeMatchingInvitation, diff --git a/main/guides/zoe/offer-safety.md b/main/guides/zoe/offer-safety.md index 48ad57dc8..3f61c8132 100644 --- a/main/guides/zoe/offer-safety.md +++ b/main/guides/zoe/offer-safety.md @@ -2,7 +2,7 @@ -**Definition**: *Offer safety* means that the user is guaranteed to either +**Definition**: _Offer safety_ means that the user is guaranteed to either get what they wanted or get back a full refund of what they offered. For Zoe to enforce offer safety, the user must @@ -10,9 +10,9 @@ give Zoe a `proposal`. This is a description of both what they want and what they are offering, and when and how the user can exit the contract. Zoe uses this last to enforce payout liveness. The exit specification is optional, and defaults to `OnDemand`, meaning a user can exit the contract instance at their -discretion. +discretion. -For example, I want to buy an event ticket for which I offer $100. In Zoe, +For example, I want to buy an event ticket for which I offer $100. In Zoe, my `proposal` is: ```js @@ -21,6 +21,7 @@ my `proposal` is: want: { Asset: ticket1 }, } ``` + `Asset` and `Price` are the `keywords` of a contract. Keywords let contract users easily and consistently refer to parts of a proposal, payments escrowed with Zoe, and payouts received from Zoe. @@ -30,11 +31,11 @@ using keywords. In this example, I would send Zoe a $100 payment to escrow my offer, as Zoe immediately escrows the `give:`-specified payment. After the user escrows, they get a promise for a payout from Zoe. -This is the payout that offer safety is enforced over. The payout *must* +This is the payout that offer safety is enforced over. The payout _must_ be either what the user wanted (an event ticket in the above example) or a full refund of what they escrowed ($100 in this example). -We can enforce offer safety because Zoe controls the payout. In the example, +We can enforce offer safety because Zoe controls the payout. In the example, if I try to buy my event ticket using a smart contract on Zoe, the contract can tell Zoe to update its bookkeeping to say I've bought a ticket. But, Zoe only actually updates its records and gives me an event ticket @@ -46,16 +47,16 @@ Tests, including edge cases, are in [test-offerSafety.js](https://github.com/Ago ## Implementation Questions -**Under offer safety, can I get a full refund *and* what I wanted?** +**Under offer safety, can I get a full refund _and_ what I wanted?** -Yes, you can get a full refund *and* what you wanted. Offer safety guarantees at least +Yes, you can get a full refund _and_ what you wanted. Offer safety guarantees at least one is true. Both could also be true. **What if there are no rules under `give`?** If there are no rules or if `give` is omitted, then you get a full refund of what you put in, fulfilling offer safety. It's just the case that -you put in nothing, so you get back nothing. However, you *might* also +you put in nothing, so you get back nothing. However, you _might_ also get what you wanted, depending on whether your offer of nothing for it is accepted. diff --git a/main/guides/zoe/price-authority.md b/main/guides/zoe/price-authority.md index 37ac1a530..e135deacf 100644 --- a/main/guides/zoe/price-authority.md +++ b/main/guides/zoe/price-authority.md @@ -18,7 +18,7 @@ official `priceQuotes`. A `priceQuote` is a record with an amount and a payment, where the amount is also the current balance of the payment: ```js -const { quoteAmount, quotePayment } = priceQuote; +const { quoteAmount, quotePayment } = priceQuote ``` Because these are ERTP amounts and payments, they have issuers. And @@ -31,7 +31,7 @@ mint associated with the quoteIssuer by using the `quoteIssuer` to obtain the `quoteAmount` of the `quotePayment`: ```js -const verifiedQuoteAmount = await E(quoteIssuer).getAmountOf(quotePayment); +const verifiedQuoteAmount = await E(quoteIssuer).getAmountOf(quotePayment) ``` Once you have a `quoteAmount` (or a `verifiedQuoteAmount`), you can extract the diff --git a/main/guides/zoe/proposal.md b/main/guides/zoe/proposal.md index 5e92b0297..0d3626c4b 100644 --- a/main/guides/zoe/proposal.md +++ b/main/guides/zoe/proposal.md @@ -5,6 +5,7 @@ ## Making An offer To make an offer, you use [`E(zoe).offer(...)`](/reference/zoe-api/zoe#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#keyword) in **proposal**. @@ -17,6 +18,7 @@ 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. - 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 @@ -30,9 +32,10 @@ Proposals are records with **give**, **want**, and/or **exit** keys. const myProposal = harden({ give: { Asset: AmountMath.make(quatloosBrand, 4n) }, want: { Price: AmountMath.make(moolaBrand, 15n) }, - exit: { onDemand: null }, -}); + exit: { onDemand: null } +}) ``` + **give** and **want** use [Keywords](/reference/zoe-api/zoe-data-types#keyword) defined by the contract. Keywords are unique identifiers per contract, that tie together proposals, payments to be escrowed, and payouts to users. @@ -52,6 +55,7 @@ In contrast, [Payments](/reference/ertp-api/payment) hold actual digital assets. ::: **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 complete (finish or fail) their offer. - `{ afterDeadline: deadlineDetails }`: The offer is automatically cancelled after a deadline, @@ -64,11 +68,12 @@ For more details, see [Proposals](/reference/zoe-api/zoe#proposals). Using the same Keywords as the **give** object in your **proposal**, you must specify a [PaymentPKeywordRecord](/reference/zoe-api/zoe-data-types#keywordrecord) containing [Payments](/reference/ertp-api/payment) 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 payments = { Asset: quatloosPayment, - Price: moolaPayment, -}; + Price: moolaPayment +} ``` ## Offer Arguments diff --git a/main/guides/zoe/pub-to-storage.md b/main/guides/zoe/pub-to-storage.md index e210c7744..292969c7e 100644 --- a/main/guides/zoe/pub-to-storage.md +++ b/main/guides/zoe/pub-to-storage.md @@ -6,14 +6,14 @@ a subscriber to a `chainStorage` node. ## Deployment Capabilities for Publishing to chainStorage -In [Adding Parameter Governance to a Contract](../governance/#adding-parameter-governance-to-a-contract), +In [Adding Parameter Governance to a Contract](../governance/#adding-parameter-governance-to-a-contract), `storageNode` and `marshaller` are passed to the contract in its `privateArgs` so it can publish to chainStorage. In [dapp-agoric-basics](https://github.com/Agoric/dapp-agoric-basics), the `startSwapContract` uses 2 [permitted deployment capabilities](../coreeval/permissions), `chainStorage` and `board` and uses them to make the `privateArgs`: ```js -const marshaller = await E(board).getPublishingMarshaller(); -const storageNode = await E(chainStorage).makeChildNode(contractName); +const marshaller = await E(board).getPublishingMarshaller() +const storageNode = await E(chainStorage).makeChildNode(contractName) ``` A `Marshaller` is parameterized by functions for mapping unforgeable object identities to plain data slot references and back. Using the [board](../integration/name-services#the-board-publishing-under-arbitrary-names) name service gives consistent slot references across contracts. @@ -103,8 +103,8 @@ a `RecorderKit` using [prepareRecorderKitMakers](/reference/zoe-api/zoe-helpers# ```js const { makeRecorderKit } = prepareRecorderKitMakers( baggage, - privateArgs.marshaller, -); + privateArgs.marshaller +) ``` The contract gets `baggage`, along with `privateArgs` when it starts in @@ -129,7 +129,7 @@ export const prepare = async (zcf, privateArgs, baggage) => { The reserve uses its `StorageNode` and makes a child to get `metricsNode`: ```js -const metricsNode = await E(storageNode).makeChildNode('metrics'); +const metricsNode = await E(storageNode).makeChildNode('metrics') ``` The `marshaller` is used to serialize data structures such as `MetricsNotification` above. @@ -140,9 +140,9 @@ To start `assetReserve`, the [setupReserve](https://github.com/Agoric/agoric-sdk the two relevant `privateArgs`, `marshaller` and `storageNode`: ```js -const STORAGE_PATH = 'reserve'; -const storageNode = await E(storageNode).makeChildNode(STORAGE_PATH); -const marshaller = await E(board).getReadonlyMarshaller(); +const STORAGE_PATH = 'reserve' +const storageNode = await E(storageNode).makeChildNode(STORAGE_PATH) +const marshaller = await E(board).getReadonlyMarshaller() ``` The `setupReserve` function gets `chainStorage` and `board` deployment capabilities passed in: diff --git a/main/reference/ertp-api/amount-math.md b/main/reference/ertp-api/amount-math.md index abfb11b7e..9f6cc6eb1 100644 --- a/main/reference/ertp-api/amount-math.md +++ b/main/reference/ertp-api/amount-math.md @@ -5,19 +5,20 @@ Library for manipulating and analyzing **[Amounts](./ertp-data-types#amount)**. ## Importing and Using AmountMath To use **AmountMath**, import it from ERTP: + - `import { AmountMath } from '@agoric/ertp';` ## Brand Parameters -Note that many **AmountMath** methods have an optional **[Brand](./brand)** parameter. -For these methods, you should pass in a **Brand** argument you got from when +Note that many **AmountMath** methods have an optional **[Brand](./brand)** parameter. +For these methods, you should pass in a **Brand** argument you got from when you need to do an "absolute" check on the **Brand** within an **[Amount](./ertp-data-types#amount)** parameter. In this case, you want to use the **Brand** you got from the **Issuer** (or from Zoe) as the optional parameter to compare the **Amount** **Brand**(s) to. If they are not equal, an error is thrown and no changes are made. - ## AmountMath.make(brand, allegedValue) + - **brand**: **[Brand](./brand)** - **allegedValue**: **[AmountValue](./ertp-data-types#amountvalue)** - Returns: **[Amount](./ertp-data-types#amount)** @@ -25,22 +26,24 @@ not equal, an error is thrown and no changes are made. Creates an **Amount** from a given **Brand** and **AmountValue**. ```js -const bid = AmountMath.make(quatloosBrand, 300n); +const bid = AmountMath.make(quatloosBrand, 300n) ``` ## AmountMath.coerce(brand, allegedAmount) + - **brand**: **[Brand](./brand)** - **allegedAmount**: **[Amount](./ertp-data-types#amount)** - Returns: **Amount** -Verifies that an **Amount** is for the specified *brand* and returns an equivalent **Amount**. +Verifies that an **Amount** is for the specified _brand_ and returns an equivalent **Amount**. If the **Amount** is not for the specified **Brand**, an error is thrown. ```js -const verifiedAmount = AmountMath.coerce(quatloosBrand, bid); +const verifiedAmount = AmountMath.coerce(quatloosBrand, bid) ``` ## AmountMath.getValue(brand, amount) + - **brand**: **[Brand](./brand)** - **amount**: **[Amount](./ertp-data-types#amount)** - Returns: **[AmountValue](./ertp-data-types#amountvalue)** @@ -48,181 +51,188 @@ const verifiedAmount = AmountMath.coerce(quatloosBrand, bid); Returns the **AmountValue** from the given **Amount**. ```js -const quatloos123 = AmountMath.make(quatloosBrand, 123n); +const quatloos123 = AmountMath.make(quatloosBrand, 123n) // Returns 123n -AmountMath.getValue(quatloosBrand, quatloos123); +AmountMath.getValue(quatloosBrand, quatloos123) ``` ## AmountMath.makeEmpty(brand, assetKind) + - **brand**: **[Brand](./brand)** - **assetKind**: **[AssetKind](./ertp-data-types#assetkind)** - Returns: **[Amount](./ertp-data-types#amount)** -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 **AmountValue** depends -on whether the *assetKind* is **AssetKind.NAT** (`0n`), **AssetKind.COPY_SET** (`[]`), or **AssetKind.COPY_BAG** (`[]`). +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 **AmountValue** depends +on whether the _assetKind_ is **AssetKind.NAT** (`0n`), **AssetKind.COPY_SET** (`[]`), or **AssetKind.COPY_BAG** (`[]`). ```js // Returns an amount with 0n as its value -const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); +const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT) ``` ## AmountMath.makeEmptyFromAmount(amount) + - **amount**: **[Amount](./ertp-data-types#amount)** - Returns: **Amount** -Returns an empty **Amount** for the **Brand** of the *amount* parameter. +Returns an empty **Amount** for the **Brand** of the _amount_ parameter. ```js // bid = { brand: quatloosBrand, value: 300n } -const bid = AmountMath.make(quatloosBrand, 300n); +const bid = AmountMath.make(quatloosBrand, 300n) // Returns { brand: quatloosBrand, value: 0n } -const zeroQuatloos = AmountMath.makeEmptyFromAmount(bid); +const zeroQuatloos = AmountMath.makeEmptyFromAmount(bid) ``` ## AmountMath.isEmpty(amount, brand?) + - **amount**: **[Amount](./ertp-data-types#amount)** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Boolean** Returns **true** if the **Amount** is empty. Otherwise returns **false**. -If the optional *brand* argument doesn't match the **Amount**'s **Brand**, an error is thrown. +If the optional _brand_ argument doesn't match the **Amount**'s **Brand**, an error is thrown. ```js -const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); -const quatloos1 = AmountMath.make(quatloosBrand, 1n); +const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT) +const quatloos1 = AmountMath.make(quatloosBrand, 1n) // Returns true -const result = AmountMath.isEmpty(empty); +const result = AmountMath.isEmpty(empty) // Returns false -const result = AmountMath.isEmpty(quatloos1); +const result = AmountMath.isEmpty(quatloos1) ``` ## AmountMath.isGTE(leftAmount, rightAmount, brand?) + - **leftAmount**: **[Amount](./ertp-data-types#amount)** - **rightAmount**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Boolean** -Returns **true** if the **[AmountValue](./ertp-data-types#amountvalue)** of *leftAmount* is greater than or equal to -the **AmountValue** of *rightAmount*. +Returns **true** if the **[AmountValue](./ertp-data-types#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. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. -For non-fungible **AmountValues**, 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 is a strict superset of the latter. ```js -const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); -const quatloos5 = AmountMath.make(quatloosBrand, 5n); -const quatloos10 = AmountMath.make(quatloosBrand, 10n); +const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT) +const quatloos5 = AmountMath.make(quatloosBrand, 5n) +const quatloos10 = AmountMath.make(quatloosBrand, 10n) // Returns true -AmountMath.isGTE(quatloos5, empty); +AmountMath.isGTE(quatloos5, empty) // Returns false -AmountMath.isGTE(empty, quatloos5, quatloosBrand); +AmountMath.isGTE(empty, quatloos5, quatloosBrand) // Returns true -AmountMath.isGTE(quatloos10, quatloos5); +AmountMath.isGTE(quatloos10, quatloos5) // Returns false -AmountMath.isGTE(quatloos5, quatloos10); +AmountMath.isGTE(quatloos5, quatloos10) // Returns true -AmountMath.isGTE(quatloos5, quatloos5); +AmountMath.isGTE(quatloos5, quatloos5) ``` ## AmountMath.isEqual(leftAmount, rightAmount, brand?) + - **leftAmount**: **[Amount](./ertp-data-types#amount)** - **rightAmount**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Boolean** -Returns **true** if the **[AmountValue](./ertp-data-types#amountvalue)** of *leftAmount* is equal to -the **AmountValue** of *rightAmount*. +Returns **true** if the **[AmountValue](./ertp-data-types#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. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. For non-fungible **AmountValues**, "equal to" depends on the value of the -**Brand's** **[AssetKind](./ertp-data-types#assetkind)**. +**Brand's** **[AssetKind](./ertp-data-types#assetkind)**. For example, { 'seat 1', 'seat 2' } is considered unequal to { 'seat 2' } because the number of elements differ. -{ 'seat 1' } is considered unequal to { 'seat 2' } because the elements do not match. +{ 'seat 1' } is considered unequal to { 'seat 2' } because the elements do not match. ```js -const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT); -const quatloos5 = AmountMath.make(quatloosBrand, 5n); -const quatloos5b = AmountMath.make(quatloosBrand, 5n); -const quatloos10 = AmountMath.make(quatloosBrand, 10n); +const empty = AmountMath.makeEmpty(quatloosBrand, AssetKind.NAT) +const quatloos5 = AmountMath.make(quatloosBrand, 5n) +const quatloos5b = AmountMath.make(quatloosBrand, 5n) +const quatloos10 = AmountMath.make(quatloosBrand, 10n) // Returns true -AmountMath.isEqual(quatloos10, quatloos10); +AmountMath.isEqual(quatloos10, quatloos10) // Returns true -AmountMath.isEqual(quatloos5, quatloos5b); +AmountMath.isEqual(quatloos5, quatloos5b) // Returns false -AmountMath.isEqual(quatloos10, quatloos5); +AmountMath.isEqual(quatloos10, quatloos5) // Returns false -AmountMath.isEqual(empty, quatloos10); +AmountMath.isEqual(empty, quatloos10) ``` ## AmountMath.add(leftAmount, rightAmount, brand?) + - **leftAmount**: **[Amount](./ertp-data-types#amount)** - **rightAmount**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Amount** -Returns a new **Amount** that is the combination of *leftAmount* and *rightAmount*. +Returns a new **Amount** that is the combination of _leftAmount_ and _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. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. For fungible **Amounts** this means adding their **[AmountValues](./ertp-data-types#amountvalue)**. For non-fungible -**Amounts**, it usually means including all of the elements from *leftAmount* -and *rightAmount*. +**Amounts**, it usually means including all of the elements from _leftAmount_ +and _rightAmount_. -If one of *leftAmount* or *rightAmount* is empty, this method returns an **Amount** equivalent to the other. +If one of _leftAmount_ or _rightAmount_ is empty, this method returns an **Amount** equivalent to the other. If both are empty, this method returns an empty **Amount**. ```js -import { AssetKind, makeIssuerKit, AmountMath } from '@agoric/ertp'; -const { brand: myItemsBrand } = makeIssuerKit('myItems', AssetKind.COPY_SET); -const listAmountA = AmountMath.make(myItemsBrand, ['1','2','4']); -const listAmountB = AmountMath.make(myItemsBrand, ['3']); +import { AssetKind, makeIssuerKit, AmountMath } from '@agoric/ertp' +const { brand: myItemsBrand } = makeIssuerKit('myItems', AssetKind.COPY_SET) +const listAmountA = AmountMath.make(myItemsBrand, ['1', '2', '4']) +const listAmountB = AmountMath.make(myItemsBrand, ['3']) // Returns an amount whose value is ['1', '2', '4', '3'] -const combinedList = AmountMath.add(listAmountA, listAmountB); +const combinedList = AmountMath.add(listAmountA, listAmountB) ``` ## AmountMath.subtract(leftAmount, rightAmount, brand?) + - **leftAmount**: **[Amount](./ertp-data-types#amount)** - **rightAmount**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Amount** -Returns a new **Amount** that is the *leftAmount* minus the *rightAmount* (i.e., -everything in the *leftAmount* that is not in the *rightAmount*). If *leftAmount* -doesn't include *rightAmount* (e.g., subtraction results in a negative), an error is thrown. -Because *leftAmount* must include *rightAmount*, this is **not** +Returns a new **Amount** that is the _leftAmount_ minus the _rightAmount_ (i.e., +everything in the _leftAmount_ that is not in the _rightAmount_). If _leftAmount_ +doesn't include _rightAmount_ (e.g., subtraction results in a negative), an error is thrown. +Because _leftAmount_ must include _rightAmount_, this is **not** equivalent to set subtraction. Both **Amount** arguments must have the same **Brand**. -If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. -If *rightAmount* is empty, this method returns *leftAmount*. If both arguments are +If _rightAmount_ is empty, this method returns _leftAmount_. If both arguments are empty, this method returns an empty **Amount**. ```js -import { AssetKind, makeIssuerKit, AmountMath } from '@agoric/ertp'; -const { brand: myItemsBrand } = makeIssuerKit('myItems', AssetKind.COPY_SET); -const listAmountA = AmountMath.make(myItemsBrand, ['1','2','4']); -const listAmountB = AmountMath.make(myItemsBrand, ['3']); -const listAmountC = AmountMath.make(myItemsBrand, ['2']); +import { AssetKind, makeIssuerKit, AmountMath } from '@agoric/ertp' +const { brand: myItemsBrand } = makeIssuerKit('myItems', AssetKind.COPY_SET) +const listAmountA = AmountMath.make(myItemsBrand, ['1', '2', '4']) +const listAmountB = AmountMath.make(myItemsBrand, ['3']) +const listAmountC = AmountMath.make(myItemsBrand, ['2']) // Returns ['1', '4'] const subtractedList = AmountMath.subtract(listAmountA, listAmountC) @@ -232,43 +242,45 @@ const badList = AmountMath.subtract(listAmountA, listAmountB) ``` ## AmountMath.min(x, y, brand?) + - **x**: **[Amount](./ertp-data-types#amount)** - **y**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Amount** -Returns the minimum value between *x* and *y*. +Returns the minimum value between _x_ and _y_. Both **Amount** arguments must have the same **Brand**. -If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. ```js -const smallerAmount = AmountMath.make(quatloosBrand, 5n); -const largerAmount = AmountMath.make(quatloosBrand, 10n); +const smallerAmount = AmountMath.make(quatloosBrand, 5n) +const largerAmount = AmountMath.make(quatloosBrand, 10n) // Returns an amount equivalent to smallerAmount -const comparisonResult = AmountMath.min(smallerAmount, largerAmount); +const comparisonResult = AmountMath.min(smallerAmount, largerAmount) ``` ## AmountMath.max(x, y, brand?) + - **x**: **[Amount](./ertp-data-types#amount)** - **y**: **Amount** - **brand**: **[Brand](./brand)** - Optional, defaults to **undefined**. - Returns: **Amount** -Returns the maximum value between *x* and *y*. +Returns the maximum value between _x_ and _y_. Both **Amount** arguments must have the same **Brand**. -If the optional *brand* argument doesn't match the **Amount**s' **Brand**, an error is thrown. +If the optional _brand_ argument doesn't match the **Amount**s' **Brand**, an error is thrown. ```js -const smallerAmount = AmountMath.make(quatloosBrand, 5n); -const largerAmount = AmountMath.make(quatloosBrand, 10n); +const smallerAmount = AmountMath.make(quatloosBrand, 5n) +const largerAmount = AmountMath.make(quatloosBrand, 10n) // Returns an amount equivalent to largerAmount -const comparisonResult = AmountMath.max(smallerAmount, largerAmount); +const comparisonResult = AmountMath.max(smallerAmount, largerAmount) ``` ## Related Methods diff --git a/main/reference/ertp-api/brand.md b/main/reference/ertp-api/brand.md index b550677cb..b8957fdbe 100644 --- a/main/reference/ertp-api/brand.md +++ b/main/reference/ertp-api/brand.md @@ -1,78 +1,85 @@ # Brand Object + A **Brand** identifies the asset type of the **[Issuer](./issuer)** and **[Mint](./mint)** associated with the **Brand**. A given **Brand** has a one-to-one relationship with an **Issuer** and a **Mint**, and a one-to-many relationship with **[Purses](./purse)** and **[Payments](./payment)**. -For example, if you were to create a **Brand** that uses *Quatloos*: -- There would be exactly one *Quatloos* **Issuer**. -- There would be exactly one *Quatloos* **Mint**. -- There could be any number of **Purses** that could hold *Quatloos*. -- There could be any number of **Payments** that could hold *Quatloos*. +For example, if you were to create a **Brand** that uses _Quatloos_: + +- There would be exactly one _Quatloos_ **Issuer**. +- There would be exactly one _Quatloos_ **Mint**. +- There could be any number of **Purses** that could hold _Quatloos_. +- There could be any number of **Payments** that could hold _Quatloos_. -All of these relationships are unchangeable. For example, if a **Mint** is created that makes -new *Quatloos*, it can never create non-*Quatloos* assets. Similarly, the *Quatloos* **Brand** -will always be associated with -the *Quatloos* **Mint** and *Quatloos* **Issuer**. +All of these relationships are unchangeable. For example, if a **Mint** is created that makes +new _Quatloos_, it can never create non-_Quatloos_ assets. Similarly, the _Quatloos_ **Brand** +will always be associated with +the _Quatloos_ **Mint** and _Quatloos_ **Issuer**. ## aBrand.isMyIssuer(allegedIssuer) + - **allegedIssuer**: **[Issuer](./issuer)** - Returns: **Boolean** -Returns **true** if *allegedIssuer* is the **Brand**'s **Issuer**. Returns **false** if it's not. +Returns **true** if _allegedIssuer_ is the **Brand**'s **Issuer**. Returns **false** if it's not. Note that a **Brand** from an untrusted source can misrepresent its association with an **Issuer**. The claim should be cross-checked using the **Issuer's** [**anIssuer.getBrand()**](./issuer#anissuer-getbrand) method for mutual agreement. ```js -const isIssuer = brand.isMyIssuer(issuer); +const isIssuer = brand.isMyIssuer(issuer) ``` ## aBrand.getAllegedName() + - Returns: **String** Returns the alleged name of the **Brand**. An alleged name is a human-readable string name of a type of digital asset. -It should not be trusted as accurate since there is no public registry or -expectation of uniqueness. This means there can be multiple **[Issuers](./issuer)**, **[Mints](./mint)**, or **Brands** -with the same alleged name, and thus the name by itself does not uniquely +It should not be trusted as accurate since there is no public registry or +expectation of uniqueness. This means there can be multiple **[Issuers](./issuer)**, **[Mints](./mint)**, or **Brands** +with the same alleged name, and thus the name by itself does not uniquely identify an **Issuer**. Rather, the **Brand** object does that. -To put it another way, nothing stops different people from creating multiple -**Issuers** with the alleged name *Quatloos*, but that doesn't make any of them the -*Quatloos* **Issuer**. The alleged name is just a human readable string which is +To put it another way, nothing stops different people from creating multiple +**Issuers** with the alleged name _Quatloos_, but that doesn't make any of them the +_Quatloos_ **Issuer**. The alleged name is just a human readable string which is helpful for debugging. + ```js -const name = brand.getAllegedName(); +const name = brand.getAllegedName() ``` ## aBrand.getDisplayInfo() + - Returns: **[DisplayInfo](./ertp-data-types#displayinfo)** -Returns the **DisplayInfo** associated with the **Brand**. +Returns the **DisplayInfo** associated with the **Brand**. -You use a **DisplayInfo** object at the dapp and UI levels to correctly +You use a **DisplayInfo** object at the dapp and UI levels to correctly display **[Amounts](./ertp-data-types#amount)**. For fungible tokens, use the **decimalPlaces** property -to display their value in the commonly used denomination, rather than +to display their value in the commonly used denomination, rather than the smallest denomination used for financial accounting (e.g., displaying in dollars rather than cents). ```js -const quatloosDisplay = quatloosBrand.getDisplayInfo(); +const quatloosDisplay = quatloosBrand.getDisplayInfo() ``` ## aBrand.getAmountShape() -- Returns: **[AmountShape](./ertp-data-types#amountshape)** -Returns the **AmountShape** for a **Brand** associated with a non-fungible asset. +- Returns: **[AmountShape](./ertp-data-types#amountshape)** +Returns the **AmountShape** for a **Brand** associated with a non-fungible asset. ## Related Methods The following methods on other ERTP components are also related to the **Brand** object. + - [**anIssuer.getBrand()**](./issuer#anissuer-getbrand): Returns -the **Brand** for the **Issuer**. + the **Brand** for the **Issuer**. - [**aPayment.getAllegedBrand()**](./payment#apayment-getallegedbrand): Returns -the **Payment**'s alleged **Brand**. + the **Payment**'s alleged **Brand**. diff --git a/main/reference/ertp-api/ertp-data-types.md b/main/reference/ertp-api/ertp-data-types.md index 6a116712a..029a20162 100644 --- a/main/reference/ertp-api/ertp-data-types.md +++ b/main/reference/ertp-api/ertp-data-types.md @@ -23,7 +23,7 @@ someAmount: { An **AmountShape** is a description of non-fungible digital assets. Similar to **[Amount](#amount)**, **AmountShape** has 2 properties: a **[Brand](./brand)**, which states what kind of asset this is, and a **ValueShape**, which is an object containing however many properties are required to describe -this non-fungible asset. Note that an asset's **ValueShape** is defined by the *elementShape* parameter +this non-fungible asset. Note that an asset's **ValueShape** is defined by the _elementShape_ parameter when the asset's **[Issuer](./issuer)** is created via the **[makeIssuerKit()](./issuer#makeissuerkit-allegedname-assetkind-displayinfo-optshutdownwithfailure-elementshape)** function. @@ -35,6 +35,7 @@ someAmountShape: { ``` + ## AmountValue An **AmountValue** is the part of an [Amount](#amount) that describes the value of something @@ -48,7 +49,7 @@ AmountValues must be [Keys](/glossary/#key). There are several kinds of Assets. -- **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.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). See [@endo/patterns CopySet](https://endojs.github.io/endo/types/_endo_patterns.CopySet.html). - **AssetKind.COPY_BAG** : Used with semi-fungible assets where there can be duplicates. The duplicates of the same asset are fungible with each other (e.g., weapons in a computer game). See [@endo/patterns CopyBag](https://endojs.github.io/endo/types/_endo_patterns.CopyBag.html). @@ -60,9 +61,9 @@ Use **[makeIssuerKit()](./issuer#makeissuerkit-allegedname-assetkind-displayinfo your contract uses. See the **[Issuer](./issuer)** documentation for details on how to use this method. ```js -import { AssetKind, makeIssuerKit } from '@agoric/ertp'; -makeIssuerKit('quatloos'); // Defaults to AssetKind.NAT and undefined DisplayInfo -makeIssuerKit('kitties', AssetKind.COPY_SET); // Defaults to undefined DisplayInfo +import { AssetKind, makeIssuerKit } from '@agoric/ertp' +makeIssuerKit('quatloos') // Defaults to AssetKind.NAT and undefined DisplayInfo +makeIssuerKit('kitties', AssetKind.COPY_SET) // Defaults to undefined DisplayInfo ``` ## DisplayInfo @@ -76,9 +77,9 @@ how many places to move the decimal point over to the left so as to display the in the commonly used denomination (e.g., display "10.00 dollars" rather than "1000 cents"). Fungible digital assets are represented in integers, in their smallest unit. -For example, the smallest unit for a US dollar might be either *dollar* or *cent*. -If it's *dollar*, **decimalPlaces** would be **0**. If it's *cent*, **decimalPlaces** -would be **2**. Similarly, if you want the smallest unit of ether (the cryptocurrency coin used on the Ethereum network) to be *wei* (one ether = 1018 wei), then **decimalPlaces** would be **18**. +For example, the smallest unit for a US dollar might be either _dollar_ or _cent_. +If it's _dollar_, **decimalPlaces** would be **0**. If it's _cent_, **decimalPlaces** +would be **2**. Similarly, if you want the smallest unit of ether (the cryptocurrency coin used on the Ethereum network) to be _wei_ (one ether = 1018 wei), then **decimalPlaces** would be **18**. Non-fungible assets have values that are arrays, so you shouldn't specify a **decimalPlaces** value for them. diff --git a/main/reference/ertp-api/index.md b/main/reference/ertp-api/index.md index 55821085d..5df43c194 100644 --- a/main/reference/ertp-api/index.md +++ b/main/reference/ertp-api/index.md @@ -2,30 +2,26 @@ The ERTP API supports the following objects: -| Object | Description | -| --- | --- | -| [Issuer](./issuer) | The authority on what holds digital assets of its kind. | -| [Mint](./mint) | Can issue new digital assets. | -| [Brand](./brand) | Identifies the asset type of the associated **Issuer** and **Mint**. | -| [Purse](./purse) | Holds digital assets. | -| [Payment](./payment) | Holds digital assets that are in transit. | - - +| Object | Description | +| -------------------- | -------------------------------------------------------------------- | +| [Issuer](./issuer) | The authority on what holds digital assets of its kind. | +| [Mint](./mint) | Can issue new digital assets. | +| [Brand](./brand) | Identifies the asset type of the associated **Issuer** and **Mint**. | +| [Purse](./purse) | Holds digital assets. | +| [Payment](./payment) | Holds digital assets that are in transit. | The ETRP API uses the following library: -| Object | Description | -| --- | --- | +| Object | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | [AmountMath](./amount-math) | The **AmountMath** object has several methods which can be used to manipulate and analyze **[Amounts](./ertp-data-types#amount)**. | - The ERTP API introduces and uses the following data types: -| Data Type | Description | -| --- | --- | -| [Amount](./ertp-data-types#amount) | Describes digital assets, specifying the number and **[Brand](./brand)** of assets. Note that **Amounts** can describe either fungible or non-fungible assets. | -| [AmountShape](./ertp-data-types#amountshape) | Describes digital assets, specifying the properties and **[Brand](./brand)** of assets. | -| [AmountValue](./ertp-data-types#amountvalue) | Describes how much of something there is. | -| [AssetKind](./ertp-data-types#assetkind) | Specifies whether an **Amount** is fungible or non-fungible. | -| [DisplayInfo](./ertp-data-types#displayinfo) | Specifies how to display a **Brand**'s **Amounts**. | - +| Data Type | Description | +| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Amount](./ertp-data-types#amount) | Describes digital assets, specifying the number and **[Brand](./brand)** of assets. Note that **Amounts** can describe either fungible or non-fungible assets. | +| [AmountShape](./ertp-data-types#amountshape) | Describes digital assets, specifying the properties and **[Brand](./brand)** of assets. | +| [AmountValue](./ertp-data-types#amountvalue) | Describes how much of something there is. | +| [AssetKind](./ertp-data-types#assetkind) | Specifies whether an **Amount** is fungible or non-fungible. | +| [DisplayInfo](./ertp-data-types#displayinfo) | Specifies how to display a **Brand**'s **Amounts**. | diff --git a/main/reference/ertp-api/issuer.md b/main/reference/ertp-api/issuer.md index 8609b1eb3..0d840041a 100644 --- a/main/reference/ertp-api/issuer.md +++ b/main/reference/ertp-api/issuer.md @@ -1,83 +1,93 @@ # Issuer Object -An **Issuer** is the authority on what holds digital assets of its kind. -While it cannot create new value by creating digital assets like a **[Mint](./mint)** can, +An **Issuer** is the authority on what holds digital assets of its kind. +While it cannot create new value by creating digital assets like a **[Mint](./mint)** can, it recognizes and identifies **[Purses](./purse)** and **[Payments](./payment)** that carry actual value. -It can create empty **Purses** and transform **Payments** (by splitting, -combining, burning, or exclusively claiming them). +It can create empty **Purses** and transform **Payments** (by splitting, +combining, burning, or exclusively claiming them). An **Issuer** has an unchangeable one-to-one relationship with the **Mint** and **[Brand](./brand)** that were created with it. For any **Brands** for which you will accept **Payments** in, you should obtain its **Issuer** from a trusted source. -You can then rely on that **Issuer** as the authority to +You can then rely on that **Issuer** as the authority to validate an untrusted **Payment** of that **Brand**. -**Note**: You should not create an **Issuer** in a deploy script. Deploy scripts +**Note**: You should not create an **Issuer** in a deploy script. Deploy scripts are ephemeral, so any object created there dies as soon as the script ends. ## makeIssuerKit(allegedName, assetKind?, displayInfo?, optShutdownWithFailure?, elementShape?) -- **allegedName**: **String** + +- **allegedName**: **String** - **assetKind**: **[AssetKind](./ertp-data-types#assetkind)** - Optional, defaults to **AssetKind.NAT**. - **displayInfo**: **[DisplayInfo](./ertp-data-types#displayinfo)** - Optional, defaults to **undefined**. - **optShutdownWithFailure** - Optional, defaults to **undefined**. - **elementShape** - Optional, defaults to **undefined**. - Returns **IssuerKit**. This is an object with three properties: - - **issuer**: **Issuer** - - **mint**: **[Mint](./mint)** - - **brand**: **[Brand](./brand)** + - **issuer**: **Issuer** + - **mint**: **[Mint](./mint)** + - **brand**: **[Brand](./brand)** Creates and returns a new **Issuer** and its associated **Mint** and **Brand**. -All three are in unchangeable one-to-one relationships with each other. +All three are in unchangeable one-to-one relationships with each other. -The *allegedName* becomes part of the **Brand** in asset descriptions. It +The _allegedName_ becomes part of the **Brand** in asset descriptions. It doesn't have to be a **String**, but it will only be used for its value. It is useful for debugging and double-checking assumptions, but should not be trusted. -The optional *assetKind* parameter specifies the kind of asset associated with the **Issuer** about -to be created. If no **AssetKind** argument is passed into the method, then the **Issuer**'s asset -kind defaults to **AssetKind.NAT**. **[AmountMath](./amount-math)**'s methods work with all the -kinds of assets, but exactly what math or manipulation is performed varies depending on -the **AssetKind**. +The optional _assetKind_ parameter specifies the kind of asset associated with the **Issuer** about +to be created. If no **AssetKind** argument is passed into the method, then the **Issuer**'s asset +kind defaults to **AssetKind.NAT**. **[AmountMath](./amount-math)**'s methods work with all the +kinds of assets, but exactly what math or manipulation is performed varies depending on +the **AssetKind**. -The optional *displayInfo* parameter tells the UI how to +The optional _displayInfo_ parameter tells the UI how to display **[Amounts](./ertp-data-types#amount)** of this **Brand**. -The optional *optShutdownWithFailure* parameter should be used for mission-critical -**Issuers**. This parameter is a function that will stop the vat hosting the +The optional _optShutdownWithFailure_ parameter should be used for mission-critical +**Issuers**. This parameter is a function that will stop the vat hosting the **Issuer** if **Issuer** invariants are violated. -The optional *elementShape* parameter is only used when creating an **Issuer** that -has a non-fungible asset associated with it. When used, the *elementShape* parameter is an object -with however many properties are required to describe the asset. This object sets the -*valueShape's* properties of the asset's **[AmountShape](./ertp-data-types#amountshape)**. - +The optional _elementShape_ parameter is only used when creating an **Issuer** that +has a non-fungible asset associated with it. When used, the _elementShape_ parameter is an object +with however many properties are required to describe the asset. This object sets the +_valueShape's_ properties of the asset's **[AmountShape](./ertp-data-types#amountshape)**. ```js -import { AssetKind, makeIssuerKit } from '@agoric/ertp'; -makeIssuerKit('quatloos'); // Defaults to AssetKind.NAT -makeIssuerKit('title', AssetKind.COPY_SET); +import { AssetKind, makeIssuerKit } from '@agoric/ertp' +makeIssuerKit('quatloos') // Defaults to AssetKind.NAT +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 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']); -const combinedProperty = AmountMath.make(propertyTitleBrand, ['1292826', '1028393']); +const cornerProperty = AmountMath.make(propertyTitleBrand, ['1292826']) +const adjacentProperty = AmountMath.make(propertyTitleBrand, ['1028393']) +const combinedProperty = AmountMath.make(propertyTitleBrand, [ + '1292826', + '1028393' +]) ``` ## anIssuer.getAllegedName() + - Returns: **allegedName** Returns the **allegedName** for the **Issuer**. -An alleged name is a human-readable string name +An alleged name is a human-readable string name of a kind of digital asset. An alleged name should not be trusted as accurate because there is no public registry or expectation of uniqueness. This @@ -86,31 +96,33 @@ same alleged name, and thus the name by itself does not uniquely identify an **Issuer**. Rather, the **Brand** does that. To put it another way, nothing stops anyone from creating an **Issuer** -with the alleged name *Quatloos* (or *BTC*, or whatever), regardless of whether +with the alleged name _Quatloos_ (or _BTC_, or whatever), regardless of whether or not such a name is already in use. The alleged name is just a human readable string which is helpful for debugging. ```js -const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); -const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName(); +const { issuer: quatloosIssuer } = makeIssuerKit('quatloos') +const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName() // quatloosIssuerAllegedName === 'quatloos' ``` ## anIssuer.getAssetKind() + - Returns: **[AssetKind](./ertp-data-types#assetkind)** Returns the kind of the **Issuer**'s asset. -The **AssetKind** specifies what kind of values are used in **[Amounts](./ertp-data-types#amount)** for this **Issuer**. +The **AssetKind** specifies what kind of values are used in **[Amounts](./ertp-data-types#amount)** for this **Issuer**. ```js -const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); -quatloosIssuer.getAssetKind(); // Returns 'nat', also known as AssetKind.NAT, the default value. -const { issuer: moolaIssuer } = makeIssuerKit('moola', AssetKind.COPY_SET); -moolaIssuer.getAssetKind(); // Returns 'copy_set', also known as 'AssetKind.COPY_SET' +const { issuer: quatloosIssuer } = makeIssuerKit('quatloos') +quatloosIssuer.getAssetKind() // Returns 'nat', also known as AssetKind.NAT, the default value. +const { issuer: moolaIssuer } = makeIssuerKit('moola', AssetKind.COPY_SET) +moolaIssuer.getAssetKind() // Returns 'copy_set', also known as 'AssetKind.COPY_SET' ``` ## anIssuer.getAmountOf(payment) + - **payment**: **[Payment](./payment)** - Returns: **[Amount](./ertp-data-types#amount)** @@ -119,14 +131,20 @@ source cannot be trusted to provide its own true value, the **Issuer** must be u validate its **[Brand](./brand)** and report how much the returned **Amount** contains. ```js -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 +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 ``` ## anIssuer.getBrand() -- Returns: **[Brand](./brand)** + +- Returns: **[Brand](./brand)** Returns the **Brand** for the **Issuer**. The **Brand** indicates the kind of digital asset and is the same for the **Issuer**'s associated **[Mint](./mint)**, and any **[Purses](./purse)** and **[Payments](./payment)** of this particular @@ -134,23 +152,25 @@ kind. The **Brand** is not closely held, so this method should not be trusted to an **Issuer** alone. Fake digital assets and amounts can use another **Issuer's** **Brand**. ```js -const { issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos'); -const quatloosBrand = quatloosIssuer.getBrand(); +const { issuer: quatloosIssuer, brand: quatloosBrand } = + makeIssuerKit('quatloos') +const quatloosBrand = quatloosIssuer.getBrand() // brand === quatloosBrand ``` ## anIssuer.makeEmptyPurse() + - Returns: **[Purse](./purse)** Makes and returns an empty **Purse** that holds assets of the **[Brand](./brand)** associated with the **Issuer**. ```js -const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); -const quatloosPurse = quatloosIssuer.makeEmptyPurse(); +const { issuer: quatloosIssuer } = makeIssuerKit('quatloos') +const quatloosPurse = quatloosIssuer.makeEmptyPurse() ``` - ## **anIssuer.burn(payment, optAmount?)** + - **payment**: **[Payment](./payment)** - **optAmount**: **[Amount](./ertp-data-types#amount)** - Optional. @@ -160,141 +180,167 @@ Destroys all of the digital assets in the **Payment**, making it unavailable for later use, and returns an **Amount** of what was burned. -If an *optAmount* argument is passed into the method, -*payment*'s balance must be equal to *optAmount* in order to prevent claiming the wrong **Payment**. -If *optAmount* does not equal the balance in the original **Payment** an error is thrown, +If an _optAmount_ argument is passed into the method, +_payment_'s balance must be equal to _optAmount_ in order to prevent claiming the wrong **Payment**. +If _optAmount_ does not equal the balance in the original **Payment** an error is thrown, and the original **Payment** is unmodified. -If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. +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 amountToBurn = AmountMath.make(quatloosBrand, 10n); -const paymentToBurn = quatloosMint.mintPayment(amountToBurn); +const { + issuer: quatloosIssuer, + mint: quatloosMint, + brand: quatloosBrand +} = makeIssuerKit('quatloos') +const amountToBurn = AmountMath.make(quatloosBrand, 10n) +const paymentToBurn = quatloosMint.mintPayment(amountToBurn) // burntAmount should equal 10 Quatloos -const burntAmount = quatloosIssuer.burn(paymentToBurn, amountToBurn); +const burntAmount = quatloosIssuer.burn(paymentToBurn, amountToBurn) ``` ## anIssuer.isLive(payment) + - **payment**: **[Payment](./payment)** - Returns: **Boolean** -Returns **true** if the *payment* was created by the **Issuer** and is available for use +Returns **true** if the _payment_ was created by the **Issuer** and is available for use (i.e., it hasn't been consumed). -If *payment* is a promise, the method proceeds after it resolves to a **Payment**. +If _payment_ is a promise, the method proceeds after it resolves to a **Payment**. ::: warning DEPRECATED ## anIssuer.claim(payment, optAmount?) + - **payment**: **[Payment](./payment)** - **optAmount**: **[Amount](./ertp-data-types#amount)** - Optional. -- Returns: **Payment** +- Returns: **Payment** -Transfers all digital assets from *payment* to a new **Payment** and consumes the +Transfers all digital assets from _payment_ to a new **Payment** and consumes the original **Payment**, making it unavailable for later use. -If the *optAmount* argument is passed into the method, *payment*'s balance must be -equal to *optAmount*, to prevent claiming the wrong **Payment**. -If *optAmount* does not equal the balance in the original **Payment** an error is thrown, +If the _optAmount_ argument is passed into the method, _payment_'s balance must be +equal to _optAmount_, to prevent claiming the wrong **Payment**. +If _optAmount_ does not equal the balance in the original **Payment** an error is thrown, and the original **Payment** is unmodified. -If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. +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 amountExpectedToTransfer = AmountMath.make(quatloosBrand, 2n); -const originalPayment = quatloosMint.mintPayment(amountExpectedToTransfer); - -const newPayment = quatloosIssuer.claim(originalPayment, amountToTransfer); +const { + issuer: quatloosIssuer, + mint: quatloosMint, + brand: quatloosBrand +} = makeIssuerKit('quatloos') +const amountExpectedToTransfer = AmountMath.make(quatloosBrand, 2n) +const originalPayment = quatloosMint.mintPayment(amountExpectedToTransfer) + +const newPayment = quatloosIssuer.claim(originalPayment, amountToTransfer) ``` ## anIssuer.combine(paymentsArray, optTotalAmount?) + - **paymentsArray**: **Array<[Payment](./payment)>** - **optTotalAmount**: **[Amount](./ertp-data-types#amount)** - Optional. - Returns: **Payment** -Combines multiple **Payments** into one new **Payment**. If any item in *paymentsArray* is +Combines multiple **Payments** into one new **Payment**. If any item in _paymentsArray_ is a promise, the operation proceeds after each such promise resolves to a **Payment**. -All **Payments** in *paymentsArray* are consumed and made unavailable for later use. +All **Payments** in _paymentsArray_ are consumed and made unavailable for later use. -If the *optTotalAmount* argument is passed into the method, -the total value of all **Payments** in *paymentsArray* -must equal *optTotalAmount*. If they don't, the method throws an error, +If the _optTotalAmount_ argument is passed into the method, +the total value of all **Payments** in _paymentsArray_ +must equal _optTotalAmount_. If they don't, the method throws an error, and the original **Payment** is unmodified. -Each **Payment** in *paymentsArray* must be associated with the same **[Brand](./brand)** as the **Issuer**. +Each **Payment** in _paymentsArray_ must be associated with the same **[Brand](./brand)** as the **Issuer**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = - makeIssuerKit('quatloos'); +const { + issuer: quatloosIssuer, + mint: quatloosMint, + brand: quatloosBrand +} = makeIssuerKit('quatloos') // Create an array of 100 payments of 1 quatloo each -const payments = []; +const payments = [] for (let i = 0; i < 100; i += 1) { - payments.push(quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1n))); + payments.push(quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1n))) } // combinedPayment equals 100 -const combinedPayment = quatloosIssuer.combine(payments); +const combinedPayment = quatloosIssuer.combine(payments) ``` ## anIssuer.split(payment, paymentAmountA) + - **payment**: **[Payment](./payment)** - **paymentAmountA**: **[Amount](./ertp-data-types#amount)** - Returns: **Array<Payment>** -Splits a single **Payment** into two new **Payments**, A and B, according to *paymentAmountA*. -For example, if the **Payment** is for 10 *Quatloos*, and *paymentAmountA* is 3 *Quatloos*, -the method returns an array of two **Payments** with balances of 3 *Quatloos* and 7 *Quatloos*. +Splits a single **Payment** into two new **Payments**, A and B, according to _paymentAmountA_. +For example, if the **Payment** is for 10 _Quatloos_, and _paymentAmountA_ is 3 _Quatloos_, +the method returns an array of two **Payments** with balances of 3 _Quatloos_ and 7 _Quatloos_. The original **Payment** is consumed and made unavailable for later use. -If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. +If _payment_ is a promise, the operation proceeds after it resolves to a **Payment**. -*payment* and *paymentAmountA* must both be associated with the same **[Brand](./brand)** as the **Issuer**. +_payment_ and _paymentAmountA_ must both be associated with the same **[Brand](./brand)** as the **Issuer**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = - makeIssuerKit('quatloos'); -const oldPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 20n)); +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)); +const [paymentA, paymentB] = quatloosIssuer.split( + oldPayment, + AmountMath.make(quatloosBrand, 5n) +) ``` ## anIssuer.splitMany(payment, amountArray) + - **payment**: **[Payment](./payment)** - **amountArray**: **Array<[Amount](./ertp-data-types#amount)>** - Returns: **Array<Payment>** Splits a single **Payment** into multiple **Payments**. -The returned array includes a **Payment** item corresponding to each **Amount** in the *amountArray* parameter, in order. +The returned array includes a **Payment** item corresponding to each **Amount** in the _amountArray_ parameter, in order. The original **Payment** is consumed and made unavailable for later use. -If *payment* is a promise, the operation proceeds after it resolves to a **Payment**. +If _payment_ is a promise, the operation proceeds after it resolves to a **Payment**. -If the **Amounts** in *amountArray* don't add up to the value of *payment*, the operation fails. -*payment* and each **Amount** in *amountArray* must be associated with the same **[Brand](./brand)** as **Issuer**. +If the **Amounts** in _amountArray_ don't add up to the value of _payment_, the operation fails. +_payment_ and each **Amount** in _amountArray_ must be associated with the same **[Brand](./brand)** as **Issuer**. ```js -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)); - -const arrayOfNewPayments = quatloosIssuer.splitMany(oldPayment, goodAmounts); +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)) + +const arrayOfNewPayments = quatloosIssuer.splitMany(oldPayment, goodAmounts) // The total amount in the amountArray must equal the original payment amount // Set original amount to 1000n -const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1000n)); +const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1000n)) // Total amounts in badAmounts equal 20n, when it should equal 1000n -const badAmounts = Array(2).fill(AmountMath.make(quatloosBrand, 10n)); +const badAmounts = Array(2).fill(AmountMath.make(quatloosBrand, 10n)) // 20n does not equal 1000n, so throws error -quatloosIssuer.splitMany(payment, badAmounts); +quatloosIssuer.splitMany(payment, badAmounts) ``` + ::: diff --git a/main/reference/ertp-api/mint.md b/main/reference/ertp-api/mint.md index 7dac98835..420ffc684 100644 --- a/main/reference/ertp-api/mint.md +++ b/main/reference/ertp-api/mint.md @@ -1,6 +1,6 @@ # Mint Object -Only a **Mint** can issue new digital assets. +Only a **Mint** can issue new digital assets. A **Mint** has a one-to-one relationship with both an **[Issuer](./issuer)** and a **[Brand](./brand)**. So it can only mint new assets of that **Brand** and is the only **Mint** that can mint @@ -9,20 +9,22 @@ new assets of that **Brand**. **Mints** are created by calling the **[makeIssuerKit()](./issuer#makeissuerkit-allegedname-assetkind-displayinfo-optshutdownwithfailure-elementshape)** function. See the **[Issuer](./issuer)** documentation for detailed information about how to use this function. ## aMint.getIssuer() + - Returns: **[Issuer](./issuer)** Returns the **Issuer** uniquely associated with this **Mint**. From its creation, a **Mint** is always -in an unchangeable one-to-one relationship with a particular **Issuer**. +in an unchangeable one-to-one relationship with a particular **Issuer**. ```js -const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit('quatloos'); -const quatloosMintIssuer = quatloosMint.getIssuer(); +const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit('quatloos') +const quatloosMintIssuer = quatloosMint.getIssuer() // Returns true -issuer === quatloosMintIssuer; +issuer === quatloosMintIssuer ``` ## aMint.mintPayment(newAmount) + - **newAmount**: **[Amount](./ertp-data-types#amount)** - Returns: **[Payment](./payment)** @@ -31,12 +33,15 @@ 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); +const quatloos1000 = amountMath.make(quatloosBrand, 1000n) // newPayment will have a balance of 1000 Quatloos -const newPayment = quatloosMint.mintPayment(quatloos1000); +const newPayment = quatloosMint.mintPayment(quatloos1000) ``` ::: tip Important diff --git a/main/reference/ertp-api/payment.md b/main/reference/ertp-api/payment.md index c2551a42c..52104c2ec 100644 --- a/main/reference/ertp-api/payment.md +++ b/main/reference/ertp-api/payment.md @@ -1,47 +1,51 @@ # Payment Object -A **Payment** holds digital assets that are in transit or -expected to soon be in transit. It can be deposited in **[Purses](./purse)**, + +A **Payment** holds digital assets that are in transit or +expected to soon be in transit. It can be deposited in **[Purses](./purse)**, split into or combined with multiple **Payments**, or claimed (i.e., getting -an exclusive **Payment** and revoking access from anyone else). +an exclusive **Payment** and revoking access from anyone else). Digital assets in **Payments** can be any of: -- Currency-like, such as our imaginary *Quatloos* currency. + +- Currency-like, such as our imaginary _Quatloos_ currency. - Goods-like digital assets, such as theater tickets or magic weapons used in a game. - Other kinds of rights, such as the right to participate in a particular contract. A **Payment** is linear, meaning either a **Payment** has its full original balance, or it is used up entirely. You cannot partially use a -**Payment**. In other words, if a **Payment** is 10 *Quatloos*, you can't -take out, say, only 3 *Quatloos* from it. +**Payment**. In other words, if a **Payment** is 10 _Quatloos_, you can't +take out, say, only 3 _Quatloos_ from it. -However, you can split a **Payment** into multiple **Payments**. For example, you could split a -10 *Quatloos* **Payment** into two new **Payments** of 3 *Quatloos* and 7 *Quatloos* by calling the -**[anIssuer.split()](./issuer#anissuer-split-payment-paymentamounta)** method which consumes the -original 10 *Quatloos* **Payment** and creates two new smaller **Payments**. +However, you can split a **Payment** into multiple **Payments**. For example, you could split a +10 _Quatloos_ **Payment** into two new **Payments** of 3 _Quatloos_ and 7 _Quatloos_ by calling the +**[anIssuer.split()](./issuer#anissuer-split-payment-paymentamounta)** method which consumes the +original 10 _Quatloos_ **Payment** and creates two new smaller **Payments**. **Payments** are often received from other actors. Since they are not self-verifying, you cannot trust **Payments**. To get the verified balance of a **Payment**, call the **[anIssuer.getAmountOf()](./issuer#anissuer-getamountof-payment)** method. -To convert a **Payment** into a new **Purse**: -1. Get the **Payment**'s trusted **[Issuer](./issuer)**. +To convert a **Payment** into a new **Purse**: + +1. Get the **Payment**'s trusted **[Issuer](./issuer)**. 2. Use the **Issuer** to create an empty **Purse**. -3. Deposit the **Payment** into the new **Purse**. +3. Deposit the **Payment** into the new **Purse**. **[aPurse.deposit()](./purse#apurse-deposit-payment-optamount)** consumes the **Payment**, making it unavailable for later use. ## aPayment.getAllegedBrand() + - Returns: **[Brand](./brand)** -Returns the **Brand** indicating the kind of digital asset this **Payment** purports to be. +Returns the **Brand** indicating the kind of digital asset this **Payment** purports to be. Because **Payments** are not trusted, any method calls on them should be treated with suspicion and verified elsewhere. Any successful operation by an **Issuer** on a **Payment** verifies it. ```js -const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 10n)); +const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 10n)) // Should return 'quatloos' -const allegedBrand = payment.getAllegedBrand(); +const allegedBrand = payment.getAllegedBrand() ``` ## Related Methods @@ -58,18 +62,18 @@ on or return a **Payment**. - [**aMint.mintPayment()**](./mint#amint-mintpayment-newamount) - Create new digital assets of the **Mint**'s associated **Brand**. - [**aPurse.deposit()**](./purse#apurse-deposit-payment-optamount) - - Deposits all the contents of *payment* into the **Purse**. + - Deposits all the contents of _payment_ into the **Purse**. - [**aPurse.getDepositFacet()**](./purse#apurse-getdepositfacet) - Creates and returns a new deposit-only facet of the **Purse** that allows arbitrary other parties to deposit **Payments** into the **Purse**. - [**aPurse.withdraw()**](./purse#apurse-withdraw-amount) - - Withdraws the *amount* of specified digital assets from **Purse** into a new **Payment**. -::: warning DEPRECATED + - Withdraws the _amount_ of specified digital assets from **Purse** into a new **Payment**. + ::: warning DEPRECATED - [**anIssuer.split()**](./issuer#anissuer-split-payment-paymentamounta) - Splits a single **Payment** into two new **Payments**. - [**anIssuer.splitMany()**](./issuer#anissuer-splitmany-payment-amountarray) - Split a single **Payment** into multiple **Payments**. - [**anIssuer.claim()**](./issuer#anissuer-claim-payment-optamount) - - Transfers all digital assets from *payment* to a new **Payment**. + - Transfers all digital assets from _payment_ to a new **Payment**. - [**anIssuer.combine()**](./issuer#anissuer-combine-paymentsarray-opttotalamount) - Combines multiple **Payments** into one new **Payment**. -::: + ::: diff --git a/main/reference/ertp-api/purse.md b/main/reference/ertp-api/purse.md index af1a96de8..1cbc3f4b1 100644 --- a/main/reference/ertp-api/purse.md +++ b/main/reference/ertp-api/purse.md @@ -1,38 +1,40 @@ # Purse Object **Purses** hold digital assets. They are created to hold assets of a single **[Brand](./brand)**, -and the **Brand** that the **Purse** holds cannot be changed. For example, if you were to create a **Purse** that holds *Quatloos*, that **Purse** wouldn't ever be able to hold *Moola*, theater -tickets, or any other non-*Quatloo* asset type. +and the **Brand** that the **Purse** holds cannot be changed. For example, if you were to create a **Purse** that holds _Quatloos_, that **Purse** wouldn't ever be able to hold _Moola_, theater +tickets, or any other non-_Quatloo_ asset type. Digital assets in **Purses** can be any of: -- Currency-like, such as our imaginary *Quatloos* currency. + +- Currency-like, such as our imaginary _Quatloos_ currency. - Goods-like digital assets, such as theater tickets or magic weapons used in a game. - Other kinds of rights, such as the right to participate in a particular contract. While each **Purse** can only hold assets of one **Brand**, any number of **Purses** can be -created that hold that **Brand**. So you could have, say, three *Quatloos* **Purses**, your -friend Alice could have eight *Quatloos* **Purses**, and so on. +created that hold that **Brand**. So you could have, say, three _Quatloos_ **Purses**, your +friend Alice could have eight _Quatloos_ **Purses**, and so on. **Purses** are created by calling the **[anIssuer.makeEmptyPurse()](./issuer#anissuer-makeemptypurse)** method on the **[Issuer](./issuer)** associated with the **Brand** of assets you want the new **Purse** to hold. ```js -const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); -const quatloosPurse = quatloosIssuer.makeEmptyPurse(); +const { issuer: quatloosIssuer } = makeIssuerKit('quatloos') +const quatloosPurse = quatloosIssuer.makeEmptyPurse() ``` You change a **Purse**'s balance by calling either -**[aPurse.deposit()](#apurse-deposit-payment-optamount)** or -**[aPurse.withdraw()](#apurse-withdraw-amount)** on it. A **Purse** can be empty, which if it holds +**[aPurse.deposit()](#apurse-deposit-payment-optamount)** or +**[aPurse.withdraw()](#apurse-withdraw-amount)** on it. A **Purse** can be empty, which if it holds a fungible currency means it has a value of 0. If it holds a non-fungible asset (e.g., theater tickets), then the **Purse** simply doesn't contain any assets if it's empty. -Unlike **[Payments](./payment)**, **Purses** are not meant to be sent to others. +Unlike **[Payments](./payment)**, **Purses** are not meant to be sent to others. To transfer digital assets, you should withdraw a **Payment** from a **Purse** and send the **Payment** to another party. ## aPurse.getCurrentAmount() + - Returns: **[Amount](./ertp-data-types#amount)** Returns the **Purse**'s current balance as an **Amount**. @@ -50,35 +52,37 @@ const currentBalance = quatloosPurse.getCurrentAmount(); ``` ## aPurse.getCurrentAmountNotifier() + - Returns: **Notifier<[Amount](./ertp-data-types#amount)>** Returns a lossy notifier for changes to this **Purse**'s balance. For more details, see [Notifiers](/guides/js-programming/notifiers). ```js -const notifier = purse.getCurrentAmountNotifier(); -let nextUpdate = notifier.getUpdateSince(); +const notifier = purse.getCurrentAmountNotifier() +let nextUpdate = notifier.getUpdateSince() const checkNotifier = async () => { - const { value: balance, updateCount } = await nextUpdate; - nextUpdate = notifier.getUpdateSince(updateCount); -}; + const { value: balance, updateCount } = await nextUpdate + nextUpdate = notifier.getUpdateSince(updateCount) +} ``` ## aPurse.deposit(payment, optAmount?) + - **payment**: **[Payment](./payment)** -- **optAmount**: **[Amount](./ertp-data-types#amount)** - Optional. +- **optAmount**: **[Amount](./ertp-data-types#amount)** - Optional. - Returns: **Amount** -Deposit all the contents of *payment* into the **Purse**, returning an **Amount** describing the -**Payment**'s digital assets (i.e. the deposited amount). If the optional argument *optAmount* does not equal the balance of -*payment*, or if *payment* is a promise, this method throws an error. +Deposit all the contents of _payment_ into the **Purse**, returning an **Amount** describing the +**Payment**'s digital assets (i.e. the deposited amount). If the optional argument _optAmount_ does not equal the balance of +_payment_, or if _payment_ is a promise, this method throws an error. -While the above applies to local and remote **Purses**, for remote **Purses** there may be effects on -this operation due to the use of promises and asynchronicity. You -have to have a non-promise **Payment** before calling **aPurse.deposit()**. -When you call **aPurse.deposit()** you get a response back (after waiting for the round trip) -telling you if it succeeded. All later arriving calls see the value has been transferred +While the above applies to local and remote **Purses**, for remote **Purses** there may be effects on +this operation due to the use of promises and asynchronicity. You +have to have a non-promise **Payment** before calling **aPurse.deposit()**. +When you call **aPurse.deposit()** you get a response back (after waiting for the round trip) +telling you if it succeeded. All later arriving calls see the value has been transferred into the **Purse**, and the **Payment** is no longer valid. If any withdrawals are waiting for promises to resolve, a deposit operation @@ -86,18 +90,23 @@ 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 quatloosPurse = quatloosIssuer.makeEmptyPurse(); -const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 123n)); -const quatloos123 = AmountMath.make(quatloosBrand, 123n); - -// Deposit a payment for 123 Quatloos into the Purse. -const depositAmountA = quatloosPurse.deposit(payment, quatloos123); - -const secondPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 100n)); +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) + +// Deposit a payment for 123 Quatloos into the Purse. +const depositAmountA = quatloosPurse.deposit(payment, quatloos123) + +const secondPayment = quatloosMint.mintPayment( + AmountMath.make(quatloosBrand, 100n) +) // Throws error -const depositAmountB = quatloosPurse.deposit(secondPayment, quatloos123); +const depositAmountB = quatloosPurse.deposit(secondPayment, quatloos123) ``` ## aPurse.withdraw(amount) @@ -107,61 +116,63 @@ const depositAmountB = quatloosPurse.deposit(secondPayment, quatloos123); Withdraws the specified **Amount** of digital assets from the **Purse** into a new **Payment** object. -If the call succeeds, it immediately extracts the value into a new **Payment**. +If the call succeeds, it immediately extracts the value into a new **Payment**. The caller won't get the new **Payment** until a later turn, since the call is (nearly always) remote. But as soon as the message is processed, the value is gone from the **Purse**. ```js // Create a Purse and give it a balance of 10 Quatloos -const { issuer, mint, brand } = makeIssuerKit('quatloos'); -const purse = issuer.makeEmptyPurse(); -const payment = mint.mintPayment(AmountMath.make(brand, 10n)); -const quatloos10 = AmountMath.make(brand, 10n); -purse.deposit(payment, quatloos10); +const { issuer, mint, brand } = makeIssuerKit('quatloos') +const purse = issuer.makeEmptyPurse() +const payment = mint.mintPayment(AmountMath.make(brand, 10n)) +const quatloos10 = AmountMath.make(brand, 10n) +purse.deposit(payment, quatloos10) // Withdraw an amount of 3 from the Purse -const quatloos3 = AmountMath.make(brand, 3n); -const withdrawalPayment = purse.withdraw(quatloos3); +const quatloos3 = AmountMath.make(brand, 3n) +const withdrawalPayment = purse.withdraw(quatloos3) // The balance of the withdrawal payment is 3 Quatloos -issuer.getAmountOf(withdrawalPayment); +issuer.getAmountOf(withdrawalPayment) // The new balance of the Purse is 7 Quatloos -purse.getCurrentAmount(); +purse.getCurrentAmount() ``` ## aPurse.getAllegedBrand() + - Returns: **[Brand](./brand)** -Returns an alleged brand (Note: a **Brand**, not a **String** as **allegedName()** methods do), -indicating what kind of digital asset the **Purse** purports to hold. This can identify the +Returns an alleged brand (Note: a **Brand**, not a **String** as **allegedName()** methods do), +indicating what kind of digital asset the **Purse** purports to hold. This can identify the **Purse**'s **Brand** if the **Purse** was made by a trusted **[Issuer](./issuer)** using **[anIssuer.makeEmptyPurse()](./issuer#anissuer-makeemptypurse)**. ```js -const purseBrand = quatloosPurse.getAllegedBrand(); +const purseBrand = quatloosPurse.getAllegedBrand() ``` ## aPurse.getDepositFacet() + - Returns: **DepositFacet** -Creates and returns a **DepositFacet**, a new deposit-only facet of the **Purse** that allows +Creates and returns a **DepositFacet**, a new deposit-only facet of the **Purse** that allows other parties to deposit **[Payments](./payment)** into the **Purse** without the ability to check the **Purse's** balance or withdraw from it. This makes it a safe way to let other people send you **Payments**. You can only deposit a **Payment** into a **DepositFacet** that's the same **[Brand](./brand)** as the original **Purse**. - + ```js -const depositOnlyFacet = purse.getDepositFacet(); +const depositOnlyFacet = purse.getDepositFacet() // Give depositOnlyFacet to someone else. Anyone with a deposit facet reference can tell it to receive // a payment, thus depositing the payment assets in the Purse associated with the deposit facet. -depositOnlyFacet.receive(payment); +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** +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** must be of the same **Brand** as what the **Purse** holds. Note the difference in method names for adding assets between a **Purse** and its **DepositFacet**. @@ -169,19 +180,20 @@ To add assets to a **Purse** directly, you use **aPurse.deposit()**. To add asse to a **Purse** via its **DepositFacet**, you use **aDepositFacet.receive()**. ## aDepositFacet.receive(payment, optAmount?) + - **payment**: **[Payment](./payment)** - **optAmount**: **[Amount](./ertp-data-types#amount)** - Optional. - Returns **Amount** -The **DepositFacet** takes the **Payment** and adds it to the balance of the **DepositFacet**'s associated **Purse**. +The **DepositFacet** takes the **Payment** and adds it to the balance of the **DepositFacet**'s associated **Purse**. -If the optional argument *optAmount* does not equal the balance of -*payment*, or if *payment* is an unresolved promise, this method throws an error. +If the optional argument _optAmount_ does not equal the balance of +_payment_, or if _payment_ is an unresolved promise, this method throws an error. ```js -const depositOnlyFacet = purse.getDepositFacet(); +const depositOnlyFacet = purse.getDepositFacet() // Give depositOnlyFacet to someone else. Anyone with a deposit facet reference can tell it to receive // a payment, thus depositing the payment assets in the Purse associated with the deposit facet. -depositOnlyFacet.receive(payment); +depositOnlyFacet.receive(payment) ``` diff --git a/main/reference/repl/index.md b/main/reference/repl/index.md index b47acb360..c3b8c588d 100644 --- a/main/reference/repl/index.md +++ b/main/reference/repl/index.md @@ -6,37 +6,38 @@ If you are instead looking for information about `node` or the Node.js REPL, see ## Introduction -When you run `agoric start --reset`, you start a local *ag-solo*. +When you run `agoric start --reset`, you start a local _ag-solo_. -You use `agoric start` to start what we call an *ag-solo*, which is a -single personal local Agoric node. You need an ag-solo running on your -machine to interact with Agoric network services, whether a built-in -simulated chain (also started by `agoric start`), or a fully-decentralized public Agoric -blockchain. +You use `agoric start` to start what we call an _ag-solo_, which is a +single personal local Agoric node. You need an ag-solo running on your +machine to interact with Agoric network services, whether a built-in +simulated chain (also started by `agoric start`), or a fully-decentralized public Agoric +blockchain. -All deployment happens via the local running Agoric process. This is usually the -ag-solo process, and frequently referred to as that or just as ag-solo. It is also +All deployment happens via the local running Agoric process. This is usually the +ag-solo process, and frequently referred to as that or just as ag-solo. It is also sometimes described as/called an Agoric VM or a local server. An ag-solo communicates with either a locally running or remote chain. This local process (the ag-solo) -has a home object, which contains references to services on-chain, including Zoe, the -Board for sharing objects, and an application user's Wallet, among others. Developers can +has a home object, which contains references to services on-chain, including Zoe, the +Board for sharing objects, and an application user's Wallet, among others. Developers can use these service references to call the service's associated API commands. -Contract code starts in a file on a user's computer, either written by them or -imported from `agoric/zoe`. The code is *bundled*; turned into a particularly formatted +Contract code starts in a file on a user's computer, either written by them or +imported from `agoric/zoe`. The code is _bundled_; turned into a particularly formatted blob of code that exists in memory while a deploy script is running. When `E(zoe).install()` is -called, the blob is sent to and stored on-chain so that Zoe can access it. +called, the blob is sent to and stored on-chain so that Zoe can access it. -An ag-solo has an associated REPL (*Read-Eval-Print Loop*). From the REPL and the `home` -object, developers can use all the on-chain commands that deployment scripts use to +An ag-solo has an associated REPL (_Read-Eval-Print Loop_). From the REPL and the `home` +object, developers can use all the on-chain commands that deployment scripts use to deploy contracts and Dapps. In addition to the on-chain commands, they can also run -any other JavaScript commands from the REPL. +any other JavaScript commands from the REPL. ## Accessing the REPL Once an ag-solo is running and on-chain, you can access its associated REPL -in two ways. +in two ways. + - In a browser tab, go to `localhost:8000`. Depending on the browser's width, you will see the Wallet UI and REPL either in separate columns or separate rows. @@ -51,8 +52,8 @@ in two ways. ## Using the REPL -You can run JavaScript commands from the REPL. You can also use the REPL's -`home` object's predefined connections to other objects and services. To see what’s +You can run JavaScript commands from the REPL. You can also use the REPL's +`home` object's predefined connections to other objects and services. To see what’s available, just type `home` into the REPL: ![home](./assets/home.png) @@ -61,6 +62,7 @@ available, just type `home` into the REPL: Command[1] home History[1] {"chainTimerService":[Presence o-50],"contractHost":[Presence o-52],"ibcport":[Presence o-53],"registrar":[Presence o-54],"registry":[Presence o-55],"zoe":[Presence o-56],"localTimerService":[Presence o-57],"uploads":[Presence o-58],"spawner":[Presence o-59],"wallet":[Presence o-60],"network":[Presence o-61],"http":[Presence o-62]} ``` + The results of what is entered into the REPL is saved under `history[N]` The following sections describe the `home` objects developers can use. Click on the @@ -70,37 +72,45 @@ are listed together in the final section. External developers should ignore them them. ### [`wallet`](../wallet-api/) + Holds on-chain digital assets and object capabilities on behalf of the user. The header link takes you to the standard non-REPL specific `wallet` API documentation. When calling -`wallet` API methods from the REPL, `wallet` must be prefaced by `home.` and use `E()`. For -example, `E(home.wallet).getPurses()`. [Full Wallet API documentation.](/guides/wallet/) +`wallet` API methods from the REPL, `wallet` must be prefaced by `home.` and use `E()`. For +example, `E(home.wallet).getPurses()`. [Full Wallet API documentation.](/guides/wallet/) ### [`chainTimerService`](./timerServices) + On-chain time authority used to schedule events. [Full `chainTimerService` documentation.](./timerServices) ### [`localTimerService`](./timerServices) + Local off-chain time authority used to schedule events. [Full `localTimerService` documentation.](./timerServices) ### [`board`](./board) + Shared on-chain location where users can post generally accessible values. [Full `board` documentation.](./board) ### [`ibcport`](./networking) -IBC implementation that lets vats open and close listening ports, -connect and disconnect to/from remote ports, and send and receive + +IBC implementation that lets vats open and close listening ports, +connect and disconnect to/from remote ports, and send and receive data over those connections. [Full `ibcport` documentation.](./networking) ### [`zoe`](../zoe-api/zoe) + Deploy and interact with smart contracts. Zoe protects smart contract users by escrowing -digital assets and guaranteeing users get either what they want or get a refund of what -they escrowed. Even if the contract is buggy or malicious. The header link takes you to the -standard, non-REPL specific, `zoe` API documentation. When calling any of the `zoe` API -methods from the REPL, `zoe` must be prefaced by `home.` and use `E()`. For +digital assets and guaranteeing users get either what they want or get a refund of what +they escrowed. Even if the contract is buggy or malicious. The header link takes you to the +standard, non-REPL specific, `zoe` API documentation. When calling any of the `zoe` API +methods from the REPL, `zoe` must be prefaced by `home.` and use `E()`. For example, `E(home.zoe).getFoo()`. [Full Zoe API documentation.](../zoe-api/zoe) ### [`priceAuthority`](./priceAuthority) + Get price quotes for pairs of digital assets. [Full `priceAuthority` documentation.](./priceAuthority) ### [`scratch`](./scratch) + An off-chain, private, place to store key-value pairs on your ag-solo for later use. [Full `scratch` documentation.](./scratch) ### Deprecated and Internal-Only Objects @@ -108,7 +118,7 @@ An off-chain, private, place to store key-value pairs on your ag-solo for later - `contractHost`: Replaced by the `spawner` object. - `faucet`: Internal for chain setup. - `http`: `api/deploy.js` uses this to install new HTTP and WebSocket handlers in an - ag-solo. You should not need to use it. + ag-solo. You should not need to use it. - `network`: Privileged object for internal use. [Full Network documentation.](./networking) - `plugin`: Privileged object for internal use. - `priceAuthorityAdmin`: Privileged object for internal use. @@ -117,4 +127,3 @@ An off-chain, private, place to store key-value pairs on your ag-solo for later - `spawner`: Privileged object for internal use. - `uploads`: Deprecated name for `scratch`. - `vattp`: Privileged object for internal use. - diff --git a/main/reference/repl/networking.md b/main/reference/repl/networking.md index a77e5d85c..16e32d1ac 100644 --- a/main/reference/repl/networking.md +++ b/main/reference/repl/networking.md @@ -1,4 +1,5 @@ # Network API +