-
Notifications
You must be signed in to change notification settings - Fork 215
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(a3p): test mintHolder functionalities after contract null upgrade (
#10617) closes: #10410 ## Description This pull request intends to ensure that the mintHolder contract continues to function as expected after a null upgrade. Key Changes: - A new `core-eval` was built, which acordingly to the agoric chain variant, will select a list of vbankAsset and execute a null upgrade to the respective mintHolder contract of each suitable asset. - A new acceptance test, `mintHolder.test.js`, has been added to the a3p-integration to verify the core-eval behaviour. MintHolder Test Plan: - Provision a receiver wallet with the respective assets - Confirm the initial balance matches expectations - Perform a null upgrade for the mintHolder contracts - Execute a core-eval to: - Mint a payment for each selected asset - Deposit the payment into the receiver's depositFacet - Verify that the balance has increased by the expected amount - Execute a PSM swap for selected assets with IST ### Security Considerations The execution of `mintHolder.test.js` had to be done prior to the `./genesis-test.sh` acceptance test. Otherwise it would trigger the error `bundle ${id} not loaded` during the `evalBundle` call. See this issue for more detail: #10620 ### Scaling Considerations This PR does not introduce any change to the mintHolder source code, or how it is being consumed. For this reason that are no scaling considerations to be made. ### Documentation Considerations ### Testing Considerations The implemented test design is expecting to have a core-eval for each mintHolder being updated. If desired, this could be refactored to have a single core-eval executing a null upgrade to a predefined list of assets. The second approach has the advantage of reducing the number of files being created, although it may hinder the testing flexibility. Which approach is more desirable? ### Upgrade Considerations
- Loading branch information
Showing
12 changed files
with
890 additions
and
392 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ addUsdOlives/ | |
upgradeProvisionPool/ | ||
upgradeAgoricNames/ | ||
publishTestInfo/ | ||
upgrade-mintHolder/ |
1 change: 1 addition & 0 deletions
1
a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
true |
56 changes: 56 additions & 0 deletions
56
a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* global E */ | ||
|
||
/// <reference types="@agoric/vats/src/core/core-eval-env"/> | ||
/// <reference types="@agoric/vats/src/core/types-ambient"/> | ||
|
||
/** | ||
* The primary purpose of this script is to mint a payment of a certain | ||
* bankAsset and deposit in an user wallet. | ||
* | ||
* The receiverAddress and label placeholders should be replaced with | ||
* the desired address and asset name during the execution of each test case. | ||
* | ||
* See z:acceptance/mintHolder.test.js | ||
* | ||
* @param {BootstrapPowers} powers | ||
*/ | ||
const sendBankAsset = async powers => { | ||
const { | ||
consume: { namesByAddress, contractKits: contractKitsP }, | ||
} = powers; | ||
|
||
const receiverAddress = '{{ADDRESS}}'; | ||
const label = '{{LABEL}}'; | ||
const valueStr = '{{VALUE}}'; | ||
const value = BigInt(valueStr) | ||
|
||
console.log(`Start sendBankAsset for ${label}`); | ||
|
||
const contractKits = await contractKitsP; | ||
const mintHolderKit = Array.from(contractKits.values()).filter( | ||
kit => kit.label && kit.label === label, | ||
); | ||
|
||
const { creatorFacet: mint, publicFacet: issuer } = mintHolderKit[0]; | ||
|
||
/* | ||
* Ensure that publicFacet holds an issuer by verifying that has | ||
* the makeEmptyPurse method. | ||
*/ | ||
await E(issuer).makeEmptyPurse() | ||
|
||
const brand = await E(issuer).getBrand(); | ||
const amount = harden({ value, brand }); | ||
const payment = await E(mint).mintPayment(amount); | ||
|
||
const receiverDepositFacet = E(namesByAddress).lookup( | ||
receiverAddress, | ||
'depositFacet', | ||
); | ||
|
||
await E(receiverDepositFacet).receive(payment); | ||
|
||
console.log(`Finished sendBankAsset for ${label}`); | ||
}; | ||
|
||
sendBankAsset; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* eslint-env node */ | ||
|
||
import '@endo/init'; | ||
import test from 'ava'; | ||
import { addUser, provisionSmartWallet } from '@agoric/synthetic-chain'; | ||
import { | ||
mintPayment, | ||
getAssetList, | ||
swap, | ||
getPSMChildren, | ||
upgradeMintHolder, | ||
} from './test-lib/mintHolder-helpers.js'; | ||
import { networkConfig } from './test-lib/index.js'; | ||
|
||
test('mintHolder contract is upgraded', async t => { | ||
const receiver = await addUser('receiver'); | ||
await provisionSmartWallet(receiver, `20000000ubld`); | ||
|
||
let assetList = await getAssetList(); | ||
t.log('List of mintHolder vats being upgraded: ', assetList); | ||
await upgradeMintHolder(`upgrade-mintHolder`, assetList); | ||
await mintPayment(t, receiver, assetList, 10); | ||
|
||
const psmLabelList = await getPSMChildren(fetch, networkConfig); | ||
assetList = await getAssetList(psmLabelList); | ||
t.log('List of assets being swapped with IST via PSM: ', assetList); | ||
await swap(t, receiver, assetList, 5); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* eslint-env node */ | ||
|
||
import { | ||
agoric, | ||
evalBundles, | ||
getDetailsMatchingVats, | ||
getISTBalance, | ||
} from '@agoric/synthetic-chain'; | ||
import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils'; | ||
import { readFile, writeFile } from 'node:fs/promises'; | ||
import { psmSwap, snapshotAgoricNames } from './psm-lib.js'; | ||
|
||
/** | ||
* @param {string} fileName base file name without .tjs extension | ||
* @param {Record<string, string>} replacements | ||
*/ | ||
export const replaceTemplateValuesInFile = async (fileName, replacements) => { | ||
let script = await readFile(`${fileName}.tjs`, 'utf-8'); | ||
for (const [template, value] of Object.entries(replacements)) { | ||
script = script.replaceAll(`{{${template}}}`, value); | ||
} | ||
await writeFile(`${fileName}.js`, script); | ||
}; | ||
|
||
export const getPSMChildren = async (fetch, networkConfig) => { | ||
const { | ||
vstorage: { keys }, | ||
} = await makeVstorageKit({ fetch }, networkConfig); | ||
|
||
const children = await keys('published.psm.IST'); | ||
|
||
return children; | ||
}; | ||
|
||
export const getAssetList = async labelList => { | ||
const assetList = []; | ||
const { vbankAssets } = await snapshotAgoricNames(); | ||
|
||
// Determine the assets to consider based on labelList | ||
const assetsToConsider = | ||
labelList || Object.values(vbankAssets).map(asset => asset.issuerName); | ||
|
||
for (const label of assetsToConsider) { | ||
if (label === 'IST') { | ||
break; | ||
} | ||
|
||
const vbankAsset = Object.values(vbankAssets).find( | ||
asset => asset.issuerName === label, | ||
); | ||
assert(vbankAsset, `vbankAsset not found for ${label}`); | ||
|
||
const { denom } = vbankAsset; | ||
const mintHolderVat = `zcf-mintHolder-${label}`; | ||
|
||
assetList.push({ label, denom, mintHolderVat }); | ||
} | ||
|
||
return assetList; | ||
}; | ||
|
||
export const mintPayment = async (t, address, assetList, value) => { | ||
const SUBMISSION_DIR = 'mint-payment'; | ||
|
||
for (const asset of assetList) { | ||
const { label, denom } = asset; | ||
const scaled = BigInt(parseInt(value, 10) * 1_000_000).toString(); | ||
|
||
await replaceTemplateValuesInFile(`${SUBMISSION_DIR}/send-script`, { | ||
ADDRESS: address, | ||
LABEL: label, | ||
VALUE: scaled, | ||
}); | ||
|
||
await evalBundles(SUBMISSION_DIR); | ||
|
||
const balance = await getISTBalance(address, denom); | ||
|
||
// Add to value the BLD provisioned to smart wallet | ||
if (label === 'BLD') { | ||
value += 10; | ||
} | ||
|
||
t.is( | ||
balance, | ||
value, | ||
`receiver ${denom} balance ${balance} is not ${value}`, | ||
); | ||
} | ||
}; | ||
|
||
export const swap = async (t, address, assetList, want) => { | ||
for (const asset of assetList) { | ||
const { label, denom } = asset; | ||
|
||
// TODO: remove condition after fixing issue #10655 | ||
if (/^DAI/.test(label)) { | ||
break; | ||
} | ||
|
||
const pair = `IST.${label}`; | ||
|
||
const istBalanceBefore = await getISTBalance(address, 'uist'); | ||
const anchorBalanceBefore = await getISTBalance(address, denom); | ||
|
||
const psmSwapIo = { | ||
now: Date.now, | ||
follow: agoric.follow, | ||
setTimeout, | ||
log: console.log, | ||
}; | ||
|
||
await psmSwap( | ||
address, | ||
['swap', '--pair', pair, '--wantMinted', want], | ||
psmSwapIo, | ||
); | ||
|
||
const istBalanceAfter = await getISTBalance(address, 'uist'); | ||
const anchorBalanceAfter = await getISTBalance(address, denom); | ||
|
||
t.is(istBalanceAfter, istBalanceBefore + want); | ||
t.is(anchorBalanceAfter, anchorBalanceBefore - want); | ||
} | ||
}; | ||
|
||
const getIncarnationForAllVats = async assetList => { | ||
const vatsIncarnation = {}; | ||
|
||
for (const asset of assetList) { | ||
const { label, mintHolderVat } = asset; | ||
const matchingVats = await getDetailsMatchingVats(label); | ||
const expectedVat = matchingVats.find(vat => vat.vatName === mintHolderVat); | ||
vatsIncarnation[label] = expectedVat.incarnation; | ||
} | ||
assert(Object.keys(vatsIncarnation).length === assetList.length); | ||
|
||
return vatsIncarnation; | ||
}; | ||
|
||
const checkVatsUpgraded = (before, current) => { | ||
for (const vatLabel in before) { | ||
if (current[vatLabel] !== before[vatLabel] + 1) { | ||
console.log(`${vatLabel} upgrade failed. `); | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
|
||
export const upgradeMintHolder = async (submissionPath, assetList) => { | ||
const before = await getIncarnationForAllVats(assetList); | ||
|
||
await evalBundles(submissionPath); | ||
|
||
return retryUntilCondition( | ||
async () => getIncarnationForAllVats(assetList), | ||
current => checkVatsUpgraded(before, current), | ||
`mintHolder upgrade not processed yet`, | ||
{ setTimeout, retryIntervalMs: 5000, maxRetries: 15 }, | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.