diff --git a/packages/inter-protocol/test/psm/gov-replace-committee.js b/packages/inter-protocol/test/psm/gov-replace-committee.js new file mode 100644 index 000000000000..fdc651e8a7ea --- /dev/null +++ b/packages/inter-protocol/test/psm/gov-replace-committee.js @@ -0,0 +1,144 @@ +/* global E */ +// @ts-nocheck +/** @file Script to replace the econ governance committee in a SwingSet Core Eval (aka big hammer) */ + +import { E } from '@endo/eventual-send'; + +const { details: X } = assert; + +const runConfig = { + committeeName: 'Economic Committee', + economicCommitteeAddresses: { + gov1: 'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce', + gov2: 'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang', + gov3: 'agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h', + }, +}; + +// #region Quasi-imports +const trace = (...args) => console.log('GovReplaceCommitee', ...args); + +/** + * Convenience function for returning a storage node at or under its input, + * falling back to an inert object with the correct interface (but incomplete + * behavior) when that is unavailable. + * + * @param {ERef} storageNodeRef + * @param {string} childName + * @returns {Promise} + */ +export async function makeStorageNodeChild(storageNodeRef, childName) { + return E(storageNodeRef).makeChildNode(childName); +} + +// TODO: Formalize segment constraints. +// Must be nonempty and disallow (unescaped) `.`, and for simplicity +// (and future possibility of e.g. escaping) we currently limit to +// ASCII alphanumeric plus underscore and dash. +const pathSegmentPattern = /^[a-zA-Z0-9_-]{1,100}$/; + +/** @type {(name: string) => void} */ +export const assertPathSegment = name => { + pathSegmentPattern.test(name) || + assert.fail( + X`Path segment names must consist of 1 to 100 characters limited to ASCII alphanumerics, underscores, and/or dashes: ${name}`, + ); +}; +harden(assertPathSegment); + +/** @type {(name: string) => string} */ +const sanitizePathSegment = name => { + const candidate = name.replace(/[ ,]/g, '_'); + assertPathSegment(candidate); + return candidate; +}; + +// #endregion + +/** + * @param {import('../../src/proposals/startPSM.js').EconomyBootstrapPowers} powers + * @returns {Invitation} new poser invitation + */ +export const startNewEconomicCommittee = async ({ + consume: { board, chainStorage, zoe }, + produce: { economicCommitteeCreatorFacet }, + installation: { + consume: { committee }, + }, +}) => { + const COMMITTEES_ROOT = 'committees'; + trace('startNewEconomicCommittee'); + const { committeeName } = runConfig; + const committeeSize = Object.values( + runConfig.economicCommitteeAddresses, + ).length; + + const committeesNode = await makeStorageNodeChild( + chainStorage, + COMMITTEES_ROOT, + ); + const storageNode = await E(committeesNode).makeChildNode( + sanitizePathSegment(committeeName), + ); + + // NB: committee must only publish what it intended to be public + const marshaller = await E(board).getPublishingMarshaller(); + + // ??? save in promise space? + const { creatorFacet } = await E(zoe).startInstance( + committee, // aka electorate + {}, + { committeeName, committeeSize }, + { + storageNode, + marshaller, + }, + ); + + const newPoserInvitationP = E(creatorFacet).getPoserInvitation(); + + // TODO reset the values in space + // economicCommitteeCreatorFacet.resolve(creatorFacet); + return newPoserInvitationP; +}; +harden(startNewEconomicCommittee); + +/** @param {import('../../src/proposals/econ-behaviors.js').EconomyBootstrapSpace} permittedPowers see gov-add-psm-permit.json */ +const main = async permittedPowers => { + console.log('starting new economic committee:', runConfig); + const newElectoratePoser = await startNewEconomicCommittee(permittedPowers); + + /* + * put the new economic committee into agoricNames + */ + + /* + * tell all the PSM contracts about it + */ + const psmFacetsMap = await permittedPowers.consume.psmFacets; + // TODO make sure new PSMs get this committee (using ".reset" in the space?) + const replacements = [...psmFacetsMap.values()].map(psmFacets => + psmFacets.psmGovernorCreatorFacet.replaceElectorate(newElectoratePoser), + ); + await Promise.all(replacements); + + // somethign with the PSM charter? + + /* + * tell the provisionPool contract about it + */ + + // done + console.log('installed new economic committee'); +}; + +/** + * How to test on chain + * + * Execute core eval with a dictorator (electorate n=1) + * Have the old electorate and new electorate vote for different PSM param changes + * Verify the old's were ignored and the new's were enacted + */ + +// "export" from script +main;