diff --git a/packages/governance/src/contractGovernance/paramManager.js b/packages/governance/src/contractGovernance/paramManager.js index 515e7579f5a..ed96f7cb3df 100644 --- a/packages/governance/src/contractGovernance/paramManager.js +++ b/packages/governance/src/contractGovernance/paramManager.js @@ -224,10 +224,10 @@ const makeParamManagerBuilder = (publisherKit, zoe) => { if (!zoe) { throw Fail`zoe must be provided for governed Invitations ${zoe}`; } - const { instance, installation } = await E(zoe).getInvitationDetails(i); - // @ts-expect-error typedefs say they're guaranteed truthy but just to be safe - assert(instance && installation, 'must be an invitation'); + // local check on isLive() gives better report than .getInvitationDetails() + const isLive = await E(E(zoe).getInvitationIssuer()).isLive(i); + isLive || Fail`Invitation passed to paramManager is not live ${i}`; }; /** diff --git a/packages/governance/src/contractHelper.js b/packages/governance/src/contractHelper.js index 4b4486e693e..f03112e29ab 100644 --- a/packages/governance/src/contractHelper.js +++ b/packages/governance/src/contractHelper.js @@ -2,19 +2,19 @@ import { Far } from '@endo/marshal'; import { makeStoredPublisherKit } from '@agoric/notifier'; import { getMethodNames, objectMap } from '@agoric/internal'; import { ignoreContext, prepareExo } from '@agoric/vat-data'; -import { keyEQ, M } from '@agoric/store'; +import { M } from '@agoric/store'; import { AmountShape, BrandShape } from '@agoric/ertp'; import { RelativeTimeRecordShape, TimestampRecordShape } from '@agoric/time'; import { E } from '@endo/eventual-send'; -import { assertElectorateMatches } from './contractGovernance/paramManager.js'; import { makeParamManagerFromTerms } from './contractGovernance/typedParamManager.js'; import { GovernorFacetShape } from './typeGuards.js'; +import { CONTRACT_ELECTORATE } from './contractGovernance/governParam.js'; /** * @import {VoteCounterCreatorFacet, VoteCounterPublicFacet, QuestionSpec, OutcomeRecord, AddQuestion, AddQuestionReturn, GovernanceSubscriptionState, GovernanceTerms, GovernedApis, GovernedCreatorFacet, GovernedPublicFacet} from './types.js'; */ -const { Fail, quote: q } = assert; +const { Fail } = assert; export const GOVERNANCE_STORAGE_KEY = 'governance'; @@ -35,22 +35,17 @@ const publicMixinAPI = harden({ }); /** + * Verify that the electorate is represented by a live invitation. + * * @param {ZCF & {}>} zcf * @param {import('./contractGovernance/typedParamManager.js').TypedParamManager} paramManager */ export const validateElectorate = (zcf, paramManager) => { - const { governedParams } = zcf.getTerms(); - return E.when(paramManager.getParams(), finishedParams => { - try { - keyEQ(governedParams, finishedParams) || - Fail`The 'governedParams' term must be an object like ${q( - finishedParams, - )}, but was ${q(governedParams)}`; - assertElectorateMatches(paramManager, governedParams); - } catch (err) { - zcf.shutdownWithFailure(err); - } - }); + const invitation = paramManager.getInternalParamValue(CONTRACT_ELECTORATE); + return E.when( + E(zcf.getInvitationIssuer()).isLive(invitation), + isLive => isLive || Fail`Electorate invitation is not live.`, + ); }; harden(validateElectorate); diff --git a/packages/inter-protocol/src/vaultFactory/params.js b/packages/inter-protocol/src/vaultFactory/params.js index 3544a6e5000..04657908848 100644 --- a/packages/inter-protocol/src/vaultFactory/params.js +++ b/packages/inter-protocol/src/vaultFactory/params.js @@ -1,5 +1,3 @@ -// @jessie-check - /// import { @@ -12,6 +10,7 @@ import { M, makeScalarMapStore } from '@agoric/store'; import { TimeMath } from '@agoric/time'; import { provideDurableMapStore } from '@agoric/vat-data'; import { subtractRatios } from '@agoric/zoe/src/contractSupport/ratio.js'; +import { makeTracer } from '@agoric/internal/src/index.js'; import { amountPattern, ratioPattern } from '../contractSupport.js'; export const CHARGING_PERIOD_KEY = 'ChargingPeriod'; @@ -35,6 +34,8 @@ export const vaultDirectorParamTypes = { }; harden(vaultDirectorParamTypes); +const trace = makeTracer('Vault Params'); + /** * @param {Amount<'set'>} electorateInvitationAmount * @param {Amount<'nat'>} minInitialDebt @@ -163,6 +164,19 @@ export const makeGovernedTerms = ({ }); }; harden(makeGovernedTerms); + +// XXX Better to declare this as VaultManagerParamValues + brand. How? +/** + * @typedef {object} VaultManagerParams + * @property {Brand} brand + * @property {Ratio} liquidationMargin + * @property {Ratio} liquidationPenalty + * @property {Ratio} interestRate + * @property {Ratio} mintFee + * @property {Amount<'nat'>} debtLimit + * @property {Ratio} [liquidationPadding] + */ + /** * Stop-gap which restores initial param values UNTIL * https://github.com/Agoric/agoric-sdk/issues/5200 @@ -171,8 +185,14 @@ harden(makeGovernedTerms); * * @param {import('@agoric/vat-data').Baggage} baggage * @param {ERef} marshaller + * @param {Record} managerParamValues - sets of + * parameters (plus brand:) keyed by Keyword. override stored initial values */ -export const provideVaultParamManagers = (baggage, marshaller) => { +export const provideVaultParamManagers = ( + baggage, + marshaller, + managerParamValues, +) => { /** @type {MapStore} */ const managers = makeScalarMapStore(); @@ -197,10 +217,23 @@ export const provideVaultParamManagers = (baggage, marshaller) => { return manager; }; - // restore from baggage - // [...managerArgs.entries()].map(([brand, args]) => makeManager(brand, args)); + // restore from baggage, unless `managerParamValues` overrides. for (const [brand, args] of managerArgs.entries()) { - makeManager(brand, args); + let values; + for (const key of Object.keys(managerParamValues)) { + if (managerParamValues[key]?.brand === brand) { + values = managerParamValues[key]; + break; + } + } + + if (values) { + trace(`reviving params, override`, brand, values); + makeManager(brand, { ...args, initialParamValues: values }); + } else { + trace(`reviving params, keeping`, brand, args.initialParamValues); + makeManager(brand, args); + } } return { diff --git a/packages/inter-protocol/src/vaultFactory/vaultDirector.js b/packages/inter-protocol/src/vaultFactory/vaultDirector.js index 4b8357ea8b9..3474100da8d 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/inter-protocol/src/vaultFactory/vaultDirector.js @@ -102,6 +102,7 @@ const prepareVaultDirector = ( marshaller, makeRecorderKit, makeERecorderKit, + managerParams, ) => { /** @type {import('../reserve/assetReserve.js').ShortfallReporter} */ let shortfallReporter; @@ -120,7 +121,11 @@ const prepareVaultDirector = ( // Non-durable map because param managers aren't durable. // In the event they're needed they can be reconstructed from contract terms and off-chain data. /** a powerful object; can modify parameters */ - const vaultParamManagers = provideVaultParamManagers(baggage, marshaller); + const vaultParamManagers = provideVaultParamManagers( + baggage, + marshaller, + managerParams, + ); const metricsNode = E(storageNode).makeChildNode('metrics'); @@ -146,12 +151,10 @@ const prepareVaultDirector = ( const oldInvitation = baggage.has(shortfallInvitationKey) ? baggage.get(shortfallInvitationKey) : undefined; - console.log('@@@@@ Old Invitation', oldInvitation); const newInvitation = await directorParamManager.getInternalParamValue( SHORTFALL_INVITATION_KEY, ); - console.log('@@@@@ New Invitation', newInvitation); if (newInvitation === oldInvitation) { shortfallReporter || diff --git a/packages/inter-protocol/src/vaultFactory/vaultFactory.js b/packages/inter-protocol/src/vaultFactory/vaultFactory.js index 2756d411de6..b6b53a9a660 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultFactory.js +++ b/packages/inter-protocol/src/vaultFactory/vaultFactory.js @@ -70,6 +70,7 @@ harden(meta); * storageNode: ERef; * marshaller: ERef; * auctioneerInstance: Instance; + * managerParams: Record; * }} privateArgs * @param {import('@agoric/swingset-liveslots').Baggage} baggage */ @@ -81,6 +82,7 @@ export const start = async (zcf, privateArgs, baggage) => { marshaller, storageNode, auctioneerInstance, + managerParams, } = privateArgs; trace('awaiting debtMint'); @@ -95,7 +97,7 @@ export const start = async (zcf, privateArgs, baggage) => { const { timerService } = zcf.getTerms(); const zoe = zcf.getZoeService(); - const auctioneerPublicFacet = await E(zoe).getPublicFacet(auctioneerInstance); + const auctioneerPublicFacet = E(zoe).getPublicFacet(auctioneerInstance); const { makeRecorderKit, makeERecorderKit } = prepareRecorderKitMakers( baggage, @@ -138,6 +140,7 @@ export const start = async (zcf, privateArgs, baggage) => { marshaller, makeRecorderKit, makeERecorderKit, + managerParams, ); // cannot await because it would make remote calls during vat restart diff --git a/packages/inter-protocol/src/vaultFactory/vaultManager.js b/packages/inter-protocol/src/vaultFactory/vaultManager.js index e3ea552a8fc..7189c4a0209 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultManager.js +++ b/packages/inter-protocol/src/vaultFactory/vaultManager.js @@ -51,7 +51,6 @@ import { } from '@agoric/zoe/src/contractSupport/index.js'; import { PriceQuoteShape, SeatShape } from '@agoric/zoe/src/typeGuards.js'; import { E } from '@endo/eventual-send'; -import { AuctionPFShape } from '../auction/auctioneer.js'; import { checkDebtLimit, makeNatAmountShape, @@ -335,7 +334,7 @@ export const prepareVaultManagerKit = ( getCollateralQuote: M.call().returns(PriceQuoteShape), getPublicFacet: M.call().returns(M.remotable('publicFacet')), lockOraclePrices: M.call().returns(PriceQuoteShape), - liquidateVaults: M.call(AuctionPFShape).returns(M.promise()), + liquidateVaults: M.call(M.promise()).returns(M.promise()), }), }, initState,