From d419cc701319d35865a91769de96f7b31f070fa4 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 27 Dec 2023 15:49:20 -0800 Subject: [PATCH] test: add priceAuthority to many vaults tests the right way --- .../test/vaultFactory/driver.js | 48 +++++++- .../test/vaultFactory/test-vaultFactory.js | 77 ++++++------ .../vaultFactory/test-vaultLiquidation.js | 112 +++++++++++------- .../test/vaultFactory/vaultFactoryUtils.js | 34 +++++- 4 files changed, 182 insertions(+), 89 deletions(-) diff --git a/packages/inter-protocol/test/vaultFactory/driver.js b/packages/inter-protocol/test/vaultFactory/driver.js index d35a87e2bf8f..7f16f1b7f692 100644 --- a/packages/inter-protocol/test/vaultFactory/driver.js +++ b/packages/inter-protocol/test/vaultFactory/driver.js @@ -6,6 +6,7 @@ import { makeNotifierFromSubscriber } from '@agoric/notifier'; import { unsafeMakeBundleCache } from '@agoric/swingset-vat/tools/bundleTool.js'; import { ceilMultiplyBy, + makeRatio, makeRatioFromAmounts, } from '@agoric/zoe/src/contractSupport/index.js'; import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority.js'; @@ -15,6 +16,9 @@ import { deeplyFulfilled } from '@endo/marshal'; import { NonNullish } from '@agoric/assert'; import { eventLoopIteration } from '@agoric/notifier/tools/testSupports.js'; +import { providePriceAuthorityRegistry } from '@agoric/zoe/tools/priceAuthorityRegistry.js'; +import { makeScalarBigMapStore } from '@agoric/vat-data/src/index.js'; + import { setupReserve, startAuctioneer, @@ -215,15 +219,27 @@ const setupServices = async (t, initialPrice, priceBase) => { const { consume, produce } = space; t.context.consume = consume; - // Cheesy hack for easy use of manual price authority - const priceAuthority = makeManualPriceAuthority({ + // priceAuthorityReg is the registry, which contains and multiplexes multiple + // individual priceAuthorities, including aethPriceAuthority. + // priceAuthorityAdmin supports registering more individual priceAuthorities + // with the registry. + const aethPriceAuthority = makeManualPriceAuthority({ actualBrandIn: aeth.brand, actualBrandOut: run.brand, initialPrice: makeRatioFromAmounts(initialPrice, priceBase), timer, quoteIssuerKit: makeIssuerKit('quote', AssetKind.SET), }); - produce.priceAuthority.resolve(priceAuthority); + const baggage = makeScalarBigMapStore('baggage'); + const { priceAuthority: priceAuthorityReg, adminFacet: priceAuthorityAdmin } = + providePriceAuthorityRegistry(baggage); + await E(priceAuthorityAdmin).registerPriceAuthority( + aethPriceAuthority, + aeth.brand, + run.brand, + ); + + produce.priceAuthority.resolve(priceAuthorityReg); const { installation: { produce: iProduce }, @@ -276,6 +292,7 @@ const setupServices = async (t, initialPrice, priceBase) => { return { zoe, + timer, governor: { governorInstance, governorPublicFacet: E(zoe).getPublicFacet(governorInstance), @@ -288,7 +305,9 @@ const setupServices = async (t, initialPrice, priceBase) => { vfPublic, aethVaultManager, }, - priceAuthority, + priceAuthority: priceAuthorityReg, + priceAuthorityAdmin, + aethPriceAuthority, }; }; @@ -307,7 +326,7 @@ export const makeManagerDriver = async ( const { zoe, aeth, run } = t.context; const { vaultFactory: { lender, vaultFactory, vfPublic }, - priceAuthority, + aethPriceAuthority, timer, } = services; const publicTopics = await E(lender).getPublicTopics(); @@ -450,6 +469,22 @@ export const makeManagerDriver = async ( addVaultType: async keyword => { /** @type {IssuerKit<'nat'>} */ const kit = makeIssuerKit(keyword.toLowerCase()); + + // for now, this priceAuthority never reports prices, but having one is + // sufficient to get a vaultManager running. + const pa = makeManualPriceAuthority({ + actualBrandIn: kit.brand, + actualBrandOut: run.brand, + timer, + initialPrice: makeRatio(100n, run.brand, 100n, kit.brand), + }); + + await services.priceAuthorityAdmin.registerPriceAuthority( + pa, + kit.brand, + run.brand, + ); + const manager = await E(vaultFactory).addVaultType( kit.issuer, keyword, @@ -477,7 +512,8 @@ export const makeManagerDriver = async ( }); }, /** @param {Amount<'nat'>} p */ - setPrice: p => priceAuthority.setPrice(makeRatioFromAmounts(p, priceBase)), + setPrice: p => + aethPriceAuthority.setPrice(makeRatioFromAmounts(p, priceBase)), // XXX the paramPath should be implied by the object `setGovernedParam` is being called on. // e.g. the manager driver should know the paramPath is `{ key: { collateralBrand: aeth.brand } }` // and the director driver should `{ key: 'governedParams }` diff --git a/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js b/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js index 62da14d5e70e..b223e77fee48 100644 --- a/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/inter-protocol/test/vaultFactory/test-vaultFactory.js @@ -20,7 +20,6 @@ import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority import { documentStorageSchema } from '@agoric/governance/tools/storageDoc.js'; import buildManualTimer from '@agoric/zoe/tools/manualTimer.js'; -import { makeScriptedPriceAuthority } from '@agoric/zoe/tools/scriptedPriceAuthority.js'; import { E } from '@endo/eventual-send'; import { deeplyFulfilled } from '@endo/marshal'; import { calculateCurrentDebt } from '../../src/interest-math.js'; @@ -156,44 +155,25 @@ const setupServices = async ( const runPayment = await getRunFromFaucet(t, stableInitialLiquidity); trace(t, 'faucet', { stableInitialLiquidity, runPayment }); - const { space } = await setupElectorateReserveAndAuction( - t, - // @ts-expect-error inconsistent types with withAmountUtils - run, - aeth, - priceOrList, - quoteInterval, - unitAmountIn, - { StartFrequency: startFrequency }, - ); - - const { consume, produce } = space; - - const quoteIssuerKit = makeIssuerKit('quote', AssetKind.SET); - // Cheesy hack for easy use of manual price authority - const pa = Array.isArray(priceOrList) - ? makeScriptedPriceAuthority({ - actualBrandIn: aeth.brand, - actualBrandOut: run.brand, - priceList: priceOrList, - timer, - quoteMint: quoteIssuerKit.mint, - unitAmountIn, - quoteInterval, - }) - : makeManualPriceAuthority({ - actualBrandIn: aeth.brand, - actualBrandOut: run.brand, - initialPrice: priceOrList, - timer, - quoteIssuerKit, - }); - produce.priceAuthority.resolve(pa); + const { space, priceAuthorityAdmin, aethPriceAuthority } = + await setupElectorateReserveAndAuction( + t, + // @ts-expect-error inconsistent types with withAmountUtils + run, + aeth, + priceOrList, + quoteInterval, + unitAmountIn, + { StartFrequency: startFrequency }, + ); + + const { consume } = space; const { installation: { produce: iProduce }, } = space; iProduce.VaultFactory.resolve(t.context.installation.VaultFactory); + iProduce.liquidate.resolve(t.context.installation.liquidate); await startVaultFactory( space, @@ -267,15 +247,38 @@ const setupServices = async ( return { zoe, + timer, governor: g, vaultFactory: v, runKit: { issuer: run.issuer, brand: run.brand }, - priceAuthority, reserveKit, space, + priceAuthorityAdmin, + aethPriceAuthority, }; }; +const addPriceAuthority = async (collateralIssuerKit, services) => { + const { priceAuthorityAdmin, timer, runKit } = services; + + const pa = makeManualPriceAuthority({ + actualBrandIn: collateralIssuerKit.brand, + actualBrandOut: runKit.brand, + timer, + initialPrice: makeRatio( + 100n, + runKit.brand, + 100n, + collateralIssuerKit.brand, + ), + }); + await E(priceAuthorityAdmin).registerPriceAuthority( + pa, + collateralIssuerKit.brand, + runKit.brand, + ); +}; + test('first', async t => { const { aeth, run, zoe, rates } = t.context; t.context.interestTiming = { @@ -1574,6 +1577,7 @@ test('addVaultType: invalid args do not modify state', async t => { ); const { vaultFactory } = services.vaultFactory; + await addPriceAuthority(chit, services); const failsForSameReason = async p => p @@ -1607,6 +1611,7 @@ test('addVaultType: extra, unexpected params', async t => { ); const { vaultFactory } = services.vaultFactory; + await addPriceAuthority(chit, services); const params = { ...defaultParamValues(aeth.brand), shoeSize: 10 }; const extraParams = { ...params, shoeSize: 10 }; @@ -1654,6 +1659,8 @@ test('director notifiers', async t => { // add a vault type const chit = makeIssuerKit('chit'); + await addPriceAuthority(chit, services); + await E(vaultFactory).addVaultType( chit.issuer, 'Chit', diff --git a/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js b/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js index 325fb3561785..857f8c7069cd 100644 --- a/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js +++ b/packages/inter-protocol/test/vaultFactory/test-vaultLiquidation.js @@ -151,16 +151,17 @@ const setupServices = async ( } = t.context; t.context.timer = timer; - const { space } = await setupElectorateReserveAndAuction( - t, - // @ts-expect-error inconsistent types with withAmountUtils - run, - aeth, - priceOrList, - quoteInterval, - unitAmountIn, - auctionParams, - ); + const { space, priceAuthorityAdmin, aethPriceAuthority } = + await setupElectorateReserveAndAuction( + t, + // @ts-expect-error inconsistent types with withAmountUtils + run, + aeth, + priceOrList, + quoteInterval, + unitAmountIn, + auctionParams, + ); const { consume } = space; @@ -247,12 +248,15 @@ const setupServices = async ( return { zoe, + timer, governor: g, vaultFactory: v, runKit: { issuer: run.issuer, brand: run.brand }, priceAuthority, reserveKit, auctioneerKit, + priceAuthorityAdmin, + aethPriceAuthority, }; }; @@ -374,7 +378,7 @@ test('price drop', async t => { const { vaultFactory: { vaultFactory, aethCollateralManager }, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, } = services; @@ -435,9 +439,9 @@ test('price drop', async t => { aeth.make(400n), 'vault holds 11 Collateral', ); - trace(t, 'pa2', priceAuthority); + trace(t, 'pa2', aethPriceAuthority); - await priceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); + await aethPriceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); trace(t, 'price dropped a little'); notification = await E(vaultNotifier).getUpdateSince(); t.is(notification.value.vaultState, Phase.ACTIVE); @@ -537,7 +541,7 @@ test('price falls precipitously', async t => { const { reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, - priceAuthority, + aethPriceAuthority, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -581,7 +585,7 @@ test('price falls precipitously', async t => { 'vault holds 4 Collateral', ); - priceAuthority.setPrice(makeRatio(130n, run.brand, 1n, aeth.brand)); + aethPriceAuthority.setPrice(makeRatio(130n, run.brand, 1n, aeth.brand)); await eventLoopIteration(); const { startTime, time } = await startAuctionClock( @@ -687,7 +691,7 @@ test('liquidate two loans', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, } = services; @@ -860,7 +864,9 @@ test('liquidate two loans', async t => { totalCollateral: { value: 800n }, }); - await E(priceAuthority).setPrice(makeRatio(70n, run.brand, 10n, aeth.brand)); + await E(aethPriceAuthority).setPrice( + makeRatio(70n, run.brand, 10n, aeth.brand), + ); trace(t, 'changed price to 7 RUN/Aeth'); // A BIDDER places a BID ////////////////////////// @@ -1041,7 +1047,7 @@ test('sell goods at auction', async t => { const { auctioneerKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -1167,7 +1173,7 @@ test('sell goods at auction', async t => { t.is(aliceUpdate.value.vaultState, Phase.ACTIVE); // price falls - await priceAuthority.setPrice(makeRatio(70n, run.brand, 10n, aeth.brand)); + await aethPriceAuthority.setPrice(makeRatio(70n, run.brand, 10n, aeth.brand)); await eventLoopIteration(); // Bob's loan is now 777 Minted (including interest) on 100 Aeth, with the price @@ -1213,7 +1219,7 @@ test('collect fees from loan', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, } = services; @@ -1347,10 +1353,12 @@ test('collect fees from loan', async t => { t.deepEqual(aliceUpdate.value.debtSnapshot.debt, aliceRunDebtLevel); trace(t, 'alice reduce collateral'); - await E(priceAuthority).setPrice(makeRatio(7n, run.brand, 1n, aeth.brand)); + await E(aethPriceAuthority).setPrice( + makeRatio(7n, run.brand, 1n, aeth.brand), + ); trace(t, 'changed price to 7'); - await priceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); + await aethPriceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); trace(t, 'price dropped a little'); notification = await E(aliceNotifier).getUpdateSince(); t.is(notification.value.vaultState, Phase.ACTIVE); @@ -1463,7 +1471,7 @@ test('Auction sells all collateral w/shortfall', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, } = services; @@ -1589,7 +1597,9 @@ test('Auction sells all collateral w/shortfall', async t => { totalCollateral: { value: 700n }, }); - await E(priceAuthority).setPrice(makeRatio(70n, run.brand, 10n, aeth.brand)); + await E(aethPriceAuthority).setPrice( + makeRatio(70n, run.brand, 10n, aeth.brand), + ); trace(t, 'changed price to 7 RUN/Aeth'); // A BIDDER places a BID ////////////////////////// @@ -1676,7 +1686,7 @@ test('liquidation Margin matters', async t => { const { auctioneerKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -1730,7 +1740,9 @@ test('liquidation Margin matters', async t => { const bidderSeat = await bid(t, zoe, auctioneerKit, aeth, bidAmount, desired); // price falls to 10.00. notice that no liquidation takes place. - await priceAuthority.setPrice(makeRatio(1000n, run.brand, 100n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(1000n, run.brand, 100n, aeth.brand), + ); await eventLoopIteration(); let { startTime } = await startAuctionClock(auctioneerKit, manualTimer); @@ -1741,7 +1753,9 @@ test('liquidation Margin matters', async t => { t.is(aliceUpdate.value.vaultState, Phase.ACTIVE); // price falls to 9.99. Now it liquidates. - await priceAuthority.setPrice(makeRatio(999n, run.brand, 100n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(999n, run.brand, 100n, aeth.brand), + ); await eventLoopIteration(); ({ startTime } = await startAuctionClock(auctioneerKit, manualTimer)); @@ -1780,7 +1794,7 @@ test('reinstate vault', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -1902,7 +1916,9 @@ test('reinstate vault', async t => { const bidderSeat = await bid(t, zoe, auctioneerKit, aeth, bidAmount, desired); // price falls - await priceAuthority.setPrice(makeRatio(400n, run.brand, 100n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(400n, run.brand, 100n, aeth.brand), + ); await eventLoopIteration(); const { startTime } = await startAuctionClock(auctioneerKit, manualTimer); @@ -1993,7 +2009,7 @@ test('auction locks low price', async t => { const { reserveKit: { reserveCreatorFacet }, auctioneerKit, - priceAuthority, + aethPriceAuthority, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); trace('addIssuer awaited'); @@ -2001,7 +2017,9 @@ test('auction locks low price', async t => { const wanted = 500n; // Lock in a low price (zero) - priceAuthority.setPrice(makeRatio(0n, run.brand, baseCollateral, aeth.brand)); + aethPriceAuthority.setPrice( + makeRatio(0n, run.brand, baseCollateral, aeth.brand), + ); await eventLoopIteration(); const schedule = await E(auctioneerKit.creatorFacet).getSchedule(); @@ -2034,7 +2052,7 @@ test('auction locks low price', async t => { ); // Bump back up to a high price - priceAuthority.setPrice( + aethPriceAuthority.setPrice( makeRatio(100n * wanted, run.brand, baseCollateral, aeth.brand), ); @@ -2081,7 +2099,7 @@ test('Bug 7422 vault reinstated with no assets', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit: auctKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -2204,7 +2222,9 @@ test('Bug 7422 vault reinstated with no assets', async t => { ); // price falls - await priceAuthority.setPrice(makeRatio(999n, run.brand, 1000n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(999n, run.brand, 1000n, aeth.brand), + ); await eventLoopIteration(); const { startTime } = await startAuctionClock(auctKit, manualTimer); @@ -2315,7 +2335,7 @@ test('Bug 7346 excess collateral to holder', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit: auctKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -2453,7 +2473,7 @@ test('Bug 7346 excess collateral to holder', async t => { // price falls const newPrice = makeRatio(9990n, run.brand, 1000n, aeth.brand); - await priceAuthority.setPrice(newPrice); + await aethPriceAuthority.setPrice(newPrice); await eventLoopIteration(); const { startTime } = await startAuctionClock(auctKit, manualTimer); @@ -2580,7 +2600,7 @@ test('refund to one of two loans', async t => { const { vaultFactory: { vaultFactory, aethCollateralManager }, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, auctioneerKit, } = services; @@ -2640,7 +2660,7 @@ test('refund to one of two loans', async t => { t.truthy(AmountMath.isEqual(lentAmount, aliceWantMinted)); t.deepEqual(await E(aliceVault).getCollateralAmount(), aeth.make(400n)); - await priceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); + await aethPriceAuthority.setPrice(makeRatio(40n, run.brand, 10n, aeth.brand)); aliceNotification = await E(aliceVaultNotifier).getUpdateSince(); t.is(aliceNotification.value.vaultState, Phase.ACTIVE); @@ -2767,7 +2787,7 @@ test('Bug 7784 reconstitute both', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit: auctKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -2882,7 +2902,9 @@ test('Bug 7784 reconstitute both', async t => { ); // price falls - await priceAuthority.setPrice(makeRatio(9990n, run.brand, 1000n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(9990n, run.brand, 1000n, aeth.brand), + ); await eventLoopIteration(); const { startTime } = await startAuctionClock(auctKit, manualTimer); @@ -2984,7 +3006,7 @@ test('Bug 7796 missing lockedPrice', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit: auctKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -3141,7 +3163,7 @@ test('Bug 7796 missing lockedPrice', async t => { trace('ADVANCING', now); // price falls const newPrice = makeRatio(9990n, run.brand, 1000n, aeth.brand); - await priceAuthority.setPrice(newPrice); + await aethPriceAuthority.setPrice(newPrice); await eventLoopIteration(); now = await setClockAndAdvanceNTimes( @@ -3262,7 +3284,7 @@ test('Bug 7851 & no bidders', async t => { const { vaultFactory: { aethVaultManager, aethCollateralManager }, auctioneerKit: auctKit, - priceAuthority, + aethPriceAuthority, reserveKit: { reserveCreatorFacet, reservePublicFacet }, } = services; await E(reserveCreatorFacet).addIssuer(aeth.issuer, 'Aeth'); @@ -3339,7 +3361,9 @@ test('Bug 7851 & no bidders', async t => { }); // price falls - await priceAuthority.setPrice(makeRatio(9990n, run.brand, 1000n, aeth.brand)); + await aethPriceAuthority.setPrice( + makeRatio(9990n, run.brand, 1000n, aeth.brand), + ); await eventLoopIteration(); await setClockAndAdvanceNTimes( diff --git a/packages/inter-protocol/test/vaultFactory/vaultFactoryUtils.js b/packages/inter-protocol/test/vaultFactory/vaultFactoryUtils.js index 16592960c9fe..89630dac60df 100644 --- a/packages/inter-protocol/test/vaultFactory/vaultFactoryUtils.js +++ b/packages/inter-protocol/test/vaultFactory/vaultFactoryUtils.js @@ -4,6 +4,8 @@ import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; import { makeNotifierFromSubscriber } from '@agoric/notifier'; import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; import { makeManualPriceAuthority } from '@agoric/zoe/tools/manualPriceAuthority.js'; +import { makeScalarBigMapStore } from '@agoric/vat-data/src/index.js'; +import { providePriceAuthorityRegistry } from '@agoric/zoe/tools/priceAuthorityRegistry.js'; import { makeScriptedPriceAuthority } from '@agoric/zoe/tools/scriptedPriceAuthority.js'; import { E } from '@endo/eventual-send'; @@ -96,8 +98,18 @@ export const setupElectorateReserveAndAuction = async ( await setupReserve(space); const quoteIssuerKit = makeIssuerKit('quote', AssetKind.SET); - // Cheesy hack for easy use of manual price authority - const pa = Array.isArray(priceOrList) + // priceAuthorityReg is the registry, which contains and multiplexes multiple + // individual priceAuthorities, including aethPriceAuthority. + // priceAuthorityAdmin supports registering more individual priceAuthorities + // with the registry. + /** + * @type {PriceAuthority & { + * setPrice: (Ratio) => void; + * disable: () => void; + * }} + */ + // @ts-expect-error scriptedPriceAuthority doesn't actually match this, but manualPriceAuthority does + const aethPriceAuthority = Array.isArray(priceOrList) ? makeScriptedPriceAuthority({ actualBrandIn: aeth.brand, actualBrandOut: run.brand, @@ -114,7 +126,16 @@ export const setupElectorateReserveAndAuction = async ( timer, quoteIssuerKit, }); - space.produce.priceAuthority.resolve(pa); + const baggage = makeScalarBigMapStore('baggage'); + const { priceAuthority: priceAuthorityReg, adminFacet: priceAuthorityAdmin } = + providePriceAuthorityRegistry(baggage); + await E(priceAuthorityAdmin).registerPriceAuthority( + aethPriceAuthority, + aeth.brand, + run.brand, + ); + + space.produce.priceAuthority.resolve(priceAuthorityReg); const auctionParams = { StartFrequency, @@ -127,7 +148,12 @@ export const setupElectorateReserveAndAuction = async ( }; await startAuctioneer(space, { auctionParams }); - return { space }; + return { + space, + priceAuthority: priceAuthorityReg, + priceAuthorityAdmin, + aethPriceAuthority, + }; }; /**