diff --git a/packages/agoric-cli/package.json b/packages/agoric-cli/package.json index 71a2e87f2d6..4ed1aa4a7ca 100644 --- a/packages/agoric-cli/package.json +++ b/packages/agoric-cli/package.json @@ -41,6 +41,7 @@ "@agoric/casting": "^0.4.2", "@agoric/cosmic-proto": "^0.3.0", "@agoric/ertp": "^0.16.2", + "@agoric/governance": "^0.10.3", "@agoric/inter-protocol": "^0.16.1", "@agoric/internal": "^0.3.2", "@agoric/network": "^0.1.0", @@ -63,6 +64,7 @@ "@endo/init": "^0.5.59", "@endo/marshal": "^0.8.8", "@endo/nat": "^4.1.30", + "@endo/patterns": "^0.2.6", "@endo/promise-kit": "^0.2.59", "@iarna/toml": "^2.2.3", "anylogger": "^0.21.0", diff --git a/packages/agoric-cli/src/commands/gov.js b/packages/agoric-cli/src/commands/gov.js index 9fcba9ddc3b..12ec24da538 100644 --- a/packages/agoric-cli/src/commands/gov.js +++ b/packages/agoric-cli/src/commands/gov.js @@ -20,6 +20,8 @@ const collectValues = (val, memo) => { return memo; }; +const defaultKeyring = process.env.AGORIC_KEYRING_BACKEND || 'test'; + /** * @param {import('anylogger').Logger} _logger * @param {{ @@ -47,10 +49,18 @@ export const makeGovCommand = (_logger, io = {}) => { // backwards compatibility with less general "ec" command. To make this work // the new CLI options default to the values used for Economic Committee cmd.alias('ec'); + cmd.option( + '--keyring-backend ', + `keyring's backend (os|file|test) (default "${defaultKeyring}")`, + defaultKeyring, + ); /** @param {string} literalOrName */ const normalizeAddress = literalOrName => - normalizeAddressWithOptions(literalOrName, { keyringBackend: 'test' }); + normalizeAddressWithOptions(literalOrName, { + // FIXME does not observe keyring-backend option, which isn't available during arg parsing + keyringBackend: defaultKeyring, + }); /** @type {(info: unknown, indent?: unknown) => boolean } */ const show = (info, indent) => @@ -71,15 +81,21 @@ export const makeGovCommand = (_logger, io = {}) => { * @param {{ * toOffer: (agoricNames: *, current: import('@agoric/smart-wallet/src/smartWallet').CurrentWalletRecord | undefined) => OfferSpec, * sendFrom?: string | undefined, + * keyringBackend: string, * instanceName?: string, * }} detail * @param {Awaited>} [optUtils] */ - const processOffer = async ({ toOffer, sendFrom }, optUtils) => { + const processOffer = async function ( + { toOffer, sendFrom, keyringBackend }, + optUtils, + ) { const networkConfig = await getNetworkConfig(env); const utils = await (optUtils || makeRpcUtils({ fetch })); const { agoricNames, readLatestHead } = utils; + assert(keyringBackend, 'missing keyring-backend option'); + let current; if (sendFrom) { current = await getCurrent(sendFrom, { readLatestHead }); @@ -97,7 +113,7 @@ export const makeGovCommand = (_logger, io = {}) => { const result = await sendAction( { method: 'executeOffer', offer }, { - keyring: { backend: 'test' }, // XXX + keyring: { backend: keyringBackend }, from: sendFrom, verbose: false, ...networkConfig, @@ -140,6 +156,7 @@ export const makeGovCommand = (_logger, io = {}) => { .requiredOption( '--name ', 'Committee instance name', + String, 'economicCommittee', ) .option('--voter ', 'Voter number', Number, 0) @@ -147,14 +164,14 @@ export const makeGovCommand = (_logger, io = {}) => { '--offerId ', 'Offer id', String, - `ecCommittee-${Date.now()}`, + `gov-committee-${Date.now()}`, ) .option( '--send-from ', 'Send from address', normalizeAddress, ) - .action(async function (opts) { + .action(async function (opts, options) { const { name: instanceName } = opts; /** @type {Parameters[0]['toOffer']} */ @@ -181,7 +198,8 @@ export const makeGovCommand = (_logger, io = {}) => { await processOffer({ toOffer, instanceName, - ...opts, + sendFrom: opts.sendFrom, + keyringBackend: options.optsWithGlobals().keyringBackend, }); }); @@ -199,7 +217,7 @@ export const makeGovCommand = (_logger, io = {}) => { 'Send from address', normalizeAddress, ) - .action(async function (opts) { + .action(async function (opts, options) { const { name: instanceName } = opts; /** @type {Parameters[0]['toOffer']} */ @@ -226,7 +244,8 @@ export const makeGovCommand = (_logger, io = {}) => { await processOffer({ toOffer, instanceName, - ...opts, + sendFrom: opts.sendFrom, + keyringBackend: options.optsWithGlobals().keyringBackend, }); }); @@ -270,7 +289,9 @@ export const makeGovCommand = (_logger, io = {}) => { const current = await getCurrent(opts.from, { readLatestHead }); const found = findContinuingIds(current, agoricNames); - found.forEach(it => show({ ...it, address: opts.from })); + for (const it of found) { + show({ ...it, address: opts.from }); + } }); cmd @@ -299,7 +320,7 @@ export const makeGovCommand = (_logger, io = {}) => { 'Send from address', normalizeAddress, ) - .action(async function (opts) { + .action(async function (opts, options) { const utils = await makeRpcUtils({ fetch }); const { readLatestHead } = utils; @@ -308,8 +329,9 @@ export const makeGovCommand = (_logger, io = {}) => { ).catch(err => { throw new CommanderError(1, 'VSTORAGE_FAILURE', err.message); }); + // XXX runtime shape-check - const questionDesc = /** @type {any} */ (info); + const questionDesc = /** @type {QuestionDetails} */ (info); // TODO support multiple position arguments const chosenPositions = [questionDesc.positions[opts.forPosition]]; @@ -343,7 +365,14 @@ export const makeGovCommand = (_logger, io = {}) => { }; }; - await processOffer({ toOffer, sendFrom: opts.sendFrom }, utils); + await processOffer( + { + toOffer, + sendFrom: opts.sendFrom, + keyringBackend: options.optsWithGlobals().keyringBackend, + }, + utils, + ); }); cmd @@ -376,7 +405,7 @@ export const makeGovCommand = (_logger, io = {}) => { Number, 1, ) - .action(async function (opts) { + .action(async function (opts, options) { const { instance: instanceName } = opts; /** @type {Parameters[0]['toOffer']} */ @@ -415,7 +444,8 @@ export const makeGovCommand = (_logger, io = {}) => { await processOffer({ toOffer, instanceName, - ...opts, + sendFrom: opts.sendFrom, + keyringBackend: options.optsWithGlobals().keyringBackend, }); });