diff --git a/a3p-integration/proposals/a:vaults-auctions/upgradeVaults.test.js b/a3p-integration/proposals/a:vaults-auctions/upgradeVaults.test.js index 7441fe2759a..ceb07eee31b 100644 --- a/a3p-integration/proposals/a:vaults-auctions/upgradeVaults.test.js +++ b/a3p-integration/proposals/a:vaults-auctions/upgradeVaults.test.js @@ -73,9 +73,25 @@ const triggerAuction = async t => { t.is(atomOut, '+5200000'); }; +// contract vat names are based on bundleID +const ORIGINAL_AUCTION_VAT_NAME = 'zcf-b1-a5683-auctioneer'; + +const newAuctioneerFromNewBundle = details => { + for (const detail of details) { + if ( + !detail.vatName.includes('governor') && + detail.vatName !== ORIGINAL_AUCTION_VAT_NAME + ) { + return true; + } + } + return false; +}; + const checkAuctionVat = async t => { const details = await getDetailsMatchingVats('auctioneer'); + t.true(newAuctioneerFromNewBundle(details)); // This query matches both the auction and its governor, so double the count t.true(Object.keys(details).length > 2); }; diff --git a/packages/builders/scripts/vats/add-auction.js b/packages/builders/scripts/vats/add-auction.js index 2f7a2fd12c7..e98d10ef39e 100644 --- a/packages/builders/scripts/vats/add-auction.js +++ b/packages/builders/scripts/vats/add-auction.js @@ -1,10 +1,20 @@ import { makeHelpers } from '@agoric/deploy-script-support'; /** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ -export const defaultProposalBuilder = async () => { +export const defaultProposalBuilder = async ({ publishRef, install }) => { return harden({ sourceSpec: '@agoric/inter-protocol/src/proposals/add-auction.js', - getManifestCall: ['getManifestForAddAuction'], + getManifestCall: [ + 'getManifestForAddAuction', + { + auctionsRef: publishRef( + install( + '@agoric/inter-protocol/src/auction/auctioneer.js', + '../../inter-protocol/bundles/bundle-auctioneer.js', + ), + ), + }, + ], }); }; diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js index ba2bef43b29..378f7485028 100644 --- a/packages/inter-protocol/src/proposals/add-auction.js +++ b/packages/inter-protocol/src/proposals/add-auction.js @@ -15,35 +15,47 @@ const trace = makeTracer('NewAuction', true); /** * @param {import('./econ-behaviors.js').EconomyBootstrapPowers & * interlockPowers} powers + * @param {{ options: { auctionsRef: { bundleID: string } } }} options */ -export const addAuction = async ({ - consume: { - zoe, - board, - chainTimerService, - priceAuthority, - chainStorage, - economicCommitteeCreatorFacet: electorateCreatorFacet, - auctioneerKit: legacyKitP, - }, - produce: { newAuctioneerKit, auctionsUpgradeComplete }, - instance: { - consume: { reserve: reserveInstance }, - }, - installation: { +export const addAuction = async ( + { consume: { - auctioneer: auctionInstallation, - contractGovernor: contractGovernorInstallation, + zoe, + board, + chainTimerService, + priceAuthority, + chainStorage, + economicCommitteeCreatorFacet: electorateCreatorFacet, + auctioneerKit: legacyKitP, + }, + produce: { auctioneerKit: produceAuctioneerKit, auctionsUpgradeComplete }, + instance: { + consume: { reserve: reserveInstance }, + }, + installation: { + consume: { contractGovernor: contractGovernorInstallation }, + produce: { auctioneer: produceInstallation }, + }, + issuer: { + consume: { [Stable.symbol]: stableIssuerP }, }, }, - issuer: { - consume: { [Stable.symbol]: stableIssuerP }, - }, -}) => { - trace('addAuction start'); + { options }, +) => { + trace('addAuction start', options); const STORAGE_PATH = 'auction'; + const { auctionsRef } = options; const poserInvitationP = E(electorateCreatorFacet).getPoserInvitation(); + const bundleID = auctionsRef.bundleID; + /** + * @type {Promise< + * Installation + * >} + */ + const installationP = E(zoe).installBundleID(bundleID); + produceInstallation.reset(); + produceInstallation.resolve(installationP); const [ initialPoserInvitation, @@ -89,10 +101,12 @@ export const addAuction = async ({ }, ); + const installation = await installationP; + const governorTerms = await deeplyFulfilledObject( harden({ timer: chainTimerService, - governedContractInstallation: auctionInstallation, + governedContractInstallation: installation, governed: { terms: auctionTerms, issuerKeywordRecord: { Bid: stableIssuer }, @@ -103,7 +117,7 @@ export const addAuction = async ({ }), ); - /** @type {GovernorStartedInstallationKit} */ + /** @type {GovernorStartedInstallationKit} */ const governorStartResult = await E(zoe).startInstance( contractGovernorInstallation, undefined, @@ -137,7 +151,8 @@ export const addAuction = async ({ ), ); - newAuctioneerKit.resolve( + produceAuctioneerKit.reset(); + produceAuctioneerKit.resolve( harden({ label: 'auctioneer', creatorFacet: governedCreatorFacet, @@ -168,7 +183,7 @@ export const ADD_AUCTION_MANIFEST = harden({ auctioneerKit: true, }, produce: { - newAuctioneerKit: true, + auctioneerKit: true, auctionsUpgradeComplete: true, }, instance: { @@ -176,9 +191,9 @@ export const ADD_AUCTION_MANIFEST = harden({ }, installation: { consume: { - auctioneer: true, contractGovernor: true, }, + produce: { auctioneer: true }, }, issuer: { consume: { [Stable.symbol]: true }, @@ -186,7 +201,15 @@ export const ADD_AUCTION_MANIFEST = harden({ }, }); -/* Add a new auction to a chain that already has one. */ -export const getManifestForAddAuction = async () => { - return { manifest: ADD_AUCTION_MANIFEST }; +/** + * Add a new auction to a chain that already has one. + * + * @param {object} _ign + * @param {any} addAuctionOptions + */ +export const getManifestForAddAuction = async (_ign, addAuctionOptions) => { + return { + manifest: ADD_AUCTION_MANIFEST, + options: addAuctionOptions, + }; }; diff --git a/packages/inter-protocol/src/proposals/upgrade-vaults.js b/packages/inter-protocol/src/proposals/upgrade-vaults.js index 5b4cc7ae125..848808d77df 100644 --- a/packages/inter-protocol/src/proposals/upgrade-vaults.js +++ b/packages/inter-protocol/src/proposals/upgrade-vaults.js @@ -2,34 +2,9 @@ import { E } from '@endo/far'; import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; import { AmountMath } from '@agoric/ertp/src/index.js'; import { makeTracer } from '@agoric/internal/src/index.js'; -import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js'; const trace = makeTracer('upgrade Vaults proposal'); -// stand-in for Promise.any() which isn't available at this point. -/** @param {Promise[]} promises */ -const any = promises => - new Promise((resolve, reject) => { - for (const promise of promises) { - void promise.then(resolve, () => {}); - } - void Promise.allSettled(promises).then(results => { - const rejects = /** @type {PromiseRejectedResult[]} */ ( - results.filter(({ status }) => status === 'rejected') - ); - if (rejects.length === results.length) { - const messages = rejects.map( - ({ reason: { message } }) => message || 'no error message', - ); - const aggregate = new Error(messages.join(';')); - /** @type {any} */ (aggregate).errors = rejects.map( - ({ reason }) => reason, - ); - reject(aggregate); - } - }); - }); - /** * @typedef {PromiseSpaceOf<{ * auctionsUpgradeComplete: boolean; @@ -41,33 +16,30 @@ const any = promises => * interlockPowers} powers * @param {{ options: { vaultsRef: { bundleID: string } } }} options */ -export const upgradeVaults = async (powers, { options }) => { - const { +export const upgradeVaults = async ( + { consume: { - agoricNamesAdmin, - newAuctioneerKit: auctioneerKitP, - priceAuthority, vaultFactoryKit, zoe, economicCommitteeCreatorFacet: electorateCreatorFacet, reserveKit, auctionsUpgradeComplete, }, - produce: { - auctioneerKit: auctioneerKitProducer, - newAuctioneerKit: tempAuctioneerKit, - auctionsUpgradeComplete: auctionsUpgradeCompleteProducer, + produce: { auctionsUpgradeComplete: auctionsUpgradeCompleteProducer }, + installation: { + produce: { VaultFactory: produceVaultInstallation }, }, instance: { - produce: { auctioneer: auctioneerProducer }, + consume: { auctioneer: auctioneerInstanceP }, }, - } = powers; + }, + { options }, +) => { const { vaultsRef } = options; const kit = await vaultFactoryKit; - const auctioneerKit = await auctioneerKitP; const { instance: directorInstance } = kit; const allBrands = await E(zoe).getBrands(directorInstance); - const { Minted: istBrand, ...vaultBrands } = allBrands; + const { Minted: _istBrand, ...vaultBrands } = allBrands; const bundleID = vaultsRef.bundleID; console.log(`upgradeVaults: bundleId`, bundleID); @@ -76,27 +48,13 @@ export const upgradeVaults = async (powers, { options }) => { * Installation * >} */ - let installationP; + const installationP = E(zoe).installBundleID(bundleID); + produceVaultInstallation.reset(); + produceVaultInstallation.resolve(installationP); await auctionsUpgradeComplete; auctionsUpgradeCompleteProducer.reset(); - if (vaultsRef) { - if (bundleID) { - installationP = E(zoe).installBundleID(bundleID); - await E.when( - installationP, - installation => - E(E(agoricNamesAdmin).lookupAdmin('installation')).update( - 'vaultFactory', - installation, - ), - err => - console.error(`🚨 failed to update vaultFactory installation`, err), - ); - } - } - const readCurrentDirectorParams = async () => { const { publicFacet: directorPF } = kit; @@ -173,14 +131,15 @@ export const upgradeVaults = async (powers, { options }) => { E.get(reserveKit).creatorFacet, ).makeShortfallReportingInvitation(); - const poserInvitation = await E( - electorateCreatorFacet, - ).getPoserInvitation(); + const [poserInvitation, auctioneerInstance] = await Promise.all([ + E(electorateCreatorFacet).getPoserInvitation(), + auctioneerInstanceP, + ]); + /** @type {import('../../src/vaultFactory/vaultFactory').VaultFactoryContract['privateArgs']} */ const newPrivateArgs = harden({ ...privateArgs, - // @ts-expect-error It has a value until reset after the upgrade - auctioneerInstance: auctioneerKit.instance, + auctioneerInstance, initialPoserInvitation: poserInvitation, initialShortfallInvitation: shortfallInvitation, managerParams: managerParamValues, @@ -195,60 +154,7 @@ export const upgradeVaults = async (powers, { options }) => { trace('upgraded vaultFactory.', upgradeResult); }; - // Wait for at least one new price feed to be ready before upgrading Vaults - void E.when( - any( - Object.values(vaultBrands).map(async brand => { - const getQuote = async lastRejectionReason => { - await null; - try { - return await E(priceAuthority).quoteGiven( - AmountMath.make(brand, 10n), - istBrand, - ); - } catch (reason) { - if ( - isUpgradeDisconnection(reason) && - (!lastRejectionReason || - reason.incarnationNumber > - lastRejectionReason.incarnationNumber) - ) { - return getQuote(reason); - } - throw reason; - } - }; - return getQuote(null); - }), - ), - async price => { - trace(`upgrading after delay`, price); - await upgradeVaultFactory(); - auctioneerKitProducer.reset(); - // @ts-expect-error auctioneerKit is non-null except between auctioneerKitProducer.reset() and auctioneerKitProducer.resolve() - auctioneerKitProducer.resolve(auctioneerKit); - auctioneerProducer.reset(); - // @ts-expect-error auctioneerKit is non-null except between auctioneerKitProducer.reset() and auctioneerKitProducer.resolve() - auctioneerProducer.resolve(auctioneerKit.instance); - // We wanted it to be valid for only a short while. - tempAuctioneerKit.reset(); - await E(E(agoricNamesAdmin).lookupAdmin('instance')).update( - 'auctioneer', - // @ts-expect-error auctioneerKit is non-null except between auctioneerKitProducer.reset() and auctioneerKitProducer.resolve() - auctioneerKit.instance, - ); - trace(`upgrading complete`, price); - }, - error => { - console.error( - 'Failed to upgrade vaultFactory', - error.message, - ...(error.errors || []), - ); - }, - ); - - console.log(`upgradeVaults scheduled; waiting for priceFeeds`); + await upgradeVaultFactory(); }; const uV = 'upgradeVaults'; @@ -265,22 +171,17 @@ export const getManifestForUpgradeVaults = async ( manifest: { [upgradeVaults.name]: { consume: { - agoricNamesAdmin: uV, - newAuctioneerKit: uV, economicCommitteeCreatorFacet: uV, - priceAuthority: uV, reserveKit: uV, vaultFactoryKit: uV, - board: uV, zoe: uV, auctionsUpgradeComplete: uV, }, - produce: { - auctioneerKit: uV, - newAuctioneerKit: uV, - auctionsUpgradeComplete: uV, + produce: { auctionsUpgradeComplete: uV }, + installation: { + produce: { VaultFactory: true }, }, - instance: { produce: { auctioneer: uV, newAuctioneerKit: uV } }, + instance: { consume: { auctioneer: uV } }, }, }, options: { ...vaultUpgradeOptions },