Skip to content

Commit

Permalink
Add PSM upgrade for upgrade-19 (#10730)
Browse files Browse the repository at this point in the history
closes: #10403

## Description
Adds the upgrade of the psm contracts to upgrade 19. To ensure that this upgrade will succeed, we've also added test coverage in A3P.

### Upgrade Considerations

This PR adds the PSM contract to the list of vat upgrades. The PSM upgrade proposal will upgrade all PSM instances on the chain. We've added A3P tests to ensure that the upgrade is successful and that assets are still in the reserve after the upgrade.
  • Loading branch information
iomekam authored Dec 30, 2024
1 parent 745f2a8 commit 3f302ba
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 0 deletions.
1 change: 1 addition & 0 deletions a3p-integration/proposals/p:upgrade-19/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ publishTestInfo/
upgrade-mintHolder/
upgradeAssetReserve/
terminate-governor/
upgradePSM/
1 change: 1 addition & 0 deletions a3p-integration/proposals/p:upgrade-19/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"testing/add-USD-LEMONS.js addUsdLemons",
"vats/upgrade-provisionPool.js upgradeProvisionPool",
"vats/upgrade-asset-reserve.js upgradeAssetReserve",
"vats/upgrade-psm.js upgradePSM",
"vats/upgrade-paRegistry.js",
"vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames",
"testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives",
Expand Down
81 changes: 81 additions & 0 deletions a3p-integration/proposals/p:upgrade-19/psm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* eslint-env node */
/**
* @file The goal of this file is to make sure all the PSM contacts are upgrade. Each set of vats are different
* per chain, but for mainnet, we expect this to be: V37-V42, V73, V76
*
* The test scenario is as follows;
* 1. Simulate trade of IST and USDC
* 2. Upgrade all PSMs
* 3. Verify metrics are the same after the upgrade
* 4. Verify trading is still possible after the upgrade
*/

import '@endo/init';
import test from 'ava';
import { evalBundles } from '@agoric/synthetic-chain';
import { makeVstorageKit } from '@agoric/client-utils';

const UPGRADE_PSM_DIR = 'upgradePSM';
const SWAP_ANCHOR = 'swapAnchorForMintedSeat';

test.before(async t => {
const vstorageKit = await makeVstorageKit(
{ fetch },
{ rpcAddrs: ['http://localhost:26657'], chainName: 'agoriclocal' },
);

t.context = {
vstorageKit,
};
});

test.serial('simulate trade of IST and USDC', async t => {
// @ts-expect-error casting
const { vstorageKit } = t.context;

await evalBundles(SWAP_ANCHOR);

const metrics = await vstorageKit.readLatestHead(
'published.psm.IST.USDC.metrics',
);

t.is(metrics.anchorPoolBalance.value, 500000n);
t.is(metrics.feePoolBalance.value, 0n);
t.is(metrics.mintedPoolBalance.value, 500000n);
t.is(metrics.totalAnchorProvided.value, 0n);
t.is(metrics.totalMintedProvided.value, 500000n);
});

test.serial('upgrade PSMs', async t => {
// @ts-expect-error casting
const { vstorageKit } = t.context;

await evalBundles(UPGRADE_PSM_DIR);

const metrics = await vstorageKit.readLatestHead(
'published.psm.IST.USDC.metrics',
);

t.is(metrics.anchorPoolBalance.value, 500000n);
t.is(metrics.feePoolBalance.value, 0n);
t.is(metrics.mintedPoolBalance.value, 500000n);
t.is(metrics.totalAnchorProvided.value, 0n);
t.is(metrics.totalMintedProvided.value, 500000n);
});

test.serial('verify trading after upgrade', async t => {
// @ts-expect-error casting
const { vstorageKit } = t.context;

await evalBundles(SWAP_ANCHOR);

const metrics = await vstorageKit.readLatestHead(
'published.psm.IST.USDC.metrics',
);

t.is(metrics.anchorPoolBalance.value, 1000000n);
t.is(metrics.feePoolBalance.value, 0n);
t.is(metrics.mintedPoolBalance.value, 1000000n);
t.is(metrics.totalAnchorProvided.value, 0n);
t.is(metrics.totalMintedProvided.value, 1000000n);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"consume": {
"contractKits": true,
"zoe": true,
"agoricNames": true,
"psmKit": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// @ts-nocheck
/* eslint-disable no-undef */

const swapAnchorForMintedSeat = async powers => {
const {
consume: { zoe, contractKits: contractKitsP, psmKit: psmKitP, agoricNames },
} = powers;

const [contractKits, psmKit, usdcIssuer, usdcBrand] = await Promise.all([
contractKitsP,
psmKitP,
E(agoricNames).lookup('issuer', 'USDC'),
E(agoricNames).lookup('brand', 'USDC'),
]);

console.log('CONTRACT_KITS', contractKits);
console.log('ISSUER', usdcIssuer);

let govCreatorFacet;
for (const { psmGovernorCreatorFacet, label } of psmKit.values()) {
if (label === 'psm-IST-USDC') {
govCreatorFacet = psmGovernorCreatorFacet;
console.log('psm-IST-USDC found', label);
}
}

const psmPublicFacet = await E(govCreatorFacet).getPublicFacet();

let usdcMint;
for (const { publicFacet, creatorFacet: mint } of contractKits.values()) {
if (publicFacet === usdcIssuer) {
usdcMint = mint;
console.log('USDC found', mint);
break;
}
}

console.log('Minting USDC');
assert(usdcMint, 'USDC mint not found');

const amt = harden({ brand: usdcBrand, value: 500000n });
const payment = await E(usdcMint).mintPayment(amt);

const seat = E(zoe).offer(
E(psmPublicFacet).makeWantMintedInvitation(),
harden({
give: { In: amt },
}),
harden({ In: payment }),
);

console.log(await E(seat).getPayouts());

// We'll check for success in the tests that run this proposal by validating the metric values in
// vstorage
console.log('Done.');
};

swapAnchorForMintedSeat;
1 change: 1 addition & 0 deletions a3p-integration/proposals/p:upgrade-19/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ yarn ava provisionPool.test.js
yarn ava agoricNames.test.js

yarn ava assetReserve.test.js
yarn ava psm.test.js

yarn ava registry.test.js
3 changes: 3 additions & 0 deletions golang/cosmos/app/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Conte
// vm.CoreProposalStepForModules(
// "@agoric/builders/scripts/vats/upgrade-asset-reserve.js",
// ),
// vm.CoreProposalStepForModules(
// "@agoric/builders/scripts/vats/upgrade-psm.js",
// ),
// )

terminateOldGovernor, err := terminateGovernorCoreProposal(targetUpgrade)
Expand Down
19 changes: 19 additions & 0 deletions packages/builders/scripts/vats/upgrade-psm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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/vats/src/proposals/upgrade-psm-proposal.js',
getManifestCall: [
'getManifestForUpgradingPSM',
{
psmRef: publishRef(install('@agoric/inter-protocol/src/psm/psm.js')),
},
],
});

/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */
export default async (homeP, endowments) => {
const { writeCoreProposal } = await makeHelpers(homeP, endowments);
await writeCoreProposal('upgrade-psm', defaultProposalBuilder);
};
74 changes: 74 additions & 0 deletions packages/vats/src/proposals/upgrade-psm-proposal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { E } from '@endo/far';
import { deeplyFulfilled } from '@endo/marshal';
import { makeTracer } from '@agoric/internal';

const trace = makeTracer('UpgradePSM');

/**
* @param {BootstrapPowers & {
* consume: {
* economicCommitteeCreatorFacet: any;
* psmKit: any;
* };
* }} powers
* @param {object} options
* @param {{
* psmRef: VatSourceRef;
* }} options.options
*/
export const upgradePSMProposal = async (
{
consume: {
psmKit: psmKitP,
economicCommitteeCreatorFacet: electorateCreatorFacet,
instancePrivateArgs: instancePrivateArgsP,
},
},
options,
) => {
const { psmRef } = options.options;

trace(`PSM BUNDLE ID: `, psmRef);

const [psmKitMap, instancePrivateArgs] = await Promise.all([
psmKitP,
instancePrivateArgsP,
]);

for (const { psm, psmAdminFacet, label } of psmKitMap.values()) {
const [originalPrivateArgs, poserInvitation] = await Promise.all([
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Local tsc sees this as an error but typedoc does not
deeplyFulfilled(instancePrivateArgs.get(psm)),
E(electorateCreatorFacet).getPoserInvitation(),
]);

const newPrivateArgs = harden({
...originalPrivateArgs,
initialPoserInvitation: poserInvitation,
});

const upgradeResult = await E(psmAdminFacet).upgradeContract(
psmRef.bundleID,
newPrivateArgs,
);

trace(`PSM ${label} upgraded: `, upgradeResult);
}

trace('Done.');
};

export const getManifestForUpgradingPSM = (_powers, { psmRef }) => ({
manifest: {
[upgradePSMProposal.name]: {
consume: {
psmKit: true,
economicCommitteeCreatorFacet: true,
instancePrivateArgs: true,
},
produce: {},
},
},
options: { psmRef },
});

0 comments on commit 3f302ba

Please sign in to comment.