diff --git a/main/.vitepress/config.mjs b/main/.vitepress/config.mjs index 9230f9981..0f9b6ed71 100644 --- a/main/.vitepress/config.mjs +++ b/main/.vitepress/config.mjs @@ -224,15 +224,15 @@ export default defineConfig({ link: '/guides/coreeval/', }, { - text: 'Declaring Required Capabilities', - link: '/guides/coreeval/permissions', + text: 'Write Code to Deploy a Contract', + link: '/guides/coreeval/proposal', }, { - text: 'Code the Proposal', - link: '/guides/coreeval/proposal', + text: 'Declare Required Capabilities', + link: '/guides/coreeval/permissions', }, { - text: 'Deploy a Governance Proposal to a Local Testnet', + text: 'Submit Transactions', link: '/guides/coreeval/local-testnet', }, ], diff --git a/main/guides/agoric-cli/agd-query-tx.md b/main/guides/agoric-cli/agd-query-tx.md index dbfb81357..dccd50670 100644 --- a/main/guides/agoric-cli/agd-query-tx.md +++ b/main/guides/agoric-cli/agd-query-tx.md @@ -43,7 +43,7 @@ Flags: In most cases, `agd query ...` is followed by a module name such as `bank`. An exception is `agd status`: -### agd status +## agd status Query remote node for status @@ -93,7 +93,7 @@ Error: post failed: Post "https://devnet.rpc.agoric.net": dial tcp: address devn ::: -### agd query bank balances +## agd query bank balances Query for account balances by address @@ -116,7 +116,7 @@ $ agd query bank balances $addr -o json {"balances":[{"denom":"ubld","amount":"331000000"},{"denom":"uist","amount":"4854000000"}],...} ``` -### agd query gov proposals +## agd query gov proposals Query for a all paginated proposals that match optional filters: @@ -135,10 +135,26 @@ $ agd query gov proposals --output json | \ Making transactions requires setting up an **account** with a private key for signing. The [basic dapp local chain](../getting-started/#starting-a-local-agoric-blockchain) container has a number of keys set up for use with `--keyring-backend=test`. Use `agd keys list --keyring-backend=test` to see them. For accounts that control real negotiable assets, using -a consumer grade wallet such as Keplr is more straightforward. +a [consumer grade wallet](https://agoric.com/ecosystem/category/wallets) such as [Keplr](https://www.keplr.app/) is more straightforward. _Consider a hardware wallet such as a Ledger as well._ -### agd tx bank send +## agd keys add + +Derive a new private key and encrypt to disk. + +Usage: + +``` + agd keys add [flags] +``` + +If run with `-i`, it will prompt the user for BIP44 path, BIP39 mnemonic, and passphrase. +The flag `--recover` allows one to recover a key from a seed passphrase. + +- For compatibility with the ledger cosmos app, use `--ledger --coin-type 118` rather than the default 564. +- To avoid signature prompts for testing, use `--keyring-backend=test` rather than the default, which is to use operating system key management. Use `--home=DIR` to store these keys under a different directory than `$HOME/.agoric`. + +## agd tx bank send Send funds from one account to another. @@ -155,7 +171,7 @@ $ agd tx bank send $src $dest $amt \ As usual, use `agd tx bank send --help` for documentation on flags such as `--yes`, `-b`, etc. -### agd tx swingset install-bundle +## agd tx swingset install-bundle ``` agd tx swingset install-bundle --compress "@bundle1.json" \ @@ -165,7 +181,7 @@ agd tx swingset install-bundle --compress "@bundle1.json" \ See also the [Agoric Gov Proposal Builder](https://cosgov.org/) web interface, especially for understanding storage fees. -### agd tx gov submit-proposal swingset-core-eval +## agd tx gov submit-proposal swingset-core-eval Usage: @@ -186,3 +202,24 @@ agd tx gov submit-proposal swingset-core-eval "$PERMIT" "$SCRIPT" \ ``` The [Agoric Gov Proposal Builder](https://cosgov.org/) web interface provides a nice interface for this as well. + +## agd tx gov vote + +Submit a vote for an active proposal. You can +find the proposal-id by running [agd query gov proposals](#agd-query-gov-proposals). + +Usage: + +``` + agd tx gov vote [proposal-id] [option] [flags] +``` + +Example: + +```sh +PROPOSAL=13 +agd tx gov vote $PROPOSAL yes \ + --keyring-backend test --chain-id agoriclocal --from validator \ + --gas auto --gas-adjustment 1.4 \ + --broadcast-mode block --output json --yes +``` diff --git a/main/guides/assets/cosgov-core-eval.png b/main/guides/assets/cosgov-core-eval.png new file mode 100644 index 000000000..2d80e2967 Binary files /dev/null and b/main/guides/assets/cosgov-core-eval.png differ diff --git a/main/guides/assets/cosgov-install-bundle.png b/main/guides/assets/cosgov-install-bundle.png new file mode 100644 index 000000000..5dab15eba Binary files /dev/null and b/main/guides/assets/cosgov-install-bundle.png differ diff --git a/main/guides/coreeval/index.md b/main/guides/coreeval/index.md index a39c64caf..0efab059a 100644 --- a/main/guides/coreeval/index.md +++ b/main/guides/coreeval/index.md @@ -5,10 +5,10 @@ permissionless [contract installation with Zoe](/guides/zoe/#contract-installati is limited to development environments. Until then, permission to deploy contracts can be granted using an Agoric extension to [Cosmos SDK Governance](https://hub.cosmos.network/main/delegators/delegator-guide-cli.html#participating-in-governance) called `swingset.CoreEval`. As discussed in [governance using Hardened JavaScript: swingset\.CoreEval](https://community.agoric.com/t/bld-staker-governance-using-hardened-javascript-swingset-coreeval/99), -if such a proposal passes, its JavaScript code is run with ocaps extracted using the proposal's declared capabilities, which the code can combine to perform privileged tasks. +if such a proposal passes, its JavaScript code is run with ocaps extracted using the proposal's permitted capabilities, which the code can combine to perform privileged tasks. -To do try it out in a local testnet chain: +To make a proposal to deploy a contract: -1. [Declare the capabilities that the proposal will require](./permissions). -2. [Code the proposal itself](./proposal). -3. [Deploy the proposal to a local testnet](./local-testnet). +1. [Write JavaScript code to deploy the contract](./proposal.md). +2. [Declare the capabilities that the script requires](./permissions.md). +3. [Submit transactions to install and deploy the contract](./local-testnet.md). diff --git a/main/guides/coreeval/local-testnet.md b/main/guides/coreeval/local-testnet.md index da4909b4b..abb4962d2 100644 --- a/main/guides/coreeval/local-testnet.md +++ b/main/guides/coreeval/local-testnet.md @@ -1,45 +1,221 @@ -# Deploy a Governance Proposal to a Local Testnet +# Deploying Contracts using Core Eval Proposals -To create, start, and deploy an Agoric governance proposal to a local Agoric Testnet, do the following: +To deploy a contract: -1. If you're using a Mac, ensure that you have [Xcode](https://apps.apple.com/us/app/xcode/id497799835) installed. -2. Create a project folder that will allow you to run a local blockchain: +1. Check access and governance norms for your target network / chain. + - `agoriclocal` is operated by you and entirely under your control. + - [testnets such as `devnet`](#deploying-to-testnets-devnet-emerynet) are shared resources. + - _Mainnet deployment is out of scope of this document; see [Mainnet 2 Deployment Checklist #8280](https://github.com/Agoric/agoric-sdk/discussions/8280)._ +2. Build the transaction contents. +3. Sign and broadcast the transactions using a web UI or CLI tools. - ```jsx - agoric init - ``` - - For example, if you wanted to run your local blockchain from a folder named "Demo", you'd run this command: - - ```jsx - agoric init Demo - ``` +## Deploying to a local agoric blockchain - **Note:** Your project folder should *not* be located within your local clone of the agoric SDK. +1. Ensure that you have [started your local agoric blockchain](../getting-started/#starting-a-local-agoric-blockchain): + use `yarn docker:logs` to check that your chain is running; if not, use `yarn start:docker` to start it. -3. Install additional dependencies by entering your project folder and running the following command. +2. Use `yarn start` to automatically + 1. Build the transaction contents (contract bundle, core eval script). + 2. Ensure you have enough IST to pay to for the `install-bundle` transaction. + 3. Sign and broadcast the transactions (`install-bundle`, `submit-proposal`), plus + 4. Vote on the submitted proposal. - ```jsx - cd - agoric install - ``` +## Bundling Contracts and Core Eval Scripts with Rollup Plugins -4. Start the chain by running the following command. (**Note:** You should still be located within your project folder.) +Core eval scripts are evaluated, not loaded as modules; so any `import` or `export` declarations are syntax errors. In **dapp-agoric-basics**, we use [rollup](https://rollupjs.org/) to support developing +a core-eval script and permit as a module: - ```jsx - agoric start local-chain --verbose --reset - ``` +- `import { E } from '@endo/far'` + A bundle strips this declaration during bundling + since the core-eval scope includes exports of `@endo/far`. +- `bundleID = ...` is replaced using updated/cached bundle hash +- `main` is appended as the script completion value +- the `permit` export is emitted to a `.json` file -5. Wait for the first block to be produced. -6. Open a second terminal. -7. Within the second terminal, navigate to `/bin` and submit the governance proposal by running the following command. (Make sure to enter "y" when asked to confirm the transaction.) +See [rollup.config.mjs](https://github.com/Agoric/dapp-agoric-basics/blob/main/contract/rollup.config.mjs) for details on using the +`moduleToScript`, `configureBundleID`, and `emitPermit` rollup plug-ins. - ``` - ./agd --chain-id=agoriclocal --title= --description= --home=/_agstate/keys --keyring-backend=test --from=provision tx gov submit-proposal swingset-core-eval - ``` +Running it looks something like this: - For example, to deploy the PSM proposal referenced in the previous topics, run the following: +```console +dapp-agoric-basics/contract$ yarn build:deployer +yarn run v1.22.19 +$ rollup -c rollup.config.mjs - ``` - ./agd --chain-id=agoriclocal --title= --description= --home=/_agstate/keys --keyring-backend=test --from=provision tx gov submit-proposal swingset-core-eval ../packages/inter-protocol/test/psm/gov-add-psm-permit.json ../packages/inter-protocol/test/psm/gov-add-psm.js - ``` +./src/sell-concert-tickets.proposal.js → bundles/deploy-sell-concert-tickets.js... +bundles add: sell-concert-tickets from ./src/sell-concert-tickets.contract.js +bundles bundled 141 files in bundle-sell-concert-tickets.js at 2024-03-09T16:22:08.531Z +created bundles/deploy-sell-concert-tickets.js in 2.4s +... + +dapp-agoric-basics/contract$ cd bundles +dapp-agoric-basics/contract/bundles$ ls deploy-sell* bundle-sell* +bundle-sell-concert-tickets.js deploy-sell-concert-tickets-permit.json deploy-sell-concert-tickets.js +``` + +## Ensuring you have enough IST to install a bundle + +The price to install a contract is subject to chain governance. +As of [proposal #61](https://agoric.explorers.guru/proposal/61) Nov 2023, it's 0.02IST per kilobyte. + +On a local chain, `yarn start` includes a `yarn docker:make mint100` step to get 100 IST, which should be enough. _`mint100` works by sending some ATOM from a `validator` account and using the ATOM to open a vault._ + +## Installing, submitting to agoriclocal with `scripts/deploy-contract.js` + +In **dapp-agoric-basics**, [contract/scripts/deploy-contract.js](https://github.com/Agoric/dapp-agoric-basics/blob/main/contract/scripts/deploy-contract.js) automates much of the process. `yarn start` automatically runs it. The `--install src/sell-concert-tickets.contract.js` option tells it to install the contract (using [agd tx swingset install-bundle](/guides/agoric-cli/agd-query-tx#agd-tx-swingset-install-bundle) from within the docker container), after bundling it if necessary: + +``` +dapp-agoric-basics/contract$ yarn start +yarn run v1.22.19 +$ yarn docker:make clean start-contract print-key +$ docker compose exec agd make -C /workspace/contract clean start-contract print-key +make: Entering directory '/workspace/contract' +yarn node ./scripts/deploy-contract.js --service . \ + --install src/sell-concert-tickets.contract.js \ + --eval ./src/sell-concert-tickets.proposal.js +yarn node v1.22.21 +bundles add: sell-concert-tickets from src/sell-concert-tickets.contract.js +bundles bundled 141 files in bundle-sell-concert-tickets.js at 2024-03-09T16:49:54.859Z +installing sell-concert-tickets b1-8dd96 +$$$ agd tx swingset install-bundle @bundles/bundle-sell-concert-tickets.json --gas auto --keyring-backend test --chain-id agoriclocal --from agoric1uddt8l5y2sfanzal42358az5dus563f2wk7ssm --broadcast-mode block --gas auto --gas-adjustment 1.4 --yes --output json +gas estimate: 53922087 +{ + id: 'b1-8dd96', + installTx: 'F18DF8CE296D29BD0283780C402D7C3D22345E13DD04D6B12CEE6AE5B4B9212B', + height: '1594' +} +follow { delay: 2 } ... +{ + name: 'sell-concert-tickets', + id: 'b1-8dd96', + installHeight: '1594', + installed: true +} +... +``` + +As a by-product, it writes a `bundles/bundle-sell-concert-tickets.json.installed` file. If you run `yarn start` again, `deploy-contract.js` uses the `Makefile` to check whether the `.installed` file is up-to-date and only repeats `agd tx swingset install-bundle` if you change the contract. + +The `--eval ./src/sell-concert-tickets.proposal.js` option tells it to submit a `swingset-core-eval` governance proposal, after building the script and permit if necessary: + +```console +... +submit proposal sell-concert-tickets +[ + 'bundles/deploy-sell-concert-tickets-permit.json', + 'bundles/deploy-sell-concert-tickets.js' +] +await tx [ + 'bundles/deploy-sell-concert-tickets-permit.json', + 'bundles/deploy-sell-concert-tickets.js' +] +$$$ agd tx gov submit-proposal swingset-core-eval bundles/deploy-sell-concert-tickets-permit.json bundles/deploy-sell-concert-tickets.js --title sell-concert-tickets --description sell-concert-tickets --deposit 10000000ubld --keyring-backend test --chain-id agoriclocal --from agoric1jkfphfd8fd7vd7erdttne3k4c0rucu8l22ndhk --broadcast-mode block --gas auto --gas-adjustment 1.4 --yes --output json +gas estimate: 1443920 +{ + txhash: '010C912FFC47AE59C33A36906DA5096C8EA8A64247699ABF958F58600E57C59E', + code: 0, + height: '1626', + gas_used: '1028352' +} +... +``` + +The `deploy-contract.js` automates adding a deposit and voting on the proposal and waiting for voting to complete: + +``` +... +await voteLatestProposalAndWait [ + 'bundles/deploy-sell-concert-tickets-permit.json', + 'bundles/deploy-sell-concert-tickets.js' +] +{ before: 'deposit', on: '13', delay: 1 } ... +$$$ agd tx gov deposit 13 50000000ubld --keyring-backend test --chain-id agoriclocal --from validator --broadcast-mode block --gas auto --gas-adjustment 1.4 --yes --output json +gas estimate: 418391 +$$$ agd tx gov vote 13 yes --keyring-backend test --chain-id agoriclocal --from validator --broadcast-mode block --gas auto --gas-adjustment 1.4 --yes --output json +gas estimate: 105278 +Waiting for proposal 13 to pass (status=PROPOSAL_STATUS_VOTING_PERIOD) +... +Waiting for proposal 13 to pass (status=PROPOSAL_STATUS_PASSED) +13 2024-03-09T16:50:36.973940196Z PROPOSAL_STATUS_PASSED +{ step: 'run', propsal: '13', delay: 1 } ... +{ + proposal_id: '13', + content: { + '@type': '/agoric.swingset.CoreEvalProposal', + title: 'sell-concert-tickets', + description: 'sell-concert-tickets', + evals: [ [Object] ] + }, + status: 'PROPOSAL_STATUS_PASSED', + final_tally_result: { yes: '5000000000', abstain: '0', no: '0', no_with_veto: '0' }, + submit_time: '2024-03-09T16:50:26.973940196Z', + deposit_end_time: '2024-03-11T16:50:26.973940196Z', + total_deposit: [ { denom: 'ubld', amount: '60000000' } ], + voting_start_time: '2024-03-09T16:50:26.973940196Z', + voting_end_time: '2024-03-09T16:50:36.973940196Z' +} +``` + +When the proposal passes, `deploy-contract.js` writes a `deploy-sell-concert-tickets.js.done` file to avoid running it again unnecessarily. + +::: tip Troubleshooting Local Core Eval Proposals + +Use `yarn docker:logs` to check for any errors in the execution of the core eval script. + +::: + +## Deploying to testnets (devnet, emerynet, ...) + +For testnet access and governance norms, see [Guide to Agoric Testnets \- Agoric Community Forum](https://community.agoric.com/t/guide-to-agoric-testnets/515). In particular: + +- Community developers who are interested to move beyond testing in a local chain are welcome to try their apps on **devnet**. https://devnet.agoric.net/ provides details such as curreint chain-id, RPC endpoints, software version, explorer, and faucet. +- Feel free to join us at [office hours](https://github.com/Agoric/agoric-sdk/wiki/Office-Hours), whether you're just getting started or you're struggling with a detailed issue. +- Let the community know what you propose to deploy by posting to [community.agoric.com](https://community.agoric.com/). +- Choose appropriate and distinct names for any entries in the [agoricNames](../integration/name-services#agoricnames-agoricnamesadmin-well-known-names) name service. +- Chat with peers on [Agoric Discord](https://agoric.com/discord). See [#get-roles](https://discord.com/channels/585576150827532298/966411985833050164) to add roles for access to channels such as `#dev` and `#devnet`. +- For troubleshooting, access to network node logs is important. Contact a [devnet validator](https://devnet.explorer.agoric.net/agoric/uptime) or [operate your own follower node](https://github.com/Agoric/agoric-sdk/wiki/Validator-Guide-for-Devnet). +- `emerynet` is primarily used for the qualification of production-ready software before it is promoted to mainnet. + +In [Getting Started](/guides/getting-started/), we [set up a keplr wallet demo account](/guides/getting-started/#setting-up-a-keplr-wallet-demo-account) with a previously generated key and address for use on the `agoriclocal` chain. You should have your own account and address for **devnet** and other chains. Generate a key and address with [Keplr](https://www.keplr.app/) or [other wallets](https://agoric.com/ecosystem/category/wallets) or with [agd keys add](../agoric-cli/agd-query-tx#agd-keys-add). + +With the [devnet faucet](https://devnet.faucet.agoric.net/), you can + +- get BLD to stake and vote on your proposal +- get IST to pay for contract storage and execution. + +### Installing, submitting with **cosgov** Web UI + +The Cosmos Proposal Builder at [cosgov.org](https://cosgov.org) is a convenient way to submit the transactions. It supports deploying to the local chain as well as **devnet** etc. + +You'll need a `.json` formatted contract bundle: + +```console +dapp-agoric-basics/contract$ yarn bundle-source --cache-json bundles/ src/sell-concert-tickets.contract.js sell-concert-tickets +bundles/ add: sell-concert-tickets from src/sell-concert-tickets.contract.js +bundles/ bundled 141 files in bundle-sell-concert-tickets.json at 2024-03-09T20:48:43.784Z +``` + +Install Bundle screenshot + +Then drop your permit and core eval script on the **CoreEval Proposal** tab: + +Install Bundle screenshot + +Note the required deposit and voting period. + +## Voting on Core Eval Proposals + +As usual with cosmos governance, stakers vote on proposals. A deposit is required to start the voting period. The deposit is returned unless the proposal is vetoed. Governance parameters such as the minimum deposit and voting period are subject to chain governance. Use an explorer or `agd query gov params` to find the current value. Typical values are: + +| chain | voting time | deposit (min) | +| ------------- | ----------- | ------------- | +| `agoriclocal` | 10 sec | 1 BLD | +| **devnet** | 5 min | 1 BLD | +| **emerynet** | 2 hrs | 1 BLD | +| **mainnet** | 3 days | 5000 BLD | + +On **devnet**, it's best to get others to vote on your proposal as well, +though if your community post is well received, it's reasonable to +stake enough BLD to unilaterally pass your proposal. + +To vote on a proposal in devnet, find it among [Governance Proposals](https://devnet.explorer.agoric.net/agoric/gov) in the devnet explorer and use Keplr to vote. Or use [agd tx gov vote](../agoric-cli/agd-query-tx.md#agd-tx-gov-vote). diff --git a/main/guides/coreeval/permissions.md b/main/guides/coreeval/permissions.md index 55d41d75b..56730f990 100644 --- a/main/guides/coreeval/permissions.md +++ b/main/guides/coreeval/permissions.md @@ -1,96 +1,54 @@ # Declaring Required Capabilities -Write a json file declaring the capabilities that the proposal will need. For example, -[gov-add-psm-permit.json](https://github.com/Agoric/agoric-sdk/blob/master/packages/inter-protocol/test/psm/gov-add-psm-permit.json) -declares capabilities needed to start a new PSM contract. Note that capabilities are declared using -their name as a property along with any truthy value. For example,`"bankManager": true` and -`"bankManager": 'hello'` are equivalent; they both set the `bankManager` capability. - -::: details Show example permissions file -``` -{ - "consume": { - "agoricNamesAdmin": true, - "bankManager": true, - "board": true, - "chainStorage": true, - "zoe": "zoe", - "feeMintAccess": "zoe", - "economicCommitteeCreatorFacet": "economicCommittee", - "econCharterKit": true, - "provisionPoolStartResult": true, - "psmKit": true, - "chainTimerService": "timer" - }, - "produce": { - "testFirstAnchorKit": true - }, - "installation": { - "consume": { - "contractGovernor": true, - "psm": true, - "mintHolder": true - } - }, - "instance": { - "consume": { - "economicCommittee": true - } +Most contract deployments don't need everything in `BootstrapPowers`. +Verifying by inspection that they don't use any more than they need +is notoriously difficult. So proposals come with +a `BootstrapManifestPermit` to declare an upper limit on the capabilities they access. For a property access `powers.P`, if the permit has `{ P: true }`, then the access succeeds. In fact, any _truthy_ value will do. +And recursively, a property access `powers.P.Q.R` succeeds if +the permit has `{ P: { Q: { R: true } } }`. + +The permit for `startSellConcertTicketsContract` is: + +```js +/** @type { import("@agoric/vats/src/core/lib-boot").BootstrapManifestPermit } */ +export const permit = harden({ + consume: { + agoricNames: true, + brandAuxPublisher: true, + startUpgradable: true, // to start contract and save adminFacet + zoe: true, // to get contract terms, including issuer/brand }, - "issuer": { - "produce": { - "DAI": true - }, - "consume": { - "DAI": true - } + installation: { + consume: { [contractName]: true }, + produce: { [contractName]: true }, }, - "brand": { - "consume": { - "DAI": true, - "IST": true - }, - "produce": { - "DAI": true - } - } -} -``` -::: - -## Top Level Consume Section - -In this section you need to set all the permissions that your contract will need to be able to use -(i.e., "consume"). Some of the listed permissions in the example PSM permission file above are of -general interest to most contracts, while others are more specific to the PSM contract. + instance: { produce: { [contractName]: true } }, + issuer: { consume: { IST: true }, produce: { Ticket: true } }, + brand: { consume: { IST: true }, produce: { Ticket: true } }, +}); -* **agoricNamesAdmin**: Grants write access to the Agoric name service. This permission is somewhat specific to the PSM contract. -* **bankManager**: Grants access to bank-related functionality within ERTP, allowing the contract to manipulate nearly all Cosmos assets in the chain. Because this capability is very powerful, this permission should only be granted to contracts that absolutely need it. -* **board**: Grants write access to the [board name service](/guides/wallet/index#the-agoric-board). -* **chainStorage**: Grants write access to the chain storage node, which is required when running `agd query` commands. Thus, most contracts will need access to this. -* **zoe**: When this permission is set, it grants access to the Zoe framework. All contracts will need access to this. -* **feeMintAccess**: When this permission is set, the contract will be able to create digital assets. Only contracts that mint privileged Agoric digital assets (i.e., not the unprivileged **[zcf.makeZCFMint()](/reference/zoe-api/zoe-contract-facet#zcf-makezcfmint-keyword-assetkind-displayinfo)**) will need access to this. -* **economicCommitteeCreatorFacet**, **econCharterKit**, **provisionPoolStartResult**: These 3 permissions are required by governed contracts. -* **chainTimerService**: When this permission is set, it grants access to the *chainTimerService*. All governed contracts need access to this so they know when a vote is complete. - -## Top Level Produce Section +export const main = startSellConcertTicketsContract; +``` -Specifies what, if anything, the contract produces. For example, the example PSM contract -produces *testFirstAnchorKit* which is used for testing purposes. +## Selected BootstrapPowers -## Installation Section +In the top level promise space, we have: -Specifies what well-known installations the contract requires. At a minimum, the contract itself should -be listed as an installation. Governed contracts should include a *contractGovernor* installation. +- **agoricNames**: read-only access to the [agoricNames](../integration/name-services.md#agoricnames-agoricnamesadmin-well-known-names) name service. -## Instance Section +- **board**: the [board](../integration/name-services.md#the-board-publishing-under-arbitrary-names) name service. + **Note: the board only grows; no mechanism to reclaim storage has been established.** -Specifies what instances, if any, the contract produces or consumes. +- **chainStorage**: to make storage nodes to write to vstorage. + **Warning: this includes the right to over-write previously allocated storage nodes.** -## Issuer Section +- **chainTimerService**: for getting the current timer and setting timer wake-ups; for example, at the conclusion of a governance vote. + **Note: this includes the right to schedule infinitely repeating events.** -Specifies what **[Issuers](/reference/ertp-api/issuer)**, if any, the contract produces or consumes. +- **agoricNamesAdmin**: admin / update access to **agoricNames** and the name hubs it contains. + **Warning: this includes the right to over-write existing bindings to instances, brands, etc.** -## Brand Section +- **bankManager**: to manage reflection of cosmos + assets as ERTP assets: to register an issuer to correspond to a denom or to get a bank of purses for any address. **Warning: this includes the right to spend assets for any account.** -Specifies what **[Brands](/reference/ertp-api/brand)**, if any, the contract produces or consumes. +- **zoe**: the Zoe service diff --git a/main/guides/coreeval/proposal.md b/main/guides/coreeval/proposal.md index eaf59b2e0..8059a5063 100644 --- a/main/guides/coreeval/proposal.md +++ b/main/guides/coreeval/proposal.md @@ -1,59 +1,154 @@ -# Code the Proposal +# Writing a Core Eval Script to Deploy a Contract -You will need to write a proposal script that runs the contract, and possibly does additional things -depending on your needs. (Usually these additional things will be dependent on a governance vote.) For -example, [gov-add-psm.js](https://github.com/Agoric/agoric-sdk/blob/master/packages/inter-protocol/test/psm/gov-add-psm.js) -is a proposal Agoric created for the PSM contract. It executes in an environment with globals such as -**[E](../js-programming/eventual-send)** and **[Far](../js-programming/far#far-api)** provided. +When a core eval script is evaluated, the completion value is expected +to be a function. The function is invoked with a _BootstrapPowers_ object +with various capabilities useful for deploying contracts. -::: details Show example proposal -```jsx -/* global startPSM */ -// @ts-nocheck +For example, in [dapp-agoric-basics](https://github.com/Agoric/dapp-agoric-basics/), +there's a contract to sell concert tickets. To deploy it, we + +- install the contract bundle as a Zoe installation +- start the contract instance, using the **IST** brand to make price amounts for terms +- publish the installation and instance in the [agoricNames](../integration/name-services.md#agoricnames-agoricnamesadmin-well-known-names) name service under the name **sellConcertTickets** + in the **installation** and **instance** section, respectively +- publish its **Ticket** issuer and brand in the **agoricNames** **issuer** and **brand** sections, respectively. + +After some preliminaries, ... + +::: details imports, makeTerms etc. + +```js +// @ts-check +import { allValues } from './objectTools.js'; +import { + AmountMath, + installContract, + startContract, +} from './platform-goals/start-contract.js'; + +const { Fail } = assert; +const IST_UNIT = 1_000_000n; + +export const makeInventory = (brand, baseUnit) => { + return { + frontRow: { + tradePrice: AmountMath.make(brand, baseUnit * 3n), + maxTickets: 3n, + }, + middleRow: { + tradePrice: AmountMath.make(brand, baseUnit * 2n), + maxTickets: 3n, + }, + lastRow: { + tradePrice: AmountMath.make(brand, baseUnit * 1n), + maxTickets: 3n, + }, + }; +}; + +export const makeTerms = (brand, baseUnit) => { + return { + inventory: makeInventory(brand, baseUnit), + }; +}; /** * @typedef {{ - * denom: string, - * keyword?: string, - * proposedName?: string, - * decimalPlaces?: number - * }} AnchorOptions + * brand: PromiseSpaceOf<{ Ticket: Brand }>; + * issuer: PromiseSpaceOf<{ Ticket: Issuer }>; + * instance: PromiseSpaceOf<{ sellConcertTickets: Instance }> + * }} SellTicketsSpace */ +``` -/** @type {AnchorOptions} */ -const DAI = { - keyword: 'DAI', - decimalPlaces: 18, - denom: 'ibc/toydai', - proposedName: 'Maker DAI', -}; +::: -const config = { - options: { anchorOptions: DAI }, - WantMintedFeeBP: 1n, - GiveMintedFeeBP: 3n, - MINT_LIMIT: 0n, -}; +... the function for deploying the contract is `startSellConcertTicketsContract`: -/** @param {unknown} permittedPowers see gov-add-psm-permit.json */ -const main = async permittedPowers => { - console.log('starting PSM:', DAI); +```js +const contractName = 'sellConcertTickets'; + +/** + * Core eval script to start contract + * + * @param {BootstrapPowers} permittedPowers + * @param {*} config + */ +export const startSellConcertTicketsContract = async (powers, config) => { + console.log('core eval for', contractName); const { - consume: { feeMintAccess: _, ...restC }, - ...restP - } = permittedPowers; - const noMinting = { consume: restC, ...restP }; - await Promise.all([ - startPSM.makeAnchorAsset(noMinting, { - options: { anchorOptions: DAI }, - }), - startPSM.startPSM(permittedPowers, config), - ]); - console.log('started PSM:', config); + // must be supplied by caller or template-replaced + bundleID = Fail`no bundleID`, + } = config?.options?.[contractName] ?? {}; + + const installation = await installContract(powers, { + name: contractName, + bundleID, + }); + + const ist = await allValues({ + brand: powers.brand.consume.IST, + issuer: powers.issuer.consume.IST, + }); + + const terms = makeTerms(ist.brand, 1n * IST_UNIT); + + await startContract(powers, { + name: contractName, + startArgs: { + installation, + issuerKeywordRecord: { Price: ist.issuer }, + terms, + }, + issuerNames: ['Ticket'], + }); + + console.log(contractName, '(re)started'); }; +``` + +A `BootstrapPowers` object is composed of several _promise spaces_. +A promise space is a `{ produce, consume }` pair where + +- `consume[name]` is a promise associated with a specific name. +- `produce[name].resolve(value)` resolves the promise associated with the same name by providing a value. + +There is one such space at the top, so that `powers.consume.zoe` is a promise for the Zoe Service. _This promise was resolved early in the execution of the virtual machine._ -// "export" from script -main; +There are also several more promise spaces one level down, including: +- `powers.installation` +- `powers.instance` +- `powers.issuer` +- `powers.brand` + +The `installContract` helper calls `E(zoe).installBundleID(bundleID)` to create an `Installation`, much like our earlier discussion of [Contract installation](http://localhost:8080/guides/zoe/#contract-installation). +It also calls `powers.installation[name].resolve(installation)`. + +```js +/** + * Given a bundleID and a permitted name, install a bundle and "produce" + * the installation, which also publishes it via agoricNames. + * + * @param {BootstrapPowers} powers - zoe, installation.produce[name] + * @param {{ name: string, bundleID: string }} opts + */ +export const installContract = async ( + { consume: { zoe }, installation: { produce: produceInstallation } }, + { name, bundleID }, +) => { + const installation = await E(zoe).installBundleID(bundleID); + produceInstallation[name].reset(); + produceInstallation[name].resolve(installation); + console.log(name, 'installed as', bundleID.slice(0, 8)); + return installation; +}; ``` -::: + +This `installation` promise space is linked to the `E(agoricNames).lookup('installation')` NameHub: when you call `produce[name].resolve(value)` on the installation promise space, it triggers an update in the NameHub. The update associates the provided name with the provided value so that `E(agoricNames).lookup('installation', name)` is a promise for `value`. + +Similarly, the `startContract()` helper does `E(zoe).startInstance(...)` as +in our earlier discussion of [starting a contract instance](../zoe/#starting-a-contract-instance). Plus, it "produces" the instance +so that it's available as `E(agoricNames).lookup('instance', 'sellConcertTickets')`. Once the contract is started, the helper +uses the `issuerNames` argument to get the `Ticket` issuer and +brand and "produces" them likewise as `E(agoricNames).lookup('issuer', 'Ticket')` and `E(agoricNames).lookup('brand', 'Ticket')`. diff --git a/main/guides/getting-started/index.md b/main/guides/getting-started/index.md index be057b144..0559bf68b 100644 --- a/main/guides/getting-started/index.md +++ b/main/guides/getting-started/index.md @@ -349,9 +349,11 @@ When the transaction is complete you will notice some IST has been debited from ![Finished transaction](./assets/new_006.png) Congratulations! You got your first Agoric dapp up and running! Now that you've got your first Agoric dapp up and running, let's focus on some key takeaways from this exercise: -- **Starting an Agoric Chain**: You have gained experience starting a local Agoric blockchain. + +- **Starting an Agoric Chain**: You have gained experience starting a local Agoric blockchain. - **Deploying a Contract**: You have deployed a smart contract onto the Agoric platform! + _Note: [testnet deployment, faucets, etc.](../coreeval/local-testnet) are discussed later._ - **Making an Offer**: Finally, you've learned to make an offer and seen that offer constraints are enforced by the Agoric platform. This means user interface can't attempt to fool a user by showing a 0.25 IST when actually charging them a much higer amount, such as 500 IST. It's also important to note that the contract cannot take the 0.25 IST without satisfying the want constraint, nor can the contract take more than the 0.25 cents in the give contraint.