UNPKG

@agoric/deploy-script-support

Version:

Helpers and other support for writing deploy scripts

169 lines (158 loc) 4.46 kB
/** * @file support for Contract Deployment Process * * 1. `agoric run XYZ.build.js` produces: * - `b1-123.json` bundle x 2: contract, aux * - `XYZ-permit.json`, `XYZ.js` script * 2. Install bundles * - permissionless with per-byte fee in IST * 3. Submit CoreEval proposal to BLD stakers * - `XYZ-permit.json`, `XYZ.js` * * @see {runBuilder} * @see {installBundles} * @see {submitCoreEval} */ import { toCLIOptions } from '@agoric/internal/src/cli-utils.js'; /** * @import {CmdRunner} from '@agoric/pola-io'; * @import {FileRd} from '@agoric/pola-io'; */ /** * * TODO: builder should be a FileRd * TODO: parameterize dest dir * * @example * to use npx to find `agoric` in node_modules/.bin: * const execP = promisify(childProcess.execFile) * const agoric = makeCmdRunner('npx', { execFile: execP }).subCommand('agoric'); * * XXX use a different name from execFile since the meaning is different * * @param {CmdRunner} agoric * @param {FileRd} builder * @param {string[]} [builderOpts] * @param {{cwd?: FileRd}} [io] * * @returns {Promise<Plan>} * * @typedef {{ * name: string, * script: string, * permit: string, * bundles: { entrypoint:string, bundleID:string, fileName:string}[]; * }} Plan */ export const runBuilder = async ( agoric, builder, builderOpts = [], { cwd = builder.join('../../') } = {}, ) => { const cmd = agoric.withFlags(...builderOpts); const { stdout } = await cmd.exec(['run', String(builder)]); const match = stdout?.match(/ (?<name>[-\w]+)-permit.json/); if (!(match && match.groups)) { throw Error('no permit found'); } /** @type {Plan} */ const plan = await cwd.join(`${match.groups.name}-plan.json`).readJSON(); return plan; }; export const txFlags = ({ node, from, chainId, keyringBackend = 'test', broadcastMode = 'block', }) => ({ node, from, 'chain-id': chainId, 'keyring-backend': keyringBackend, 'broadcast-mode': broadcastMode, // TODO: parameterize these? gas: 'auto', 'gas-adjustment': '1.4', }); /** * @param {CmdRunner} agd * @param {number} n */ export const waitForBlock = async (agd, n = 1) => { const getHeight = async () => { const { stdout } = await agd.exec(['status']); const status = JSON.parse(stdout); const { latest_block_height: height } = status.sync_info || status.SyncInfo; return height; }; const initialHeight = await getHeight(); const SEC = 1000; let currentHeight; do { await new Promise(resolve => setTimeout(resolve, 1 * SEC)); // XXX ambient currentHeight = await getHeight(); } while (currentHeight - initialHeight < n); console.log('block height:', initialHeight, currentHeight); }; /** * @param {CmdRunner} agd - agd with --from etc. * @param {string[]} txArgs */ export const runTx = async (agd, txArgs) => { const { stdout } = await agd.withFlags('-o', 'json').exec(['tx', ...txArgs]); const result = JSON.parse(stdout); if (result.code !== 0) { throw Object.assign(Error(result.raw_log), result); } return result; }; /** * @param {CmdRunner} agd * @param {FileRd} bundle */ export const installBundle = async (agd, bundle) => runTx(agd, ['swingset', 'install-bundle', `@${bundle}`]); export const txAbbr = tx => { const { txhash, code, height, gas_used: g } = tx; return { txhash, code, height, gas_used: g }; }; /** * @param {CmdRunner} agd * @param {Plan['bundles']} bundles * @param {FileRd} files */ export const installBundles = (agd, bundles, files) => { const ps = bundles.map(b => installBundle(agd, files.join(files.relative(b.fileName))), ); return Promise.all(ps); }; /** * @param {CmdRunner} agd * @param {Pick<Plan, 'permit' | 'script'>[]} evals * @param {object} [opts] * @param {string} [opts.title] * @param {string} [opts.description] * @param {object} [opts.depositOpts] * @param {string} [opts.depositOpts.denom] * @param {number} [opts.depositOpts.unit] * @param {number} [opts.depositOpts.qty] * @param {string} [opts.deposit] */ export const submitCoreEval = async ( agd, evals, { title = evals[0].script, description = title, depositOpts: { denom = 'ubld', unit = 1_000_000, qty = 10 } = {}, deposit = `${qty * unit}${denom}`, } = {}, ) => runTx(agd, [ ...'gov submit-proposal swingset-core-eval'.split(' '), ...evals.map(e => [e.permit, e.script]).flat(), ...toCLIOptions({ title, description, deposit }), ]);