diff --git a/packages/vats/src/bootstrap-behaviors.js b/packages/vats/src/bootstrap-behaviors.js index 1bb8b37c34c..df6ad5361aa 100644 --- a/packages/vats/src/bootstrap-behaviors.js +++ b/packages/vats/src/bootstrap-behaviors.js @@ -2,6 +2,9 @@ import { E, Far } from '@agoric/far'; import { AssetKind } from '@agoric/ertp'; import { makeNotifierKit } from '@agoric/notifier'; +import { installOnChain as installVaultFactoryOnChain } from '@agoric/run-protocol/bundles/install-on-chain.js'; + +import { makeStore } from '@agoric/store'; import { makeNameHubKit } from './nameHub'; const { entries, fromEntries } = Object; @@ -33,10 +36,11 @@ export const bootstrapManifest = harden({ }, makeBoard: { consume: { loadVat: true, client: true }, + produce: { board: true }, }, makeAddressNameHubs: { consume: { client: true }, - produce: { agoricNamesAdmin: true }, + produce: { agoricNames: true, agoricNamesAdmin: true, nameAdmins: true }, }, makeClientBanks: { consume: { @@ -48,6 +52,21 @@ export const bootstrapManifest = harden({ }, }); +export const governanceActions = harden({ + startVaultFactory: { + devices: { timer: true }, + vats: { timer: true }, + consume: { + agoricNames: true, + nameAdmins: true, + board: true, + loadVat: true, + zoe: true, + feeMintAccess: true, + }, + }, +}); + /** * @param {{ * vatPowers: { D: EProxy }, // D type is approximate @@ -82,6 +101,7 @@ const makeVatsFromBundles = ({ const svc = E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); vatAdminSvc.resolve(svc); // TODO: getVat? do we need to memoize this by name? + // TODO: rename loadVat to createVatByName? loadVat.resolve(bundleName => { console.info(`createVatByName(${bundleName})`); const root = E(svc) @@ -117,34 +137,65 @@ const buildZoe = async ({ }; /** + * TODO: rename this to getBoard? + * * @param {{ - * consume: { loadVat: ERef>, client: ERef } + * consume: { loadVat: ERef>, client: ERef }, + * produce: { board: Producer> }, * }} powers * @typedef {ERef>} BoardVat */ -const makeBoard = async ({ consume: { loadVat, client } }) => { +const makeBoard = async ({ + consume: { loadVat, client }, + produce: { + board: { resolve: resolveBoard }, + }, +}) => { const board = E(E(loadVat)('board')).getBoard(); + resolveBoard(board); return E(client).assignBundle({ board: _addr => board }); }; /** * @param {{ * consume: { client: ERef }, - * produce: { agoricNamesAdmin: Producer }, + * produce: { + * agoricNames: Producer, + * agoricNamesAdmin: Producer, + * nameAdmins: Producer>, + * }, * }} powers */ -const makeAddressNameHubs = async ({ - consume: { client }, - produce: { agoricNamesAdmin }, -}) => { - const { nameHub: agoricNames, nameAdmin } = makeNameHubKit(); - agoricNamesAdmin.resolve(nameAdmin); +const makeAddressNameHubs = async ({ consume: { client }, produce }) => { + const { + nameHub: agoricNames, + nameAdmin: agoricNamesAdmin, + } = makeNameHubKit(); + produce.agoricNames.resolve(agoricNames); + produce.agoricNamesAdmin.resolve(agoricNamesAdmin); const { nameHub: namesByAddress, nameAdmin: namesByAddressAdmin, } = makeNameHubKit(); + /** @type {Store} */ + const nameAdmins = makeStore('nameHub'); + await Promise.all( + ['brand', 'installation', 'issuer', 'instance', 'uiConfig'].map( + async nm => { + const { nameHub, nameAdmin } = makeNameHubKit(); + await E(agoricNamesAdmin).update(nm, nameHub); + nameAdmins.init(nameHub, nameAdmin); + if (nm === 'uiConfig') { + // Reserve the Vault Factory's config until we've populated it. + nameAdmin.reserve('vaultFactory'); + } + }, + ), + ); + produce.nameAdmins.resolve(nameAdmins); + const perAddress = address => { // Create a name hub for this address. const { @@ -234,6 +285,58 @@ const makeClientBanks = async ({ }); }; +/** + * @param {{ + * devices: { timer: unknown }, + * vats: { timer: TimerVat }, + * consume: { + * agoricNames: ERef, + * nameAdmins: ERef>, + * board: ERef, + * loadVat: ERef>, + * zoe: ERef, + * feeMintAccess: ERef, + * } + * }} powers + */ +const startVaultFactory = async ({ + devices: { timer: timerDevice }, + vats: { timer: timerVat }, + consume: { + agoricNames, + nameAdmins: nameAdminsP, + board, + loadVat, + zoe, + feeMintAccess: feeMintAccessP, + }, +}) => { + // TODO: Zoe should accept a promise, since the value is in that vat. + const [feeMintAccess, nameAdmins] = await Promise.all([ + feeMintAccessP, + nameAdminsP, + ]); + + const chainTimerService = E(timerVat).createTimerService(timerDevice); + + /** @typedef { any } PriceAuthorityVat todo */ + const { priceAuthority, adminFacet: priceAuthorityAdmin } = await E( + /** @type { PriceAuthorityVat } */ (E(loadVat)('priceAuthority')), + ).makePriceAuthority(); + + return installVaultFactoryOnChain({ + agoricNames, + board, + centralName: CENTRAL_ISSUER_NAME, + chainTimerService, + nameAdmins, + priceAuthority, + zoe, + bootstrapPaymentValue: 0n, // TODO: this is obsolete, right? + feeMintAccess, + }); +}; + harden({ connectVattpWithMailbox, makeVatsFromBundles, @@ -242,6 +345,7 @@ harden({ makeAddressNameHubs, installClientEgress, makeClientBanks, + startVaultFactory, }); export { connectVattpWithMailbox, @@ -251,4 +355,5 @@ export { makeAddressNameHubs, installClientEgress, makeClientBanks, + startVaultFactory, }; diff --git a/packages/vats/src/bootstrap-core.js b/packages/vats/src/bootstrap-core.js index fad4870f299..b15834e8dc6 100644 --- a/packages/vats/src/bootstrap-core.js +++ b/packages/vats/src/bootstrap-core.js @@ -3,6 +3,7 @@ import { Far } from '@agoric/far'; import { makePromiseKit } from '@agoric/promise-kit'; // TODO: choose sim behaviors based on runtime config import * as behaviors from './bootstrap-behaviors-sim.js'; +import { governanceActions } from './bootstrap-behaviors.js'; import { simBootstrapManifest } from './bootstrap-behaviors-sim.js'; const { entries, fromEntries } = Object; @@ -109,23 +110,25 @@ const buildRootObject = (vatPowers, vatParameters) => { * @param {SwingsetVats} vats * @param {SwingsetDevices} devices */ - bootstrap: (vats, devices) => - Promise.all( - entries(manifest).map(([name, permit]) => + bootstrap: (vats, devices) => { + const powers = { + vatPowers, + vatParameters, + vats, + devices, + produce, + consume, + }; + return Promise.all( + entries({ ...manifest, ...governanceActions }).map(([name, permit]) => Promise.resolve().then(() => { - const endowments = extract(permit, { - vatPowers, - vatParameters, - vats, - devices, - produce, - consume, - }); + const endowments = extract(permit, powers); console.info(`bootstrap: ${name}(${q(permit)})`); return behaviors[name](endowments); }), ), - ), + ); + }, }); }; diff --git a/packages/vats/src/types.js b/packages/vats/src/types.js index 0b91f4fb6e5..a6aa0b6ea20 100644 --- a/packages/vats/src/types.js +++ b/packages/vats/src/types.js @@ -101,9 +101,10 @@ * }>} CommsVatRoot * * @typedef {{ - * vattp: VattpVat, * comms: CommsVatRoot, + * timer: TimerVat, * vatAdmin: VatAdminVat, + * vattp: VattpVat, * }} SwingsetVats * @typedef {{ * mailbox: MailboxDevice,