diff --git a/a3p-integration/proposals/a:upgrade-next/invite-submission/README.md b/a3p-integration/proposals/a:upgrade-next/invite-submission/README.md new file mode 100644 index 00000000000..345d5cd67f2 --- /dev/null +++ b/a3p-integration/proposals/a:upgrade-next/invite-submission/README.md @@ -0,0 +1,8 @@ +These files enable a test of the walletFactory changes, by +verifying that upgraded wallets that aren't backed by vbanks can still add +assets, in this case an invitation. + +sendInvite is a secondary submission, which is transmitted in ../wallet-repair.test.js. +Some template values in the `.tjs` file are replaced before submitting the +core-eval. The test then verifies that the invitation details were written to +the wallet in vstorage. diff --git a/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite-permit.json b/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite-permit.json new file mode 100644 index 00000000000..27ba77ddaf6 --- /dev/null +++ b/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite-permit.json @@ -0,0 +1 @@ +true diff --git a/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite.tjs b/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite.tjs new file mode 100644 index 00000000000..e0ac3556255 --- /dev/null +++ b/a3p-integration/proposals/a:upgrade-next/invite-submission/sendInvite.tjs @@ -0,0 +1,39 @@ +#! false node --ignore-this-line +/* global E */ + +/// +/// + +// to be replaced before execution +const addr = '{{ADDRESS}}'; + +/** + * verify that a pre-existing wallet has an invitation purse that is still monitored + * + * @param {BootstrapPowers} powers + */ +const sendInvitation = async powers => { + console.log('sendInvitation start'); + // namesByAddress is broken #8113 + const { + consume: { namesByAddressAdmin, zoe }, + instance: { + consume: { reserve }, + }, + } = powers; + const pf = E(zoe).getPublicFacet(reserve); + const anInvitation = await E(pf).makeAddCollateralInvitation(); + + await E(namesByAddressAdmin).reserve(addr); + // don't trigger the namesByAddressAdmin.readonly() bug + const addressAdmin = E(namesByAddressAdmin).lookupAdmin(addr); + + await E(addressAdmin).reserve('depositFacet'); + const addressHub = E(addressAdmin).readonly(); + const addressDepositFacet = E(addressHub).lookup('depositFacet'); + + await E(addressDepositFacet).receive(anInvitation); + console.log('ADDED an invitation to a purse!'); +}; + +sendInvitation; diff --git a/a3p-integration/proposals/a:upgrade-next/wallet-repairs.test.js b/a3p-integration/proposals/a:upgrade-next/wallet-repairs.test.js new file mode 100755 index 00000000000..6d50acb1d2f --- /dev/null +++ b/a3p-integration/proposals/a:upgrade-next/wallet-repairs.test.js @@ -0,0 +1,46 @@ +import { readFile, writeFile } from 'node:fs/promises'; + +import test from 'ava'; + +import { agd, getUser, evalBundles } from '@agoric/synthetic-chain'; + +const SUBMISSION_DIR = 'invite-submission'; + +/** + * @param {string} fileName base file name without .tjs extension + * @param {Record} replacements + */ +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); +}; + +test('smartWallet repairs', async t => { + const gov1Address = await getUser('gov1'); + + await replaceTemplateValuesInFile(`${SUBMISSION_DIR}/sendInvite`, { + ADDRESS: gov1Address, + }); + + await evalBundles(SUBMISSION_DIR); + + // agd query vstorage data published.wallet.$GOV1ADDR.current -o json \ + // |& jq '.value | fromjson | .values[0] | fromjson | .body[1:] \ + // | fromjson | .purses ' + const walletCurrent = await agd.query( + 'vstorage', + 'data', + `published.wallet.${gov1Address}.current`, + ); + + const body = JSON.parse(JSON.parse(walletCurrent.value).values[0]); + const bodyTruncated = JSON.parse(body.body.substring(1)); + const invitePurseBalance = bodyTruncated.purses[0].balance; + t.truthy(invitePurseBalance.value[0], 'expecting a non-empty purse'); + const description = invitePurseBalance.value[0].description; + + t.is(description, 'Add Collateral', 'invitation purse should not be empty'); +});