diff --git a/a3p-integration/proposals/e:upgrade-next/priceFeed-follower-auction.test.js b/a3p-integration/proposals/e:upgrade-next/priceFeed-follower-auction.test.js deleted file mode 100644 index 30ae903b075..00000000000 --- a/a3p-integration/proposals/e:upgrade-next/priceFeed-follower-auction.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import test from 'ava'; -import { getDetailsMatchingVats } from './vatDetails.js'; - -test('new auction vat', async t => { - const details = await getDetailsMatchingVats('auctioneer'); - // This query matches both the auction and its governor, so 2*2 - t.is(Object.keys(details).length, 4); -}); diff --git a/a3p-integration/proposals/f:replace-price-feeds/README.md b/a3p-integration/proposals/f:replace-price-feeds/README.md new file mode 100644 index 00000000000..414bb07fe81 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/README.md @@ -0,0 +1,10 @@ +# CoreEvalProposal to replace existing price_feed and scaledPriceAuthority vats +# with new contracts. Auctions will need to be replaced, and Vaults will need to +# get at least a null upgrade in order to make use of the new prices. Oracle +# operators will need to accept new invitations, and sync to the roundId (0) of +# the new contracts in order to feed the new pipelines. + +The `submission` for this proposal is automatically generated during `yarn build` +in [a3p-integration](../..) using the code in agoric-sdk through +[build-all-submissions.sh](../../scripts/build-all-submissions.sh) and +[build-submission.sh](../../scripts/build-submission.sh). diff --git a/a3p-integration/proposals/e:upgrade-next/agd-tools.js b/a3p-integration/proposals/f:replace-price-feeds/agd-tools.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/agd-tools.js rename to a3p-integration/proposals/f:replace-price-feeds/agd-tools.js diff --git a/a3p-integration/proposals/f:replace-price-feeds/package.json b/a3p-integration/proposals/f:replace-price-feeds/package.json new file mode 100644 index 00000000000..fe1c38a203a --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/package.json @@ -0,0 +1,34 @@ +{ + "agoricProposal": { + "releaseNotes": false, + "sdkImageTag": "unreleased", + "planName": "UNRELEASED_A3P_INTEGRATION", + "upgradeInfo": { + "coreProposals": [] + }, + "sdk-generate": [ + "vats/replacePriceFeeds.js", + "vats/replace-scaledPriceAuthorities.js", + "vats/add-auction.js", + "vats/upgradeVaults.js" + ], + "type": "Software Upgrade Proposal" + }, + "type": "module", + "license": "Apache-2.0", + "dependencies": { + "@agoric/synthetic-chain": "^0.1.0", + "ava": "^5.3.1" + }, + "ava": { + "concurrency": 1, + "timeout": "2m", + "files": [ + "!submission" + ] + }, + "scripts": { + "agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops" + }, + "packageManager": "yarn@4.2.2" +} diff --git a/a3p-integration/proposals/f:replace-price-feeds/test.sh b/a3p-integration/proposals/f:replace-price-feeds/test.sh new file mode 100755 index 00000000000..23a194f7f79 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Place here any test that should be executed using the proposal. +# The effects of this step are not persisted in further layers. + +yarn ava ./*.test.js diff --git a/a3p-integration/proposals/e:upgrade-next/.gitignore b/a3p-integration/proposals/n:upgrade-next/.gitignore similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/.gitignore rename to a3p-integration/proposals/n:upgrade-next/.gitignore diff --git a/a3p-integration/proposals/e:upgrade-next/.yarnrc.yml b/a3p-integration/proposals/n:upgrade-next/.yarnrc.yml similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/.yarnrc.yml rename to a3p-integration/proposals/n:upgrade-next/.yarnrc.yml diff --git a/a3p-integration/proposals/e:upgrade-next/README.md b/a3p-integration/proposals/n:upgrade-next/README.md similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/README.md rename to a3p-integration/proposals/n:upgrade-next/README.md diff --git a/a3p-integration/proposals/n:upgrade-next/agd-tools.js b/a3p-integration/proposals/n:upgrade-next/agd-tools.js new file mode 100644 index 00000000000..550668e110b --- /dev/null +++ b/a3p-integration/proposals/n:upgrade-next/agd-tools.js @@ -0,0 +1,208 @@ +import { + agd, + agops, + agopsLocation, + CHAINID, + executeCommand, + executeOffer, + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, + newOfferId, + VALIDATORADDR, +} from '@agoric/synthetic-chain'; + +const ORACLE_ADDRESSES = [GOV1ADDR, GOV2ADDR, GOV3ADDR]; + +export const BID_OFFER_ID = 'bid-vaultUpgrade-test3'; + +const queryVstorage = path => + agd.query('vstorage', 'data', '--output', 'json', path); + +// XXX use endo/marshal? +const getQuoteBody = async path => { + const queryOut = await queryVstorage(path); + + const body = JSON.parse(JSON.parse(queryOut.value).values[0]); + return JSON.parse(body.body.substring(1)); +}; + +export const getOracleInstance = async price => { + const instanceRec = await queryVstorage(`published.agoricNames.instance`); + + const value = JSON.parse(instanceRec.value); + const body = JSON.parse(value.values.at(-1)); + + const feeds = JSON.parse(body.body.substring(1)); + const feedName = `${price}-USD price feed`; + + const key = Object.keys(feeds).find(k => feeds[k][0] === feedName); + if (key) { + return body.slots[key]; + } + return null; +}; + +export const checkForOracle = async (t, name) => { + const instance = await getOracleInstance(name); + t.truthy(instance); +}; + +export const registerOraclesForBrand = async (brandIn, oraclesByBrand) => { + await null; + const promiseArray = []; + + const oraclesWithID = oraclesByBrand.get(brandIn); + for (const oracle of oraclesWithID) { + const { address, offerId } = oracle; + promiseArray.push( + executeOffer( + address, + agops.oracle('accept', '--offerId', offerId, `--pair ${brandIn}.USD`), + ), + ); + } + + return Promise.all(promiseArray); +}; + +/** + * Generate a consistent map of oracleIDs for a brand that can be used to + * register oracles or to push prices. The baseID changes each time new + * invitations are sent/accepted, and need to be maintained as constants in + * scripts that use the oracles. Each oracleAddress and brand needs a unique + * offerId, so we create recoverable IDs using the brandName and oracle id, + * mixed with the upgrade at which the invitations were accepted. + * + * @param {string} baseId + * @param {string} brandName + */ +const addOraclesForBrand = (baseId, brandName) => { + const oraclesWithID = []; + for (let i = 0; i < ORACLE_ADDRESSES.length; i += 1) { + const oracleAddress = ORACLE_ADDRESSES[i]; + const offerId = `${brandName}.${baseId}.${i}`; + oraclesWithID.push({ address: oracleAddress, offerId }); + } + return oraclesWithID; +}; + +export const addPreexistingOracles = async (brandIn, oraclesByBrand) => { + await null; + + const oraclesWithID = []; + for (let i = 0; i < ORACLE_ADDRESSES.length; i += 1) { + const oracleAddress = ORACLE_ADDRESSES[i]; + + const path = `published.wallet.${oracleAddress}.current`; + const wallet = await getQuoteBody(path); + const idToInvitation = wallet.offerToUsedInvitation.find(([k]) => { + return !isNaN(k[0]); + }); + if (idToInvitation) { + oraclesWithID.push({ + address: oracleAddress, + offerId: idToInvitation[0], + }); + } else { + console.log('AGD addO skip', oraclesWithID); + } + } + + oraclesByBrand.set(brandIn, oraclesWithID); +}; + +/** + * Generate a consistent map of oracleIDs and brands that can be used to + * register oracles or to push prices. The baseID changes each time new + * invitations are sent/accepted, and need to be maintained as constants in + * scripts that use these records to push prices. + * + * @param {string} baseId + * @param {string[]} brandNames + */ +export const generateOracleMap = (baseId, brandNames) => { + const oraclesByBrand = new Map(); + for (const brandName of brandNames) { + const oraclesWithID = addOraclesForBrand(baseId, brandName); + oraclesByBrand.set(brandName, oraclesWithID); + } + return oraclesByBrand; +}; + +export const pushPrices = (price, brandIn, oraclesByBrand) => { + const promiseArray = []; + + for (const oracle of oraclesByBrand.get(brandIn)) { + promiseArray.push( + executeOffer( + oracle.address, + agops.oracle( + 'pushPriceRound', + '--price', + price, + '--oracleAdminAcceptOfferId', + oracle.offerId, + ), + ), + ); + } + + return Promise.all(promiseArray); +}; + +export const getPriceQuote = async price => { + const path = `published.priceFeed.${price}-USD_price_feed`; + const body = await getQuoteBody(path); + return body.amountOut.value; +}; + +export const agopsInter = (...params) => { + const newParams = ['inter', ...params]; + return executeCommand(agopsLocation, newParams); +}; + +export const createBid = (price, addr, offerId) => { + return agopsInter( + 'bid', + 'by-price', + `--price ${price}`, + `--give 1.0IST`, + '--from', + addr, + '--keyring-backend test', + `--offer-id ${offerId}`, + ); +}; + +export const getLiveOffers = async addr => { + const path = `published.wallet.${addr}.current`; + const body = await getQuoteBody(path); + return body.liveOffers; +}; + +export const getAuctionCollateral = async index => { + const path = `published.auction.book${index}`; + const body = await getQuoteBody(path); + return body.collateralAvailable.value; +}; + +export const getVaultPrices = async index => { + const path = `published.vaultFactory.managers.manager${index}.quotes`; + const body = await getQuoteBody(path); + return body.quoteAmount; +}; + +export const bankSend = (addr, wanted) => { + const chain = ['--chain-id', CHAINID]; + const from = ['--from', VALIDATORADDR]; + const testKeyring = ['--keyring-backend', 'test']; + const noise = [...from, ...chain, ...testKeyring, '--yes']; + + return agd.tx('bank', 'send', VALIDATORADDR, addr, wanted, ...noise); +}; + +export const getProvisionPoolMetrics = async () => { + const path = `published.provisionPool.metrics`; + return getQuoteBody(path); +}; diff --git a/a3p-integration/proposals/e:upgrade-next/initial.test.js b/a3p-integration/proposals/n:upgrade-next/initial.test.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/initial.test.js rename to a3p-integration/proposals/n:upgrade-next/initial.test.js diff --git a/a3p-integration/proposals/e:upgrade-next/localchain.test.js b/a3p-integration/proposals/n:upgrade-next/localchain.test.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/localchain.test.js rename to a3p-integration/proposals/n:upgrade-next/localchain.test.js diff --git a/a3p-integration/proposals/e:upgrade-next/package.json b/a3p-integration/proposals/n:upgrade-next/package.json similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/package.json rename to a3p-integration/proposals/n:upgrade-next/package.json diff --git a/a3p-integration/proposals/e:upgrade-next/prepare.sh b/a3p-integration/proposals/n:upgrade-next/prepare.sh similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/prepare.sh rename to a3p-integration/proposals/n:upgrade-next/prepare.sh diff --git a/a3p-integration/proposals/e:upgrade-next/provisionPool.test.js b/a3p-integration/proposals/n:upgrade-next/provisionPool.test.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/provisionPool.test.js rename to a3p-integration/proposals/n:upgrade-next/provisionPool.test.js diff --git a/a3p-integration/proposals/e:upgrade-next/synthetic-chain-excerpt.js b/a3p-integration/proposals/n:upgrade-next/synthetic-chain-excerpt.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/synthetic-chain-excerpt.js rename to a3p-integration/proposals/n:upgrade-next/synthetic-chain-excerpt.js diff --git a/a3p-integration/proposals/e:upgrade-next/test.sh b/a3p-integration/proposals/n:upgrade-next/test.sh similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/test.sh rename to a3p-integration/proposals/n:upgrade-next/test.sh diff --git a/a3p-integration/proposals/e:upgrade-next/tsconfig.json b/a3p-integration/proposals/n:upgrade-next/tsconfig.json similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/tsconfig.json rename to a3p-integration/proposals/n:upgrade-next/tsconfig.json diff --git a/a3p-integration/proposals/e:upgrade-next/vatDetails.js b/a3p-integration/proposals/n:upgrade-next/vatDetails.js similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/vatDetails.js rename to a3p-integration/proposals/n:upgrade-next/vatDetails.js diff --git a/a3p-integration/proposals/e:upgrade-next/yarn.lock b/a3p-integration/proposals/n:upgrade-next/yarn.lock similarity index 100% rename from a3p-integration/proposals/e:upgrade-next/yarn.lock rename to a3p-integration/proposals/n:upgrade-next/yarn.lock diff --git a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js new file mode 100644 index 00000000000..d3b22f57dae --- /dev/null +++ b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js @@ -0,0 +1,61 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { strictPriceFeedProposalBuilder } from '../vats/priceFeedSupport.js'; + +const configurations = { + UNRELEASED_A3P_INTEGRATION: { + oracleAddresses: [ + 'agoric1lu9hh5vgx05hmlpfu47hukershgdxctk6l5s05', // GOV1 + 'agoric15lpnq2mjsdhtztf6khp7mrsq66hyrssspy92pd', // GOV2 + 'agoric1mwm224epc4l3pjcz7qsxnudcuktpynwkmnfqfp', // GOV3 + ], + inBrandNames: ['ATOM', 'stATOM'], + }, + UNRELEASED_main: { + oracleAddresses: [ + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', // DSRV + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', // Stakin + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', // 01node + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', // Simply Staking + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', // P2P + ], + inBrandName: ['ATOM', 'stATOM', 'stOSMO', 'stTIA', 'stkATOM'], + }, + UNRELEASED_devnet: { + oracleAddresses: [ + 'agoric1lw4e4aas9q84tq0q92j85rwjjjapf8dmnllnft', // DSRV + 'agoric1zj6vrrrjq4gsyr9lw7dplv4vyejg3p8j2urm82', // Stakin + 'agoric1ra0g6crtsy6r3qnpu7ruvm7qd4wjnznyzg5nu4', // 01node + 'agoric1qj07c7vfk3knqdral0sej7fa6eavkdn8vd8etf', // Simply Staking + 'agoric10vjkvkmpp9e356xeh6qqlhrny2htyzp8hf88fk', // P2P + ], + inBrandNames: ['ATOM', 'stTIA', 'stkATOM'], + }, +}; + +export default async (homeP, endowments) => { + const upgradeEnvironment = endowments.scriptArgs?.[0]; + console.log('UPPrices', upgradeEnvironment); + + const { writeCoreEval } = await makeHelpers(homeP, endowments); + + const coreEvalSteps = []; + for (const config of configurations[upgradeEnvironment]) { + const { inBrandNames, oracleAddresses } = config; + for (const inBrandName of inBrandNames) { + const options = { + AGORIC_INSTANCE_NAME: `${inBrandName}-USD price feed`, + ORACLE_ADDRESSES: oracleAddresses, + IN_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', inBrandName], + }; + coreEvalSteps.push( + writeCoreEval(options.AGORIC_INSTANCE_NAME, opts => + strictPriceFeedProposalBuilder({ ...opts, ...options }), + ), + ); + } + } + + // TODO(hibbert) leave a marker in promise space as a signal to vaults upgrade + + await Promise.all(coreEvalSteps); +}; diff --git a/packages/builders/scripts/vats/replaceScaledPriceAuthorities.js b/packages/builders/scripts/vats/replaceScaledPriceAuthorities.js new file mode 100644 index 00000000000..805a6feae82 --- /dev/null +++ b/packages/builders/scripts/vats/replaceScaledPriceAuthorities.js @@ -0,0 +1,22 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }) => + harden({ + sourceSpec: + '@agoric/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js', + getManifestCall: [ + 'getManifestForReplaceScaledPriceAuthorities', + { + scaledPARef: publishRef( + install('@agoric/zoe/src/contracts/scaledPriceAuthority.js'), + ), + }, + ], + }); + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + + await writeCoreEval('replaceScaledPriceAuthorities', defaultProposalBuilder); +}; diff --git a/packages/inter-protocol/src/proposals/addAssetToVault.js b/packages/inter-protocol/src/proposals/addAssetToVault.js index f1481e09099..671aa8fec31 100644 --- a/packages/inter-protocol/src/proposals/addAssetToVault.js +++ b/packages/inter-protocol/src/proposals/addAssetToVault.js @@ -129,7 +129,7 @@ export const publishInterchainAssetFromBank = async ( * @param {object} config.options * @param {InterchainAssetOptions} config.options.interchainAssetOptions */ -export const registerScaledPriceAuthority = async ( +export const startScaledPriceAuthority = async ( { consume: { agoricNamesAdmin, @@ -137,7 +137,6 @@ export const registerScaledPriceAuthority = async ( priceAuthorityAdmin, priceAuthority, }, - instance: { produce: produceInstance }, }, { options: { interchainAssetOptions } }, ) => { @@ -230,6 +229,25 @@ export const registerScaledPriceAuthority = async ( true, // force ); + return spaKit; +}; + +/** + * @param {BootstrapPowers} powers + * @param {object} config + * @param {object} config.options + */ +export const registerScaledPriceAuthority = async (powers, { options }) => { + const { + instance: { produce: produceInstance }, + } = powers; + + const { keyword, issuerName = keyword } = options.interchainAssetOptions; + + const spaKit = await startScaledPriceAuthority(powers, { options }); + + const label = scaledPriceFeedName(issuerName); + // publish into agoricNames so that others can await its presence. // This must stay after registerPriceAuthority above so it's evidence of registration. // eslint-disable-next-line no-restricted-syntax -- computed property diff --git a/packages/inter-protocol/src/proposals/price-feed-proposal.js b/packages/inter-protocol/src/proposals/price-feed-proposal.js index ef0808cea6e..ffe124dbd4d 100644 --- a/packages/inter-protocol/src/proposals/price-feed-proposal.js +++ b/packages/inter-protocol/src/proposals/price-feed-proposal.js @@ -227,7 +227,8 @@ export const createPriceFeed = async ( // being after the above awaits means that when this resolves, the consumer // gets notified that the authority is in the registry and its instance is in - // agoricNames. + // agoricNames. reset() in case we're replacing an existing feed. + produceInstance[AGORIC_INSTANCE_NAME].reset(); produceInstance[AGORIC_INSTANCE_NAME].resolve(faKit.instance); E(E.get(econCharterKit).creatorFacet).addInstance( diff --git a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthority.js b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthority.js new file mode 100644 index 00000000000..a4fa673c6af --- /dev/null +++ b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthority.js @@ -0,0 +1,127 @@ +import { makeTracer } from '@agoric/internal'; +import { E } from '@endo/far'; +import { deeplyFulfilled } from '@endo/marshal'; + +import { startScaledPriceAuthority } from './addAssetToVault.js'; +import { scaledPriceFeedName } from './utils.js'; + +const trace = makeTracer('replaceScaledPA', true); + +/** + * @param {BootstrapPowers} powers + * @param {object} config + * @param {object} config.options + */ +export const replaceScaledPriceAuthority = async (powers, { options }) => { + const { + instance: { produce: produceInstance }, + } = powers; + const { keyword, issuerName = keyword } = options.interchainAssetOptions; + + const spaKit = await startScaledPriceAuthority(powers, { options }); + + const label = scaledPriceFeedName(issuerName); + produceInstance[label].reset(); + + // publish into agoricNames so that others can await its presence. + // This must stay after registerPriceAuthority above so it's evidence of registration. + produceInstance[label].resolve(spaKit.instance); +}; + +/** + * @typedef {PromiseSpaceOf<{ scaledPriceAuthoritiesDone: boolean }>} donePowers + */ + +/** + * Look up the existing assets known to auctions, and replace the corresponding + * scaledPriceAuthorities. The existing contracts will be left behind to be + * cleaned up later. + * + * @param {ChainBootstrapSpace & BootstrapPowers & donePowers} powers + * @param {{ options: { scaledPARef: { bundleID: string } } }} options + */ +export const replaceScaledPriceAuthorities = async (powers, { options }) => { + trace('start'); + const { + consume: { agoricNamesAdmin, contractKits: contractKitsP, zoe }, + produce: { scaledPriceAuthoritiesDone }, + } = powers; + + const { scaledPARef } = options; + + const installationsAdmin = E(agoricNamesAdmin).lookupAdmin('installation'); + const [spaInstallation, contractKits] = await Promise.all([ + E(E(installationsAdmin).readonly()).lookup('scaledPriceAuthority'), + contractKitsP, + ]); + + const bundleID = scaledPARef.bundleID; + if (scaledPARef && bundleID) { + await E.when( + E(zoe).installBundleID(bundleID), + installation => + E(installationsAdmin).update('scaledPriceAuthority', installation), + err => + console.error( + `🚨 failed to update scaledPriceAuthority installation`, + err, + ), + ); + trace('installed scaledPriceAuthority bundle', bundleID); + } + + // Ask Zoe for the installation for each kit's instance, and return all the + // kits where that matches the given installation. + async function selectKitsWithInstallation(kits) { + /** @type {StartedInstanceKit[]} */ + const scaledPAKitMapP = Array.from(kits.values()).map(kit => [ + kit, + E(zoe).getInstallationForInstance(kit.instance), + ]); + const scaledPAKitMap = await deeplyFulfilled(harden(scaledPAKitMapP)); + const scaledPAKitEntries = []; + for (const [instance, installation] of scaledPAKitMap) { + if (spaInstallation === installation) { + scaledPAKitEntries.push(instance); + } + } + return scaledPAKitEntries; + } + const scaledPAKitEntries = await selectKitsWithInstallation(contractKits); + + for (const kitEntry of scaledPAKitEntries) { + trace({ kitEntry }); + + const keyword = kitEntry.label.match(/scaledPriceAuthority-(.*)/)[1]; + const interchainAssetOptions = { keyword }; + await replaceScaledPriceAuthority(powers, { + options: { interchainAssetOptions }, + }); + } + + scaledPriceAuthoritiesDone.resolve(true); +}; + +const t = 'replaceScaledPriceAuthority'; +export const getManifestForReplaceScaledPriceAuthorities = async ( + _ign, + upgradeSPAOptions, +) => ({ + manifest: { + [replaceScaledPriceAuthorities.name]: { + consume: { + agoricNamesAdmin: t, + contractKits: t, + priceAuthority: t, + priceAuthorityAdmin: t, + zoe: t, + startUpgradable: t, + }, + produce: { scaledPriceAuthoritiesDone: t }, + instance: { + produce: t, + }, + }, + }, + options: { ...upgradeSPAOptions }, +}); diff --git a/packages/zoe/src/contractSupport/priceAuthorityInitial.js b/packages/zoe/src/contractSupport/priceAuthorityInitial.js index 110c5affc9b..ff4808f9369 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityInitial.js +++ b/packages/zoe/src/contractSupport/priceAuthorityInitial.js @@ -110,7 +110,7 @@ export const makeInitialTransform = ( : quoteP; }; - return Far('PriceAuthority', { + return Far('ScaledPriceAuthorityWithInitialValue', { ...priceAuthority, makeQuoteNotifier, quoteGiven, diff --git a/packages/zoe/src/contractSupport/priceAuthorityTransform.js b/packages/zoe/src/contractSupport/priceAuthorityTransform.js index ce2d79217b9..ac6425c2b9f 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityTransform.js +++ b/packages/zoe/src/contractSupport/priceAuthorityTransform.js @@ -182,7 +182,7 @@ export const makePriceAuthorityTransform = async ({ }; /** @type {PriceAuthority} */ - const priceAuthority = Far('PriceAuthority', { + const priceAuthority = Far('ScaledPriceAuthority', { getQuoteIssuer(brandIn, brandOut) { assertBrands(brandIn, brandOut); return quoteIssuer; diff --git a/packages/zoe/src/contracts/scaledPriceAuthority.js b/packages/zoe/src/contracts/scaledPriceAuthority.js index b558a315c16..2b43bff8fcf 100644 --- a/packages/zoe/src/contracts/scaledPriceAuthority.js +++ b/packages/zoe/src/contracts/scaledPriceAuthority.js @@ -52,7 +52,9 @@ export const prepare = async (zcf, privateArgs, baggage) => { const priceAuthority = makePriceAuthorityTransform({ quoteMint, - sourcePriceAuthority, + // If the priceAuthority is overridden in privateArgs, use that version + sourcePriceAuthority: + privateArgs?.newPriceAuthority || sourcePriceAuthority, sourceBrandIn, sourceBrandOut, actualBrandIn,