diff --git a/a3p-integration/proposals/p:upgrade-19/.gitignore b/a3p-integration/proposals/p:upgrade-19/.gitignore
index 9c595f7f2c6..b1f2bfa095d 100644
--- a/a3p-integration/proposals/p:upgrade-19/.gitignore
+++ b/a3p-integration/proposals/p:upgrade-19/.gitignore
@@ -5,4 +5,5 @@ addUsdOlives/
upgradeProvisionPool/
upgradeAgoricNames/
publishTestInfo/
+upgrade-mintHolder/
upgradeAssetReserve/
diff --git a/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json
new file mode 100644
index 00000000000..27ba77ddaf6
--- /dev/null
+++ b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json
@@ -0,0 +1 @@
+true
diff --git a/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs
new file mode 100644
index 00000000000..eb1a4815470
--- /dev/null
+++ b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs
@@ -0,0 +1,56 @@
+/* global E */
+
+///
+///
+
+/**
+ * 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;
diff --git a/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js
new file mode 100644
index 00000000000..32a187bcb25
--- /dev/null
+++ b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js
@@ -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);
+});
diff --git a/a3p-integration/proposals/p:upgrade-19/package.json b/a3p-integration/proposals/p:upgrade-19/package.json
index d9e5edccb02..666230406a8 100644
--- a/a3p-integration/proposals/p:upgrade-19/package.json
+++ b/a3p-integration/proposals/p:upgrade-19/package.json
@@ -11,13 +11,14 @@
"testing/test-upgraded-board.js testUpgradedBoard",
"vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames",
"testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives",
- "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo"
+ "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo",
+ "vats/upgrade-mintHolder.js upgrade-mintHolder A3P_INTEGRATION"
]
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
- "@agoric/client-utils": "0.1.1-dev-02c06c4.0",
+ "@agoric/client-utils": "dev",
"@agoric/ertp": "dev",
"@agoric/internal": "dev",
"@agoric/synthetic-chain": "^0.4.3",
diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js
new file mode 100644
index 00000000000..9639fd98662
--- /dev/null
+++ b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js
@@ -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} 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 },
+ );
+};
diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js
index 8f8d0abadc8..f98f5f6508c 100644
--- a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js
+++ b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js
@@ -3,10 +3,15 @@
import { execa } from 'execa';
import { getNetworkConfig } from 'agoric/src/helpers.js';
-import { waitUntilOfferResult } from '@agoric/client-utils';
+import {
+ waitUntilOfferResult,
+ makeFromBoard,
+ boardSlottingMarshaller,
+} from '@agoric/client-utils';
import { deepMapObject } from '@agoric/internal';
import {
agd,
+ agoric,
agopsLocation,
CHAINID,
executeCommand,
@@ -285,3 +290,23 @@ export const tryISTBalances = async (t, actualBalance, expectedBalance) => {
const minFeeDebit = 200_000;
t.is(actualBalance + minFeeDebit, expectedBalance);
};
+
+const fromBoard = makeFromBoard();
+const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal);
+
+/**
+ * @param {string} path
+ */
+const objectFromVstorageEntries = async path => {
+ const rawEntries = await agoric.follow('-lF', `:${path}`, '-o', 'text');
+ return Object.fromEntries(marshaller.fromCapData(JSON.parse(rawEntries)));
+};
+
+export const snapshotAgoricNames = async () => {
+ const [brands, instances, vbankAssets] = await Promise.all([
+ objectFromVstorageEntries('published.agoricNames.brand'),
+ objectFromVstorageEntries('published.agoricNames.instance'),
+ objectFromVstorageEntries('published.agoricNames.vbankAsset'),
+ ]);
+ return { brands, instances, vbankAssets };
+};
diff --git a/a3p-integration/proposals/p:upgrade-19/test.sh b/a3p-integration/proposals/p:upgrade-19/test.sh
index 9b998c5fa7e..193e27da231 100644
--- a/a3p-integration/proposals/p:upgrade-19/test.sh
+++ b/a3p-integration/proposals/p:upgrade-19/test.sh
@@ -2,7 +2,7 @@
yarn ava replaceFeeDistributor.test.js
yarn ava upgradedBoard.test.js
-
+yarn ava mintHolder.test.js
yarn ava provisionPool.test.js
yarn ava agoricNames.test.js
diff --git a/a3p-integration/proposals/p:upgrade-19/yarn.lock b/a3p-integration/proposals/p:upgrade-19/yarn.lock
index a9c86ac69e3..29afd5a4438 100644
--- a/a3p-integration/proposals/p:upgrade-19/yarn.lock
+++ b/a3p-integration/proposals/p:upgrade-19/yarn.lock
@@ -27,21 +27,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/base-zone@npm:0.1.1-dev-02c06c4.0+02c06c4":
- version: 0.1.1-dev-02c06c4.0
- resolution: "@agoric/base-zone@npm:0.1.1-dev-02c06c4.0"
- dependencies:
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@endo/common": "npm:^1.2.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/exo": "npm:^1.5.6"
- "@endo/far": "npm:^1.1.8"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- checksum: 10c0/54c4fc0855010809b09aa0558454639ecd87152af8c52024e07b1a46f38aeeef8d4642318eaf933b5219fc16e849a832d7a2c6d0e1827634dc6a64dd7530353b
- languageName: node
- linkType: hard
-
"@agoric/base-zone@npm:0.1.1-dev-1dd4589.0+1dd4589":
version: 0.1.1-dev-1dd4589.0
resolution: "@agoric/base-zone@npm:0.1.1-dev-1dd4589.0"
@@ -72,6 +57,21 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/base-zone@npm:0.1.1-dev-c1ae023.0+c1ae023":
+ version: 0.1.1-dev-c1ae023.0
+ resolution: "@agoric/base-zone@npm:0.1.1-dev-c1ae023.0"
+ dependencies:
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@endo/common": "npm:^1.2.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/exo": "npm:^1.5.7"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ checksum: 10c0/d7c75720d675c5f2fd524d0c597e83957fecee138392b3fc6dfa5610e8f301ccffecc8fbacb6c5a0700e4f5b9f95496029d0eb05320c92e23bbbeaa428ed9f87
+ languageName: node
+ linkType: hard
+
"@agoric/base-zone@npm:0.1.1-dev-e596a01.0+e596a01":
version: 0.1.1-dev-e596a01.0
resolution: "@agoric/base-zone@npm:0.1.1-dev-e596a01.0"
@@ -101,24 +101,24 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/casting@npm:0.4.3-dev-02c06c4.0+02c06c4":
- version: 0.4.3-dev-02c06c4.0
- resolution: "@agoric/casting@npm:0.4.3-dev-02c06c4.0"
+"@agoric/casting@npm:0.4.3-dev-c1ae023.0+c1ae023":
+ version: 0.4.3-dev-c1ae023.0
+ resolution: "@agoric/casting@npm:0.4.3-dev-c1ae023.0"
dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
"@cosmjs/encoding": "npm:^0.32.3"
"@cosmjs/proto-signing": "npm:^0.32.3"
"@cosmjs/stargate": "npm:^0.32.3"
"@cosmjs/tendermint-rpc": "npm:^0.32.3"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/init": "npm:^1.1.6"
- "@endo/lockdown": "npm:^1.0.12"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/e0fbef620ff0b358961f23d0545f962e2255dd0c490ee0c2635ba47fbe77f5b0f0c1b64a2bd638ca0030d9e81a099253feeef74b236652a8cb80dbc4932f4e08
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/init": "npm:^1.1.7"
+ "@endo/lockdown": "npm:^1.0.13"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/e4a8985d94ad49b785102f9db08415aaf07052178974dd2007fa0e359c50f83b9fead0934e9f0e7e81090dddde2c0e1b42e6f9b149989ec29e6887d980153dd6
languageName: node
linkType: hard
@@ -143,27 +143,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/client-utils@npm:0.1.1-dev-02c06c4.0":
- version: 0.1.1-dev-02c06c4.0
- resolution: "@agoric/client-utils@npm:0.1.1-dev-02c06c4.0"
- dependencies:
- "@agoric/casting": "npm:0.4.3-dev-02c06c4.0+02c06c4"
- "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/smart-wallet": "npm:0.5.4-dev-02c06c4.0+02c06c4"
- "@agoric/vats": "npm:0.15.2-dev-02c06c4.0+02c06c4"
- "@cosmjs/stargate": "npm:^0.32.3"
- "@cosmjs/tendermint-rpc": "npm:^0.32.3"
- "@endo/common": "npm:^1.2.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/75009c017319e9d641d2653ee582307185363bb54a091aad3d85cbf59e514e3243c05f06e4ef7dd96bd5de1a702bd037e15bf03331c41333ce089664de13966f
- languageName: node
- linkType: hard
-
"@agoric/client-utils@npm:0.1.1-dev-e596a01.0+e596a01":
version: 0.1.1-dev-e596a01.0
resolution: "@agoric/client-utils@npm:0.1.1-dev-e596a01.0"
@@ -185,42 +164,44 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/cosmic-proto@npm:0.4.1-dev-02c06c4.0+02c06c4":
- version: 0.4.1-dev-02c06c4.0
- resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-02c06c4.0"
+"@agoric/client-utils@npm:dev":
+ version: 0.1.1-dev-c1ae023.0
+ resolution: "@agoric/client-utils@npm:0.1.1-dev-c1ae023.0"
dependencies:
- "@endo/base64": "npm:^1.0.8"
- "@endo/init": "npm:^1.1.6"
- checksum: 10c0/a691d32d5aeb4152ee75ed1a9dd6fcaa49500da939fb3ca8a3b2949b5c3d67afe5ac27f824966850be42831e4bba7a0c83702fc525da800a5a1721ec2566548a
+ "@agoric/casting": "npm:0.4.3-dev-c1ae023.0+c1ae023"
+ "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/smart-wallet": "npm:0.5.4-dev-c1ae023.0+c1ae023"
+ "@agoric/vats": "npm:0.15.2-dev-c1ae023.0+c1ae023"
+ "@cosmjs/stargate": "npm:^0.32.3"
+ "@cosmjs/tendermint-rpc": "npm:^0.32.3"
+ "@endo/common": "npm:^1.2.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/be944d730e4b3c5a0f811d999a9a707f90c447ef8a35f5fabf6db104671252c1c549d8c62c297508de40406d8a8965e8650b7cd827271fd9f6cbad2291a2e9ed
languageName: node
linkType: hard
-"@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0+e596a01":
- version: 0.4.1-dev-e596a01.0
- resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0"
+"@agoric/cosmic-proto@npm:0.4.1-dev-c1ae023.0+c1ae023":
+ version: 0.4.1-dev-c1ae023.0
+ resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-c1ae023.0"
dependencies:
"@endo/base64": "npm:^1.0.9"
"@endo/init": "npm:^1.1.7"
- checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35
+ checksum: 10c0/78571d7f2c64df92d7f186ffad8c1e4c31c428495344555dc38ce74fc66397a4ac44f8d121b0929e6bb64a919bd7ecac708d04b4050021d69c68e388a2ea2de7
languageName: node
linkType: hard
-"@agoric/ertp@npm:0.16.3-dev-02c06c4.0+02c06c4":
- version: 0.16.3-dev-02c06c4.0
- resolution: "@agoric/ertp@npm:0.16.3-dev-02c06c4.0"
+"@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0+e596a01":
+ version: 0.4.1-dev-e596a01.0
+ resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0"
dependencies:
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/079356fee7cb840873effc2a78b3659d1979f57f3aecdbbaea5dc876f506671d8d6a4e8b169f739457e7fb1e96e5c1e3806d88fab2cec8cd2c4b370d7a70aeef
+ "@endo/base64": "npm:^1.0.9"
+ "@endo/init": "npm:^1.1.7"
+ checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35
languageName: node
linkType: hard
@@ -243,6 +224,25 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/ertp@npm:0.16.3-dev-c1ae023.0+c1ae023":
+ version: 0.16.3-dev-c1ae023.0
+ resolution: "@agoric/ertp@npm:0.16.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/5a437d6a2b6b418dd016407c2095d7d98415818c422c3c53db217d99b3bbb2e476f5b7e9decbc628b82c8e85d2da939cf3846248eeb5d688b4789b21a1118194
+ languageName: node
+ linkType: hard
+
"@agoric/ertp@npm:0.16.3-dev-e596a01.0+e596a01":
version: 0.16.3-dev-e596a01.0
resolution: "@agoric/ertp@npm:0.16.3-dev-e596a01.0"
@@ -262,27 +262,27 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/governance@npm:0.10.4-dev-02c06c4.0+02c06c4":
- version: 0.10.4-dev-02c06c4.0
- resolution: "@agoric/governance@npm:0.10.4-dev-02c06c4.0"
+"@agoric/governance@npm:0.10.4-dev-c1ae023.0+c1ae023":
+ version: 0.10.4-dev-c1ae023.0
+ resolution: "@agoric/governance@npm:0.10.4-dev-c1ae023.0"
dependencies:
- "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4"
- "@endo/bundle-source": "npm:^3.4.2"
- "@endo/captp": "npm:^4.4.2"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/promise-kit": "npm:^1.1.7"
+ "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023"
+ "@endo/bundle-source": "npm:^3.5.0"
+ "@endo/captp": "npm:^4.4.3"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/promise-kit": "npm:^1.1.8"
import-meta-resolve: "npm:^2.2.1"
- checksum: 10c0/888427200f47bc141ccc4dd07801d6b62c265edaae62abccf81d0bc0f4181fe544942d052a0f1f4a69e1c71fed287f60957b1667b1d951d4c61a1abfeec92c60
+ checksum: 10c0/445a41d4d2f226bbb99ad274d94d9f90cd4b4277db0428cc62046d7fdc508bbac6745859dfc4d16159a7e83629f501aa22a0752b99481a99b76e7d31f628290c
languageName: node
linkType: hard
@@ -336,11 +336,11 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/internal@npm:0.3.3-dev-02c06c4.0+02c06c4":
- version: 0.3.3-dev-02c06c4.0
- resolution: "@agoric/internal@npm:0.3.3-dev-02c06c4.0"
+"@agoric/internal@npm:0.3.3-dev-3b799b8.0+3b799b8":
+ version: 0.3.3-dev-3b799b8.0
+ resolution: "@agoric/internal@npm:0.3.3-dev-3b799b8.0"
dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4"
+ "@agoric/base-zone": "npm:0.1.1-dev-3b799b8.0+3b799b8"
"@endo/common": "npm:^1.2.7"
"@endo/errors": "npm:^1.2.7"
"@endo/far": "npm:^1.1.8"
@@ -352,27 +352,27 @@ __metadata:
"@endo/stream": "npm:^1.2.7"
anylogger: "npm:^0.21.0"
jessie.js: "npm:^0.3.4"
- checksum: 10c0/ec9ab609f0e55c777748e870f7f00e9e19c2f41b9ac0967d0f98ebf1559aa59b69cbfa4f2b95c698187bc1d6a578ff3b67e1c6e3fba7c501bcf4567c3a52e122
+ checksum: 10c0/332369a9acb41e46a579c9e0d084a12e16a78ad71f794f10d631235694281580b06ea88e25bf31d9eadc353b9c8d62e561232a21bb4c45f17c41057d0fb4c171
languageName: node
linkType: hard
-"@agoric/internal@npm:0.3.3-dev-3b799b8.0+3b799b8":
- version: 0.3.3-dev-3b799b8.0
- resolution: "@agoric/internal@npm:0.3.3-dev-3b799b8.0"
+"@agoric/internal@npm:0.3.3-dev-c1ae023.0+c1ae023":
+ version: 0.3.3-dev-c1ae023.0
+ resolution: "@agoric/internal@npm:0.3.3-dev-c1ae023.0"
dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-3b799b8.0+3b799b8"
- "@endo/common": "npm:^1.2.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/init": "npm:^1.1.6"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- "@endo/stream": "npm:^1.2.7"
+ "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@endo/common": "npm:^1.2.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/init": "npm:^1.1.7"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ "@endo/stream": "npm:^1.2.8"
anylogger: "npm:^0.21.0"
jessie.js: "npm:^0.3.4"
- checksum: 10c0/332369a9acb41e46a579c9e0d084a12e16a78ad71f794f10d631235694281580b06ea88e25bf31d9eadc353b9c8d62e561232a21bb4c45f17c41057d0fb4c171
+ checksum: 10c0/6ef8c160be33be88adefa67a861fb0758d03933a4bcc6f225e3b4e41c592553555fc9d477c1731e9ce86d28e2db49c72053f53188a199ab0f8c81a06423adc2c
languageName: node
linkType: hard
@@ -416,17 +416,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/kmarshal@npm:0.1.1-dev-02c06c4.0+02c06c4":
- version: 0.1.1-dev-02c06c4.0
- resolution: "@agoric/kmarshal@npm:0.1.1-dev-02c06c4.0"
- dependencies:
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/marshal": "npm:^1.6.1"
- checksum: 10c0/f7a124e2d9876edeb72fe8d66f090acb7fbbb7ad8d6bbcad3d60a25e7eee98e005a52222d3c570b1e9ecc504dd7bea4444232fe756824c97000bba439ea142ee
- languageName: node
- linkType: hard
-
"@agoric/kmarshal@npm:0.1.1-dev-3b799b8.0+3b799b8":
version: 0.1.1-dev-3b799b8.0
resolution: "@agoric/kmarshal@npm:0.1.1-dev-3b799b8.0"
@@ -438,6 +427,17 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/kmarshal@npm:0.1.1-dev-c1ae023.0+c1ae023":
+ version: 0.1.1-dev-c1ae023.0
+ resolution: "@agoric/kmarshal@npm:0.1.1-dev-c1ae023.0"
+ dependencies:
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/marshal": "npm:^1.6.2"
+ checksum: 10c0/5f4c1784fa4fa6de50f288722794ac0c98d0719e3558bc9147b726014a72dc3222a68f4c7f40e42f170e4b59481579a4d318e3cffb665720dafc23c80915ec6b
+ languageName: node
+ linkType: hard
+
"@agoric/kmarshal@npm:0.1.1-dev-e596a01.0+e596a01":
version: 0.1.1-dev-e596a01.0
resolution: "@agoric/kmarshal@npm:0.1.1-dev-e596a01.0"
@@ -449,20 +449,20 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/network@npm:0.1.1-dev-02c06c4.0+02c06c4":
- version: 0.1.1-dev-02c06c4.0
- resolution: "@agoric/network@npm:0.1.1-dev-02c06c4.0"
+"@agoric/network@npm:0.1.1-dev-c1ae023.0+c1ae023":
+ version: 0.1.1-dev-c1ae023.0
+ resolution: "@agoric/network@npm:0.1.1-dev-c1ae023.0"
dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@endo/base64": "npm:^1.0.8"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/0e14d617b90a1bf63ebe5776182f6cab2b87c9f18e951740ce7cddcdd418d630835a21c88af3910c2d73b5b6dc28a455a8f32dc15f66f48089f414916f5c541e
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@endo/base64": "npm:^1.0.9"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/93fd60ad6a0ce650427853677be076c77ce00d3201f29ec0922eb5fd38ce5ec2316fb9a564a76d3fae809299ef193e80109b89b79c4191ddb9525e5e4cb33302
languageName: node
linkType: hard
@@ -483,21 +483,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/notifier@npm:0.6.3-dev-02c06c4.0+02c06c4":
- version: 0.6.3-dev-02c06c4.0
- resolution: "@agoric/notifier@npm:0.6.3-dev-02c06c4.0"
- dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/6b4698c179c1483231124c6f6abc535bf86cef0bf61f3db05821031e06a3c63e7676fbba88170c2fb4716cd6dd96dc18b5c90d10b04aeee89e7be80c3b825e92
- languageName: node
- linkType: hard
-
"@agoric/notifier@npm:0.6.3-dev-3b799b8.0+3b799b8":
version: 0.6.3-dev-3b799b8.0
resolution: "@agoric/notifier@npm:0.6.3-dev-3b799b8.0"
@@ -513,6 +498,21 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/notifier@npm:0.6.3-dev-c1ae023.0+c1ae023":
+ version: 0.6.3-dev-c1ae023.0
+ resolution: "@agoric/notifier@npm:0.6.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/b810e7c98305e3e398fc1b97fa611c48b6af9a0144a865d357c2e5ac10cb60fc55bd01d87f8165fbc09c009166c7bc3a0513e2b1bf35e0742c0607e0c6579060
+ languageName: node
+ linkType: hard
+
"@agoric/notifier@npm:0.6.3-dev-e596a01.0+e596a01":
version: 0.6.3-dev-e596a01.0
resolution: "@agoric/notifier@npm:0.6.3-dev-e596a01.0"
@@ -528,26 +528,26 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/smart-wallet@npm:0.5.4-dev-02c06c4.0+02c06c4":
- version: 0.5.4-dev-02c06c4.0
- resolution: "@agoric/smart-wallet@npm:0.5.4-dev-02c06c4.0"
+"@agoric/smart-wallet@npm:0.5.4-dev-c1ae023.0+c1ae023":
+ version: 0.5.4-dev-c1ae023.0
+ resolution: "@agoric/smart-wallet@npm:0.5.4-dev-c1ae023.0"
dependencies:
- "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/vats": "npm:0.15.2-dev-02c06c4.0+02c06c4"
- "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4"
- "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/a2bc7bf868bdc578f4c2251f04119b1e72eeae5ff14334eeffbd8bfd8706b4ded203e2f239d8a85283fd06dfa6910c9b01b9a7d55de0fe6767c0f729c3915034
+ "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vats": "npm:0.15.2-dev-c1ae023.0+c1ae023"
+ "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023"
+ "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/94096186933d72b4db40e965adcef8d2e36b4917e6f4e1ca5d103d949c201daeaa16ad4d48ce121aec7048defb6177f75270418f175ae7ba390f169e8e37c380
languageName: node
linkType: hard
@@ -574,19 +574,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/store@npm:0.9.3-dev-02c06c4.0+02c06c4":
- version: 0.9.3-dev-02c06c4.0
- resolution: "@agoric/store@npm:0.9.3-dev-02c06c4.0"
- dependencies:
- "@endo/errors": "npm:^1.2.7"
- "@endo/exo": "npm:^1.5.6"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- checksum: 10c0/975d6d7f72bc3e0bb9087a1998c4c6092504cf084d1615a74d7bd7ea10d9032d5a0845e24399f787a7a9b1974e00a61a995f73d47bf8a8444ac1d9ed8aeb94a6
- languageName: node
- linkType: hard
-
"@agoric/store@npm:0.9.3-dev-1dd4589.0+1dd4589":
version: 0.9.3-dev-1dd4589.0
resolution: "@agoric/store@npm:0.9.3-dev-1dd4589.0"
@@ -613,31 +600,29 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/store@npm:0.9.3-dev-e596a01.0+e596a01":
- version: 0.9.3-dev-e596a01.0
- resolution: "@agoric/store@npm:0.9.3-dev-e596a01.0"
+"@agoric/store@npm:0.9.3-dev-c1ae023.0+c1ae023":
+ version: 0.9.3-dev-c1ae023.0
+ resolution: "@agoric/store@npm:0.9.3-dev-c1ae023.0"
dependencies:
"@endo/errors": "npm:^1.2.8"
"@endo/exo": "npm:^1.5.7"
"@endo/marshal": "npm:^1.6.2"
"@endo/pass-style": "npm:^1.4.7"
"@endo/patterns": "npm:^1.4.7"
- checksum: 10c0/b931aa2566d2ef2fea087938c34a79a6682a15f0fc9a5084e73c671d970f22ab3a1040febab4f7f0ae793858597834d76840b1d9c20a89048b725e3b5443b84f
+ checksum: 10c0/9fd6d5464906144140a868d38e63d1ee2f8f06240a8ba2e71ed73eb7df5ce9c03a74a79290b4dc2b2e4c3c3d59ba07228f7019965cf234a4178b815f8861f002
languageName: node
linkType: hard
-"@agoric/swing-store@npm:0.9.2-dev-02c06c4.0+02c06c4":
- version: 0.9.2-dev-02c06c4.0
- resolution: "@agoric/swing-store@npm:0.9.2-dev-02c06c4.0"
+"@agoric/store@npm:0.9.3-dev-e596a01.0+e596a01":
+ version: 0.9.3-dev-e596a01.0
+ resolution: "@agoric/store@npm:0.9.3-dev-e596a01.0"
dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@endo/base64": "npm:^1.0.8"
- "@endo/bundle-source": "npm:^3.4.2"
- "@endo/check-bundle": "npm:^1.0.11"
- "@endo/errors": "npm:^1.2.7"
- "@endo/nat": "npm:^5.0.12"
- better-sqlite3: "npm:^9.1.1"
- checksum: 10c0/71fd32035b20398c2a28eb8c7ada724c601cde1408f2ffadcbf6b06c06899ce9d0e595f75a570e9cc466c864c5ea29bdddf2b4a4f07e9031496588ea5904fabe
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/exo": "npm:^1.5.7"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ checksum: 10c0/b931aa2566d2ef2fea087938c34a79a6682a15f0fc9a5084e73c671d970f22ab3a1040febab4f7f0ae793858597834d76840b1d9c20a89048b725e3b5443b84f
languageName: node
linkType: hard
@@ -656,6 +641,21 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/swing-store@npm:0.9.2-dev-c1ae023.0+c1ae023":
+ version: 0.9.2-dev-c1ae023.0
+ resolution: "@agoric/swing-store@npm:0.9.2-dev-c1ae023.0"
+ dependencies:
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@endo/base64": "npm:^1.0.9"
+ "@endo/bundle-source": "npm:^3.5.0"
+ "@endo/check-bundle": "npm:^1.0.12"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/nat": "npm:^5.0.13"
+ better-sqlite3: "npm:^9.1.1"
+ checksum: 10c0/56adf70976c1c7f6f2437045fdd2c10f128b0d79224f83aed842b8b42f2253328d24151817748e2d4bc8c1f70a840d254646423a69496ff25e049bc3909233d5
+ languageName: node
+ linkType: hard
+
"@agoric/swing-store@npm:0.9.2-dev-e596a01.0+e596a01":
version: 0.9.2-dev-e596a01.0
resolution: "@agoric/swing-store@npm:0.9.2-dev-e596a01.0"
@@ -671,27 +671,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/swingset-liveslots@npm:0.10.3-dev-02c06c4.0+02c06c4":
- version: 0.10.3-dev-02c06c4.0
- resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-02c06c4.0"
- dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@endo/env-options": "npm:^1.1.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/exo": "npm:^1.5.6"
- "@endo/far": "npm:^1.1.8"
- "@endo/init": "npm:^1.1.6"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/0c0b7a9ff81b173b6610ef4b7af296ae1b1dbb753d4f2ef36e4b276aeb8e4a54a7a53e7293b051f3e196e8175e085db71728e986f7d226e90a08f9c7eb25b874
- languageName: node
- linkType: hard
-
"@agoric/swingset-liveslots@npm:0.10.3-dev-3b799b8.0+3b799b8":
version: 0.10.3-dev-3b799b8.0
resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-3b799b8.0"
@@ -713,6 +692,27 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/swingset-liveslots@npm:0.10.3-dev-c1ae023.0+c1ae023":
+ version: 0.10.3-dev-c1ae023.0
+ resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@endo/env-options": "npm:^1.1.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/exo": "npm:^1.5.7"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/init": "npm:^1.1.7"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/a44a74766ce6be12d65f7328a544993a07a2b3b74f8f998c48c085a39b38746644005d285cb5d3e6282b1e327e7e809c9cd23e36667da2b7f11926808000b1f0
+ languageName: node
+ linkType: hard
+
"@agoric/swingset-liveslots@npm:0.10.3-dev-e596a01.0+e596a01":
version: 0.10.3-dev-e596a01.0
resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-e596a01.0"
@@ -734,19 +734,19 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/swingset-vat@npm:0.32.3-dev-02c06c4.0+02c06c4":
- version: 0.32.3-dev-02c06c4.0
- resolution: "@agoric/swingset-vat@npm:0.32.3-dev-02c06c4.0"
+"@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0+3b799b8":
+ version: 0.32.3-dev-3b799b8.0
+ resolution: "@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0"
dependencies:
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/kmarshal": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/swing-store": "npm:0.9.2-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-02c06c4.0+02c06c4"
- "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/xsnap-lockdown": "npm:0.14.1-dev-02c06c4.0+02c06c4"
+ "@agoric/internal": "npm:0.3.3-dev-3b799b8.0+3b799b8"
+ "@agoric/kmarshal": "npm:0.1.1-dev-3b799b8.0+3b799b8"
+ "@agoric/store": "npm:0.9.3-dev-3b799b8.0+3b799b8"
+ "@agoric/swing-store": "npm:0.9.2-dev-3b799b8.0+3b799b8"
+ "@agoric/swingset-liveslots": "npm:0.10.3-dev-3b799b8.0+3b799b8"
+ "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-3b799b8.0+3b799b8"
+ "@agoric/time": "npm:0.3.3-dev-3b799b8.0+3b799b8"
+ "@agoric/vat-data": "npm:0.5.3-dev-3b799b8.0+3b799b8"
+ "@agoric/xsnap-lockdown": "npm:0.14.1-dev-3b799b8.0+3b799b8"
"@endo/base64": "npm:^1.0.8"
"@endo/bundle-source": "npm:^3.4.2"
"@endo/captp": "npm:^4.4.2"
@@ -778,41 +778,41 @@ __metadata:
ava: ^5.3.0
bin:
vat: bin/vat
- checksum: 10c0/43e4f64c6b157c7f343cd1a9a710061d8d81926986b5aec43d7b79e3a7b4ca46ab309285104767b780c6877f64ae79d8ecbb1847b84541a0f26cc38999e94ce4
+ checksum: 10c0/661426721b4106f9e51bc5f86858b166a24b3954429ec8cfe20f3a6650017807c4af12a78b9f64aa549b317356d1a52f44aee9137dde738f74d077d789dad482
languageName: node
linkType: hard
-"@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0+3b799b8":
- version: 0.32.3-dev-3b799b8.0
- resolution: "@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0"
+"@agoric/swingset-vat@npm:0.32.3-dev-c1ae023.0+c1ae023":
+ version: 0.32.3-dev-c1ae023.0
+ resolution: "@agoric/swingset-vat@npm:0.32.3-dev-c1ae023.0"
dependencies:
- "@agoric/internal": "npm:0.3.3-dev-3b799b8.0+3b799b8"
- "@agoric/kmarshal": "npm:0.1.1-dev-3b799b8.0+3b799b8"
- "@agoric/store": "npm:0.9.3-dev-3b799b8.0+3b799b8"
- "@agoric/swing-store": "npm:0.9.2-dev-3b799b8.0+3b799b8"
- "@agoric/swingset-liveslots": "npm:0.10.3-dev-3b799b8.0+3b799b8"
- "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-3b799b8.0+3b799b8"
- "@agoric/time": "npm:0.3.3-dev-3b799b8.0+3b799b8"
- "@agoric/vat-data": "npm:0.5.3-dev-3b799b8.0+3b799b8"
- "@agoric/xsnap-lockdown": "npm:0.14.1-dev-3b799b8.0+3b799b8"
- "@endo/base64": "npm:^1.0.8"
- "@endo/bundle-source": "npm:^3.4.2"
- "@endo/captp": "npm:^4.4.2"
- "@endo/check-bundle": "npm:^1.0.11"
- "@endo/compartment-mapper": "npm:^1.3.1"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/import-bundle": "npm:^1.3.1"
- "@endo/init": "npm:^1.1.6"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- "@endo/ses-ava": "npm:^1.2.7"
- "@endo/stream": "npm:^1.2.7"
- "@endo/zip": "npm:^1.0.8"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/kmarshal": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swing-store": "npm:0.9.2-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-c1ae023.0+c1ae023"
+ "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/xsnap-lockdown": "npm:0.14.1-dev-c1ae023.0+c1ae023"
+ "@endo/base64": "npm:^1.0.9"
+ "@endo/bundle-source": "npm:^3.5.0"
+ "@endo/captp": "npm:^4.4.3"
+ "@endo/check-bundle": "npm:^1.0.12"
+ "@endo/compartment-mapper": "npm:^1.4.0"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/import-bundle": "npm:^1.3.2"
+ "@endo/init": "npm:^1.1.7"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ "@endo/ses-ava": "npm:^1.2.8"
+ "@endo/stream": "npm:^1.2.8"
+ "@endo/zip": "npm:^1.0.9"
ansi-styles: "npm:^6.2.1"
anylogger: "npm:^0.21.0"
better-sqlite3: "npm:^9.1.1"
@@ -826,7 +826,7 @@ __metadata:
ava: ^5.3.0
bin:
vat: bin/vat
- checksum: 10c0/661426721b4106f9e51bc5f86858b166a24b3954429ec8cfe20f3a6650017807c4af12a78b9f64aa549b317356d1a52f44aee9137dde738f74d077d789dad482
+ checksum: 10c0/66482c449eeccd00167dec73899a5c510719620eba2ad457e77c04790b3573e8e82138e4d362f1b4ee859719278bdb49835df0007318d216ce6e54e67d08ee95
languageName: node
linkType: hard
@@ -878,13 +878,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-02c06c4.0+02c06c4":
- version: 0.10.3-dev-02c06c4.0
- resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-02c06c4.0"
- checksum: 10c0/a269373b02fcfcb10a47d601ef13ee1c01c2a8666bed7119e0b6f47027ce5f8d2321d5aaf6d22cbd949db69f4403cfda4d439d84c27bb4d7dd0fe421173fcb58
- languageName: node
- linkType: hard
-
"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-3b799b8.0+3b799b8":
version: 0.10.3-dev-3b799b8.0
resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-3b799b8.0"
@@ -892,6 +885,13 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-c1ae023.0+c1ae023":
+ version: 0.10.3-dev-c1ae023.0
+ resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-c1ae023.0"
+ checksum: 10c0/9f5b3bfe1f76f74f0ab605a67a8c822ba76fd80f7da9a13ee7933425effce76877240b5bd155a677c20740259bab1f0087131784035ef8a85e1278d718450589
+ languageName: node
+ linkType: hard
+
"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-e596a01.0+e596a01":
version: 0.10.3-dev-e596a01.0
resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-e596a01.0"
@@ -914,18 +914,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/time@npm:0.3.3-dev-02c06c4.0+02c06c4":
- version: 0.3.3-dev-02c06c4.0
- resolution: "@agoric/time@npm:0.3.3-dev-02c06c4.0"
- dependencies:
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/nat": "npm:^5.0.12"
- "@endo/patterns": "npm:^1.4.6"
- checksum: 10c0/ffe92b98f6f0f0d88aa1ecc2782775af94e77c4ba23f55005c5d201abb7ecd7b75dcb703f5b11e13588ad15e643fff2a42ebe74b0934872446e6647ff8caf3ef
- languageName: node
- linkType: hard
-
"@agoric/time@npm:0.3.3-dev-3b799b8.0+3b799b8":
version: 0.3.3-dev-3b799b8.0
resolution: "@agoric/time@npm:0.3.3-dev-3b799b8.0"
@@ -938,6 +926,18 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/time@npm:0.3.3-dev-c1ae023.0+c1ae023":
+ version: 0.3.3-dev-c1ae023.0
+ resolution: "@agoric/time@npm:0.3.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/patterns": "npm:^1.4.7"
+ checksum: 10c0/f4c6c900f25eda4bc32ee045f0b87ad1f3b38aa400047d51fbac534aa69bceaaf4f07130c539276a96c51a885394847ccd0a42da950722c58276998bdd7555ed
+ languageName: node
+ linkType: hard
+
"@agoric/time@npm:0.3.3-dev-e596a01.0+e596a01":
version: 0.3.3-dev-e596a01.0
resolution: "@agoric/time@npm:0.3.3-dev-e596a01.0"
@@ -950,20 +950,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/vat-data@npm:0.5.3-dev-02c06c4.0+02c06c4":
- version: 0.5.3-dev-02c06c4.0
- resolution: "@agoric/vat-data@npm:0.5.3-dev-02c06c4.0"
- dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/exo": "npm:^1.5.6"
- "@endo/patterns": "npm:^1.4.6"
- checksum: 10c0/b381d8e22d6d51b3dbad23820e61c97e269117c822679405b149882269e26366f3f15fff4520ca3d72ceb30bdad3fa713599573235335220689e0c37f040af5a
- languageName: node
- linkType: hard
-
"@agoric/vat-data@npm:0.5.3-dev-3b799b8.0+3b799b8":
version: 0.5.3-dev-3b799b8.0
resolution: "@agoric/vat-data@npm:0.5.3-dev-3b799b8.0"
@@ -978,6 +964,20 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/vat-data@npm:0.5.3-dev-c1ae023.0+c1ae023":
+ version: 0.5.3-dev-c1ae023.0
+ resolution: "@agoric/vat-data@npm:0.5.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/exo": "npm:^1.5.7"
+ "@endo/patterns": "npm:^1.4.7"
+ checksum: 10c0/009a8ca0f385770d4be37f8db2970ca03b035717193c18e43ce2f8ea6c212fba9a6f925dd376971e449416c6c3569178446318ecebdfc22016b03a50aed3fea4
+ languageName: node
+ linkType: hard
+
"@agoric/vat-data@npm:0.5.3-dev-e596a01.0+e596a01":
version: 0.5.3-dev-e596a01.0
resolution: "@agoric/vat-data@npm:0.5.3-dev-e596a01.0"
@@ -992,34 +992,34 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/vats@npm:0.15.2-dev-02c06c4.0+02c06c4":
- version: 0.15.2-dev-02c06c4.0
- resolution: "@agoric/vats@npm:0.15.2-dev-02c06c4.0"
- dependencies:
- "@agoric/cosmic-proto": "npm:0.4.1-dev-02c06c4.0+02c06c4"
- "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4"
- "@agoric/governance": "npm:0.10.4-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/network": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-vat": "npm:0.32.3-dev-02c06c4.0+02c06c4"
- "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4"
- "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/import-bundle": "npm:^1.3.1"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
+"@agoric/vats@npm:0.15.2-dev-c1ae023.0+c1ae023":
+ version: 0.15.2-dev-c1ae023.0
+ resolution: "@agoric/vats@npm:0.15.2-dev-c1ae023.0"
+ dependencies:
+ "@agoric/cosmic-proto": "npm:0.4.1-dev-c1ae023.0+c1ae023"
+ "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023"
+ "@agoric/governance": "npm:0.10.4-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/network": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-vat": "npm:0.32.3-dev-c1ae023.0+c1ae023"
+ "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023"
+ "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/import-bundle": "npm:^1.3.2"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
import-meta-resolve: "npm:^2.2.1"
jessie.js: "npm:^0.3.4"
- checksum: 10c0/0b2b6b9a964f1194c68818e1b5b65fef15138b6b670e58fb35322b169d540a73fa453d7918290d7311caeef3cd4db5423bf0b8490a0b31087eb12230a429a9ce
+ checksum: 10c0/d8920290ce6cab7f7dccbc6890df6ee0dfb2d25a4b63b9e6d5794aec8379d17bc253196162668ab1c02c824af07bb2aa890053ef9c55206b62342d43079ef806
languageName: node
linkType: hard
@@ -1054,22 +1054,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/vow@npm:0.1.1-dev-02c06c4.0+02c06c4":
- version: 0.1.1-dev-02c06c4.0
- resolution: "@agoric/vow@npm:0.1.1-dev-02c06c4.0"
- dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@endo/env-options": "npm:^1.1.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
- checksum: 10c0/6da30cb8fe91333fa6d961df09ce293ee9ee24104c6e86ff87832f4975016b02e0c520e82dd9338a69059106417bdd86be0aaf2df59295f1424d8c86d9f0eb11
- languageName: node
- linkType: hard
-
"@agoric/vow@npm:0.1.1-dev-3b799b8.0+3b799b8":
version: 0.1.1-dev-3b799b8.0
resolution: "@agoric/vow@npm:0.1.1-dev-3b799b8.0"
@@ -1086,6 +1070,22 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/vow@npm:0.1.1-dev-c1ae023.0+c1ae023":
+ version: 0.1.1-dev-c1ae023.0
+ resolution: "@agoric/vow@npm:0.1.1-dev-c1ae023.0"
+ dependencies:
+ "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@endo/env-options": "npm:^1.1.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
+ checksum: 10c0/094266768c8ff75032ce96faae9163e7dfa4e9ada55ce88354ca6de4b993d28252bcb6637900793f4e3f7b16afe62ac2f2bcc8825613b5cf95701ca46d4b4066
+ languageName: node
+ linkType: hard
+
"@agoric/vow@npm:0.1.1-dev-e596a01.0+e596a01":
version: 0.1.1-dev-e596a01.0
resolution: "@agoric/vow@npm:0.1.1-dev-e596a01.0"
@@ -1102,13 +1102,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/xsnap-lockdown@npm:0.14.1-dev-02c06c4.0+02c06c4":
- version: 0.14.1-dev-02c06c4.0
- resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-02c06c4.0"
- checksum: 10c0/7b883c30a1ec8bc4fb727c5e442acc6ddd4af98067ce86f2f85c333ce8bafe525049a8b09668b4fec7671c368205095949d096df5c45be827a40e550863398a9
- languageName: node
- linkType: hard
-
"@agoric/xsnap-lockdown@npm:0.14.1-dev-3b799b8.0+3b799b8":
version: 0.14.1-dev-3b799b8.0
resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-3b799b8.0"
@@ -1116,6 +1109,13 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/xsnap-lockdown@npm:0.14.1-dev-c1ae023.0+c1ae023":
+ version: 0.14.1-dev-c1ae023.0
+ resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-c1ae023.0"
+ checksum: 10c0/65aefeb29497f8780849677ee81ba6f46f358d9f29ad5790541d5626ad8b08e34e27fa9063e24a4ddef5e2bf616e7aec16b6fff505a5bd3bbd0c87ceac110f49
+ languageName: node
+ linkType: hard
+
"@agoric/xsnap-lockdown@npm:0.14.1-dev-e596a01.0+e596a01":
version: 0.14.1-dev-e596a01.0
resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-e596a01.0"
@@ -1123,36 +1123,36 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/zoe@npm:0.26.3-dev-02c06c4.0+02c06c4":
- version: 0.26.3-dev-02c06c4.0
- resolution: "@agoric/zoe@npm:0.26.3-dev-02c06c4.0"
+"@agoric/zoe@npm:0.26.3-dev-c1ae023.0+c1ae023":
+ version: 0.26.3-dev-c1ae023.0
+ resolution: "@agoric/zoe@npm:0.26.3-dev-c1ae023.0"
dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4"
- "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4"
- "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4"
- "@agoric/swingset-vat": "npm:0.32.3-dev-02c06c4.0+02c06c4"
- "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4"
- "@endo/bundle-source": "npm:^3.4.2"
- "@endo/captp": "npm:^4.4.2"
- "@endo/common": "npm:^1.2.7"
- "@endo/errors": "npm:^1.2.7"
- "@endo/eventual-send": "npm:^1.2.7"
- "@endo/exo": "npm:^1.5.6"
- "@endo/far": "npm:^1.1.8"
- "@endo/import-bundle": "npm:^1.3.1"
- "@endo/marshal": "npm:^1.6.1"
- "@endo/nat": "npm:^5.0.12"
- "@endo/pass-style": "npm:^1.4.6"
- "@endo/patterns": "npm:^1.4.6"
- "@endo/promise-kit": "npm:^1.1.7"
+ "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023"
+ "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023"
+ "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023"
+ "@agoric/swingset-vat": "npm:0.32.3-dev-c1ae023.0+c1ae023"
+ "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023"
+ "@endo/bundle-source": "npm:^3.5.0"
+ "@endo/captp": "npm:^4.4.3"
+ "@endo/common": "npm:^1.2.8"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/eventual-send": "npm:^1.2.8"
+ "@endo/exo": "npm:^1.5.7"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/import-bundle": "npm:^1.3.2"
+ "@endo/marshal": "npm:^1.6.2"
+ "@endo/nat": "npm:^5.0.13"
+ "@endo/pass-style": "npm:^1.4.7"
+ "@endo/patterns": "npm:^1.4.7"
+ "@endo/promise-kit": "npm:^1.1.8"
yargs-parser: "npm:^21.1.1"
- checksum: 10c0/9aa34ecf57ea7882241206da18e88235152c05be6bf267eda2b51156ca2c48730b70be3429b5881e7fa0a02dfd97334da94ece9c82537277b0fd0b2f125c6e48
+ checksum: 10c0/3b54c53506206d7406c0ffb309cb59d90a5cae13d0697320055127be163379369114a032b2af7c272e5646b9d9b65f1131c88750544ba859d5e1a11b618210b0
languageName: node
linkType: hard
@@ -1222,19 +1222,6 @@ __metadata:
languageName: node
linkType: hard
-"@agoric/zone@npm:0.2.3-dev-02c06c4.0+02c06c4":
- version: 0.2.3-dev-02c06c4.0
- resolution: "@agoric/zone@npm:0.2.3-dev-02c06c4.0"
- dependencies:
- "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4"
- "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4"
- "@endo/errors": "npm:^1.2.7"
- "@endo/far": "npm:^1.1.8"
- "@endo/pass-style": "npm:^1.4.6"
- checksum: 10c0/f4cf6df5a81cba46762a3ebfb63c3f13633974205eb3b7051c845d0ac2adb2cac2b9b6ab100c64c8dc63eec8ad9c051f2ddc04153f4f07f1046a763869f589fe
- languageName: node
- linkType: hard
-
"@agoric/zone@npm:0.2.3-dev-3b799b8.0+3b799b8":
version: 0.2.3-dev-3b799b8.0
resolution: "@agoric/zone@npm:0.2.3-dev-3b799b8.0"
@@ -1248,6 +1235,19 @@ __metadata:
languageName: node
linkType: hard
+"@agoric/zone@npm:0.2.3-dev-c1ae023.0+c1ae023":
+ version: 0.2.3-dev-c1ae023.0
+ resolution: "@agoric/zone@npm:0.2.3-dev-c1ae023.0"
+ dependencies:
+ "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023"
+ "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023"
+ "@endo/errors": "npm:^1.2.8"
+ "@endo/far": "npm:^1.1.9"
+ "@endo/pass-style": "npm:^1.4.7"
+ checksum: 10c0/292be1e4198ecdbc87a300efc1548190d26698c6c541dd8e0f6794dc0407b9e3bfc013f8dadd6788e995327044ce8f8e4181ff01b851b77562224aa273d066bf
+ languageName: node
+ linkType: hard
+
"@agoric/zone@npm:0.2.3-dev-e596a01.0+e596a01":
version: 0.2.3-dev-e596a01.0
resolution: "@agoric/zone@npm:0.2.3-dev-e596a01.0"
@@ -1749,7 +1749,7 @@ __metadata:
languageName: node
linkType: hard
-"@endo/lockdown@npm:^1.0.12, @endo/lockdown@npm:^1.0.13":
+"@endo/lockdown@npm:^1.0.13":
version: 1.0.13
resolution: "@endo/lockdown@npm:1.0.13"
dependencies:
@@ -6349,7 +6349,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "root-workspace-0b6124@workspace:."
dependencies:
- "@agoric/client-utils": "npm:0.1.1-dev-02c06c4.0"
+ "@agoric/client-utils": "npm:dev"
"@agoric/ertp": "npm:dev"
"@agoric/internal": "npm:dev"
"@agoric/synthetic-chain": "npm:^0.4.3"
diff --git a/a3p-integration/proposals/s:stake-bld/package.json b/a3p-integration/proposals/s:stake-bld/package.json
index 2c0a5093c38..2432417370d 100644
--- a/a3p-integration/proposals/s:stake-bld/package.json
+++ b/a3p-integration/proposals/s:stake-bld/package.json
@@ -26,7 +26,8 @@
},
"packageManager": "yarn@4.5.3",
"devDependencies": {
- "@types/node": "^22.0.0"
+ "@types/node": "^22.0.0",
+ "typescript": "^5.7.2"
},
"resolutions": {
"@agoric/cosmos": "portal:../../agoric-sdk/golang/cosmos",
diff --git a/a3p-integration/proposals/s:stake-bld/stakeBld.test.js b/a3p-integration/proposals/s:stake-bld/stakeBld.test.js
index 549e4562545..13836f6cf3d 100644
--- a/a3p-integration/proposals/s:stake-bld/stakeBld.test.js
+++ b/a3p-integration/proposals/s:stake-bld/stakeBld.test.js
@@ -8,7 +8,7 @@ import { GOV1ADDR } from '@agoric/synthetic-chain';
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
import assert from 'node:assert';
import process from 'node:process';
-import { networkConfig, walletUtils } from './test-lib/index.js';
+import { networkConfig, agdWalletUtils } from './test-lib/index.js';
// XXX not the same as VALIDATOR_ADDRESS, which is actually the delegator
const VALIDATOR_ADDRESS = process.env.VALIDATOR_ADDRESS;
@@ -26,14 +26,15 @@ const currentDelegation = async () => {
test('basic', async t => {
assert(GOV1ADDR);
- const { brand } = walletUtils.agoricNames;
+ const { brand } = agdWalletUtils.agoricNames;
t.is((await currentDelegation()).length, 1, 'just the initial delegation');
/** @type {import('@agoric/ertp').Brand} */
+ // @ts-expect-error actually a BoardRemote
const BLDBrand = brand.BLD;
- await walletUtils.broadcastBridgeAction(GOV1ADDR, {
+ await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, {
method: 'executeOffer',
offer: {
id: 'request-stake',
@@ -50,7 +51,7 @@ test('basic', async t => {
},
});
- await walletUtils.broadcastBridgeAction(GOV1ADDR, {
+ await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, {
method: 'executeOffer',
offer: {
id: 'request-delegate-6',
@@ -75,7 +76,7 @@ test('basic', async t => {
// omit 'delegation' because it has 'delegatorAddress' which is different every test run
});
- await walletUtils.broadcastBridgeAction(GOV1ADDR, {
+ await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, {
method: 'executeOffer',
offer: {
id: 'request-undelegate',
diff --git a/a3p-integration/proposals/s:stake-bld/test-lib/index.js b/a3p-integration/proposals/s:stake-bld/test-lib/index.js
index 9c22b218e19..b56da4836cc 100644
--- a/a3p-integration/proposals/s:stake-bld/test-lib/index.js
+++ b/a3p-integration/proposals/s:stake-bld/test-lib/index.js
@@ -1,9 +1,9 @@
/* eslint-env node */
+import { makeSmartWalletKit, LOCAL_CONFIG } from '@agoric/client-utils';
import { execFileSync } from 'child_process';
-import { LOCAL_CONFIG as networkConfig } from '@agoric/client-utils';
-import { makeWalletUtils } from './wallet.js';
+import { makeAgdWalletKit } from './wallet.js';
-export { networkConfig };
+export const networkConfig = LOCAL_CONFIG;
/**
* Resolve after a delay in milliseconds.
@@ -13,7 +13,12 @@ export { networkConfig };
*/
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
-export const walletUtils = await makeWalletUtils(
- { execFileSync, delay, fetch },
+export const smartWalletKit = await makeSmartWalletKit(
+ { delay, fetch },
+ networkConfig,
+);
+
+export const agdWalletUtils = await makeAgdWalletKit(
+ { execFileSync, smartWalletKit, delay },
networkConfig,
);
diff --git a/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js b/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js
index e3ef23af929..fa8e8ca5112 100644
--- a/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js
+++ b/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js
@@ -1,16 +1,21 @@
// @ts-check
-import { makeVstorageKit } from '@agoric/client-utils';
import { sendAction } from 'agoric/src/lib/index.js';
import { inspect } from 'util';
-export const makeWalletUtils = async (
- { delay, execFileSync, fetch },
+/**
+ * Stop-gap using execFileSync until we have a pure JS signing client.
+ *
+ * @param {object} root0
+ * @param {import('child_process')['execFileSync']} root0.execFileSync
+ * @param {import('@agoric/client-utils').SmartWalletKit} root0.smartWalletKit
+ * @param {any} root0.delay
+ * @param {import('@agoric/client-utils').MinimalNetworkConfig} networkConfig
+ */
+export const makeAgdWalletKit = async (
+ { execFileSync, smartWalletKit, delay },
networkConfig,
) => {
- const { agoricNames, fromBoard, marshaller, readLatestHead, vstorage } =
- await makeVstorageKit({ fetch }, networkConfig);
-
/**
*
* @param {string} from
@@ -23,17 +28,12 @@ export const makeWalletUtils = async (
delay,
execFileSync,
from,
- marshaller,
keyring: { backend: 'test' },
});
};
return {
- agoricNames,
+ ...smartWalletKit,
broadcastBridgeAction,
- fromBoard,
- networkConfig,
- readLatestHead,
- vstorage,
};
};
diff --git a/a3p-integration/proposals/s:stake-bld/yarn.lock b/a3p-integration/proposals/s:stake-bld/yarn.lock
index a406cffd13a..cad8d9ce435 100644
--- a/a3p-integration/proposals/s:stake-bld/yarn.lock
+++ b/a3p-integration/proposals/s:stake-bld/yarn.lock
@@ -4617,6 +4617,7 @@ __metadata:
agoric: "npm:dev"
ava: "npm:^5.3.1"
execa: "npm:^8.0.1"
+ typescript: "npm:^5.7.2"
languageName: unknown
linkType: soft
@@ -5189,6 +5190,16 @@ __metadata:
languageName: node
linkType: hard
+"typescript@npm:^5.7.2":
+ version: 5.7.2
+ resolution: "typescript@npm:5.7.2"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622
+ languageName: node
+ linkType: hard
+
"typescript@patch:typescript@npm%3A5.1.6 - 5.6.x#optional!builtin":
version: 5.6.3
resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40"
@@ -5199,6 +5210,16 @@ __metadata:
languageName: node
linkType: hard
+"typescript@patch:typescript@npm%3A^5.7.2#optional!builtin":
+ version: 5.7.2
+ resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5786d5"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/f3b8082c9d1d1629a215245c9087df56cb784f9fb6f27b5d55577a20e68afe2a889c040aacff6d27e35be165ecf9dca66e694c42eb9a50b3b2c451b36b5675cb
+ languageName: node
+ linkType: hard
+
"undici-types@npm:~5.26.4":
version: 5.26.5
resolution: "undici-types@npm:5.26.5"
diff --git a/a3p-integration/proposals/z:acceptance/.gitignore b/a3p-integration/proposals/z:acceptance/.gitignore
index 3d143254692..7f5da265d56 100644
--- a/a3p-integration/proposals/z:acceptance/.gitignore
+++ b/a3p-integration/proposals/z:acceptance/.gitignore
@@ -2,3 +2,4 @@
restart-valueVow
start-valueVow
localchaintest-submission
+recorded-instances-submission
diff --git a/a3p-integration/proposals/z:acceptance/package.json b/a3p-integration/proposals/z:acceptance/package.json
index 8a906d701b8..fd4b89562ae 100644
--- a/a3p-integration/proposals/z:acceptance/package.json
+++ b/a3p-integration/proposals/z:acceptance/package.json
@@ -3,6 +3,7 @@
"type": "/agoric.swingset.CoreEvalProposal",
"sdk-generate": [
"testing/start-valueVow.js start-valueVow",
+ "testing/recorded-retired-instances.js recorded-instances-submission",
"vats/test-localchain.js localchaintest-submission",
"testing/restart-valueVow.js restart-valueVow"
]
diff --git a/a3p-integration/proposals/z:acceptance/psm.test.js b/a3p-integration/proposals/z:acceptance/psm.test.js
index 8496cc1d3b3..ae176ec51c8 100644
--- a/a3p-integration/proposals/z:acceptance/psm.test.js
+++ b/a3p-integration/proposals/z:acceptance/psm.test.js
@@ -21,7 +21,7 @@ import {
} from '@agoric/synthetic-chain';
import { waitUntilAccountFunded } from '@agoric/client-utils';
import test from 'ava';
-import { NonNullish } from './test-lib/errors.js';
+import { NonNullish } from '@agoric/internal/src/errors.js';
import {
adjustBalancesIfNotProvisioned,
bankSend,
diff --git a/a3p-integration/proposals/z:acceptance/recorded-retired.test.js b/a3p-integration/proposals/z:acceptance/recorded-retired.test.js
new file mode 100644
index 00000000000..a5a00d01107
--- /dev/null
+++ b/a3p-integration/proposals/z:acceptance/recorded-retired.test.js
@@ -0,0 +1,11 @@
+import test from 'ava';
+
+import { evalBundles } from '@agoric/synthetic-chain';
+
+const SUBMISSION_DIR = 'recorded-instances-submission';
+
+test(`recorded instances in u18`, async t => {
+ const result = await evalBundles(SUBMISSION_DIR);
+ console.log('recorded retired instance result:', result);
+ t.pass('checked names');
+});
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/chain.js b/a3p-integration/proposals/z:acceptance/test-lib/chain.js
deleted file mode 100644
index 74cc0d3c14f..00000000000
--- a/a3p-integration/proposals/z:acceptance/test-lib/chain.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/** @file copied from packages/agoric-cli */
-// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109
-// @ts-check
-/* global process */
-
-const agdBinary = 'agd';
-
-/**
- * @param {ReadonlyArray} swingsetArgs
- * @param {import('./rpc.js').MinimalNetworkConfig & {
- * from: string,
- * fees?: string,
- * dryRun?: boolean,
- * verbose?: boolean,
- * keyring?: {home?: string, backend: string}
- * stdout?: Pick
- * execFileSync: typeof import('child_process').execFileSync
- * }} opts
- */
-export const execSwingsetTransaction = (swingsetArgs, opts) => {
- const {
- from,
- fees,
- dryRun = false,
- verbose = true,
- keyring = undefined,
- chainName,
- rpcAddrs,
- stdout = process.stdout,
- execFileSync,
- } = opts;
- const homeOpt = keyring?.home ? [`--home=${keyring.home}`] : [];
- const backendOpt = keyring?.backend
- ? [`--keyring-backend=${keyring.backend}`]
- : [];
- const feeOpt = fees ? ['--fees', fees] : [];
- const cmd = [`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`].concat(
- homeOpt,
- backendOpt,
- feeOpt,
- [`--from=${from}`, 'tx', 'swingset'],
- swingsetArgs,
- );
-
- if (dryRun) {
- stdout.write(`Run this interactive command in shell:\n\n`);
- stdout.write(`${agdBinary} `);
- stdout.write(cmd.join(' '));
- stdout.write('\n');
- } else {
- const yesCmd = cmd.concat(['--yes']);
- if (verbose) console.log('Executing ', agdBinary, yesCmd);
- const out = execFileSync(agdBinary, yesCmd, { encoding: 'utf-8' });
-
- // agd puts this diagnostic on stdout rather than stderr :-/
- // "Default sign-mode 'direct' not supported by Ledger, using sign-mode 'amino-json'.
- if (out.startsWith('Default sign-mode')) {
- const stripDiagnostic = out.replace(/^Default[^\n]+\n/, '');
- return stripDiagnostic;
- }
- return out;
- }
-};
-harden(execSwingsetTransaction);
-
-/**
- * @param {import('./rpc.js').MinimalNetworkConfig & {
- * execFileSync: typeof import('child_process').execFileSync,
- * delay: (ms: number) => Promise,
- * period?: number,
- * retryMessage?: string,
- * }} opts
- * @returns {(l: (b: { time: string, height: string }) => Promise) => Promise}
- */
-export const pollBlocks = opts => async lookup => {
- const { execFileSync, delay, rpcAddrs, period = 3 * 1000 } = opts;
- assert(execFileSync, 'missing execFileSync');
- const { retryMessage } = opts;
-
- const nodeArgs = [`--node=${rpcAddrs[0]}`];
-
- await null; // separate sync prologue
-
- for (;;) {
- const sTxt = execFileSync(agdBinary, ['status', ...nodeArgs]);
- const status = JSON.parse(sTxt.toString());
- const {
- SyncInfo: { latest_block_time: time, latest_block_height: height },
- } = status;
- try {
- // see await null above
- const result = await lookup({ time, height });
- return result;
- } catch (_err) {
- console.error(
- time,
- retryMessage || 'not in block',
- height,
- 'retrying...',
- );
- await delay(period);
- }
- }
-};
-
-/**
- * @param {string} txhash
- * @param {import('./rpc.js').MinimalNetworkConfig & {
- * execFileSync: typeof import('child_process').execFileSync,
- * delay: (ms: number) => Promise,
- * period?: number,
- * }} opts
- */
-export const pollTx = async (txhash, opts) => {
- const { execFileSync, rpcAddrs, chainName } = opts;
- assert(execFileSync, 'missing execFileSync in pollTx');
-
- const nodeArgs = [`--node=${rpcAddrs[0]}`];
- const outJson = ['--output', 'json'];
-
- const lookup = async () => {
- const out = execFileSync(
- agdBinary,
- [
- 'query',
- 'tx',
- txhash,
- `--chain-id=${chainName}`,
- ...nodeArgs,
- ...outJson,
- ],
- { stdio: ['ignore', 'pipe', 'ignore'] },
- );
- // XXX this type is defined in a .proto file somewhere
- /** @type {{ height: string, txhash: string, code: number, timestamp: string }} */
- const info = JSON.parse(out.toString());
- return info;
- };
- return pollBlocks({ ...opts, retryMessage: 'tx not in block' })(lookup);
-};
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/errors.js b/a3p-integration/proposals/z:acceptance/test-lib/errors.js
deleted file mode 100644
index 57dc771e6a5..00000000000
--- a/a3p-integration/proposals/z:acceptance/test-lib/errors.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * @file Copied from "@agoric/internal"
- */
-
-import { q } from '@endo/errors';
-
-/**
- * @template T
- * @param {T | null | undefined} val
- * @param {string} [optDetails]
- * @returns {T}
- */
-export const NonNullish = (val, optDetails = `unexpected ${q(val)}`) => {
- if (val != null) {
- // This `!= null` idiom checks that `val` is neither `null` nor `undefined`.
- return val;
- }
- assert.fail(optDetails);
-};
-harden(NonNullish);
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/index.js b/a3p-integration/proposals/z:acceptance/test-lib/index.js
index 479d81503fc..b56da4836cc 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/index.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/index.js
@@ -1,12 +1,9 @@
/* eslint-env node */
-import { makeWalletUtils } from '@agoric/client-utils';
+import { makeSmartWalletKit, LOCAL_CONFIG } from '@agoric/client-utils';
import { execFileSync } from 'child_process';
-import { makeAgdWalletUtils } from './wallet.js';
+import { makeAgdWalletKit } from './wallet.js';
-export const networkConfig = {
- rpcAddrs: ['http://0.0.0.0:26657'],
- chainName: 'agoriclocal',
-};
+export const networkConfig = LOCAL_CONFIG;
/**
* Resolve after a delay in milliseconds.
@@ -16,12 +13,12 @@ export const networkConfig = {
*/
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
-export const walletUtils = await makeWalletUtils(
+export const smartWalletKit = await makeSmartWalletKit(
{ delay, fetch },
networkConfig,
);
-export const agdWalletUtils = await makeAgdWalletUtils(
- { execFileSync, setTimeout, walletUtils },
+export const agdWalletUtils = await makeAgdWalletKit(
+ { execFileSync, smartWalletKit, delay },
networkConfig,
);
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/kread.js b/a3p-integration/proposals/z:acceptance/test-lib/kread.js
index 01cd0d29b5f..1bb58b3eef1 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/kread.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/kread.js
@@ -1,4 +1,5 @@
// @ts-nocheck FIXME
+// XXX uses agoric.follow to read data through spawned processes; replace with VstorageKit
import assert from 'node:assert';
import {
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
index 7b5beceb1d1..74763e6f401 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js
@@ -26,7 +26,7 @@ import {
VALIDATORADDR,
} from '@agoric/synthetic-chain';
import fsp from 'node:fs/promises';
-import { NonNullish } from './errors.js';
+import { NonNullish } from '@agoric/internal/src/errors.js';
import { getBalances } from './utils.js';
/** @import {Result as ExecaResult, ExecaError} from 'execa'; */
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js b/a3p-integration/proposals/z:acceptance/test-lib/rpc.js
deleted file mode 100644
index 2a25b534911..00000000000
--- a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js
+++ /dev/null
@@ -1,272 +0,0 @@
-/** @file copied from packages/agoric-cli */
-// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109
-// @ts-check
-/* global Buffer */
-
-import {
- boardSlottingMarshaller,
- makeBoardRemote,
-} from '@agoric/internal/src/marshal.js';
-import { Fail } from '@endo/errors';
-
-export { boardSlottingMarshaller };
-
-/** @type {(val: any) => string} */
-export const boardValToSlot = val => {
- if ('getBoardId' in val) {
- return val.getBoardId();
- }
- throw Fail`unknown obj in boardSlottingMarshaller.valToSlot ${val}`;
-};
-
-/** @param {string} agoricNetSubdomain */
-export const networkConfigUrl = agoricNetSubdomain =>
- `https://${agoricNetSubdomain}.agoric.net/network-config`;
-/** @param {string} agoricNetSubdomain */
-export const rpcUrl = agoricNetSubdomain =>
- `https://${agoricNetSubdomain}.rpc.agoric.net:443`;
-
-/**
- * @typedef {{ rpcAddrs: string[], chainName: string }} MinimalNetworkConfig
- */
-
-/** @type {MinimalNetworkConfig} */
-const networkConfig = {
- rpcAddrs: ['http://0.0.0.0:26657'],
- chainName: 'agoriclocal',
-};
-export { networkConfig };
-// console.warn('networkConfig', networkConfig);
-
-/**
- * @param {object} powers
- * @param {typeof window.fetch} powers.fetch
- * @param {MinimalNetworkConfig} config
- */
-export const makeVStorage = ({ fetch }, config = networkConfig) => {
- /** @param {string} path */
- const getJSON = path => {
- const url = config.rpcAddrs[0] + path;
- // console.warn('fetching', url);
- return fetch(url, { keepalive: true }).then(res => res.json());
- };
- // height=0 is the same as omitting height and implies the highest block
- const url = (path = 'published', { kind = 'children', height = 0 } = {}) =>
- `/abci_query?path=%22/custom/vstorage/${kind}/${path}%22&height=${height}`;
-
- const readStorage = (path = 'published', { kind = 'children', height = 0 }) =>
- getJSON(url(path, { kind, height }))
- .catch(err => {
- throw Error(`cannot read ${kind} of ${path}: ${err.message}`);
- })
- .then(data => {
- const {
- result: { response },
- } = data;
- if (response?.code !== 0) {
- /** @type {any} */
- const err = Error(
- `error code ${response?.code} reading ${kind} of ${path}: ${response.log}`,
- );
- err.code = response?.code;
- err.codespace = response?.codespace;
- throw err;
- }
- return data;
- });
-
- return {
- url,
- /** @param {{ result: { response: { code: number, value: string } } }} rawResponse */
- decode({ result: { response } }) {
- const { code } = response;
- if (code !== 0) {
- throw response;
- }
- const { value } = response;
- return Buffer.from(value, 'base64').toString();
- },
- /**
- *
- * @param {string} path
- * @returns {Promise} latest vstorage value at path
- */
- async readLatest(path = 'published') {
- const raw = await readStorage(path, { kind: 'data' });
- return this.decode(raw);
- },
- async keys(path = 'published') {
- const raw = await readStorage(path, { kind: 'children' });
- return JSON.parse(this.decode(raw)).children;
- },
- /**
- * @param {string} path
- * @param {number} [height] default is highest
- * @returns {Promise<{blockHeight: number, values: string[]}>}
- */
- async readAt(path, height = undefined) {
- const raw = await readStorage(path, { kind: 'data', height });
- const txt = this.decode(raw);
- /** @type {{ value: string }} */
- const { value } = JSON.parse(txt);
- return JSON.parse(value);
- },
- /**
- * Read values going back as far as available
- *
- * @param {string} path
- * @param {number | string} [minHeight]
- * @returns {Promise}
- */
- async readFully(path, minHeight = undefined) {
- const parts = [];
- // undefined the first iteration, to query at the highest
- let blockHeight;
- await null;
- do {
- // console.debug('READING', { blockHeight });
- let values;
- try {
- ({ blockHeight, values } = await this.readAt(
- path,
- blockHeight && Number(blockHeight) - 1,
- ));
- // console.debug('readAt returned', { blockHeight });
- } catch (err) {
- if (
- // CosmosSDK ErrNotFound; there is no data at the path
- (err.codespace === 'sdk' && err.code === 38) ||
- // CosmosSDK ErrUnknownRequest; misrepresentation of the same until
- // https://github.com/Agoric/agoric-sdk/commit/dafc7c1708977aaa55e245dc09a73859cf1df192
- // TODO remove after upgrade-12
- err.message.match(/unknown request/)
- ) {
- // console.error(err);
- break;
- }
- throw err;
- }
- parts.push(values);
- // console.debug('PUSHED', values);
- // console.debug('NEW', { blockHeight, minHeight });
- if (minHeight && Number(blockHeight) <= Number(minHeight)) break;
- } while (blockHeight > 0);
- return parts.flat();
- },
- };
-};
-/** @typedef {ReturnType} VStorage */
-
-export const makeFromBoard = () => {
- const cache = new Map();
- /** @type {(boardId: string, iface?: string) => ReturnType} */
- const convertSlotToVal = (boardId, iface) => {
- if (cache.has(boardId)) {
- return cache.get(boardId);
- }
- const val = makeBoardRemote({ boardId, iface });
- cache.set(boardId, val);
- return val;
- };
- return harden({ convertSlotToVal });
-};
-/** @typedef {ReturnType} IdMap */
-
-export const storageHelper = {
- /** @param { string } txt */
- parseCapData: txt => {
- assert(typeof txt === 'string', typeof txt);
- /** @type {{ value: string }} */
- const { value } = JSON.parse(txt);
- const specimen = JSON.parse(value);
- const { blockHeight, values } = specimen;
- assert(values, `empty values in specimen ${value}`);
- const capDatas = storageHelper.parseMany(values);
- return { blockHeight, capDatas };
- },
- /**
- * @param {string} txt
- * @param {IdMap} ctx
- */
- unserializeTxt: (txt, ctx) => {
- const { capDatas } = storageHelper.parseCapData(txt);
- return capDatas.map(capData =>
- boardSlottingMarshaller(ctx.convertSlotToVal).fromCapData(capData),
- );
- },
- /** @param {string[]} capDataStrings array of stringified capData */
- parseMany: capDataStrings => {
- assert(capDataStrings && capDataStrings.length);
- /** @type {{ body: string, slots: string[] }[]} */
- const capDatas = capDataStrings.map(s => JSON.parse(s));
- for (const capData of capDatas) {
- assert(typeof capData === 'object' && capData !== null);
- assert('body' in capData && 'slots' in capData);
- assert(typeof capData.body === 'string');
- assert(Array.isArray(capData.slots));
- }
- return capDatas;
- },
-};
-harden(storageHelper);
-
-/**
- * @param {IdMap} ctx
- * @param {VStorage} vstorage
- * @returns {Promise}
- */
-export const makeAgoricNames = async (ctx, vstorage) => {
- /** @type {Record} */
- const reverse = {};
- const entries = await Promise.all(
- ['brand', 'instance', 'vbankAsset'].map(async kind => {
- const content = await vstorage.readLatest(
- `published.agoricNames.${kind}`,
- );
- /** @type {Array<[string, import('@agoric/vats/tools/board-utils.js').BoardRemote]>} */
- const parts = storageHelper.unserializeTxt(content, ctx).at(-1);
- for (const [name, remote] of parts) {
- if ('getBoardId' in remote) {
- reverse[/** @type {string} */ (remote.getBoardId())] = name;
- }
- }
- return [kind, Object.fromEntries(parts)];
- }),
- );
- return { ...Object.fromEntries(entries), reverse };
-};
-
-/**
- * @param {{ fetch: typeof window.fetch }} io
- * @param {MinimalNetworkConfig} config
- */
-export const makeVstorageKit = async ({ fetch }, config = networkConfig) => {
- await null;
- try {
- const vstorage = makeVStorage({ fetch }, config);
- const fromBoard = makeFromBoard();
- const agoricNames = await makeAgoricNames(fromBoard, vstorage);
-
- const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal);
-
- /** @type {(txt: string) => unknown} */
- const unserializeHead = txt =>
- storageHelper.unserializeTxt(txt, fromBoard).at(-1);
-
- /** @type {(path: string) => Promise} */
- const readLatestHead = path =>
- vstorage.readLatest(path).then(unserializeHead);
-
- return {
- agoricNames,
- fromBoard,
- marshaller,
- readLatestHead,
- unserializeHead,
- vstorage,
- };
- } catch (err) {
- throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`);
- }
-};
-/** @typedef {Awaited>} RpcUtils */
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/utils.js b/a3p-integration/proposals/z:acceptance/test-lib/utils.js
index 330fb799c6d..0826daa3660 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/utils.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/utils.js
@@ -1,10 +1,13 @@
/* eslint-env node */
-import { makeStargateClient, makeVstorageKit } from '@agoric/client-utils';
+import {
+ LOCAL_CONFIG,
+ makeStargateClient,
+ makeVstorageKit,
+} from '@agoric/client-utils';
import { readFile, writeFile } from 'node:fs/promises';
-import { networkConfig } from './rpc.js';
-export const stargateClientP = makeStargateClient(networkConfig, { fetch });
-export const vstorageKitP = makeVstorageKit({ fetch }, networkConfig);
+export const stargateClientP = makeStargateClient(LOCAL_CONFIG, { fetch });
+export const vstorageKit = makeVstorageKit({ fetch }, LOCAL_CONFIG);
/**
* @import {WalletUtils} from '@agoric/client-utils';
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js
index 88a07564ca9..1dabb741e95 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js
@@ -1,10 +1,6 @@
/* eslint-env node */
-import {
- boardSlottingMarshaller,
- makeFromBoard,
- retryUntilCondition,
-} from '@agoric/client-utils';
+import { makeAgoricNames, retryUntilCondition } from '@agoric/client-utils';
import { AmountMath } from '@agoric/ertp';
import {
agops,
@@ -18,19 +14,15 @@ import {
ceilMultiplyBy,
makeRatio,
} from '@agoric/zoe/src/contractSupport/ratio.js';
-import { E } from '@endo/far';
-import { walletUtils } from './index.js';
-import { listVaults, vstorageKitP } from './utils.js';
-
-const fromBoard = makeFromBoard();
-const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal);
+import { smartWalletKit } from './index.js';
+import { listVaults, vstorageKit } from './utils.js';
/**
* @param {string} address
* @returns {Promise<{ vaultID: string, debt: bigint, collateral: bigint, state: string }>}
*/
export const getLastVaultFromAddress = async address => {
- const activeVaults = await listVaults(address, walletUtils);
+ const activeVaults = await listVaults(address, smartWalletKit);
const vaultPath = activeVaults[activeVaults.length - 1];
const vaultID = vaultPath.split('.').pop();
@@ -97,7 +89,10 @@ export const getMinInitialDebt = async () => {
* @returns {Promise<{ mintFee: import('@agoric/ertp/src/types.js').NatAmount, adjustedToMintAmount: import('@agoric/ertp/src/types.js').NatAmount }>}
*/
export const calculateMintFee = async (toMintValue, vaultManager) => {
- const { brand } = await E.get(vstorageKitP).agoricNames;
+ const { brand } = await makeAgoricNames(
+ vstorageKit.fromBoard,
+ vstorageKit.vstorage,
+ );
/** @type {import('@agoric/ertp').Brand} */
// @ts-expect-error let this BoardRemote masquerade as a Brand
const ISTBrand = brand.IST;
@@ -157,11 +152,16 @@ const paramChangeOfferGeneration = async (
) => {
const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 }
- const { brand } = await E.get(vstorageKitP).agoricNames;
+ const agoricNames = await makeAgoricNames(
+ vstorageKit.fromBoard,
+ vstorageKit.vstorage,
+ );
+
+ const { brand } = agoricNames;
assert(brand.IST);
assert(brand.ATOM);
- const { instance } = await E.get(vstorageKitP).agoricNames;
+ const { instance } = agoricNames;
assert(instance.VaultFactory);
const voteDurSec = BigInt(voteDur);
@@ -203,7 +203,7 @@ const paramChangeOfferGeneration = async (
};
// @ts-expect-error tolerate BoardRemote instances with getBoardId methods
- return JSON.stringify(marshaller.toCapData(harden(body)));
+ return JSON.stringify(vstorageKit.marshaller.toCapData(harden(body)));
};
/**
diff --git a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js
index 11813654bbc..fa8e8ca5112 100644
--- a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js
+++ b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js
@@ -1,74 +1,21 @@
-// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109
// @ts-check
-/* global */
+import { sendAction } from 'agoric/src/lib/index.js';
import { inspect } from 'util';
-import { execSwingsetTransaction, pollTx } from './chain.js';
-import { makeTimerUtils } from './utils.js';
-
-/**
- * Sign and broadcast a wallet-action.
- *
- * @throws { Error & { code: number } } if transaction fails
- * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
- * @param {import('./rpc.js').MinimalNetworkConfig & {
- * from: string,
- * marshaller: Pick, 'toCapData'>,
- * fees?: string,
- * verbose?: boolean,
- * keyring?: {home?: string, backend: string},
- * stdout?: Pick,
- * execFileSync: typeof import('child_process').execFileSync,
- * delay: (ms: number) => Promise,
- * dryRun?: boolean,
- * }} opts
- */
-export const sendAction = async (bridgeAction, opts) => {
- const { marshaller } = opts;
- // @ts-expect-error BridgeAction has methods disallowed by Passable
- const offerBody = JSON.stringify(marshaller.toCapData(harden(bridgeAction)));
-
- // tryExit should not require --allow-spend
- // https://github.com/Agoric/agoric-sdk/issues/7291
- const spendMethods = ['executeOffer', 'tryExitOffer'];
- const spendArg = spendMethods.includes(bridgeAction.method)
- ? ['--allow-spend']
- : [];
-
- const act = ['wallet-action', ...spendArg, offerBody];
- const out = execSwingsetTransaction([...act, '--output', 'json'], opts);
- if (opts.dryRun) {
- return;
- }
-
- assert(out); // not dry run
- const tx = JSON.parse(out);
- if (tx.code !== 0) {
- const err = Error(`failed to send tx: ${tx.raw_log} code: ${tx.code}`);
- // @ts-expect-error XXX how to add properties to an error?
- err.code = tx.code;
- throw err;
- }
-
- return pollTx(tx.txhash, opts);
-};
/**
* Stop-gap using execFileSync until we have a pure JS signing client.
*
* @param {object} root0
- * @param {import('@agoric/client-utils').WalletUtils} root0.walletUtils
* @param {import('child_process')['execFileSync']} root0.execFileSync
- * @param {typeof setTimeout} root0.setTimeout
+ * @param {import('@agoric/client-utils').SmartWalletKit} root0.smartWalletKit
+ * @param {any} root0.delay
* @param {import('@agoric/client-utils').MinimalNetworkConfig} networkConfig
*/
-export const makeAgdWalletUtils = async (
- { execFileSync, walletUtils, setTimeout },
+export const makeAgdWalletKit = async (
+ { execFileSync, smartWalletKit, delay },
networkConfig,
) => {
- const { marshaller } = walletUtils;
-
- const { delay } = await makeTimerUtils({ setTimeout });
/**
*
* @param {string} from
@@ -81,13 +28,12 @@ export const makeAgdWalletUtils = async (
delay,
execFileSync,
from,
- // @ts-expect-error version skew in @endo/marshal and/or @endo/pass-style
- marshaller,
keyring: { backend: 'test' },
});
};
return {
+ ...smartWalletKit,
broadcastBridgeAction,
};
};
diff --git a/a3p-integration/proposals/z:acceptance/test.sh b/a3p-integration/proposals/z:acceptance/test.sh
index a029b8d6e8a..e45cced45d1 100755
--- a/a3p-integration/proposals/z:acceptance/test.sh
+++ b/a3p-integration/proposals/z:acceptance/test.sh
@@ -12,6 +12,9 @@ yarn ava core-eval.test.js
scripts/test-vaults.ts
+echo ACCEPTANCE TESTING recorded instances
+yarn ava recorded-retired.test.js
+
echo ACCEPTANCE TESTING kread
yarn ava kread.test.js
diff --git a/a3p-integration/proposals/z:acceptance/valueVow.test.js b/a3p-integration/proposals/z:acceptance/valueVow.test.js
index 7e62e16420d..8490351eb58 100644
--- a/a3p-integration/proposals/z:acceptance/valueVow.test.js
+++ b/a3p-integration/proposals/z:acceptance/valueVow.test.js
@@ -10,7 +10,7 @@ import {
GOV1ADDR as GETTER, // not particular to governance, just a handy wallet
GOV2ADDR as SETTER,
} from '@agoric/synthetic-chain';
-import { agdWalletUtils, walletUtils } from './test-lib/index.js';
+import { agdWalletUtils } from './test-lib/index.js';
const START_VALUEVOW_DIR = 'start-valueVow';
const RESTART_VALUEVOW_DIR = 'restart-valueVow';
@@ -37,7 +37,7 @@ test('vow survives restart', async t => {
t.log('confirm the value is not in offer results');
let getterStatus = await retryUntilCondition(
/** @type {() => Promise} */
- async () => walletUtils.readLatestHead(`published.wallet.${GETTER}`),
+ async () => agdWalletUtils.readLatestHead(`published.wallet.${GETTER}`),
value => value.status.id === 'get-value' && value.updated === 'offerStatus',
'Offer get-value not succeeded',
{
@@ -79,7 +79,9 @@ test('vow survives restart', async t => {
});
t.log('confirm the value is now in offer results');
- getterStatus = await walletUtils.readLatestHead(`published.wallet.${GETTER}`);
+ getterStatus = await agdWalletUtils.readLatestHead(
+ `published.wallet.${GETTER}`,
+ );
t.like(getterStatus, { status: { result: offerArgs.value } });
});
diff --git a/a3p-integration/proposals/z:acceptance/vaults.test.js b/a3p-integration/proposals/z:acceptance/vaults.test.js
index 62086e7ad68..d99c8fe45e1 100644
--- a/a3p-integration/proposals/z:acceptance/vaults.test.js
+++ b/a3p-integration/proposals/z:acceptance/vaults.test.js
@@ -17,7 +17,7 @@ import {
openVault,
USER1ADDR,
} from '@agoric/synthetic-chain';
-import { agdWalletUtils, walletUtils } from './test-lib/index.js';
+import { agdWalletUtils } from './test-lib/index.js';
import {
getPriceFeedRoundId,
verifyPushedPrice,
@@ -55,7 +55,7 @@ const exec = {
offerId = `openVault-${Date.now()}`,
collateralBrandKey = 'ATOM',
) => {
- const offer = Offers.vaults.OpenVault(walletUtils.agoricNames, {
+ const offer = Offers.vaults.OpenVault(agdWalletUtils.agoricNames, {
giveCollateral,
wantMinted,
offerId,
@@ -73,14 +73,14 @@ test.serial('open new vault', async t => {
await bankSend(USER1ADDR, `20000000${ATOM_DENOM}`);
const istBalanceBefore = await getISTBalance(USER1ADDR);
- const activeVaultsBefore = await listVaults(USER1ADDR, walletUtils);
+ const activeVaultsBefore = await listVaults(USER1ADDR, agdWalletUtils);
const mint = 5.0;
const collateral = 10.0;
await exec.vaults.OpenVault(USER1ADDR, mint, collateral);
const istBalanceAfter = await getISTBalance(USER1ADDR);
- const activeVaultsAfter = await listVaults(USER1ADDR, walletUtils);
+ const activeVaultsAfter = await listVaults(USER1ADDR, agdWalletUtils);
await tryISTBalances(
t,
@@ -178,7 +178,7 @@ test.serial(
'user cannot open a vault under the minimum initial debt',
async t => {
await bankSend(GOV1ADDR, `200000000000000000${ATOM_DENOM}`);
- const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils);
const minInitialDebt = await getMinInitialDebt();
@@ -192,7 +192,7 @@ test.serial(
},
);
- const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils);
t.is(
activeVaultsAfter.length,
@@ -203,7 +203,7 @@ test.serial(
);
test.serial('user cannot open a vault above debt limit', async t => {
- const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils);
const { availableDebtForMint } = await getAvailableDebtForMint(VAULT_MANAGER);
@@ -217,7 +217,7 @@ test.serial('user cannot open a vault above debt limit', async t => {
},
);
- const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils);
t.is(
activeVaultsAfter.length,
@@ -228,7 +228,7 @@ test.serial('user cannot open a vault above debt limit', async t => {
test.serial('user can open a vault under debt limit', async t => {
const istBalanceBefore = await getISTBalance(GOV1ADDR);
- const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils);
const { availableDebtForMint } = await getAvailableDebtForMint(VAULT_MANAGER);
@@ -238,7 +238,7 @@ test.serial('user can open a vault under debt limit', async t => {
await openVault(GOV1ADDR, mint.toString(), collateral.toString());
const istBalanceAfter = await getISTBalance(GOV1ADDR);
- const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils);
+ const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils);
await tryISTBalances(
t,
diff --git a/golang/cosmos/app/upgrade.go b/golang/cosmos/app/upgrade.go
index 242fa9374ef..89857e26166 100644
--- a/golang/cosmos/app/upgrade.go
+++ b/golang/cosmos/app/upgrade.go
@@ -157,6 +157,22 @@ func replacePriceFeedsCoreProposal(upgradeName string) (vm.CoreProposalStep, err
)
}
+// func upgradeMintHolderCoreProposal(upgradeName string) (vm.CoreProposalStep, error) {
+// variant := getVariantFromUpgradeName(upgradeName)
+
+// if variant == "" {
+// return nil, nil
+// }
+
+// return buildProposalStepWithArgs(
+// "@agoric/builders/scripts/vats/upgrade-mintHolder.js",
+// "defaultProposalBuilder",
+// map[string]any{
+// "variant": variant,
+// },
+// )
+// }
+
// unreleasedUpgradeHandler performs standard upgrade actions plus custom actions for the unreleased upgrade.
func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) {
return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
@@ -216,6 +232,14 @@ func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Conte
// CoreProposals for Upgrade 19. These should not be introduced
// before upgrade 18 is done because they would be run in n:upgrade-next
+ //
+ // upgradeMintHolderStep, err := upgradeMintHolderCoreProposal(targetUpgrade)
+ // if err != nil {
+ // return nil, err
+ // } else if upgradeMintHolderStep != nil {
+ // CoreProposalSteps = append(CoreProposalSteps, upgradeMintHolderStep)
+ // }
+ //
// CoreProposalSteps = append(CoreProposalSteps,
// vm.CoreProposalStepForModules(
// "@agoric/builders/scripts/inter-protocol/replace-feeDistributor.js",
diff --git a/golang/cosmos/types/address_hooks.go b/golang/cosmos/types/address_hooks.go
index b26fe1e85f4..073e9d48cf4 100644
--- a/golang/cosmos/types/address_hooks.go
+++ b/golang/cosmos/types/address_hooks.go
@@ -23,9 +23,9 @@ const (
BaseAddressLengthBytes = 2
)
-// AddressHookMagic is a magic byte prefix that identifies a hooked address.
+// AddressHookBytePrefix is a magic prefix that identifies a hooked address.
// Chosen to make bech32 address hooks that look like "agoric10rch..."
-var AddressHookMagic = []byte{0x78, 0xf1, 0x70 | AddressHookVersion}
+var AddressHookBytePrefix = []byte{0x78, 0xf1, 0x70 /* | AddressHookVersion */}
func init() {
if AddressHookVersion&0x0f != AddressHookVersion {
@@ -51,12 +51,19 @@ func SplitHookedAddress(addr string) (string, []byte, error) {
return "", []byte{}, err
}
- bz := bytes.TrimPrefix(payload, AddressHookMagic)
- if len(bz) == len(payload) {
+ lastPrefixHighNibble := AddressHookBytePrefix[len(AddressHookBytePrefix)-1]
+ bz := bytes.TrimPrefix(payload, AddressHookBytePrefix[:len(AddressHookBytePrefix)-1])
+ if len(bz) == len(payload) || len(bz) == 0 || bz[0]&0xf0 != lastPrefixHighNibble {
// Return an unhooked address.
return addr, []byte{}, nil
}
+ version := bz[0] & 0x0f
+ bz = bz[1:]
+ if version != AddressHookVersion {
+ return "", []byte{}, fmt.Errorf("unsupported address hook version %d", version)
+ }
+
if len(bz) < BaseAddressLengthBytes {
return "", []byte{}, fmt.Errorf("hooked address must have at least %d bytes", BaseAddressLengthBytes)
}
@@ -97,8 +104,9 @@ func JoinHookedAddress(baseAddr string, hookData []byte) (string, error) {
return "", fmt.Errorf("base address length 0x%x is longer than the maximum 0x%x", b, maxB)
}
- payload := make([]byte, 0, len(AddressHookMagic)+b+len(hookData)+BaseAddressLengthBytes)
- payload = append(payload, AddressHookMagic...)
+ payload := make([]byte, 0, len(AddressHookBytePrefix)+b+len(hookData)+BaseAddressLengthBytes)
+ payload = append(payload, AddressHookBytePrefix...)
+ payload[len(payload)-1] |= byte(AddressHookVersion)
payload = append(payload, bz...)
payload = append(payload, hookData...)
baLen := make([]byte, BaseAddressLengthBytes)
diff --git a/golang/cosmos/types/address_hooks_test.go b/golang/cosmos/types/address_hooks_test.go
index 8ae9faad1e7..8dd7ed6c5b7 100644
--- a/golang/cosmos/types/address_hooks_test.go
+++ b/golang/cosmos/types/address_hooks_test.go
@@ -15,6 +15,53 @@ import (
"github.com/Agoric/agoric-sdk/golang/cosmos/types"
)
+func TestSplitHookedAddress(t *testing.T) {
+ cases := []struct {
+ name string
+ hook string
+ baseAddr string
+ hookData []byte
+ err string
+ }{
+ {"empty", "", "", []byte{}, "decoding bech32 failed: invalid bech32 string length 0"},
+ {"no hook", "agoric1qqp0e5ys", "agoric1qqp0e5ys", []byte{}, ""},
+ {"Fast USDC", "agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423padaek6me38qekget2vdhx66mtvy6kg7nrw5uhsaekd4uhwufswqex6dtsv44hxv3cd4jkuqpqvduyhf",
+ "agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek",
+ []byte("?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"),
+ ""},
+ {"version 0",
+ "agoric10rchqqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9qx0p9wp",
+ "agoric1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn3tn9p0",
+ []byte{4, 3, 2, 1},
+ ""},
+ {"version 1 reject",
+ "agoric10rchzqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q04n2fg",
+ "",
+ []byte{},
+ "unsupported address hook version 1"},
+ {"version 15 reject",
+ "agoric10rch7qqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q25ez2d",
+ "",
+ []byte{},
+ "unsupported address hook version 15"},
+ }
+
+ for _, tc := range cases {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ baseAddr, hookData, err := types.SplitHookedAddress(tc.hook)
+ if len(tc.err) > 0 {
+ require.Error(t, err)
+ require.Equal(t, tc.err, err.Error())
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.baseAddr, baseAddr)
+ require.Equal(t, string(tc.hookData), string(hookData))
+ }
+ })
+ }
+}
+
func TestExtractBaseAddress(t *testing.T) {
bases := []struct {
name string
diff --git a/multichain-testing/ava.main.config.js b/multichain-testing/ava.main.config.js
index 37c7ca0b467..da0d373e10c 100644
--- a/multichain-testing/ava.main.config.js
+++ b/multichain-testing/ava.main.config.js
@@ -9,4 +9,5 @@ export default {
concurrency: 1,
serial: true,
timeout: '125s',
+ failFast: true,
};
diff --git a/multichain-testing/test/account-balance-queries.test.ts b/multichain-testing/test/account-balance-queries.test.ts
index 6707d9b102e..c067ced9446 100644
--- a/multichain-testing/test/account-balance-queries.test.ts
+++ b/multichain-testing/test/account-balance-queries.test.ts
@@ -20,7 +20,7 @@ const contractBuilder =
test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
- deleteTestKeys(accounts).catch();
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
diff --git a/multichain-testing/test/auto-stake-it.test.ts b/multichain-testing/test/auto-stake-it.test.ts
index d4bfded2086..10e3bac8db8 100644
--- a/multichain-testing/test/auto-stake-it.test.ts
+++ b/multichain-testing/test/auto-stake-it.test.ts
@@ -18,15 +18,11 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
- deleteTestKeys(accounts).catch();
+ const { commonBuilderOpts, deleteTestKeys, startContract } = common;
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
-
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
});
test.after(async t => {
diff --git a/multichain-testing/test/basic-flows.test.ts b/multichain-testing/test/basic-flows.test.ts
index 689db323524..1d53b4aae8d 100644
--- a/multichain-testing/test/basic-flows.test.ts
+++ b/multichain-testing/test/basic-flows.test.ts
@@ -17,14 +17,11 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
- deleteTestKeys(accounts).catch();
+ const { commonBuilderOpts, deleteTestKeys, startContract } = common;
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
});
test.after(async t => {
diff --git a/multichain-testing/test/chain-queries.test.ts b/multichain-testing/test/chain-queries.test.ts
index a9b91c97fe3..56673742582 100644
--- a/multichain-testing/test/chain-queries.test.ts
+++ b/multichain-testing/test/chain-queries.test.ts
@@ -28,7 +28,7 @@ const contractBuilder =
test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
- deleteTestKeys(accounts).catch();
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
diff --git a/multichain-testing/test/deposit-withdraw-lca.test.ts b/multichain-testing/test/deposit-withdraw-lca.test.ts
index ad7fd4824d9..7d1cbafa97c 100644
--- a/multichain-testing/test/deposit-withdraw-lca.test.ts
+++ b/multichain-testing/test/deposit-withdraw-lca.test.ts
@@ -15,14 +15,11 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
- deleteTestKeys(accounts).catch();
+ const { commonBuilderOpts, deleteTestKeys, startContract } = common;
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
});
test.after(async t => {
diff --git a/multichain-testing/test/deposit-withdraw-portfolio.test.ts b/multichain-testing/test/deposit-withdraw-portfolio.test.ts
index ea97f1e7f17..49b7f3d8ad7 100644
--- a/multichain-testing/test/deposit-withdraw-portfolio.test.ts
+++ b/multichain-testing/test/deposit-withdraw-portfolio.test.ts
@@ -15,14 +15,11 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
- deleteTestKeys(accounts).catch();
+ const { commonBuilderOpts, deleteTestKeys, startContract } = common;
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
});
test.after(async t => {
diff --git a/multichain-testing/test/fast-usdc/config.ts b/multichain-testing/test/fast-usdc/config.ts
new file mode 100644
index 00000000000..c7b1833ec6d
--- /dev/null
+++ b/multichain-testing/test/fast-usdc/config.ts
@@ -0,0 +1,28 @@
+import type { IBCChannelID } from '@agoric/vats';
+
+export const oracleMnemonics = {
+ oracle1:
+ 'cause eight cattle slot course mail more aware vapor slab hobby match',
+ oracle2:
+ 'flower salute inspire label latin cattle believe sausage match total bless refuse',
+ oracle3:
+ 'surge magnet typical drive cement artist stay latin chief obey word always',
+};
+harden(oracleMnemonics);
+
+export const makeFeedPolicy = (nobleAgoricChannelId: IBCChannelID) => {
+ return {
+ nobleAgoricChannelId,
+ nobleDomainId: 4,
+ chainPolicies: {
+ Arbitrum: {
+ attenuatedCttpBridgeAddress:
+ '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
+ cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A',
+ chainId: 42161,
+ confirmations: 2,
+ },
+ },
+ };
+};
+harden(makeFeedPolicy);
diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts
new file mode 100644
index 00000000000..8997384e031
--- /dev/null
+++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts
@@ -0,0 +1,382 @@
+import anyTest from '@endo/ses-ava/prepare-endo.js';
+import type { TestFn } from 'ava';
+import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
+import { AmountMath } from '@agoric/ertp';
+import type { Denom } from '@agoric/orchestration';
+import { divideBy, multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js';
+import type { IBCChannelID } from '@agoric/vats';
+import { makeDoOffer, type WalletDriver } from '../../tools/e2e-tools.js';
+import { makeDenomTools } from '../../tools/asset-info.js';
+import { createWallet } from '../../tools/wallet.js';
+import { makeQueryClient } from '../../tools/query.js';
+import { commonSetup, type SetupContextWithWallets } from '../support.js';
+import { makeFeedPolicy, oracleMnemonics } from './config.js';
+import { makeRandomDigits } from '../../tools/random.js';
+import { balancesFromPurses } from '../../tools/purse.js';
+
+const { keys, values, fromEntries } = Object;
+const { isGTE, isEmpty, make } = AmountMath;
+
+const makeRandomNumber = () => Math.random();
+
+const test = anyTest as TestFn<
+ SetupContextWithWallets & {
+ lpUser: WalletDriver;
+ oracleWds: WalletDriver[];
+ nobleAgoricChannelId: IBCChannelID;
+ usdcOnOsmosis: Denom;
+ /** usdc on agoric */
+ usdcDenom: Denom;
+ }
+>;
+
+const accounts = [...keys(oracleMnemonics), 'lp'];
+const contractName = 'fastUsdc';
+const contractBuilder =
+ '../packages/builders/scripts/fast-usdc/init-fast-usdc.js';
+const LP_DEPOSIT_AMOUNT = 10_000_000n;
+
+test.before(async t => {
+ const { setupTestKeys, ...common } = await commonSetup(t);
+ const {
+ chainInfo,
+ commonBuilderOpts,
+ deleteTestKeys,
+ faucetTools,
+ provisionSmartWallet,
+ startContract,
+ } = common;
+ await deleteTestKeys(accounts).catch();
+ const wallets = await setupTestKeys(accounts, values(oracleMnemonics));
+
+ // provision oracle wallets first so invitation deposits don't fail
+ const oracleWds = await Promise.all(
+ keys(oracleMnemonics).map(n =>
+ provisionSmartWallet(wallets[n], {
+ BLD: 100n,
+ }),
+ ),
+ );
+
+ // calculate denomHash and channelId for privateArgs / builder opts
+ const { getTransferChannelId, toDenomHash } = makeDenomTools(chainInfo);
+ const usdcDenom = toDenomHash('uusdc', 'noblelocal', 'agoric');
+ const usdcOnOsmosis = toDenomHash('uusdc', 'noblelocal', 'osmosis');
+ const nobleAgoricChannelId = getTransferChannelId('agoriclocal', 'noble');
+ if (!nobleAgoricChannelId) throw new Error('nobleAgoricChannelId not found');
+ t.log('nobleAgoricChannelId', nobleAgoricChannelId);
+ t.log('usdcDenom', usdcDenom);
+
+ await startContract(contractName, contractBuilder, {
+ oracle: keys(oracleMnemonics).map(n => `${n}:${wallets[n]}`),
+ usdcDenom,
+ feedPolicy: JSON.stringify(makeFeedPolicy(nobleAgoricChannelId)),
+ ...commonBuilderOpts,
+ });
+
+ // provide faucet funds for LPs
+ await faucetTools.fundFaucet([['noble', 'uusdc']]);
+
+ // save an LP in test context
+ const lpUser = await provisionSmartWallet(wallets['lp'], {
+ USDC: 100n,
+ BLD: 100n,
+ });
+
+ t.context = {
+ ...common,
+ lpUser,
+ oracleWds,
+ nobleAgoricChannelId,
+ usdcOnOsmosis,
+ usdcDenom,
+ wallets,
+ };
+});
+
+test.after(async t => {
+ const { deleteTestKeys } = t.context;
+ deleteTestKeys(accounts);
+});
+
+const toOracleOfferId = (idx: number) => `oracle${idx + 1}-accept`;
+
+test.serial('oracles accept', async t => {
+ const { oracleWds, retryUntilCondition, vstorageClient, wallets } = t.context;
+
+ const instances = await vstorageClient.queryData(
+ 'published.agoricNames.instance',
+ );
+ const instance = fromEntries(instances)[contractName];
+
+ // accept oracle operator invitations
+ await Promise.all(
+ oracleWds.map(makeDoOffer).map((doOffer, i) =>
+ doOffer({
+ id: toOracleOfferId(i),
+ invitationSpec: {
+ source: 'purse',
+ instance,
+ description: 'oracle operator invitation', // TODO export/import INVITATION_MAKERS_DESC
+ },
+ proposal: {},
+ }),
+ ),
+ );
+
+ for (const name of keys(oracleMnemonics)) {
+ const addr = wallets[name];
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => vstorageClient.queryData(`published.wallet.${addr}.current`),
+ ({ offerToUsedInvitation }) => {
+ return offerToUsedInvitation[0][0] === `${name}-accept`;
+ },
+ `${name} invitation used`,
+ ),
+ );
+ }
+});
+
+test.serial('lp deposits', async t => {
+ const { lpUser, retryUntilCondition, vstorageClient, wallets } = t.context;
+
+ const lpDoOffer = makeDoOffer(lpUser);
+ const brands = await vstorageClient.queryData('published.agoricNames.brand');
+ const { USDC, FastLP } = Object.fromEntries(brands);
+
+ const usdcToGive = make(USDC, LP_DEPOSIT_AMOUNT);
+
+ const { shareWorth: currShareWorth } = await vstorageClient.queryData(
+ `published.${contractName}.poolMetrics`,
+ );
+ const poolSharesWanted = divideBy(usdcToGive, currShareWorth);
+
+ await lpDoOffer({
+ id: `lp-deposit-${Date.now()}`,
+ invitationSpec: {
+ source: 'agoricContract',
+ instancePath: [contractName],
+ callPipe: [['makeDepositInvitation']],
+ },
+ proposal: {
+ give: { USDC: usdcToGive },
+ want: { PoolShare: poolSharesWanted },
+ },
+ });
+
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => vstorageClient.queryData(`published.${contractName}.poolMetrics`),
+ ({ shareWorth }) =>
+ !isGTE(currShareWorth.numerator, shareWorth.numerator),
+ 'share worth numerator increases from deposit',
+ ),
+ );
+
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () =>
+ vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`),
+ ({ purses }) => {
+ const currentPoolShares = balancesFromPurses(purses)[FastLP];
+ return currentPoolShares && isGTE(currentPoolShares, poolSharesWanted);
+ },
+ 'lp has pool shares',
+ ),
+ );
+});
+
+test.serial('advance and settlement', async t => {
+ const {
+ nobleTools,
+ nobleAgoricChannelId,
+ oracleWds,
+ retryUntilCondition,
+ useChain,
+ usdcOnOsmosis,
+ vstorageClient,
+ } = t.context;
+
+ // EUD wallet on osmosis
+ const eudWallet = await createWallet(useChain('osmosis').chain.bech32_prefix);
+ const EUD = (await eudWallet.getAccounts())[0].address;
+
+ // parameterize agoric address
+ const { settlementAccount } = await vstorageClient.queryData(
+ `published.${contractName}`,
+ );
+ t.log('settlementAccount address', settlementAccount);
+
+ const recipientAddress = encodeAddressHook(settlementAccount, { EUD });
+ t.log('recipientAddress', recipientAddress);
+
+ // register forwarding address on noble
+ const txRes = nobleTools.registerForwardingAcct(
+ nobleAgoricChannelId,
+ recipientAddress,
+ );
+ t.is(txRes?.code, 0, 'registered forwarding account');
+
+ const { address: userForwardingAddr } = nobleTools.queryForwardingAddress(
+ nobleAgoricChannelId,
+ recipientAddress,
+ );
+ t.log('got forwardingAddress', userForwardingAddr);
+
+ const mintAmount = 800_000n;
+
+ // TODO export CctpTxEvidence type
+ const evidence = harden({
+ blockHash:
+ '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665',
+ blockNumber: 21037663n,
+ txHash: `0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617${makeRandomDigits(makeRandomNumber(), 2n)}`,
+ tx: {
+ amount: mintAmount,
+ forwardingAddress: userForwardingAddr,
+ },
+ aux: {
+ forwardingChannel: nobleAgoricChannelId,
+ recipientAddress,
+ },
+ chainId: 42161,
+ });
+
+ console.log('User initiates evm mint', evidence.txHash);
+
+ // submit evidences
+ await Promise.all(
+ oracleWds.map(makeDoOffer).map((doOffer, i) =>
+ doOffer({
+ id: `${Date.now()}-evm-evidence`,
+ invitationSpec: {
+ source: 'continuing',
+ previousOffer: toOracleOfferId(i),
+ invitationMakerName: 'SubmitEvidence',
+ invitationArgs: [evidence],
+ },
+ proposal: {},
+ }),
+ ),
+ );
+
+ const queryClient = makeQueryClient(
+ await useChain('osmosis').getRestEndpoint(),
+ );
+
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => queryClient.queryBalance(EUD, usdcOnOsmosis),
+ ({ balance }) => !!balance?.amount && BigInt(balance.amount) < mintAmount,
+ `${EUD} advance available from fast-usdc`,
+ {
+ // this resolves quickly, so _decrease_ the interval so the timing is more apparent
+ retryIntervalMs: 500,
+ },
+ ),
+ );
+
+ const queryTxStatus = async () =>
+ vstorageClient.queryData(
+ `published.${contractName}.status.${evidence.txHash}`,
+ );
+
+ const assertTxStatus = async (status: string) =>
+ t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => queryTxStatus(),
+ txStatus => {
+ console.log('tx status', txStatus);
+ return txStatus === status;
+ },
+ `${evidence.txHash} is ${status}`,
+ ),
+ );
+
+ await assertTxStatus('ADVANCED');
+ console.log('Advance completed, waiting for mint...');
+
+ nobleTools.mockCctpMint(mintAmount, userForwardingAddr);
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => vstorageClient.queryData(`published.${contractName}.poolMetrics`),
+ ({ encumberedBalance }) =>
+ encumberedBalance && isEmpty(encumberedBalance),
+ 'encumberedBalance returns to 0',
+ ),
+ );
+
+ await assertTxStatus('DISBURSED');
+});
+
+test.serial('lp withdraws', async t => {
+ const {
+ lpUser,
+ retryUntilCondition,
+ useChain,
+ usdcDenom,
+ vstorageClient,
+ wallets,
+ } = t.context;
+ const queryClient = makeQueryClient(
+ await useChain('agoric').getRestEndpoint(),
+ );
+ const lpDoOffer = makeDoOffer(lpUser);
+ const brands = await vstorageClient.queryData('published.agoricNames.brand');
+ const { FastLP } = Object.fromEntries(brands);
+ t.log('FastLP brand', FastLP);
+
+ const { shareWorth: currShareWorth } = await vstorageClient.queryData(
+ `published.${contractName}.poolMetrics`,
+ );
+ const { purses } = await vstorageClient.queryData(
+ `published.wallet.${wallets['lp']}.current`,
+ );
+ const currentPoolShares = balancesFromPurses(purses)[FastLP];
+ t.log('currentPoolShares', currentPoolShares);
+ const usdcWanted = multiplyBy(currentPoolShares, currShareWorth);
+ t.log('usdcWanted', usdcWanted);
+
+ const { balance: currentUSDCBalance } = await queryClient.queryBalance(
+ wallets['lp'],
+ usdcDenom,
+ );
+ t.log(`current ${usdcDenom} balance`, currentUSDCBalance);
+
+ await lpDoOffer({
+ id: `lp-withdraw-${Date.now()}`,
+ invitationSpec: {
+ source: 'agoricContract',
+ instancePath: [contractName],
+ callPipe: [['makeWithdrawInvitation']],
+ },
+ proposal: {
+ give: { PoolShare: currentPoolShares },
+ want: { USDC: usdcWanted },
+ },
+ });
+
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () =>
+ vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`),
+ ({ purses }) => {
+ const currentPoolShares = balancesFromPurses(purses)[FastLP];
+ return !currentPoolShares || isEmpty(currentPoolShares);
+ },
+ 'lp no longer has pool shares',
+ ),
+ );
+
+ await t.notThrowsAsync(() =>
+ retryUntilCondition(
+ () => queryClient.queryBalance(wallets['lp'], usdcDenom),
+ ({ balance }) =>
+ !!balance?.amount &&
+ BigInt(balance.amount) - BigInt(currentUSDCBalance!.amount!) >
+ LP_DEPOSIT_AMOUNT,
+ "lp's USDC balance increases",
+ ),
+ );
+});
diff --git a/multichain-testing/test/ica-channel-close.test.ts b/multichain-testing/test/ica-channel-close.test.ts
index 03b0ef9ac95..6ee59dc825f 100644
--- a/multichain-testing/test/ica-channel-close.test.ts
+++ b/multichain-testing/test/ica-channel-close.test.ts
@@ -23,14 +23,11 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
- deleteTestKeys(accounts).catch();
+ const { commonBuilderOpts, deleteTestKeys, startContract } = common;
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
});
test.after(async t => {
diff --git a/multichain-testing/test/send-anywhere.test.ts b/multichain-testing/test/send-anywhere.test.ts
index 11508f22cc6..df4bbdca8d6 100644
--- a/multichain-testing/test/send-anywhere.test.ts
+++ b/multichain-testing/test/send-anywhere.test.ts
@@ -21,16 +21,12 @@ const contractBuilder =
test.before(async t => {
const { setupTestKeys, ...common } = await commonSetup(t);
- const { assetInfo, chainInfo, deleteTestKeys, faucetTools, startContract } =
+ const { commonBuilderOpts, deleteTestKeys, faucetTools, startContract } =
common;
- deleteTestKeys(accounts).catch();
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...common, wallets };
-
- await startContract(contractName, contractBuilder, {
- chainInfo,
- assetInfo,
- });
+ await startContract(contractName, contractBuilder, commonBuilderOpts);
await faucetTools.fundFaucet([
['cosmoshub', 'uatom'],
diff --git a/multichain-testing/test/stake-ica.test.ts b/multichain-testing/test/stake-ica.test.ts
index af73531bf61..7ef65ad33eb 100644
--- a/multichain-testing/test/stake-ica.test.ts
+++ b/multichain-testing/test/stake-ica.test.ts
@@ -18,7 +18,7 @@ test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
// XXX not necessary for CI, but helpful for unexpected failures in
// active development (test.after cleanup doesn't run).
- deleteTestKeys(accounts).catch();
+ await deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
});
diff --git a/multichain-testing/test/support.ts b/multichain-testing/test/support.ts
index 18e8006f155..f71e2c112cc 100644
--- a/multichain-testing/test/support.ts
+++ b/multichain-testing/test/support.ts
@@ -4,7 +4,6 @@ import { execa } from 'execa';
import fse from 'fs-extra';
import childProcess from 'node:child_process';
import { withChainCapabilities } from '@agoric/orchestration';
-import { objectMap } from '@endo/patterns';
import { makeAgdTools } from '../tools/agd-tools.js';
import { type E2ETools } from '../tools/e2e-tools.js';
import {
@@ -42,13 +41,19 @@ const makeKeyring = async (
e2eTools: Pick,
) => {
let _keys = ['user1'];
- const setupTestKeys = async (keys = ['user1']) => {
+ const setupTestKeys = async (
+ keys = ['user1'],
+ mnemonics?: (string | undefined)[],
+ ) => {
_keys = keys;
const wallets: Record = {};
- for (const name of keys) {
- const res = await e2eTools.addKey(name, generateMnemonic());
+ for (const i in keys) {
+ const res = await e2eTools.addKey(
+ keys[i],
+ mnemonics?.[i] || generateMnemonic(),
+ );
const { address } = JSON.parse(res);
- wallets[name] = address;
+ wallets[keys[i]] = address;
}
return wallets;
};
@@ -91,6 +96,10 @@ export const commonSetup = async (t: ExecutionContext) => {
retryUntilCondition,
useChain,
);
+ const commonBuilderOpts = harden({
+ assetInfo: JSON.stringify(assetInfo),
+ chainInfo: JSON.stringify(chainInfo),
+ });
/**
* Starts a contract if instance not found. Takes care of installing
@@ -102,7 +111,7 @@ export const commonSetup = async (t: ExecutionContext) => {
const startContract = async (
contractName: string,
contractBuilder: string,
- builderOpts?: Record,
+ builderOpts?: Record,
) => {
const { vstorageClient } = tools;
const instances = Object.fromEntries(
@@ -112,18 +121,7 @@ export const commonSetup = async (t: ExecutionContext) => {
return t.log('Contract found. Skipping installation...');
}
t.log('bundle and install contract', contractName);
-
- const formattedOpts = builderOpts
- ? objectMap(
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- builderOpts as Record,
- value => {
- if (typeof value === 'string') return value;
- return JSON.stringify(value);
- },
- )
- : undefined;
- await deployBuilder(contractBuilder, formattedOpts);
+ await deployBuilder(contractBuilder, builderOpts);
await retryUntilCondition(
() => vstorageClient.queryData(`published.agoricNames.instance`),
res => contractName in Object.fromEntries(res),
@@ -142,6 +140,7 @@ export const commonSetup = async (t: ExecutionContext) => {
startContract,
assetInfo,
chainInfo,
+ commonBuilderOpts,
faucetTools,
};
};
diff --git a/multichain-testing/tools/agd-lib.js b/multichain-testing/tools/agd-lib.js
index a28d408493b..71ed0f69cbd 100644
--- a/multichain-testing/tools/agd-lib.js
+++ b/multichain-testing/tools/agd-lib.js
@@ -16,7 +16,7 @@ const binaryArgs = [
];
/**
- * @param {Record} record - e.g. { color: 'blue' }
+ * @param {Record} record - e.g. { color: 'blue' }
* @returns {string[]} - e.g. ['--color', 'blue']
*/
export const flags = record => {
@@ -25,7 +25,12 @@ export const flags = record => {
/** @type {[string, string][]} */
// @ts-expect-error undefined is filtered out
const skipUndef = Object.entries(record).filter(([_k, v]) => v !== undefined);
- return skipUndef.map(([k, v]) => [`--${k}`, v]).flat();
+ return skipUndef.flatMap(([key, value]) => {
+ if (Array.isArray(value)) {
+ return value.flatMap(v => [`--${key}`, v]);
+ }
+ return [`--${key}`, value];
+ });
};
/**
diff --git a/multichain-testing/tools/asset-info.ts b/multichain-testing/tools/asset-info.ts
index ef4faf1d5ac..568cf6019c3 100644
--- a/multichain-testing/tools/asset-info.ts
+++ b/multichain-testing/tools/asset-info.ts
@@ -6,6 +6,31 @@ import {
} from '@agoric/orchestration';
import type { IBCChannelID } from '@agoric/vats';
+export const makeDenomTools = (chainInfo: Record) => {
+ const getTransferChannelId = (
+ destChainId: string,
+ fromChainName: string,
+ ): IBCChannelID | undefined =>
+ chainInfo[fromChainName]?.connections?.[destChainId]?.transferChannel
+ .channelId;
+
+ const toDenomHash = (
+ denom: Denom,
+ destChainId: string,
+ fromChainName: string,
+ ): Denom => {
+ const channelId = getTransferChannelId(destChainId, fromChainName);
+ if (!channelId) {
+ throw new Error(
+ `No channel found for ${destChainId} -> ${fromChainName}`,
+ );
+ }
+ return `ibc/${denomHash({ denom, channelId })}`;
+ };
+
+ return harden({ getTransferChannelId, toDenomHash });
+};
+
/**
* Make asset info for the current environment.
*
@@ -21,26 +46,7 @@ export const makeAssetInfo = (
osmosis: ['uosmo', 'uion'],
},
): [Denom, DenomDetail][] => {
- const getChannelId = (
- issuingChainId: string,
- holdingChainName: string,
- ): IBCChannelID | undefined =>
- chainInfo[holdingChainName]?.connections?.[issuingChainId]?.transferChannel
- .channelId;
-
- const toDenomHash = (
- denom: Denom,
- issuingChainId: string,
- holdingChainName: string,
- ): Denom => {
- const channelId = getChannelId(issuingChainId, holdingChainName);
- if (!channelId) {
- throw new Error(
- `No channel found for ${issuingChainId} -> ${holdingChainName}`,
- );
- }
- return `ibc/${denomHash({ denom, channelId })}`;
- };
+ const { toDenomHash } = makeDenomTools(chainInfo);
// only include chains present in `chainInfo`
const tokens = Object.entries(tokenMap)
diff --git a/multichain-testing/tools/deploy.ts b/multichain-testing/tools/deploy.ts
index 52a460f6094..289c4d971e9 100755
--- a/multichain-testing/tools/deploy.ts
+++ b/multichain-testing/tools/deploy.ts
@@ -13,7 +13,7 @@ export const makeDeployBuilder = (
) =>
async function deployBuilder(
builder: string,
- builderOpts?: Record,
+ builderOpts?: Record,
) {
console.log(`building plan: ${builder}`);
const args = ['run', builder];
diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js
index f820e7c8077..4710761e014 100644
--- a/multichain-testing/tools/e2e-tools.js
+++ b/multichain-testing/tools/e2e-tools.js
@@ -8,8 +8,12 @@ import { flags, makeAgd, makeCopyFiles } from './agd-lib.js';
import { makeHttpClient, makeAPI } from './makeHttpClient.js';
import { dedup, makeQueryKit, poll } from './queryKit.js';
import { makeVStorage } from './batchQuery.js';
+import { makeRetryUntilCondition } from './sleep.js';
-/** @import { EnglishMnemonic } from '@cosmjs/crypto'; */
+/**
+ * @import { EnglishMnemonic } from '@cosmjs/crypto';
+ * @import { RetryUntilCondition } from './sleep.js';
+ */
const BLD = '000000ubld';
@@ -121,6 +125,7 @@ const installBundle = async (fullPath, opts) => {
* blockTool: BlockTool;
* lcd: import('./makeHttpClient.js').LCD;
* delay: (ms: number) => Promise;
+ * retryUntilCondition: RetryUntilCondition;
* chainId?: string;
* whale?: string;
* progress?: typeof console.log;
@@ -139,14 +144,15 @@ export const provisionSmartWallet = async (
whale = 'faucet',
progress = console.log,
q = makeQueryKit(makeVStorage(lcd)).query,
+ retryUntilCondition,
},
) => {
// TODO: skip this query if balances is {}
const vbankEntries = await q.queryData('published.agoricNames.vbankAsset');
const byName = Object.fromEntries(
- vbankEntries.map(([denom, info]) => {
- /// XXX better way to filter out old ATOM denom?
- if (denom === 'ibc/toyatom') return [undefined, undefined];
+ // reverse entries, so we get the latest view on the denom since there are
+ // multiple entries in the testing environment
+ [...vbankEntries].reverse().map(([_, info]) => {
return [info.issuerName, info];
}),
);
@@ -187,7 +193,12 @@ export const provisionSmartWallet = async (
{ chainId, from: address, yes: true },
);
- const info = await q.queryData(`published.wallet.${address}.current`);
+ const info = await retryUntilCondition(
+ () => q.queryData(`published.wallet.${address}.current`),
+ result => !!result,
+ `wallet in vstorage ${address}`,
+ { log: () => {} }, // suppress logs as this is already noisy
+ );
progress({
provisioned: address,
purses: info.purses.length,
@@ -297,6 +308,8 @@ export const provisionSmartWallet = async (
return { offers, deposit, peek, query: q };
};
+/** @typedef {Awaited>} WalletDriver */
+
/**
* @param {{
* agd: import('./agd-lib.js').Agd;
@@ -426,6 +439,7 @@ const runCoreEval = async (
* @param {string} [io.rpcAddress]
* @param {string} [io.apiAddress]
* @param {(...parts: string[]) => string} [io.join]
+ * * @param {RetryUntilCondition} [io.retryUntilCondition]
*/
export const makeE2ETools = async (
log,
@@ -436,6 +450,7 @@ export const makeE2ETools = async (
setTimeout,
rpcAddress = 'http://localhost:26657',
apiAddress = 'http://localhost:1317',
+ retryUntilCondition = makeRetryUntilCondition({ log, setTimeout }),
},
) => {
const agd = makeAgd({ execFileSync }).withOpts({ keyringBackend: 'test' });
@@ -533,6 +548,7 @@ export const makeE2ETools = async (
lcd,
delay,
q: vstorageClient,
+ retryUntilCondition,
}),
/**
* @param {string} name
diff --git a/multichain-testing/tools/noble-tools.ts b/multichain-testing/tools/noble-tools.ts
index 0ece8dfd8b8..8a08e6a85bb 100644
--- a/multichain-testing/tools/noble-tools.ts
+++ b/multichain-testing/tools/noble-tools.ts
@@ -19,11 +19,14 @@ const makeKubeArgs = () => {
];
};
-export const makeNobleTools = ({
- execFileSync,
-}: {
- execFileSync: ExecSync;
-}) => {
+export const makeNobleTools = (
+ {
+ execFileSync,
+ }: {
+ execFileSync: ExecSync;
+ },
+ log: (...args: unknown[]) => void = console.log,
+) => {
const exec = (
args: string[],
opts = { encoding: 'utf-8' as const, stdio: ['ignore', 'pipe', 'ignore'] },
@@ -38,8 +41,9 @@ export const makeNobleTools = ({
const registerForwardingAcct = (
channelId: IBCChannelID,
address: ChainAddress['value'],
- ) => {
+ ): { txhash: string; code: number; data: string; height: string } => {
checkEnv();
+ log('creating forwarding address', address, channelId);
return JSON.parse(
exec([
'tx',
@@ -57,6 +61,8 @@ export const makeNobleTools = ({
const mockCctpMint = (amount: bigint, destination: ChainAddress['value']) => {
checkEnv();
+ const denomAmount = `${Number(amount)}uusdc`;
+ log('mock cctp mint', destination, denomAmount);
return JSON.parse(
exec([
'tx',
@@ -64,7 +70,7 @@ export const makeNobleTools = ({
'send',
'faucet',
destination,
- `${Number(amount)}uusdc`,
+ denomAmount,
'--from=faucet',
'-y',
'-b',
@@ -76,8 +82,9 @@ export const makeNobleTools = ({
const queryForwardingAddress = (
channelId: IBCChannelID,
address: ChainAddress['value'],
- ) => {
+ ): { address: string; exists: boolean } => {
checkEnv();
+ log('querying forwarding address', address, channelId);
return JSON.parse(
exec([
'query',
diff --git a/multichain-testing/tools/purse.ts b/multichain-testing/tools/purse.ts
new file mode 100644
index 00000000000..82a76d2a3f4
--- /dev/null
+++ b/multichain-testing/tools/purse.ts
@@ -0,0 +1,10 @@
+import type { Amount, Brand } from '@agoric/ertp';
+const { fromEntries } = Object;
+
+// @ts-expect-error Type 'Brand' does not satisfy the constraint 'string | number | symbol'
+type BrandToBalance = Record;
+
+export const balancesFromPurses = (
+ purses: { balance: Amount; brand: Brand }[],
+): BrandToBalance =>
+ fromEntries(purses.map(({ balance, brand }) => [brand, balance]));
diff --git a/multichain-testing/tools/random.ts b/multichain-testing/tools/random.ts
new file mode 100644
index 00000000000..1928bb1ebd3
--- /dev/null
+++ b/multichain-testing/tools/random.ts
@@ -0,0 +1,11 @@
+/**
+ * @param randomN pseudorandom number between 0 and 1, e.g. Math.random()
+ * @param digits number of digits to generate
+ * @returns a string of digits
+ */
+export function makeRandomDigits(randomN: number, digits = 2n) {
+ if (digits < 1n) throw new Error('digits must be positive');
+ const maxValue = Math.pow(10, Number(digits)) - 1;
+ const num = Math.floor(randomN * (maxValue + 1));
+ return num.toString().padStart(Number(digits), '0');
+}
diff --git a/multichain-testing/tools/sleep.ts b/multichain-testing/tools/sleep.ts
index 1b0d1a58807..eca0392c1b7 100644
--- a/multichain-testing/tools/sleep.ts
+++ b/multichain-testing/tools/sleep.ts
@@ -28,11 +28,11 @@ const retryUntilCondition = async (
{
maxRetries = 6,
retryIntervalMs = 3500,
- log = () => {},
+ log = console.log,
setTimeout = ambientSetTimeout,
}: RetryOptions = {},
): Promise => {
- console.log({ maxRetries, retryIntervalMs, message });
+ log({ maxRetries, retryIntervalMs, message });
let retries = 0;
while (retries < maxRetries) {
@@ -50,7 +50,7 @@ const retryUntilCondition = async (
}
retries++;
- console.log(
+ log(
`Retry ${retries}/${maxRetries} - Waiting for ${retryIntervalMs}ms for ${message}...`,
);
await sleep(retryIntervalMs, { log, setTimeout });
diff --git a/multichain-testing/yarn.lock b/multichain-testing/yarn.lock
index 66b1b0557dc..fd3e9510370 100644
--- a/multichain-testing/yarn.lock
+++ b/multichain-testing/yarn.lock
@@ -6,12 +6,14 @@ __metadata:
cacheKey: 10c0
"@agoric/cosmic-proto@npm:dev":
- version: 0.4.1-dev-e596a01.0
- resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0"
+ version: 0.4.1-dev-bdf5c17.0
+ resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-bdf5c17.0"
dependencies:
"@endo/base64": "npm:^1.0.9"
"@endo/init": "npm:^1.1.7"
- checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35
+ bech32: "npm:^2.0.0"
+ query-string: "npm:^9.1.1"
+ checksum: 10c0/20d4f8763a091b0b741c754fcceb82d666c4eb55bab2eaaef8821f8f7da644e2ee70c1134ef0e1cf90cc940150d61437d935913549d0da8ea17a8f0c80f2d36c
languageName: node
linkType: hard
@@ -1028,6 +1030,13 @@ __metadata:
languageName: node
linkType: hard
+"bech32@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "bech32@npm:2.0.0"
+ checksum: 10c0/45e7cc62758c9b26c05161b4483f40ea534437cf68ef785abadc5b62a2611319b878fef4f86ddc14854f183b645917a19addebc9573ab890e19194bc8f521942
+ languageName: node
+ linkType: hard
+
"bfs-path@npm:^1.0.2":
version: 1.0.2
resolution: "bfs-path@npm:1.0.2"
@@ -1369,6 +1378,13 @@ __metadata:
languageName: node
linkType: hard
+"decode-uri-component@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "decode-uri-component@npm:0.4.1"
+ checksum: 10c0/a180bbdb5398ec8270d236a3ac07cb988bbf6097428481780b85840f088951dc0318a8d8f9d56796e1a322b55b29859cea29982f22f9b03af0bc60974c54e591
+ languageName: node
+ linkType: hard
+
"deep-is@npm:^0.1.3":
version: 0.1.4
resolution: "deep-is@npm:0.1.4"
@@ -1764,6 +1780,13 @@ __metadata:
languageName: node
linkType: hard
+"filter-obj@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "filter-obj@npm:5.1.0"
+ checksum: 10c0/716e8ad2bc352e206556b3e5695b3cdff8aab80c53ea4b00c96315bbf467b987df3640575100aef8b84e812cf5ea4251db4cd672bbe33b1e78afea88400c67dd
+ languageName: node
+ linkType: hard
+
"find-up-simple@npm:^1.0.0":
version: 1.0.0
resolution: "find-up-simple@npm:1.0.0"
@@ -2924,6 +2947,17 @@ __metadata:
languageName: node
linkType: hard
+"query-string@npm:^9.1.1":
+ version: 9.1.1
+ resolution: "query-string@npm:9.1.1"
+ dependencies:
+ decode-uri-component: "npm:^0.4.1"
+ filter-obj: "npm:^5.1.0"
+ split-on-first: "npm:^3.0.0"
+ checksum: 10c0/16481f17754f660aec3cae7abb838a70e383dfcf152414d184e0d0f81fae426acf112b4d51bf754f9c256eaf83ba4241241ba907c8d58b6ed9704425e1712e8c
+ languageName: node
+ linkType: hard
+
"queue-microtask@npm:^1.2.2":
version: 1.2.3
resolution: "queue-microtask@npm:1.2.3"
@@ -3183,6 +3217,13 @@ __metadata:
languageName: node
linkType: hard
+"split-on-first@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "split-on-first@npm:3.0.0"
+ checksum: 10c0/a1262eae12b68de235e1a08e011bf5b42c42621985ddf807e6221fb1e2b3304824913ae7019f18436b96b8fab8aef5f1ad80dedd2385317fdc51b521c3882cd0
+ languageName: node
+ linkType: hard
+
"sprintf-js@npm:~1.0.2":
version: 1.0.3
resolution: "sprintf-js@npm:1.0.3"
diff --git a/packages/agoric-cli/src/commands/auction.js b/packages/agoric-cli/src/commands/auction.js
index ac9306ffb45..684cd4356a4 100644
--- a/packages/agoric-cli/src/commands/auction.js
+++ b/packages/agoric-cli/src/commands/auction.js
@@ -1,6 +1,10 @@
// @ts-check
/* eslint-env node */
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
+import {
+ fetchEnvNetworkConfig,
+ makeAgoricNames,
+ makeVstorageKit,
+} from '@agoric/client-utils';
import { Fail } from '@endo/errors';
import { InvalidArgumentError } from 'commander';
import { outputActionAndHint } from '../lib/wallet.js';
@@ -88,10 +92,11 @@ export const makeAuctionCommand = (
* }} opts
*/
async opts => {
- const { agoricNames, readPublished } = await makeVstorageKit(
+ const { readPublished, ...vsk } = makeVstorageKit(
{ fetch },
networkConfig,
);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const { current } = await readPublished(`auction.governance`);
diff --git a/packages/agoric-cli/src/commands/gov.js b/packages/agoric-cli/src/commands/gov.js
index be116b87514..007b6b1a2ea 100644
--- a/packages/agoric-cli/src/commands/gov.js
+++ b/packages/agoric-cli/src/commands/gov.js
@@ -1,7 +1,11 @@
// @ts-check
/* eslint-disable func-names */
/* eslint-env node */
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
+import {
+ fetchEnvNetworkConfig,
+ makeAgoricNames,
+ makeVstorageKit,
+} from '@agoric/client-utils';
import { execFileSync as execFileSyncAmbient } from 'child_process';
import { Command, CommanderError } from 'commander';
import { normalizeAddressWithOptions, pollBlocks } from '../lib/chain.js';
@@ -14,8 +18,10 @@ import {
} from '../lib/wallet.js';
/**
- * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js'
- * @import {QuestionDetails} from '@agoric/governance/src/types.js'
+ * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
+ * @import {AgoricNamesRemotes} from '@agoric/vats/tools/board-utils.js';
+ * @import {CurrentWalletRecord} from '@agoric/smart-wallet/src/smartWallet.js';
+ * @import {VstorageKit} from '@agoric/client-utils';
*/
const collectValues = (val, memo) => {
@@ -85,19 +91,21 @@ export const makeGovCommand = (_logger, io = {}) => {
* given a sendFrom address; else print it.
*
* @param {{
- * toOffer: (agoricNames: *, current: import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord | undefined) => OfferSpec,
+ * toOffer: (agoricNames: AgoricNamesRemotes, current: CurrentWalletRecord | undefined) => OfferSpec,
* sendFrom?: string | undefined,
* keyringBackend: string,
* instanceName?: string,
* }} detail
- * @param {Awaited>} [optUtils]
+ * @param {VstorageKit} [vsk]
*/
const processOffer = async function (
{ toOffer, sendFrom, keyringBackend },
- optUtils,
+ vsk,
) {
- const utils = await (optUtils || makeVstorageKit({ fetch }, networkConfig));
- const { agoricNames, readPublished } = utils;
+ await null;
+ vsk ||= makeVstorageKit({ fetch }, networkConfig);
+ const { readPublished } = vsk;
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
assert(keyringBackend, 'missing keyring-backend option');
@@ -264,10 +272,11 @@ export const makeGovCommand = (_logger, io = {}) => {
)
.requiredOption('--for ', 'description of the invitation')
.action(async opts => {
- const { agoricNames, readPublished } = await makeVstorageKit(
+ const { readPublished, ...vsk } = makeVstorageKit(
{ fetch },
networkConfig,
);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const current = await getCurrent(opts.from, { readPublished });
const known = findContinuingIds(current, agoricNames);
@@ -293,10 +302,11 @@ export const makeGovCommand = (_logger, io = {}) => {
normalizeAddress,
)
.action(async opts => {
- const { agoricNames, readPublished } = await makeVstorageKit(
+ const { readPublished, ...vsk } = makeVstorageKit(
{ fetch },
networkConfig,
);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const current = await getCurrent(opts.from, { readPublished });
const found = findContinuingIds(current, agoricNames);
@@ -332,8 +342,8 @@ export const makeGovCommand = (_logger, io = {}) => {
normalizeAddress,
)
.action(async function (opts, options) {
- const utils = await makeVstorageKit({ fetch }, networkConfig);
- const { readPublished } = utils;
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+ const { readPublished } = vsk;
const questionDesc = await readPublished(
`committees.${opts.pathname}.latestQuestion`,
@@ -383,7 +393,7 @@ export const makeGovCommand = (_logger, io = {}) => {
sendFrom: opts.sendFrom,
keyringBackend: options.optsWithGlobals().keyringBackend,
},
- utils,
+ vsk,
);
});
diff --git a/packages/agoric-cli/src/commands/oracle.js b/packages/agoric-cli/src/commands/oracle.js
index 2882cef094a..e91d9967be7 100644
--- a/packages/agoric-cli/src/commands/oracle.js
+++ b/packages/agoric-cli/src/commands/oracle.js
@@ -3,6 +3,7 @@
/* eslint-env node */
import {
fetchEnvNetworkConfig,
+ makeAgoricNames,
makeVstorageKit,
makeWalletUtils,
storageHelper,
@@ -90,19 +91,20 @@ export const makeOracleCommand = (logger, io = {}) => {
env: process.env,
fetch,
});
- const utils = await makeVstorageKit({ fetch }, networkConfig);
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const lookupPriceAggregatorInstance = ([brandIn, brandOut]) => {
const name = oracleBrandFeedName(brandIn, brandOut);
- const instance = utils.agoricNames.instance[name];
+ const instance = agoricNames.instance[name];
if (!instance) {
- logger.debug('known instances:', utils.agoricNames.instance);
+ logger.debug('known instances:', agoricNames.instance);
throw Error(`Unknown instance ${name}`);
}
return instance;
};
- return { ...utils, networkConfig, lookupPriceAggregatorInstance };
+ return { ...vsk, networkConfig, lookupPriceAggregatorInstance };
};
oracle
diff --git a/packages/agoric-cli/src/commands/psm.js b/packages/agoric-cli/src/commands/psm.js
index a59a8b81639..e800b5f1c16 100644
--- a/packages/agoric-cli/src/commands/psm.js
+++ b/packages/agoric-cli/src/commands/psm.js
@@ -3,6 +3,7 @@
/* eslint-env node */
import {
fetchEnvNetworkConfig,
+ makeAgoricNames,
makeVstorageKit,
storageHelper,
} from '@agoric/client-utils';
@@ -66,13 +67,14 @@ export const makePsmCommand = logger => {
);
const rpcTools = async () => {
- const utils = await makeVstorageKit({ fetch }, networkConfig);
+ const vsk = await makeVstorageKit({ fetch }, networkConfig);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const lookupPsmInstance = ([minted, anchor]) => {
const name = `psm-${minted}-${anchor}`;
- const instance = utils.agoricNames.instance[name];
+ const instance = agoricNames.instance[name];
if (!instance) {
- logger.debug('known instances:', utils.agoricNames.instance);
+ logger.debug('known instances:', agoricNames.instance);
throw Error(`Unknown instance ${name}`);
}
return instance;
@@ -83,20 +85,19 @@ export const makePsmCommand = logger => {
* @param {[Minted: string, Anchor: string]} pair
*/
const getGovernanceState = async ([Minted, Anchor]) => {
- const govContent = await utils.vstorage.readLatest(
+ const govContent = await vsk.vstorage.readLatest(
`published.psm.${Minted}.${Anchor}.governance`,
);
assert(govContent, 'no gov content');
const { current: governance } = last(
- storageHelper.unserializeTxt(govContent, utils.fromBoard),
+ storageHelper.unserializeTxt(govContent, vsk.fromBoard),
);
- const { [`psm.${Minted}.${Anchor}`]: instance } =
- utils.agoricNames.instance;
+ const { [`psm.${Minted}.${Anchor}`]: instance } = agoricNames.instance;
return { instance, governance };
};
- return { ...utils, lookupPsmInstance, getGovernanceState };
+ return { ...vsk, agoricNames, lookupPsmInstance, getGovernanceState };
};
psm
diff --git a/packages/agoric-cli/src/commands/reserve.js b/packages/agoric-cli/src/commands/reserve.js
index eebb6c7d73d..9716590402e 100644
--- a/packages/agoric-cli/src/commands/reserve.js
+++ b/packages/agoric-cli/src/commands/reserve.js
@@ -1,7 +1,11 @@
// @ts-check
/* eslint-disable func-names */
/* eslint-env node */
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
+import {
+ fetchEnvNetworkConfig,
+ makeAgoricNames,
+ makeVstorageKit,
+} from '@agoric/client-utils';
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
import { Command } from 'commander';
import { outputActionAndHint } from '../lib/wallet.js';
@@ -31,7 +35,8 @@ export const makeReserveCommand = (_logger, io = {}) => {
* }} opts
*/
async ({ collateralBrand, ...opts }) => {
- const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const offer = Offers.reserve.AddCollateral(agoricNames, {
collateralBrandKey: collateralBrand,
@@ -65,7 +70,8 @@ export const makeReserveCommand = (_logger, io = {}) => {
1,
)
.action(async function (opts) {
- const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const reserveInstance = agoricNames.instance.reserve;
assert(reserveInstance, 'missing reserve in names');
diff --git a/packages/agoric-cli/src/commands/vaults.js b/packages/agoric-cli/src/commands/vaults.js
index 51032d89482..006831862e7 100644
--- a/packages/agoric-cli/src/commands/vaults.js
+++ b/packages/agoric-cli/src/commands/vaults.js
@@ -1,7 +1,11 @@
// @ts-check
/* eslint-disable func-names */
/* eslint-env node */
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
+import {
+ fetchEnvNetworkConfig,
+ makeAgoricNames,
+ makeVstorageKit,
+} from '@agoric/client-utils';
import {
lookupOfferIdForVault,
Offers,
@@ -63,7 +67,8 @@ export const makeVaultsCommand = logger => {
.option('--collateralBrand ', 'Collateral brand key', 'ATOM')
.action(async function (opts) {
logger.warn('running with options', opts);
- const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const offer = Offers.vaults.OpenVault(agoricNames, {
giveCollateral: opts.giveCollateral,
@@ -98,10 +103,11 @@ export const makeVaultsCommand = logger => {
.requiredOption('--vaultId ', 'Key of vault (e.g. vault1)')
.action(async function (opts) {
logger.warn('running with options', opts);
- const { agoricNames, readPublished } = await makeVstorageKit(
+ const { readPublished, ...vsk } = makeVstorageKit(
{ fetch },
networkConfig,
);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const previousOfferId = await lookupOfferIdForVault(
opts.vaultId,
@@ -142,10 +148,11 @@ export const makeVaultsCommand = logger => {
)
.action(async function (opts) {
logger.warn('running with options', opts);
- const { agoricNames, readPublished } = await makeVstorageKit(
+ const { readPublished, ...vsk } = makeVstorageKit(
{ fetch },
networkConfig,
);
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const previousOfferId = await lookupOfferIdForVault(
opts.vaultId,
diff --git a/packages/agoric-cli/src/commands/wallet.js b/packages/agoric-cli/src/commands/wallet.js
index e41258716d4..18d3d597c2b 100644
--- a/packages/agoric-cli/src/commands/wallet.js
+++ b/packages/agoric-cli/src/commands/wallet.js
@@ -8,7 +8,11 @@ import {
makeLeader,
makeLeaderFromRpcAddresses,
} from '@agoric/casting';
-import { makeVstorageKit, fetchEnvNetworkConfig } from '@agoric/client-utils';
+import {
+ makeVstorageKit,
+ fetchEnvNetworkConfig,
+ makeAgoricNames,
+} from '@agoric/client-utils';
import { execFileSync } from 'child_process';
import fs from 'fs';
import util from 'util';
@@ -214,13 +218,11 @@ export const makeWalletCommand = async command => {
normalizeAddress,
)
.action(async function (opts) {
- const { agoricNames, unserializer, readPublished } =
- await makeVstorageKit(
- {
- fetch,
- },
- networkConfig,
- );
+ const { readPublished, unserializer, ...vsk } = makeVstorageKit(
+ { fetch },
+ networkConfig,
+ );
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
const leader = makeLeader(networkConfig.rpcAddrs[0]);
const follower = await makeFollower(
diff --git a/packages/agoric-cli/src/lib/wallet.js b/packages/agoric-cli/src/lib/wallet.js
index e9eff2f2ca1..c4e66cf2437 100644
--- a/packages/agoric-cli/src/lib/wallet.js
+++ b/packages/agoric-cli/src/lib/wallet.js
@@ -149,7 +149,7 @@ export const coalesceWalletState = async (follower, invitationBrand) => {
* fees?: string,
* verbose?: boolean,
* keyring?: {home?: string, backend: string},
- * stdout: Pick,
+ * stdout?: Pick,
* execFileSync: typeof import('child_process').execFileSync,
* delay: (ms: number) => Promise,
* dryRun?: boolean,
diff --git a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts
index c9a6178f0fd..d2cd27af919 100644
--- a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts
+++ b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts
@@ -105,7 +105,7 @@ test.serial('setupVaults; run updatePriceFeeds proposals', async t => {
t.log('building all relevant CoreEvals');
const coreEvals = await Promise.all([
- buildProposal(priceFeedBuilder, ['MAINNET']),
+ buildProposal(priceFeedBuilder, ['BOOT_TEST']),
buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'),
buildProposal('@agoric/builders/scripts/vats/add-auction.js'),
]);
diff --git a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts
index 5410fcc59d7..07c4e711289 100644
--- a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts
+++ b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts
@@ -134,7 +134,7 @@ test('modify manager & director params; update vats, check', async t => {
const priceFeedBuilder =
'@agoric/builders/scripts/inter-protocol/updatePriceFeeds.js';
const coreEvals = await Promise.all([
- buildProposal(priceFeedBuilder, ['MAINNET']),
+ buildProposal(priceFeedBuilder, ['BOOT_TEST']),
buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'),
buildProposal('@agoric/builders/scripts/vats/add-auction.js'),
]);
diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts
index 0853f6b183b..6eae95b9ad2 100644
--- a/packages/boot/test/fast-usdc/fast-usdc.test.ts
+++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts
@@ -187,7 +187,7 @@ test.serial('writes account addresses to vstorage', async t => {
await documentStorageSchema(t, storage, doc);
});
-test.skip('makes usdc advance', async t => {
+test.serial('makes usdc advance', async t => {
const {
walletFactoryDriver: wd,
storage,
diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md
index 4b19508a1d9..f27a41da2c4 100644
--- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md
+++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md
@@ -17,10 +17,10 @@ Generated by [AVA](https://avajs.dev).
{
chainPolicies: {
Arbitrum: {
+ attenuatedCttpBridgeAddress: '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A',
chainId: 42161,
confirmations: 2,
- nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A',
},
},
nobleAgoricChannelId: 'channel-21',
diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap
index 0245ac61053..4647d12715f 100644
Binary files a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap and b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap differ
diff --git a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js
index f5e71a6c137..f99db1caa59 100644
--- a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js
+++ b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js
@@ -41,6 +41,16 @@ const configurations = {
],
inBrandNames: ['ATOM', 'stATOM', 'stOSMO', 'stTIA', 'stkATOM'],
},
+ BOOT_TEST: {
+ oracleAddresses: [
+ 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', // DSRV
+ 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', // Stakin
+ 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', // 01node
+ 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', // Simply Staking
+ 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', // P2P
+ ],
+ inBrandNames: ['ATOM'],
+ },
};
const { keys } = Object;
diff --git a/packages/builders/scripts/testing/recorded-retired-instances.js b/packages/builders/scripts/testing/recorded-retired-instances.js
new file mode 100644
index 00000000000..58bc79c969e
--- /dev/null
+++ b/packages/builders/scripts/testing/recorded-retired-instances.js
@@ -0,0 +1,73 @@
+import { makeTracer } from '@agoric/internal';
+import { E } from '@endo/far';
+
+const trace = makeTracer('RecordedRetired', true);
+
+/**
+ * @param {BootstrapPowers &
+ * PromiseSpaceOf<{ retiredContractInstances: MapStore;
+ * }>
+ * } powers
+ */
+export const testRecordedRetiredInstances = async ({
+ consume: {
+ contractKits,
+ // governedContractKits,
+ retiredContractInstances: retiredContractInstancesP,
+ },
+}) => {
+ trace('Start');
+ const retiredContractInstances = await retiredContractInstancesP;
+
+ const auctionIDs = Array.from(retiredContractInstances.keys()).filter(k =>
+ k.startsWith('auction'),
+ );
+ assert(auctionIDs);
+ assert(auctionIDs.length === 1);
+ const auctionInstance = retiredContractInstances.get(auctionIDs[0]);
+ trace({ auctionInstance });
+ // I don't know why it's neither in governedContractKits nor contractKits
+ // assert(await E(governedContractKits).get(auctionInstance));
+
+ const committeeIDs = Array.from(retiredContractInstances.keys()).filter(k =>
+ k.startsWith('economicCommittee'),
+ );
+ assert(committeeIDs);
+ assert(committeeIDs.length === 1);
+ const committeeInstance = retiredContractInstances.get(committeeIDs[0]);
+ assert(await E(contractKits).get(committeeInstance));
+
+ trace('done');
+};
+harden(testRecordedRetiredInstances);
+
+export const getManifestForRecordedRetiredInstances = () => {
+ return {
+ manifest: {
+ [testRecordedRetiredInstances.name]: {
+ consume: {
+ contractKits: true,
+ // governedContractKits: true,
+ retiredContractInstances: true,
+ },
+ },
+ },
+ };
+};
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
+export const defaultProposalBuilder = async () =>
+ harden({
+ sourceSpec:
+ '@agoric/builders/scripts/testing/recorded-retired-instances.js',
+ getManifestCall: ['getManifestForRecordedRetiredInstances', {}],
+ });
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */
+export default async (homeP, endowments) => {
+ // import dynamically so the module can work in CoreEval environment
+ const dspModule = await import('@agoric/deploy-script-support');
+ const { makeHelpers } = dspModule;
+ const { writeCoreEval } = await makeHelpers(homeP, endowments);
+ await writeCoreEval('recorded-retired', defaultProposalBuilder);
+};
diff --git a/packages/builders/scripts/vats/upgrade-mintHolder.js b/packages/builders/scripts/vats/upgrade-mintHolder.js
new file mode 100644
index 00000000000..18cb47854c2
--- /dev/null
+++ b/packages/builders/scripts/vats/upgrade-mintHolder.js
@@ -0,0 +1,126 @@
+import { makeHelpers } from '@agoric/deploy-script-support';
+import { getManifestForUpgradingMintHolder } from '@agoric/vats/src/proposals/upgrade-mintHolder-proposal.js';
+
+const configurations = {
+ A3P_INTEGRATION: {
+ labelList: [
+ 'USDC_axl',
+ 'USDT_grv',
+ 'DAI_axl',
+ 'DAI_grv',
+ 'stATOM',
+ 'USDC_grv',
+ 'ATOM',
+ 'USDT_axl',
+ 'USDC',
+ 'BLD',
+ ],
+ },
+ MAINNET: {
+ labelList: [
+ 'USDT',
+ 'USDT_axl',
+ 'USDT_grv',
+ 'USDC',
+ 'USDC_axl',
+ 'USDC_grv',
+ 'DAI_axl',
+ 'DAI_grv',
+ 'ATOM',
+ 'stATOM',
+ 'stkATOM',
+ 'stTIA',
+ 'stOSMO',
+ ],
+ },
+ DEVNET: {
+ labelList: [
+ 'stATOM3',
+ 'stATOM',
+ 'dATOM',
+ 'stOSMO',
+ 'stkATOM',
+ 'stATOM2',
+ 'STOSMO',
+ 'stTIA',
+ 'ATOM',
+ 'AUSD',
+ 'USDT_grv',
+ 'USDC_axl',
+ 'USDC_grv',
+ 'USDT_axl',
+ 'BLD',
+ ],
+ },
+ EMERYNET: {
+ labelList: [
+ 'ATOM',
+ 'USDT',
+ 'DAI_axl',
+ 'DAI_grv',
+ 'USDC_axl',
+ 'stOSMO',
+ 'stATOM',
+ 'stkATOM',
+ 'stOSMO2',
+ 'ToyUSD',
+ 'BLD',
+ ],
+ },
+};
+
+const { keys } = Object;
+const knownVariants = keys(configurations);
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
+export const defaultProposalBuilder = async ({ publishRef, install }, opts) => {
+ const config = opts.config || configurations[opts.variant];
+ if (!config) {
+ const error = `Unknown variant "${opts.variant}". Expected one of ${knownVariants.join(', ')}`;
+ console.error(error);
+ throw Error(error);
+ }
+ const { labelList } = config;
+
+ return harden({
+ sourceSpec: '@agoric/vats/src/proposals/upgrade-mintHolder-proposal.js',
+ getManifestCall: [
+ getManifestForUpgradingMintHolder.name,
+ {
+ labelList,
+ contractRef: publishRef(install('@agoric/vats/src/mintHolder.js')),
+ },
+ ],
+ });
+};
+
+const Usage = `agoric run upgrade-mintHolder.js ${[...knownVariants, ''].join(' | ')}`;
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */
+export default async (homeP, endowments) => {
+ const { scriptArgs } = endowments;
+ const variantOrConfig = scriptArgs?.[0];
+ console.log('upgrade-mintHolder', variantOrConfig);
+
+ const opts = {};
+
+ if (typeof variantOrConfig === 'string') {
+ if (variantOrConfig[0] === '{') {
+ try {
+ opts.config = JSON.parse(variantOrConfig);
+ } catch (err) {
+ throw Error(`Failed to parse config argument ${variantOrConfig}`);
+ }
+ } else {
+ opts.variant = variantOrConfig;
+ }
+ } else {
+ console.error(Usage);
+ throw Error(Usage);
+ }
+
+ const { writeCoreEval } = await makeHelpers(homeP, endowments);
+ await writeCoreEval(`upgrade-mintHolder`, utils =>
+ defaultProposalBuilder(utils, opts),
+ );
+};
diff --git a/packages/client-utils/src/main.js b/packages/client-utils/src/main.js
index fad3e63225e..decf0366b5b 100644
--- a/packages/client-utils/src/main.js
+++ b/packages/client-utils/src/main.js
@@ -1,6 +1,7 @@
export * from './cli.js';
export * from './network-config.js';
export * from './rpc.js';
+export * from './smart-wallet-kit.js';
export * from './sync-tools.js';
export * from './vstorage.js';
export * from './vstorage-kit.js';
diff --git a/packages/client-utils/src/smart-wallet-kit.js b/packages/client-utils/src/smart-wallet-kit.js
new file mode 100644
index 00000000000..a570fe9855a
--- /dev/null
+++ b/packages/client-utils/src/smart-wallet-kit.js
@@ -0,0 +1,113 @@
+import { makeWalletStateCoalescer } from '@agoric/smart-wallet/src/utils.js';
+import { pollBlocks } from './chain.js';
+import { makeStargateClient } from './rpc.js';
+import { makeAgoricNames, makeVstorageKit } from './vstorage-kit.js';
+
+/**
+ * @import {Amount, Brand} from '@agoric/ertp/src/types.js'
+ * @import {CurrentWalletRecord, UpdateRecord} from '@agoric/smart-wallet/src/smartWallet.js';
+ * @import {MinimalNetworkConfig} from './network-config.js';
+ */
+
+/**
+ * Augment VstorageKit with addtional convenience methods for working with
+ * Agoric smart wallets.
+ *
+ * @param {object} root0
+ * @param {typeof globalThis.fetch} root0.fetch
+ * @param {(ms: number) => Promise} root0.delay
+ * @param {MinimalNetworkConfig} networkConfig
+ */
+export const makeSmartWalletKit = async ({ fetch, delay }, networkConfig) => {
+ const vsk = makeVstorageKit({ fetch }, networkConfig);
+
+ const client = await makeStargateClient(networkConfig, { fetch });
+
+ const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage);
+
+ /**
+ * @param {string} from
+ * @param {number|string} [minHeight]
+ */
+ const storedWalletState = async (from, minHeight = undefined) => {
+ const history = await vsk.vstorage.readFully(
+ `published.wallet.${from}`,
+ minHeight,
+ );
+
+ /** @type {{ Invitation: Brand<'set'> }} */
+ // @ts-expect-error XXX how to narrow AssetKind to set?
+ const { Invitation } = agoricNames.brand;
+ const coalescer = makeWalletStateCoalescer(Invitation);
+ // update with oldest first
+ for (const txt of history.reverse()) {
+ const { body, slots } = JSON.parse(txt);
+ const record = vsk.marshaller.fromCapData({ body, slots });
+ coalescer.update(record);
+ }
+ const coalesced = coalescer.state;
+ harden(coalesced);
+ return coalesced;
+ };
+
+ /**
+ * Get OfferStatus by id, polling until available.
+ *
+ * @param {string} from
+ * @param {string|number} id
+ * @param {number|string} minHeight
+ * @param {boolean} [untilNumWantsSatisfied]
+ */
+ const pollOffer = async (
+ from,
+ id,
+ minHeight,
+ untilNumWantsSatisfied = false,
+ ) => {
+ const poll = pollBlocks({
+ client,
+ delay,
+ retryMessage: 'offer not in wallet at block',
+ });
+
+ const lookup = async () => {
+ const { offerStatuses } = await storedWalletState(from, minHeight);
+ const offerStatus = [...offerStatuses.values()].find(s => s.id === id);
+ if (!offerStatus) throw Error('retry');
+ harden(offerStatus);
+ if (untilNumWantsSatisfied && !('numWantsSatisfied' in offerStatus)) {
+ throw Error('retry (no numWantsSatisfied yet)');
+ }
+ return offerStatus;
+ };
+ return poll(lookup);
+ };
+
+ /**
+ * @param {string} addr
+ * @returns {Promise}
+ */
+ const getLastUpdate = addr => {
+ return vsk.readPublished(`wallet.${addr}`);
+ };
+
+ /**
+ * @param {string} addr
+ * @returns {Promise}
+ */
+ const getCurrentWalletRecord = addr => {
+ return vsk.readPublished(`wallet.${addr}.current`);
+ };
+
+ return {
+ // pass along all of VstorageKit
+ ...vsk,
+ agoricNames,
+ networkConfig,
+ getLastUpdate,
+ getCurrentWalletRecord,
+ storedWalletState,
+ pollOffer,
+ };
+};
+/** @typedef {Awaited>} SmartWalletKit */
diff --git a/packages/client-utils/src/vstorage-kit.js b/packages/client-utils/src/vstorage-kit.js
index bca8d7b074e..6643d81fe63 100644
--- a/packages/client-utils/src/vstorage-kit.js
+++ b/packages/client-utils/src/vstorage-kit.js
@@ -2,6 +2,7 @@ import {
boardSlottingMarshaller,
makeBoardRemote,
} from '@agoric/vats/tools/board-utils.js';
+import { assertAllDefined } from '@agoric/internal';
import { makeVStorage } from './vstorage.js';
export { boardSlottingMarshaller };
@@ -73,6 +74,7 @@ harden(storageHelper);
* @returns {Promise}
*/
export const makeAgoricNames = async (ctx, vstorage) => {
+ assertAllDefined({ ctx, vstorage });
const reverse = {};
const entries = await Promise.all(
['brand', 'instance', 'vbankAsset'].map(async kind => {
@@ -96,12 +98,10 @@ export const makeAgoricNames = async (ctx, vstorage) => {
* @param {{ fetch: typeof window.fetch }} io
* @param {MinimalNetworkConfig} config
*/
-export const makeVstorageKit = async ({ fetch }, config) => {
- await null;
+export const makeVstorageKit = ({ fetch }, config) => {
try {
const vstorage = makeVStorage({ fetch }, config);
const fromBoard = makeFromBoard();
- const agoricNames = await makeAgoricNames(fromBoard, vstorage);
const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal);
@@ -131,7 +131,6 @@ export const makeVstorageKit = async ({ fetch }, config) => {
readLatestHead(`published.${subpath}`);
return {
- agoricNames,
fromBoard,
marshaller,
readLatestHead,
@@ -143,4 +142,4 @@ export const makeVstorageKit = async ({ fetch }, config) => {
throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`);
}
};
-/** @typedef {Awaited>} VstorageKit */
+/** @typedef {ReturnType} VstorageKit */
diff --git a/packages/client-utils/src/wallet-utils.js b/packages/client-utils/src/wallet-utils.js
index 2cd63a1498d..79f0d9edc96 100644
--- a/packages/client-utils/src/wallet-utils.js
+++ b/packages/client-utils/src/wallet-utils.js
@@ -1,113 +1,8 @@
-import { makeWalletStateCoalescer } from '@agoric/smart-wallet/src/utils.js';
-import { pollBlocks } from './chain.js';
-import { makeStargateClient } from './rpc.js';
-import { boardSlottingMarshaller, makeVstorageKit } from './vstorage-kit.js';
+/** @file backwards compat */
-/**
- * @import {Amount, Brand} from '@agoric/ertp/src/types.js'
- * @import {CurrentWalletRecord, UpdateRecord} from '@agoric/smart-wallet/src/smartWallet.js';
- * @import {MinimalNetworkConfig} from './network-config.js';
- */
+import { makeSmartWalletKit } from './smart-wallet-kit.js';
-// XXX this is really a SmartWalletKit
-/**
- * Augment VstorageKit with addtional convenience methods for working with
- * Agoric smart wallets.
- *
- * @param {object} root0
- * @param {typeof globalThis.fetch} root0.fetch
- * @param {(ms: number) => Promise} root0.delay
- * @param {MinimalNetworkConfig} networkConfig
- */
-export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => {
- const vsk = await makeVstorageKit({ fetch }, networkConfig);
+/** @typedef {import('./smart-wallet-kit.js').SmartWalletKit} WalletUtils */
- const m = boardSlottingMarshaller(vsk.fromBoard.convertSlotToVal);
-
- const client = await makeStargateClient(networkConfig, { fetch });
-
- /**
- * @param {string} from
- * @param {number|string} [minHeight]
- */
- const storedWalletState = async (from, minHeight = undefined) => {
- const history = await vsk.vstorage.readFully(
- `published.wallet.${from}`,
- minHeight,
- );
-
- /** @type {{ Invitation: Brand<'set'> }} */
- // @ts-expect-error XXX how to narrow AssetKind to set?
- const { Invitation } = vsk.agoricNames.brand;
- const coalescer = makeWalletStateCoalescer(Invitation);
- // update with oldest first
- for (const txt of history.reverse()) {
- const { body, slots } = JSON.parse(txt);
- const record = m.fromCapData({ body, slots });
- coalescer.update(record);
- }
- const coalesced = coalescer.state;
- harden(coalesced);
- return coalesced;
- };
-
- /**
- * Get OfferStatus by id, polling until available.
- *
- * @param {string} from
- * @param {string|number} id
- * @param {number|string} minHeight
- * @param {boolean} [untilNumWantsSatisfied]
- */
- const pollOffer = async (
- from,
- id,
- minHeight,
- untilNumWantsSatisfied = false,
- ) => {
- const poll = pollBlocks({
- client,
- delay,
- retryMessage: 'offer not in wallet at block',
- });
-
- const lookup = async () => {
- const { offerStatuses } = await storedWalletState(from, minHeight);
- const offerStatus = [...offerStatuses.values()].find(s => s.id === id);
- if (!offerStatus) throw Error('retry');
- harden(offerStatus);
- if (untilNumWantsSatisfied && !('numWantsSatisfied' in offerStatus)) {
- throw Error('retry (no numWantsSatisfied yet)');
- }
- return offerStatus;
- };
- return poll(lookup);
- };
-
- /**
- * @param {string} addr
- * @returns {Promise}
- */
- const getLastUpdate = addr => {
- return vsk.readPublished(`wallet.${addr}`);
- };
-
- /**
- * @param {string} addr
- * @returns {Promise}
- */
- const getCurrentWalletRecord = addr => {
- return vsk.readPublished(`wallet.${addr}.current`);
- };
-
- return {
- // pass along all of VstorageKit
- ...vsk,
- networkConfig,
- getLastUpdate,
- getCurrentWalletRecord,
- storedWalletState,
- pollOffer,
- };
-};
-/** @typedef {Awaited>} WalletUtils */
+/** @deprecated use `makeSmartWalletKit` */
+export const makeWalletUtils = makeSmartWalletKit;
diff --git a/packages/client-utils/test/snapshots/exports.test.js.md b/packages/client-utils/test/snapshots/exports.test.js.md
index 22f45e43b82..1dc0f08ff90 100644
--- a/packages/client-utils/test/snapshots/exports.test.js.md
+++ b/packages/client-utils/test/snapshots/exports.test.js.md
@@ -16,6 +16,7 @@ Generated by [AVA](https://avajs.dev).
'fetchNetworkConfig',
'makeAgoricNames',
'makeFromBoard',
+ 'makeSmartWalletKit',
'makeStargateClient',
'makeTendermint34Client',
'makeVStorage',
diff --git a/packages/client-utils/test/snapshots/exports.test.js.snap b/packages/client-utils/test/snapshots/exports.test.js.snap
index c6c052973b5..f44f9a7329c 100644
Binary files a/packages/client-utils/test/snapshots/exports.test.js.snap and b/packages/client-utils/test/snapshots/exports.test.js.snap differ
diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.md b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md
new file mode 100644
index 00000000000..fb788564f20
--- /dev/null
+++ b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md
@@ -0,0 +1,352 @@
+# Snapshot report for `test/vstorage-kit.test.js`
+
+The actual snapshot is saved in `vstorage-kit.test.js.snap`.
+
+Generated by [AVA](https://avajs.dev).
+
+## agoricNames contains expected structure
+
+> agoricNames from A3P
+
+ {
+ brand: {
+ ATOM: Object @Alleged: BoardRemoteATOM brand {
+ getBoardId: Function getBoardId {},
+ },
+ BLD: Object @Alleged: BoardRemoteBLD brand {
+ getBoardId: Function getBoardId {},
+ },
+ DAI_axl: Object @Alleged: BoardRemoteDAI_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ DAI_grv: Object @Alleged: BoardRemoteDAI_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ IST: Object @Alleged: BoardRemoteIST brand {
+ getBoardId: Function getBoardId {},
+ },
+ Invitation: Object @Alleged: BoardRemoteZoe Invitation brand {
+ getBoardId: Function getBoardId {},
+ },
+ KREAdCHARACTER: Object @Alleged: BoardRemoteKREAdCHARACTER brand {
+ getBoardId: Function getBoardId {},
+ },
+ KREAdITEM: Object @Alleged: BoardRemoteKREAdITEM brand {
+ getBoardId: Function getBoardId {},
+ },
+ USDC_axl: Object @Alleged: BoardRemoteUSDC_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ USDC_grv: Object @Alleged: BoardRemoteUSDC_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ USDT_axl: Object @Alleged: BoardRemoteUSDT_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ USDT_grv: Object @Alleged: BoardRemoteUSDT_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ stATOM: Object @Alleged: BoardRemotestATOM brand {
+ getBoardId: Function getBoardId {},
+ },
+ timer: Object @Alleged: BoardRemotetimerBrand {
+ getBoardId: Function getBoardId {},
+ },
+ },
+ instance: {
+ 'ATOM-USD price feed': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ Crabble: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ CrabbleCommittee: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ CrabbleGovernor: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ VaultFactory: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ VaultFactoryGovernor: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ auctioneer: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ econCommitteeCharter: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ economicCommittee: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ feeDistributor: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ kread: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ kreadCommittee: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ kreadCommitteeCharter: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ provisionPool: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-DAI_axl': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-DAI_grv': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-USDC_axl': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-USDC_grv': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-USDT_axl': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'psm-IST-USDT_grv': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ reserve: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ reserveGovernor: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'scaledPriceAuthority-stATOM': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ 'stATOM-USD price feed': Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ walletFactory: Object @Alleged: BoardRemoteInstanceHandle {
+ getBoardId: Function getBoardId {},
+ },
+ },
+ reverse: {
+ board00282: 'KREAdITEM',
+ board00360: 'VaultFactory',
+ board0074: 'Invitation',
+ board00990: 'stATOM',
+ board01272: 'psm-IST-USDT_grv',
+ board01664: 'provisionPool',
+ board01744: 'USDT_axl',
+ board01867: 'psm-IST-DAI_axl',
+ board01985: 'kreadCommittee',
+ board02271: 'psm-IST-USDT_axl',
+ board02393: 'CrabbleCommittee',
+ board02568: 'psm-IST-DAI_grv',
+ board0257: 'IST',
+ board02963: 'ATOM-USD price feed',
+ board03040: 'USDC_axl',
+ board03138: 'DAI_grv',
+ board03281: 'KREAdCHARACTER',
+ board03365: 'reserveGovernor',
+ board03446: 'USDT_grv',
+ board03773: 'VaultFactoryGovernor',
+ board04091: 'stATOM-USD price feed',
+ board04149: 'economicCommittee',
+ board0425: 'timer',
+ board04395: 'Crabble',
+ board04542: 'USDC_grv',
+ board04661: 'econCommitteeCharter',
+ board04783: 'kread',
+ board05262: 'feeDistributor',
+ board05396: 'CrabbleGovernor',
+ board05557: 'ATOM',
+ board0566: 'BLD',
+ board05669: 'psm-IST-USDC_axl',
+ board05736: 'DAI_axl',
+ board05892: 'scaledPriceAuthority-stATOM',
+ board05970: 'psm-IST-USDC_grv',
+ board06284: 'kreadCommitteeCharter',
+ board06299: 'auctioneer',
+ board06366: 'walletFactory',
+ board06458: 'reserve',
+ },
+ vbankAsset: {
+ 'ibc/295548A78785A1007F232DE286149A6FF512F180AF5657780FC89C009E2C348F': {
+ brand: Object @Alleged: BoardRemoteUSDC_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/295548A78785A1007F232DE286149A6FF512F180AF5657780FC89C009E2C348F',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteUSDC_axl issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'USDC_axl',
+ proposedName: 'USD Coin',
+ },
+ 'ibc/386D09AE31DA7C0C93091BB45D08CB7A0730B1F697CD813F06A5446DCF02EEB2': {
+ brand: Object @Alleged: BoardRemoteUSDT_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/386D09AE31DA7C0C93091BB45D08CB7A0730B1F697CD813F06A5446DCF02EEB2',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteUSDT_grv issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'USDT_grv',
+ proposedName: 'Tether USD',
+ },
+ 'ibc/3914BDEF46F429A26917E4D8D434620EC4817DC6B6E68FB327E190902F1E9242': {
+ brand: Object @Alleged: BoardRemoteDAI_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/3914BDEF46F429A26917E4D8D434620EC4817DC6B6E68FB327E190902F1E9242',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 18,
+ },
+ issuer: Object @Alleged: BoardRemoteDAI_axl issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'DAI_axl',
+ proposedName: 'DAI',
+ },
+ 'ibc/3D5291C23D776C3AA7A7ABB34C7B023193ECD2BC42EA19D3165B2CF9652117E7': {
+ brand: Object @Alleged: BoardRemoteDAI_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/3D5291C23D776C3AA7A7ABB34C7B023193ECD2BC42EA19D3165B2CF9652117E7',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 18,
+ },
+ issuer: Object @Alleged: BoardRemoteDAI_grv issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'DAI_grv',
+ proposedName: 'DAI',
+ },
+ 'ibc/42225F147137DDEB5FEF0F1D0A92F2AD57557AFA2C4D6F30B21E0D983001C002': {
+ brand: Object @Alleged: BoardRemotestATOM brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/42225F147137DDEB5FEF0F1D0A92F2AD57557AFA2C4D6F30B21E0D983001C002',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemotestATOM issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'stATOM',
+ proposedName: 'stATOM',
+ },
+ 'ibc/6831292903487E58BF9A195FDDC8A2E626B3DF39B88F4E7F41C935CADBAF54AC': {
+ brand: Object @Alleged: BoardRemoteUSDC_grv brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/6831292903487E58BF9A195FDDC8A2E626B3DF39B88F4E7F41C935CADBAF54AC',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteUSDC_grv issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'USDC_grv',
+ proposedName: 'USC Coin',
+ },
+ 'ibc/BA313C4A19DFBF943586C0387E6B11286F9E416B4DD27574E6909CABE0E342FA': {
+ brand: Object @Alleged: BoardRemoteATOM brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/BA313C4A19DFBF943586C0387E6B11286F9E416B4DD27574E6909CABE0E342FA',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteATOM issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'ATOM',
+ proposedName: 'ATOM',
+ },
+ 'ibc/F2331645B9683116188EF36FC04A809C28BD36B54555E8705A37146D0182F045': {
+ brand: Object @Alleged: BoardRemoteUSDT_axl brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ibc/F2331645B9683116188EF36FC04A809C28BD36B54555E8705A37146D0182F045',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteUSDT_axl issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'USDT_axl',
+ proposedName: 'Tether USD',
+ },
+ ubld: {
+ brand: Object @Alleged: BoardRemoteBLD brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'ubld',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteBLD issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'BLD',
+ proposedName: 'Agoric staking token',
+ },
+ uist: {
+ brand: Object @Alleged: BoardRemoteIST brand {
+ getBoardId: Function getBoardId {},
+ },
+ denom: 'uist',
+ displayInfo: {
+ assetKind: 'nat',
+ decimalPlaces: 6,
+ },
+ issuer: Object @Alleged: BoardRemoteIST issuer {
+ getBoardId: Function getBoardId {},
+ },
+ issuerName: 'IST',
+ proposedName: 'Agoric stable token',
+ },
+ },
+ }
+
+> priceFeed from A3P
+
+ {
+ amountIn: {
+ brand: Object @Alleged: BoardRemoteBrand {
+ getBoardId: Function getBoardId {},
+ },
+ value: 1000000n,
+ },
+ amountOut: {
+ brand: Object @Alleged: BoardRemoteBrand {
+ getBoardId: Function getBoardId {},
+ },
+ value: 12010000n,
+ },
+ timer: Object @Alleged: BoardRemotetimerService {
+ getBoardId: Function getBoardId {},
+ },
+ timestamp: {
+ absValue: 1729176290n,
+ timerBrand: Object @Alleged: BoardRemotetimerBrand {
+ getBoardId: Function getBoardId {},
+ },
+ },
+ }
diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap b/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap
new file mode 100644
index 00000000000..b36c073f925
Binary files /dev/null and b/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap differ
diff --git a/packages/client-utils/test/vstorage-kit.test.js b/packages/client-utils/test/vstorage-kit.test.js
new file mode 100644
index 00000000000..a6d11c6972f
--- /dev/null
+++ b/packages/client-utils/test/vstorage-kit.test.js
@@ -0,0 +1,88 @@
+/* eslint-env node */
+import test from 'ava';
+import { makeAgoricNames, makeVstorageKit } from '../src/vstorage-kit.js';
+
+const makeMockFetch = (responses = {}) => {
+ return async url => {
+ const response = responses[url] || {
+ result: {
+ response: {
+ code: 0,
+ value: Buffer.from(
+ JSON.stringify({ value: '{"blockHeight":1,"values":[]}' }),
+ ).toString('base64'),
+ },
+ },
+ };
+ return { json: () => Promise.resolve(response) };
+ };
+};
+
+const makeTestConfig = () => ({
+ chainName: 'test-chain',
+ rpcAddrs: ['http://localhost:26657'],
+});
+
+test('agoricNames contains expected structure', async t => {
+ /** @type {typeof window.fetch} */
+ // @ts-expect-error mock
+ const fetch = makeMockFetch({
+ 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.brand%22&height=0':
+ {
+ result: {
+ response: {
+ code: 0,
+ value:
+ // observed in a3p
+ 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNzY5XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIjW1tcXFxcXFxcIkFUT01cXFxcXFxcIixcXFxcXFxcIiQwLkFsbGVnZWQ6IEFUT00gYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiQkxEXFxcXFxcXCIsXFxcXFxcXCIkMS5BbGxlZ2VkOiBCTEQgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiREFJX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogREFJX2F4bCBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJEQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBEQUlfZ3J2IGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIklTVFxcXFxcXFwiLFxcXFxcXFwiJDQuQWxsZWdlZDogSVNUIGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIkludml0YXRpb25cXFxcXFxcIixcXFxcXFxcIiQ1LkFsbGVnZWQ6IFpvZSBJbnZpdGF0aW9uIGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIktSRUFkQ0hBUkFDVEVSXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBLUkVBZENIQVJBQ1RFUiBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJLUkVBZElURU1cXFxcXFxcIixcXFxcXFxcIiQ3LkFsbGVnZWQ6IEtSRUFkSVRFTSBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJVU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDguQWxsZWdlZDogVVNEQ19heGwgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcIiQ5LkFsbGVnZWQ6IFVTRENfZ3J2IGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIlVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTAuQWxsZWdlZDogVVNEVF9heGwgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiVVNEVF9ncnZcXFxcXFxcIixcXFxcXFxcIiQxMS5BbGxlZ2VkOiBVU0RUX2dydiBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJ0aW1lclxcXFxcXFwiLFxcXFxcXFwiJDEyLkFsbGVnZWQ6IHRpbWVyQnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwic3RBVE9NXFxcXFxcXCIsXFxcXFxcXCIkMTMuQWxsZWdlZDogc3RBVE9NIGJyYW5kXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDU1NTdcXFwiLFxcXCJib2FyZDA1NjZcXFwiLFxcXCJib2FyZDA1NzM2XFxcIixcXFwiYm9hcmQwMzEzOFxcXCIsXFxcImJvYXJkMDI1N1xcXCIsXFxcImJvYXJkMDA3NFxcXCIsXFxcImJvYXJkMDMyODFcXFwiLFxcXCJib2FyZDAwMjgyXFxcIixcXFwiYm9hcmQwMzA0MFxcXCIsXFxcImJvYXJkMDQ1NDJcXFwiLFxcXCJib2FyZDAxNzQ0XFxcIixcXFwiYm9hcmQwMzQ0NlxcXCIsXFxcImJvYXJkMDQyNVxcXCIsXFxcImJvYXJkMDA5OTBcXFwiXX1cIl19Igp9',
+ },
+ },
+ },
+ 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.instance%22&height=0':
+ {
+ result: {
+ response: {
+ code: 0,
+ value:
+ // observed in a3p
+ 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiMTE0MVwiLFwidmFsdWVzXCI6W1wie1xcXCJib2R5XFxcIjpcXFwiI1tbXFxcXFxcXCJBVE9NLVVTRCBwcmljZSBmZWVkXFxcXFxcXCIsXFxcXFxcXCIkMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlXFxcXFxcXCIsXFxcXFxcXCIkMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlQ29tbWl0dGVlXFxcXFxcXCIsXFxcXFxcXCIkMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlR292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQzLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeVxcXFxcXFwiLFxcXFxcXFwiJDQuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiVmF1bHRGYWN0b3J5R292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQ1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImVjb25Db21taXR0ZWVDaGFydGVyXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29ub21pY0NvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZmVlRGlzdHJpYnV0b3JcXFxcXFxcIixcXFxcXFxcIiQ4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkXFxcXFxcXCIsXFxcXFxcXCIkOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZENvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDEwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDExLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInByb3Zpc2lvblBvb2xcXFxcXFxcIixcXFxcXFxcIiQxMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULURBSV9heGxcXFxcXFxcIixcXFxcXFxcIiQxMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULURBSV9ncnZcXFxcXFxcIixcXFxcXFxcIiQxNC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRENfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTUuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RDX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE2LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEVF9heGxcXFxcXFxcIixcXFxcXFxcIiQxNy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRFRfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTguQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicmVzZXJ2ZVxcXFxcXFwiLFxcXFxcXFwiJDE5LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInJlc2VydmVHb3Zlcm5vclxcXFxcXFwiLFxcXFxcXFwiJDIwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInNjYWxlZFByaWNlQXV0aG9yaXR5LXN0QVRPTVxcXFxcXFwiLFxcXFxcXFwiJDIxLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInN0QVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDIyLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIndhbGxldEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQyMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXV1cXFwiLFxcXCJzbG90c1xcXCI6W1xcXCJib2FyZDAyOTYzXFxcIixcXFwiYm9hcmQwNDM5NVxcXCIsXFxcImJvYXJkMDIzOTNcXFwiLFxcXCJib2FyZDA1Mzk2XFxcIixcXFwiYm9hcmQwMDM2MFxcXCIsXFxcImJvYXJkMDM3NzNcXFwiLFxcXCJib2FyZDA0NjYxXFxcIixcXFwiYm9hcmQwNDE0OVxcXCIsXFxcImJvYXJkMDUyNjJcXFwiLFxcXCJib2FyZDA0NzgzXFxcIixcXFwiYm9hcmQwMTk4NVxcXCIsXFxcImJvYXJkMDYyODRcXFwiLFxcXCJib2FyZDAxNjY0XFxcIixcXFwiYm9hcmQwMTg2N1xcXCIsXFxcImJvYXJkMDI1NjhcXFwiLFxcXCJib2FyZDA1NjY5XFxcIixcXFwiYm9hcmQwNTk3MFxcXCIsXFxcImJvYXJkMDIyNzFcXFwiLFxcXCJib2FyZDAxMjcyXFxcIixcXFwiYm9hcmQwNjQ1OFxcXCIsXFxcImJvYXJkMDMzNjVcXFwiLFxcXCJib2FyZDA1ODkyXFxcIixcXFwiYm9hcmQwNDA5MVxcXCIsXFxcImJvYXJkMDYzNjZcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiNbW1xcXFxcXFwiQVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZVxcXFxcXFwiLFxcXFxcXFwiJDEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUNvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJWYXVsdEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQ0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkNS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29uQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDYuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZWNvbm9taWNDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQ3LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImZlZURpc3RyaWJ1dG9yXFxcXFxcXCIsXFxcXFxcXCIkOC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZFxcXFxcXFwiLFxcXFxcXFwiJDkuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwia3JlYWRDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQxMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZENvbW1pdHRlZUNoYXJ0ZXJcXFxcXFxcIixcXFxcXFxcIiQxMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwcm92aXNpb25Qb29sXFxcXFxcXCIsXFxcXFxcXCIkMTIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1EQUlfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1EQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTQuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcIiQxNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RUX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInJlc2VydmVcXFxcXFxcIixcXFxcXFxcIiQxOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJyZXNlcnZlR292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQyMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJzY2FsZWRQcmljZUF1dGhvcml0eS1zdEFUT01cXFxcXFxcIixcXFxcXFxcIiQyMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJzdEFUT00tVVNEIHByaWNlIGZlZWRcXFxcXFxcIixcXFxcXFxcIiQyMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJ3YWxsZXRGYWN0b3J5XFxcXFxcXCIsXFxcXFxcXCIkMjMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiYXVjdGlvbmVlclxcXFxcXFwiLFxcXFxcXFwiJDI0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDI5NjNcXFwiLFxcXCJib2FyZDA0Mzk1XFxcIixcXFwiYm9hcmQwMjM5M1xcXCIsXFxcImJvYXJkMDUzOTZcXFwiLFxcXCJib2FyZDAwMzYwXFxcIixcXFwiYm9hcmQwMzc3M1xcXCIsXFxcImJvYXJkMDQ2NjFcXFwiLFxcXCJib2FyZDA0MTQ5XFxcIixcXFwiYm9hcmQwNTI2MlxcXCIsXFxcImJvYXJkMDQ3ODNcXFwiLFxcXCJib2FyZDAxOTg1XFxcIixcXFwiYm9hcmQwNjI4NFxcXCIsXFxcImJvYXJkMDE2NjRcXFwiLFxcXCJib2FyZDAxODY3XFxcIixcXFwiYm9hcmQwMjU2OFxcXCIsXFxcImJvYXJkMDU2NjlcXFwiLFxcXCJib2FyZDA1OTcwXFxcIixcXFwiYm9hcmQwMjI3MVxcXCIsXFxcImJvYXJkMDEyNzJcXFwiLFxcXCJib2FyZDA2NDU4XFxcIixcXFwiYm9hcmQwMzM2NVxcXCIsXFxcImJvYXJkMDU4OTJcXFwiLFxcXCJib2FyZDA0MDkxXFxcIixcXFwiYm9hcmQwNjM2NlxcXCIsXFxcImJvYXJkMDYyOTlcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiNbW1xcXFxcXFwiQVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZVxcXFxcXFwiLFxcXFxcXFwiJDEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUNvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJWYXVsdEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQ0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkNS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJhdWN0aW9uZWVyXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29uQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZWNvbm9taWNDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQ4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImZlZURpc3RyaWJ1dG9yXFxcXFxcXCIsXFxcXFxcXCIkOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZFxcXFxcXFwiLFxcXFxcXFwiJDEwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkQ29tbWl0dGVlXFxcXFxcXCIsXFxcXFxcXCIkMTEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwia3JlYWRDb21taXR0ZWVDaGFydGVyXFxcXFxcXCIsXFxcXFxcXCIkMTIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHJvdmlzaW9uUG9vbFxcXFxcXFwiLFxcXFxcXFwiJDEzLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtREFJX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtREFJX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEQ19heGxcXFxcXFxcIixcXFxcXFxcIiQxNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRENfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RUX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEVF9ncnZcXFxcXFxcIixcXFxcXFxcIiQxOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJyZXNlcnZlXFxcXFxcXCIsXFxcXFxcXCIkMjAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicmVzZXJ2ZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMjEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwic2NhbGVkUHJpY2VBdXRob3JpdHktc3RBVE9NXFxcXFxcXCIsXFxcXFxcXCIkMjIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwic3RBVE9NLVVTRCBwcmljZSBmZWVkXFxcXFxcXCIsXFxcXFxcXCIkMjMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwid2FsbGV0RmFjdG9yeVxcXFxcXFwiLFxcXFxcXFwiJDI0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDI5NjNcXFwiLFxcXCJib2FyZDA0Mzk1XFxcIixcXFwiYm9hcmQwMjM5M1xcXCIsXFxcImJvYXJkMDUzOTZcXFwiLFxcXCJib2FyZDAwMzYwXFxcIixcXFwiYm9hcmQwMzc3M1xcXCIsXFxcImJvYXJkMDYyOTlcXFwiLFxcXCJib2FyZDA0NjYxXFxcIixcXFwiYm9hcmQwNDE0OVxcXCIsXFxcImJvYXJkMDUyNjJcXFwiLFxcXCJib2FyZDA0NzgzXFxcIixcXFwiYm9hcmQwMTk4NVxcXCIsXFxcImJvYXJkMDYyODRcXFwiLFxcXCJib2FyZDAxNjY0XFxcIixcXFwiYm9hcmQwMTg2N1xcXCIsXFxcImJvYXJkMDI1NjhcXFwiLFxcXCJib2FyZDA1NjY5XFxcIixcXFwiYm9hcmQwNTk3MFxcXCIsXFxcImJvYXJkMDIyNzFcXFwiLFxcXCJib2FyZDAxMjcyXFxcIixcXFwiYm9hcmQwNjQ1OFxcXCIsXFxcImJvYXJkMDMzNjVcXFwiLFxcXCJib2FyZDA1ODkyXFxcIixcXFwiYm9hcmQwNDA5MVxcXCIsXFxcImJvYXJkMDYzNjZcXFwiXX1cIl19Igp9',
+ },
+ },
+ },
+ 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.vbankAsset%22&height=0':
+ {
+ result: {
+ response: {
+ code: 0,
+ value:
+ // observed in a3p
+ 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNzY5XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIjW1tcXFxcXFxcImliYy8yOTU1NDhBNzg3ODVBMTAwN0YyMzJERTI4NjE0OUE2RkY1MTJGMTgwQUY1NjU3NzgwRkM4OUMwMDlFMkMzNDhGXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQwLkFsbGVnZWQ6IFVTRENfYXhsIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzI5NTU0OEE3ODc4NUExMDA3RjIzMkRFMjg2MTQ5QTZGRjUxMkYxODBBRjU2NTc3ODBGQzg5QzAwOUUyQzM0OEZcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDEuQWxsZWdlZDogVVNEQ19heGwgaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJVU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwicHJvcG9zZWROYW1lXFxcXFxcXCI6XFxcXFxcXCJVU0QgQ29pblxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzM4NkQwOUFFMzFEQTdDMEM5MzA5MUJCNDVEMDhDQjdBMDczMEIxRjY5N0NEODEzRjA2QTU0NDZEQ0YwMkVFQjJcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDIuQWxsZWdlZDogVVNEVF9ncnYgYnJhbmRcXFxcXFxcIixcXFxcXFxcImRlbm9tXFxcXFxcXCI6XFxcXFxcXCJpYmMvMzg2RDA5QUUzMURBN0MwQzkzMDkxQkI0NUQwOENCN0EwNzMwQjFGNjk3Q0Q4MTNGMDZBNTQ0NkRDRjAyRUVCMlxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjZ9LFxcXFxcXFwiaXNzdWVyXFxcXFxcXCI6XFxcXFxcXCIkMy5BbGxlZ2VkOiBVU0RUX2dydiBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIlVTRFRfZ3J2XFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIlRldGhlciBVU0RcXFxcXFxcIn1dLFtcXFxcXFxcImliYy8zOTE0QkRFRjQ2RjQyOUEyNjkxN0U0RDhENDM0NjIwRUM0ODE3REM2QjZFNjhGQjMyN0UxOTA5MDJGMUU5MjQyXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQ0LkFsbGVnZWQ6IERBSV9heGwgYnJhbmRcXFxcXFxcIixcXFxcXFxcImRlbm9tXFxcXFxcXCI6XFxcXFxcXCJpYmMvMzkxNEJERUY0NkY0MjlBMjY5MTdFNEQ4RDQzNDYyMEVDNDgxN0RDNkI2RTY4RkIzMjdFMTkwOTAyRjFFOTI0MlxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjE4fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDUuQWxsZWdlZDogREFJX2F4bCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIkRBSV9heGxcXFxcXFxcIixcXFxcXFxcInByb3Bvc2VkTmFtZVxcXFxcXFwiOlxcXFxcXFwiREFJXFxcXFxcXCJ9XSxbXFxcXFxcXCJpYmMvM0Q1MjkxQzIzRDc3NkMzQUE3QTdBQkIzNEM3QjAyMzE5M0VDRDJCQzQyRUExOUQzMTY1QjJDRjk2NTIxMTdFN1xcXFxcXFwiLHtcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkNi5BbGxlZ2VkOiBEQUlfZ3J2IGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzNENTI5MUMyM0Q3NzZDM0FBN0E3QUJCMzRDN0IwMjMxOTNFQ0QyQkM0MkVBMTlEMzE2NUIyQ0Y5NjUyMTE3RTdcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjoxOH0sXFxcXFxcXCJpc3N1ZXJcXFxcXFxcIjpcXFxcXFxcIiQ3LkFsbGVnZWQ6IERBSV9ncnYgaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJEQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkRBSVxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzQyMjI1RjE0NzEzN0RERUI1RkVGMEYxRDBBOTJGMkFENTc1NTdBRkEyQzRENkYzMEIyMUUwRDk4MzAwMUMwMDJcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDguQWxsZWdlZDogc3RBVE9NIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzQyMjI1RjE0NzEzN0RERUI1RkVGMEYxRDBBOTJGMkFENTc1NTdBRkEyQzRENkYzMEIyMUUwRDk4MzAwMUMwMDJcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDkuQWxsZWdlZDogc3RBVE9NIGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwic3RBVE9NXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcInN0QVRPTVxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzY4MzEyOTI5MDM0ODdFNThCRjlBMTk1RkREQzhBMkU2MjZCM0RGMzlCODhGNEU3RjQxQzkzNUNBREJBRjU0QUNcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDEwLkFsbGVnZWQ6IFVTRENfZ3J2IGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzY4MzEyOTI5MDM0ODdFNThCRjlBMTk1RkREQzhBMkU2MjZCM0RGMzlCODhGNEU3RjQxQzkzNUNBREJBRjU0QUNcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDExLkFsbGVnZWQ6IFVTRENfZ3J2IGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwiVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcInByb3Bvc2VkTmFtZVxcXFxcXFwiOlxcXFxcXFwiVVNDIENvaW5cXFxcXFxcIn1dLFtcXFxcXFxcImliYy9CQTMxM0M0QTE5REZCRjk0MzU4NkMwMzg3RTZCMTEyODZGOUU0MTZCNEREMjc1NzRFNjkwOUNBQkUwRTM0MkZBXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxMi5BbGxlZ2VkOiBBVE9NIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjL0JBMzEzQzRBMTlERkJGOTQzNTg2QzAzODdFNkIxMTI4NkY5RTQxNkI0REQyNzU3NEU2OTA5Q0FCRTBFMzQyRkFcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDEzLkFsbGVnZWQ6IEFUT00gaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJBVE9NXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkFUT01cXFxcXFxcIn1dLFtcXFxcXFxcImliYy9GMjMzMTY0NUI5NjgzMTE2MTg4RUYzNkZDMDRBODA5QzI4QkQzNkI1NDU1NUU4NzA1QTM3MTQ2RDAxODJGMDQ1XFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxNC5BbGxlZ2VkOiBVU0RUX2F4bCBicmFuZFxcXFxcXFwiLFxcXFxcXFwiZGVub21cXFxcXFxcIjpcXFxcXFxcImliYy9GMjMzMTY0NUI5NjgzMTE2MTg4RUYzNkZDMDRBODA5QzI4QkQzNkI1NDU1NUU4NzA1QTM3MTQ2RDAxODJGMDQ1XFxcXFxcXCIsXFxcXFxcXCJkaXNwbGF5SW5mb1xcXFxcXFwiOntcXFxcXFxcImFzc2V0S2luZFxcXFxcXFwiOlxcXFxcXFwibmF0XFxcXFxcXCIsXFxcXFxcXCJkZWNpbWFsUGxhY2VzXFxcXFxcXCI6Nn0sXFxcXFxcXCJpc3N1ZXJcXFxcXFxcIjpcXFxcXFxcIiQxNS5BbGxlZ2VkOiBVU0RUX2F4bCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIlVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIlRldGhlciBVU0RcXFxcXFxcIn1dLFtcXFxcXFxcInVibGRcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDE2LkFsbGVnZWQ6IEJMRCBicmFuZFxcXFxcXFwiLFxcXFxcXFwiZGVub21cXFxcXFxcIjpcXFxcXFxcInVibGRcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDE3LkFsbGVnZWQ6IEJMRCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIkJMRFxcXFxcXFwiLFxcXFxcXFwicHJvcG9zZWROYW1lXFxcXFxcXCI6XFxcXFxcXCJBZ29yaWMgc3Rha2luZyB0b2tlblxcXFxcXFwifV0sW1xcXFxcXFwidWlzdFxcXFxcXFwiLHtcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMTguQWxsZWdlZDogSVNUIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwidWlzdFxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjZ9LFxcXFxcXFwiaXNzdWVyXFxcXFxcXCI6XFxcXFxcXCIkMTkuQWxsZWdlZDogSVNUIGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwiSVNUXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkFnb3JpYyBzdGFibGUgdG9rZW5cXFxcXFxcIn1dXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDMwNDBcXFwiLFxcXCJib2FyZDA1MTQxXFxcIixcXFwiYm9hcmQwMzQ0NlxcXCIsXFxcImJvYXJkMDE1NDdcXFwiLFxcXCJib2FyZDA1NzM2XFxcIixcXFwiYm9hcmQwMjQzN1xcXCIsXFxcImJvYXJkMDMxMzhcXFwiLFxcXCJib2FyZDA1MDM5XFxcIixcXFwiYm9hcmQwMDk5MFxcXCIsXFxcImJvYXJkMDA2ODlcXFwiLFxcXCJib2FyZDA0NTQyXFxcIixcXFwiYm9hcmQwMDQ0M1xcXCIsXFxcImJvYXJkMDU1NTdcXFwiLFxcXCJib2FyZDAyNjU2XFxcIixcXFwiYm9hcmQwMTc0NFxcXCIsXFxcImJvYXJkMDY0NDVcXFwiLFxcXCJib2FyZDA1NjZcXFwiLFxcXCJib2FyZDA1OTJcXFwiLFxcXCJib2FyZDAyNTdcXFwiLFxcXCJib2FyZDAyMjNcXFwiXX1cIl19Igp9',
+ },
+ },
+ },
+ 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.priceFeed.ATOM-USD_price_feed%22&height=0':
+ {
+ result: {
+ response: {
+ code: 0,
+ value:
+ // observed in a3p
+ 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNTA4XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIje1xcXFxcXFwiYW1vdW50SW5cXFxcXFxcIjp7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDAuQWxsZWdlZDogQnJhbmRcXFxcXFxcIixcXFxcXFxcInZhbHVlXFxcXFxcXCI6XFxcXFxcXCIrMTAwMDAwMFxcXFxcXFwifSxcXFxcXFxcImFtb3VudE91dFxcXFxcXFwiOntcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMS5BbGxlZ2VkOiBCcmFuZFxcXFxcXFwiLFxcXFxcXFwidmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxMjAxMDAwMFxcXFxcXFwifSxcXFxcXFxcInRpbWVyXFxcXFxcXCI6XFxcXFxcXCIkMi5BbGxlZ2VkOiB0aW1lclNlcnZpY2VcXFxcXFxcIixcXFxcXFxcInRpbWVzdGFtcFxcXFxcXFwiOntcXFxcXFxcImFic1ZhbHVlXFxcXFxcXCI6XFxcXFxcXCIrMTcyOTE3NjI5MFxcXFxcXFwiLFxcXFxcXFwidGltZXJCcmFuZFxcXFxcXFwiOlxcXFxcXFwiJDMuQWxsZWdlZDogdGltZXJCcmFuZFxcXFxcXFwifX1cXFwiLFxcXCJzbG90c1xcXCI6W1xcXCJib2FyZDAzOTM1XFxcIixcXFwiYm9hcmQwMTAzNFxcXCIsXFxcImJvYXJkMDU2NzRcXFwiLFxcXCJib2FyZDA0MjVcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiN7XFxcXFxcXCJhbW91bnRJblxcXFxcXFwiOntcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMC5BbGxlZ2VkOiBCcmFuZFxcXFxcXFwiLFxcXFxcXFwidmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxMDAwMDAwXFxcXFxcXCJ9LFxcXFxcXFwiYW1vdW50T3V0XFxcXFxcXCI6e1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxLkFsbGVnZWQ6IEJyYW5kXFxcXFxcXCIsXFxcXFxcXCJ2YWx1ZVxcXFxcXFwiOlxcXFxcXFwiKzEyMDEwMDAwXFxcXFxcXCJ9LFxcXFxcXFwidGltZXJcXFxcXFxcIjpcXFxcXFxcIiQyLkFsbGVnZWQ6IHRpbWVyU2VydmljZVxcXFxcXFwiLFxcXFxcXFwidGltZXN0YW1wXFxcXFxcXCI6e1xcXFxcXFwiYWJzVmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxNzI5MTc2MjkwXFxcXFxcXCIsXFxcXFxcXCJ0aW1lckJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMy5BbGxlZ2VkOiB0aW1lckJyYW5kXFxcXFxcXCJ9fVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDM5MzVcXFwiLFxcXCJib2FyZDAxMDM0XFxcIixcXFwiYm9hcmQwNTY3NFxcXCIsXFxcImJvYXJkMDQyNVxcXCJdfVwiXX0iCn0',
+ },
+ },
+ },
+ });
+
+ const vstorageKit = makeVstorageKit({ fetch }, makeTestConfig());
+ const agoricNames = await makeAgoricNames(
+ vstorageKit.fromBoard,
+ vstorageKit.vstorage,
+ );
+
+ t.snapshot(agoricNames, 'agoricNames from A3P');
+
+ const priceFeed = await vstorageKit.readPublished(
+ 'priceFeed.ATOM-USD_price_feed',
+ );
+ t.snapshot(priceFeed, 'priceFeed from A3P');
+});
diff --git a/packages/cosmic-proto/src/address-hooks.js b/packages/cosmic-proto/src/address-hooks.js
index 073f0783c71..c1dcb2e415a 100644
--- a/packages/cosmic-proto/src/address-hooks.js
+++ b/packages/cosmic-proto/src/address-hooks.js
@@ -23,7 +23,7 @@
* const decoded = decodeAddressHook(addressHook);
* // {
* // baseAddress: 'agoric1qqp0e5ys',
- * // query: [Object: null prototype] { foo: [ 'bar', 'baz' ], key: 'value' }
+ * // query: { foo: [ 'bar', 'baz' ], key: 'value' }
* // }
*/
@@ -31,6 +31,10 @@
import { bech32 } from 'bech32';
import queryString from 'query-string';
+/* global globalThis */
+/** @type {(x: T) => T} */
+const harden = globalThis.harden || Object.freeze;
+
// ADDRESS_HOOK_VERSION is the version of the address hook format used in this
// module.
const ADDRESS_HOOK_VERSION = 0;
@@ -39,13 +43,14 @@ if ((ADDRESS_HOOK_VERSION & 0x0f) !== ADDRESS_HOOK_VERSION) {
throw Error(`ADDRESS_HOOK_VERSION ${ADDRESS_HOOK_VERSION} exceeds 0x0f`);
}
-// AddressHookMagic is a magic byte prefix that identifies a hooked address.
+// ADDRESS_HOOK_BYTE_PREFIX is a magic prefix that identifies a hooked address.
// Chosen to make bech32 address hooks that look like "agoric10rch..."
-const ADDRESS_HOOK_MAGIC = new Uint8Array([
+const ADDRESS_HOOK_BYTE_PREFIX = [
0x78,
0xf1,
- 0x70 | ADDRESS_HOOK_VERSION,
-]);
+ 0x70, // | ADDRESS_HOOK_VERSION
+];
+harden(ADDRESS_HOOK_BYTE_PREFIX);
/**
* The default maximum number of characters in a bech32-encoded hooked address.
@@ -63,6 +68,9 @@ export const DEFAULT_HOOKED_ADDRESS_CHAR_LIMIT = 1024;
* { key: ['value1', null, 'value3'] } // '?key=value1&key&key=value3'
*/
+/**
+ * How many bytes are used to store the length of the base address.
+ */
export const BASE_ADDRESS_LENGTH_BYTES = 2;
/**
@@ -78,8 +86,9 @@ export const decodeBech32 = (
const rawBytes = bech32.fromWords(words);
const bytes = new Uint8Array(rawBytes);
- return { prefix, bytes };
+ return harden({ prefix, bytes });
};
+harden(decodeBech32);
/**
* @param {string} humanReadablePart
@@ -95,6 +104,7 @@ export const encodeBech32 = (
const words = bech32.toWords(bytes);
return bech32.encode(humanReadablePart, words, charLimit);
};
+harden(encodeBech32);
/**
* Join raw base address bytes and hook data into a bech32-encoded hooked
@@ -140,13 +150,14 @@ export const joinHookedAddress = (
throw RangeError(`Hook data length ${hd} is not a non-negative integer`);
}
- const magicLength = ADDRESS_HOOK_MAGIC.length;
+ const prefixLength = ADDRESS_HOOK_BYTE_PREFIX.length;
const hookBuf = new Uint8Array(
- magicLength + b + hd + BASE_ADDRESS_LENGTH_BYTES,
+ prefixLength + b + hd + BASE_ADDRESS_LENGTH_BYTES,
);
- hookBuf.set(ADDRESS_HOOK_MAGIC, 0);
- hookBuf.set(bytes, magicLength);
- hookBuf.set(hookData, magicLength + b);
+ hookBuf.set(ADDRESS_HOOK_BYTE_PREFIX, 0);
+ hookBuf[prefixLength - 1] |= ADDRESS_HOOK_VERSION;
+ hookBuf.set(bytes, prefixLength);
+ hookBuf.set(hookData, prefixLength + b);
// Append the address length bytes, since we've already ensured these do not
// exceed maxBaseAddressLength above. These are big-endian because the length
@@ -161,6 +172,7 @@ export const joinHookedAddress = (
return encodeBech32(prefix, hookBuf, charLimit);
};
+harden(joinHookedAddress);
/**
* @param {string} baseAddress
@@ -174,11 +186,13 @@ export const encodeAddressHook = (baseAddress, query, charLimit) => {
const hookData = te.encode(`?${queryStr}`);
return joinHookedAddress(baseAddress, hookData, charLimit);
};
+harden(encodeAddressHook);
/**
* @param {string} addressHook
* @param {number} [charLimit]
* @returns {{ baseAddress: string; query: HookQuery }}
+ * @throws {Error} if no hook string or hook string does not start with `?`
*/
export const decodeAddressHook = (addressHook, charLimit) => {
const { baseAddress, hookData } = splitHookedAddress(addressHook, charLimit);
@@ -187,64 +201,69 @@ export const decodeAddressHook = (addressHook, charLimit) => {
throw Error(`Hook data does not start with '?': ${hookStr}`);
}
- /** @type {HookQuery} */
- const query = queryString.parse(hookStr);
- return { baseAddress, query };
+ const parsedQuery = queryString.parse(hookStr);
+
+ /**
+ * @type {HookQuery}
+ */
+ const query = harden({ ...parsedQuery });
+ return harden({ baseAddress, query });
};
+harden(decodeAddressHook);
/**
* @param {string} specimen
* @param {number} [charLimit]
- * @returns {string | { baseAddress: string; hookData: Uint8Array }}
+ * @returns {{ baseAddress: string; hookData: Uint8Array }}
*/
-export const splitHookedAddressUnsafe = (
+export const splitHookedAddress = (
specimen,
charLimit = DEFAULT_HOOKED_ADDRESS_CHAR_LIMIT,
) => {
const { prefix, bytes } = decodeBech32(specimen, charLimit);
- const magicLength = ADDRESS_HOOK_MAGIC.length;
- for (let i = 0; i < magicLength; i += 1) {
- if (bytes[i] !== ADDRESS_HOOK_MAGIC[i]) {
- return { baseAddress: specimen, hookData: new Uint8Array() };
+ const prefixLength = ADDRESS_HOOK_BYTE_PREFIX.length;
+ let version = 0xff;
+ for (let i = 0; i < prefixLength; i += 1) {
+ let maybeMagicByte = bytes[i];
+ if (i === prefixLength - 1) {
+ // Final byte has a low version nibble and a high magic nibble.
+ version = maybeMagicByte & 0x0f;
+ maybeMagicByte &= 0xf0;
}
+ if (maybeMagicByte !== ADDRESS_HOOK_BYTE_PREFIX[i]) {
+ return harden({ baseAddress: specimen, hookData: new Uint8Array() });
+ }
+ }
+
+ if (version !== ADDRESS_HOOK_VERSION) {
+ throw TypeError(`Unsupported address hook version ${version}`);
}
let len = 0;
for (let i = BASE_ADDRESS_LENGTH_BYTES - 1; i >= 0; i -= 1) {
const byte = bytes.at(-i - 1);
if (byte === undefined) {
- return `Cannot get base address length from byte ${-i - 1} of ${bytes.length}`;
+ throw TypeError(
+ `Cannot get base address length from byte ${-i - 1} of ${bytes.length}`,
+ );
}
len <<= 8;
len |= byte;
}
const b = len;
- if (b > bytes.length - BASE_ADDRESS_LENGTH_BYTES - magicLength) {
- return `Base address length 0x${b.toString(16)} is longer than specimen length ${bytes.length - BASE_ADDRESS_LENGTH_BYTES - magicLength}`;
+ if (b > bytes.length - BASE_ADDRESS_LENGTH_BYTES - prefixLength) {
+ throw TypeError(
+ `Base address length 0x${b.toString(16)} is longer than specimen length ${bytes.length - BASE_ADDRESS_LENGTH_BYTES - prefixLength}`,
+ );
}
- const baseAddressBuf = bytes.subarray(magicLength, magicLength + b);
+ const baseAddressBuf = bytes.subarray(prefixLength, prefixLength + b);
const baseAddress = encodeBech32(prefix, baseAddressBuf, charLimit);
- const hookData = bytes.subarray(magicLength + b, -BASE_ADDRESS_LENGTH_BYTES);
+ const hookData = bytes.subarray(prefixLength + b, -BASE_ADDRESS_LENGTH_BYTES);
- return { baseAddress, hookData };
-};
-
-/**
- * @param {string} specimen
- * @param {number} [charLimit]
- * @returns {{
- * baseAddress: string;
- * hookData: Uint8Array;
- * }}
- */
-export const splitHookedAddress = (specimen, charLimit) => {
- const result = splitHookedAddressUnsafe(specimen, charLimit);
- if (typeof result === 'object') {
- return result;
- }
- throw Error(result);
+ return harden({ baseAddress, hookData });
};
+harden(splitHookedAddress);
diff --git a/packages/cosmic-proto/test/address-hooks.test.js b/packages/cosmic-proto/test/address-hooks.test.js
index 31ce2334f10..a216fc3159d 100644
--- a/packages/cosmic-proto/test/address-hooks.test.js
+++ b/packages/cosmic-proto/test/address-hooks.test.js
@@ -42,6 +42,62 @@ test.before(async t => {
t.context = await makeTestContext();
});
+/**
+ * @type {import('ava').Macro<
+ * [addressHook: string, baseAddress: string, hookDataStr: string, error?: any],
+ * { addressHooks: import('../src/address-hooks.js') }
+ * >}
+ */
+const splitMacro = test.macro({
+ title(providedTitle = '', addressHook, _baseAddress, _hookDataStr, _error) {
+ return `${providedTitle} split ${addressHook}`;
+ },
+ exec(t, addressHook, baseAddress, hookDataStr, error) {
+ const { splitHookedAddress } = t.context.addressHooks;
+ if (error) {
+ t.throws(() => splitHookedAddress(addressHook), error);
+ return;
+ }
+ const { baseAddress: ba, hookData: hd } = splitHookedAddress(addressHook);
+ t.is(ba, baseAddress);
+ const hookData = new TextEncoder().encode(hookDataStr);
+ t.deepEqual(hd, hookData);
+ },
+});
+
+test('empty', splitMacro, '', '', '', { message: ' too short' });
+test('no hook', splitMacro, 'agoric1qqp0e5ys', 'agoric1qqp0e5ys', '', '');
+test(
+ 'Fast USDC',
+ splitMacro,
+ 'agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423padaek6me38qekget2vdhx66mtvy6kg7nrw5uhsaekd4uhwufswqex6dtsv44hxv3cd4jkuqpqvduyhf',
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
+ '?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
+);
+test(
+ 'version 0',
+ splitMacro,
+ 'agoric10rchqqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9qx0p9wp',
+ 'agoric1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn3tn9p0',
+ '\x04\x03\x02\x01',
+);
+test(
+ 'version 1 reject',
+ splitMacro,
+ 'agoric10rchzqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q04n2fg',
+ '',
+ '',
+ { message: 'Unsupported address hook version 1' },
+);
+test(
+ 'version 15 reject',
+ splitMacro,
+ 'agoric10rch7qqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q25ez2d',
+ '',
+ '',
+ { message: 'Unsupported address hook version 15' },
+);
+
/**
* @type {import('ava').Macro<
* [string, ArrayLike | undefined, ArrayLike, string],
diff --git a/packages/fast-usdc/package.json b/packages/fast-usdc/package.json
index 9f8e87b89ad..30e20a49253 100644
--- a/packages/fast-usdc/package.json
+++ b/packages/fast-usdc/package.json
@@ -33,6 +33,7 @@
},
"dependencies": {
"@agoric/client-utils": "^0.1.0",
+ "@agoric/cosmic-proto": "^0.4.0",
"@agoric/ertp": "^0.16.2",
"@agoric/internal": "^0.3.2",
"@agoric/notifier": "^0.6.2",
diff --git a/packages/fast-usdc/src/cli/lp-commands.js b/packages/fast-usdc/src/cli/lp-commands.js
index 4b829cfbfba..afcbd063650 100644
--- a/packages/fast-usdc/src/cli/lp-commands.js
+++ b/packages/fast-usdc/src/cli/lp-commands.js
@@ -1,3 +1,4 @@
+/* eslint-env node */
/**
* @import {Command} from 'commander';
* @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
@@ -5,17 +6,22 @@
* @import {USDCProposalShapes} from '../pool-share-math.js';
*/
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
-import { InvalidArgumentError } from 'commander';
+import {
+ fetchEnvNetworkConfig,
+ makeSmartWalletKit,
+} from '@agoric/client-utils';
+import { AmountMath } from '@agoric/ertp';
import {
assertParsableNumber,
ceilDivideBy,
multiplyBy,
parseRatio,
} from '@agoric/zoe/src/contractSupport/ratio.js';
-import { AmountMath } from '@agoric/ertp';
+import { InvalidArgumentError } from 'commander';
import { outputActionAndHint } from './bridge-action.js';
+export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
+
/** @param {string} arg */
const parseDecimal = arg => {
try {
@@ -41,7 +47,7 @@ const parseUSDCAmount = (amountString, usdc) => {
* @param {Command} program
* @param {{
* fetch?: Window['fetch'];
- * vstorageKit?: Awaited>;
+ * smartWalletKit?: import('@agoric/client-utils').SmartWalletKit;
* stdout: typeof process.stdout;
* stderr: typeof process.stderr;
* env: typeof process.env;
@@ -50,18 +56,18 @@ const parseUSDCAmount = (amountString, usdc) => {
*/
export const addLPCommands = (
program,
- { fetch, vstorageKit, stderr, stdout, env, now },
+ { fetch, smartWalletKit, stderr, stdout, env, now },
) => {
- const loadVsk = async () => {
- if (vstorageKit) {
- return vstorageKit;
+ const loadSwk = async () => {
+ if (smartWalletKit) {
+ return smartWalletKit;
}
assert(fetch);
const networkConfig = await fetchEnvNetworkConfig({ env, fetch });
- return makeVstorageKit({ fetch }, networkConfig);
+ return makeSmartWalletKit({ delay, fetch }, networkConfig);
};
- /** @type {undefined | ReturnType} */
- let vskP;
+ /** @type {undefined | ReturnType} */
+ let swkP;
program
.command('deposit')
@@ -73,11 +79,11 @@ export const addLPCommands = (
.requiredOption('--amount ', 'USDC amount', parseDecimal)
.option('--offerId ', 'Offer id', String, `lpDeposit-${now()}`)
.action(async opts => {
- vskP ||= loadVsk();
- const vsk = await vskP;
+ swkP ||= loadSwk();
+ const swk = await swkP;
/** @type {Brand<'nat'>} */
// @ts-expect-error it doesnt recognize usdc as a Brand type
- const usdc = vsk.agoricNames.brand.USDC;
+ const usdc = swk.agoricNames.brand.USDC;
assert(usdc, 'USDC brand not in agoricNames');
const usdcAmount = parseUSDCAmount(opts.amount, usdc);
@@ -106,7 +112,7 @@ export const addLPCommands = (
offer,
};
- outputActionAndHint(bridgeAction, { stderr, stdout }, vsk.marshaller);
+ outputActionAndHint(bridgeAction, { stderr, stdout }, swk.marshaller);
});
program
@@ -119,24 +125,25 @@ export const addLPCommands = (
.requiredOption('--amount ', 'USDC amount', parseDecimal)
.option('--offerId ', 'Offer id', String, `lpWithdraw-${now()}`)
.action(async opts => {
- vskP ||= loadVsk();
- const vsk = await vskP;
+ swkP ||= loadSwk();
+ swkP ||= loadSwk();
+ const swk = await swkP;
/** @type {Brand<'nat'>} */
// @ts-expect-error it doesnt recognize FastLP as a Brand type
- const poolShare = vsk.agoricNames.brand.FastLP;
+ const poolShare = swk.agoricNames.brand.FastLP;
assert(poolShare, 'FastLP brand not in agoricNames');
/** @type {Brand<'nat'>} */
// @ts-expect-error it doesnt recognize usdc as a Brand type
- const usdc = vsk.agoricNames.brand.USDC;
+ const usdc = swk.agoricNames.brand.USDC;
assert(usdc, 'USDC brand not in agoricNames');
const usdcAmount = parseUSDCAmount(opts.amount, usdc);
/** @type {import('../types.js').PoolMetrics} */
// @ts-expect-error it treats this as "unknown"
- const metrics = await vsk.readPublished('fastUsdc.poolMetrics');
+ const metrics = await swk.readPublished('fastUsdc.poolMetrics');
const fastLPAmount = ceilDivideBy(usdcAmount, metrics.shareWorth);
/** @type {USDCProposalShapes['withdraw']} */
@@ -163,7 +170,7 @@ export const addLPCommands = (
outputActionAndHint(
{ method: 'executeOffer', offer },
{ stderr, stdout },
- vsk.marshaller,
+ swk.marshaller,
);
});
diff --git a/packages/fast-usdc/src/cli/operator-commands.js b/packages/fast-usdc/src/cli/operator-commands.js
index 196a48af8a4..8f849f760db 100644
--- a/packages/fast-usdc/src/cli/operator-commands.js
+++ b/packages/fast-usdc/src/cli/operator-commands.js
@@ -1,3 +1,4 @@
+/* eslint-env node */
/**
* @import {Command} from 'commander';
* @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js';
@@ -5,7 +6,10 @@
* @import {OperatorKit} from '../exos/operator-kit.js';
*/
-import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils';
+import {
+ fetchEnvNetworkConfig,
+ makeSmartWalletKit,
+} from '@agoric/client-utils';
import { mustMatch } from '@agoric/internal';
import { Nat } from '@endo/nat';
import { InvalidArgumentError } from 'commander';
@@ -13,6 +17,8 @@ import { INVITATION_MAKERS_DESC } from '../exos/transaction-feed.js';
import { CctpTxEvidenceShape } from '../type-guards.js';
import { outputActionAndHint } from './bridge-action.js';
+export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
+
/** @param {string} arg */
const parseNat = arg => {
const n = Nat(BigInt(arg));
@@ -53,8 +59,9 @@ export const addOperatorCommands = (
.option('--offerId ', 'Offer id', String, `operatorAccept-${now()}`)
.action(async opts => {
const networkConfig = await fetchEnvNetworkConfig({ env, fetch });
- const vsk = await makeVstorageKit({ fetch }, networkConfig);
- const instance = vsk.agoricNames.instance.fastUsdc;
+
+ const swk = await makeSmartWalletKit({ delay, fetch }, networkConfig);
+ const instance = swk.agoricNames.instance.fastUsdc;
assert(instance, 'fastUsdc instance not in agoricNames');
/** @type {OfferSpec} */
diff --git a/packages/fast-usdc/src/cli/transfer.js b/packages/fast-usdc/src/cli/transfer.js
index 9120f93be0a..41719ac1c37 100644
--- a/packages/fast-usdc/src/cli/transfer.js
+++ b/packages/fast-usdc/src/cli/transfer.js
@@ -6,6 +6,7 @@ import {
makeVStorage,
pickEndpoint,
} from '@agoric/client-utils';
+import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import { queryFastUSDCLocalChainAccount } from '../util/agoric.js';
import { depositForBurn, makeProvider } from '../util/cctp.js';
import {
@@ -22,7 +23,7 @@ import {
const transfer = async (
/** @type {File} */ configFile,
/** @type {string} */ amount,
- /** @type {string} */ destination,
+ /** @type {string} */ EUD,
out = console,
fetch = globalThis.fetch,
/** @type {VStorage | undefined} */ vstorage,
@@ -39,13 +40,13 @@ const transfer = async (
{ chainName: 'agoric', rpcAddrs: [pickEndpoint(netConfig)] },
);
const agoricAddr = await queryFastUSDCLocalChainAccount(vstorage, out);
- const appendedAddr = `${agoricAddr}?EUD=${destination}`;
- out.log(`forwarding destination ${appendedAddr}`);
+ const encodedAddr = encodeAddressHook(agoricAddr, { EUD });
+ out.log(`forwarding destination ${encodedAddr}`);
const { exists, address } = await queryForwardingAccount(
config.nobleApi,
config.nobleToAgoricChannel,
- appendedAddr,
+ encodedAddr,
out,
fetch,
);
@@ -58,13 +59,13 @@ const transfer = async (
signer,
signerAddress,
config.nobleToAgoricChannel,
- appendedAddr,
+ encodedAddr,
out,
);
out.log(res);
} catch (e) {
out.error(
- `Error registering noble forwarding account for ${appendedAddr} on channel ${config.nobleToAgoricChannel}`,
+ `Error registering noble forwarding account for ${encodedAddr} on channel ${config.nobleToAgoricChannel}`,
);
throw e;
}
diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js
index 5fc01abfa38..f63c2b7474c 100644
--- a/packages/fast-usdc/src/exos/advancer.js
+++ b/packages/fast-usdc/src/exos/advancer.js
@@ -1,17 +1,16 @@
+import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import { AmountMath } from '@agoric/ertp';
import { assertAllDefined, makeTracer } from '@agoric/internal';
import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration';
import { pickFacet } from '@agoric/vat-data';
import { VowShape } from '@agoric/vow';
-import { q } from '@endo/errors';
import { E } from '@endo/far';
-import { M } from '@endo/patterns';
+import { M, mustMatch } from '@endo/patterns';
import {
CctpTxEvidenceShape,
- EudParamShape,
+ AddressHookShape,
EvmHashShape,
} from '../type-guards.js';
-import { addressTools } from '../utils/address.js';
import { makeFeeTools } from '../utils/fees.js';
/**
@@ -22,7 +21,7 @@ import { makeFeeTools } from '../utils/fees.js';
* @import {ZoeTools} from '@agoric/orchestration/src/utils/zoe-tools.js';
* @import {VowTools} from '@agoric/vow';
* @import {Zone} from '@agoric/zone';
- * @import {CctpTxEvidence, EvmHash, FeeConfig, LogFn, NobleAddress} from '../types.js';
+ * @import {CctpTxEvidence, AddressHook, EvmHash, FeeConfig, LogFn, NobleAddress} from '../types.js';
* @import {StatusManager} from './status-manager.js';
* @import {LiquidityPoolKit} from './liquidity-pool.js';
*/
@@ -148,11 +147,10 @@ export const prepareAdvancerKit = (
const { borrowerFacet, poolAccount } = this.state;
const { recipientAddress } = evidence.aux;
- // throws if EUD is not found
- const { EUD } = addressTools.getQueryParams(
- recipientAddress,
- EudParamShape,
- );
+ const decoded = decodeAddressHook(recipientAddress);
+ mustMatch(decoded, AddressHookShape);
+ const { EUD } = /** @type {AddressHook['query']} */ (decoded.query);
+ log(`decoded EUD: ${EUD}`);
// throws if the bech32 prefix is not found
const destination = chainHub.makeChainAddress(EUD);
@@ -161,9 +159,8 @@ export const prepareAdvancerKit = (
const advanceAmount = feeTools.calculateAdvance(fullAmount);
const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit();
- const amountKWR = harden({ USDC: advanceAmount });
// throws if the pool has insufficient funds
- borrowerFacet.borrow(tmpSeat, amountKWR);
+ borrowerFacet.borrow(tmpSeat, advanceAmount);
// this cannot throw since `.isSeen()` is called in the same turn
statusManager.advance(evidence);
@@ -172,7 +169,7 @@ export const prepareAdvancerKit = (
tmpSeat,
// @ts-expect-error LocalAccountMethods vs OrchestrationAccount
poolAccount,
- amountKWR,
+ harden({ USDC: advanceAmount }),
);
void watch(depositV, this.facets.depositHandler, {
fullAmount,
@@ -182,8 +179,8 @@ export const prepareAdvancerKit = (
tmpSeat,
txHash: evidence.txHash,
});
- } catch (e) {
- log('Advancer error:', q(e).toString());
+ } catch (error) {
+ log('Advancer error:', error);
statusManager.observe(evidence);
}
},
@@ -212,18 +209,28 @@ export const prepareAdvancerKit = (
});
},
/**
+ * We do not expect this to be a common failure. it should only occur
+ * if USDC is not registered in vbank or the tmpSeat has less than
+ * `advanceAmount`.
+ *
+ * If we do hit this path, we return funds to the Liquidity Pool and
+ * notify of Advancing failure.
+ *
* @param {Error} error
* @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx
*/
- onRejected(error, { tmpSeat }) {
- // TODO return seat allocation from ctx to LP?
- log('🚨 advance deposit failed', q(error).toString());
- // TODO #10510 (comprehensive error testing) determine
- // course of action here
+ onRejected(error, { tmpSeat, advanceAmount, ...restCtx }) {
log(
- 'TODO live payment on seat to return to LP',
- q(tmpSeat).toString(),
+ '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP',
+ error,
);
+ try {
+ const { borrowerFacet, notifyFacet } = this.state;
+ notifyFacet.notifyAdvancingResult(restCtx, false);
+ borrowerFacet.returnToPool(tmpSeat, advanceAmount);
+ } catch (e) {
+ log('🚨 deposit to localOrchAccount failure recovery failed', e);
+ }
},
},
transferHandler: {
@@ -234,10 +241,11 @@ export const prepareAdvancerKit = (
onFulfilled(result, ctx) {
const { notifyFacet } = this.state;
const { advanceAmount, destination, ...detail } = ctx;
- log(
- 'Advance transfer fulfilled',
- q({ advanceAmount, destination, result }).toString(),
- );
+ log('Advance transfer fulfilled', {
+ advanceAmount,
+ destination,
+ result,
+ });
// During development, due to a bug, this call threw.
// The failure was silent (no diagnostics) due to:
// - #10576 Vows do not report unhandled rejections
@@ -252,7 +260,7 @@ export const prepareAdvancerKit = (
*/
onRejected(error, ctx) {
const { notifyFacet } = this.state;
- log('Advance transfer rejected', q(error).toString());
+ log('Advance transfer rejected', error);
notifyFacet.notifyAdvancingResult(ctx, false);
},
},
diff --git a/packages/fast-usdc/src/exos/liquidity-pool.js b/packages/fast-usdc/src/exos/liquidity-pool.js
index d8b2991a4df..5df4c86bbf2 100644
--- a/packages/fast-usdc/src/exos/liquidity-pool.js
+++ b/packages/fast-usdc/src/exos/liquidity-pool.js
@@ -28,7 +28,7 @@ import {
* @import {PoolStats} from '../types.js';
*/
-const { add, isEqual, makeEmpty } = AmountMath;
+const { add, isEqual, isGTE, makeEmpty } = AmountMath;
/** @param {Brand} brand */
const makeDust = brand => AmountMath.make(brand, 1n);
@@ -84,10 +84,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
'Liquidity Pool',
{
borrower: M.interface('borrower', {
- borrow: M.call(
- SeatShape,
- harden({ USDC: makeNatAmountShape(USDC, 1n) }),
- ).returns(),
+ borrow: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
+ returnToPool: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(),
}),
repayer: M.interface('repayer', {
repay: M.call(
@@ -153,32 +151,48 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
borrower: {
/**
* @param {ZCFSeat} toSeat
- * @param {{ USDC: Amount<'nat'>}} amountKWR
+ * @param {Amount<'nat'>} amount
*/
- borrow(toSeat, amountKWR) {
+ borrow(toSeat, amount) {
const { encumberedBalance, poolSeat, poolStats } = this.state;
// Validate amount is available in pool
const post = borrowCalc(
- amountKWR.USDC,
+ amount,
poolSeat.getAmountAllocated('USDC', USDC),
encumberedBalance,
poolStats,
);
// COMMIT POINT
- try {
- zcf.atomicRearrange(harden([[poolSeat, toSeat, amountKWR]]));
- } catch (cause) {
- const reason = Error('🚨 cannot commit borrow', { cause });
- console.error(reason.message, cause);
- zcf.shutdownWithFailure(reason);
- }
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
+ zcf.atomicRearrange(harden([[poolSeat, toSeat, { USDC: amount }]]));
Object.assign(this.state, post);
this.facets.external.publishPoolMetrics();
},
- // TODO method to repay failed `LOA.deposit()`
+ /**
+ * If something fails during advance, return funds to the pool.
+ *
+ * @param {ZCFSeat} borrowSeat
+ * @param {Amount<'nat'>} amount
+ */
+ returnToPool(borrowSeat, amount) {
+ const { zcfSeat: repaySeat } = zcf.makeEmptySeatKit();
+ const returnAmounts = harden({
+ Principal: amount,
+ PoolFee: makeEmpty(USDC),
+ ContractFee: makeEmpty(USDC),
+ });
+ const borrowSeatAllocation = borrowSeat.getCurrentAllocation();
+ isGTE(borrowSeatAllocation.USDC, amount) ||
+ Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amount)}`;
+ // arrange payments in a format repay is expecting
+ zcf.atomicRearrange(
+ harden([[borrowSeat, repaySeat, { USDC: amount }, returnAmounts]]),
+ );
+ return this.facets.repayer.repay(repaySeat, returnAmounts);
+ },
},
repayer: {
/**
@@ -208,23 +222,18 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
const { ContractFee, ...rest } = amounts;
// COMMIT POINT
- try {
- zcf.atomicRearrange(
- harden([
- [
- fromSeat,
- poolSeat,
- rest,
- { USDC: add(amounts.PoolFee, amounts.Principal) },
- ],
- [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }],
- ]),
- );
- } catch (cause) {
- const reason = Error('🚨 cannot commit repay', { cause });
- console.error(reason.message, cause);
- zcf.shutdownWithFailure(reason);
- }
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
+ zcf.atomicRearrange(
+ harden([
+ [
+ fromSeat,
+ poolSeat,
+ rest,
+ { USDC: add(amounts.PoolFee, amounts.Principal) },
+ ],
+ [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }],
+ ]),
+ );
Object.assign(this.state, post);
this.facets.external.publishPoolMetrics();
@@ -259,9 +268,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
const post = depositCalc(shareWorth, proposal);
// COMMIT POINT
-
+ const mint = shareMint.mintGains(post.payouts);
try {
- const mint = shareMint.mintGains(post.payouts);
this.state.shareWorth = post.shareWorth;
zcf.atomicRearrange(
harden([
@@ -271,12 +279,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
[mint, lp, post.payouts],
]),
);
+ } catch (cause) {
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
+ throw new Error('🚨 cannot commit deposit', { cause });
+ } finally {
lp.exit();
mint.exit();
- } catch (cause) {
- const reason = Error('🚨 cannot commit deposit', { cause });
- console.error(reason.message, cause);
- zcf.shutdownWithFailure(reason);
}
external.publishPoolMetrics();
},
@@ -296,7 +304,6 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
const post = withdrawCalc(shareWorth, proposal);
// COMMIT POINT
-
try {
this.state.shareWorth = post.shareWorth;
zcf.atomicRearrange(
@@ -308,12 +315,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => {
]),
);
shareMint.burnLosses(proposal.give, burn);
+ } catch (cause) {
+ // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract
+ throw new Error('🚨 cannot commit withdraw', { cause });
+ } finally {
lp.exit();
burn.exit();
- } catch (cause) {
- const reason = Error('🚨 cannot commit withdraw', { cause });
- console.error(reason.message, cause);
- zcf.shutdownWithFailure(reason);
}
external.publishPoolMetrics();
},
diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js
index 5d092dd87cb..931961c01b7 100644
--- a/packages/fast-usdc/src/exos/settler.js
+++ b/packages/fast-usdc/src/exos/settler.js
@@ -5,8 +5,8 @@ import { atob } from '@endo/base64';
import { E } from '@endo/far';
import { M } from '@endo/patterns';
+import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import { PendingTxStatus } from '../constants.js';
-import { addressTools } from '../utils/address.js';
import { makeFeeTools } from '../utils/fees.js';
import { EvmHashShape } from '../type-guards.js';
@@ -151,14 +151,19 @@ export const prepareSettler = (
return;
}
- if (!addressTools.hasQueryParams(tx.receiver)) {
- console.log('not query params', tx.receiver);
- return;
- }
-
- const { EUD } = addressTools.getQueryParams(tx.receiver);
- if (!EUD) {
- console.log('no EUD parameter', tx.receiver);
+ let EUD;
+ try {
+ ({ EUD } = decodeAddressHook(tx.receiver).query);
+ if (!EUD) {
+ log('no EUD parameter', tx.receiver);
+ return;
+ }
+ if (typeof EUD !== 'string') {
+ log('EUD is not a string', EUD);
+ return;
+ }
+ } catch (e) {
+ log('no query params', tx.receiver);
return;
}
@@ -237,13 +242,13 @@ export const prepareSettler = (
const split = calculateSplit(received);
log('disbursing', split);
- // TODO: what if this throws?
- // arguably, it cannot. Even if deposits
- // and notifications get out of order,
- // we don't ever withdraw more than has been deposited.
+ // If this throws, which arguably can't occur since we don't ever
+ // withdraw more than has been deposited (as denoted by
+ // `FungibleTokenPacketData`), funds will remain in the
+ // `settlementAccount`. A remediation can occur in a future upgrade.
await vowTools.when(
withdrawToSeat(
- // @ts-expect-error Vow vs. Promise stuff. TODO: is this OK???
+ // @ts-expect-error LocalAccountMethods vs OrchestrationAccount
settlementAccount,
settlingSeat,
harden({ In: received }),
diff --git a/packages/fast-usdc/src/type-guards.js b/packages/fast-usdc/src/type-guards.js
index a645f90bae4..5281521ef12 100644
--- a/packages/fast-usdc/src/type-guards.js
+++ b/packages/fast-usdc/src/type-guards.js
@@ -6,7 +6,7 @@ import { PendingTxStatus } from './constants.js';
* @import {TypedPattern} from '@agoric/internal';
* @import {FastUsdcTerms} from './fast-usdc.contract.js';
* @import {USDCProposalShapes} from './pool-share-math.js';
- * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy} from './types.js';
+ * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook} from './types.js';
*/
/**
@@ -67,10 +67,12 @@ export const PendingTxShape = {
};
harden(PendingTxShape);
-export const EudParamShape = {
- EUD: M.string(),
+/** @type {TypedPattern} */
+export const AddressHookShape = {
+ baseAddress: M.string(),
+ query: { EUD: M.string() },
};
-harden(EudParamShape);
+harden(AddressHookShape);
const NatAmountShape = { brand: BrandShape, value: M.nat() };
/** @type {TypedPattern} */
@@ -94,16 +96,13 @@ export const PoolMetricsShape = {
harden(PoolMetricsShape);
/** @type {TypedPattern} */
-export const ChainPoliciesShape = M.splitRecord(
- {
- nobleContractAddress: EvmHashShape,
- cctpTokenMessengerAddress: EvmHashShape,
- confirmations: M.number(),
- chainId: M.number(),
- },
- { chainType: M.number() },
-);
-harden(ChainPoliciesShape);
+export const ChainPolicyShape = {
+ attenuatedCttpBridgeAddress: EvmHashShape,
+ cctpTokenMessengerAddress: EvmHashShape,
+ confirmations: M.number(),
+ chainId: M.number(),
+};
+harden(ChainPolicyShape);
/**
* @type {TypedPattern}
@@ -115,7 +114,7 @@ export const FeedPolicyShape = M.splitRecord(
{
nobleDomainId: M.number(),
nobleAgoricChannelId: M.string(),
- chainPolicies: M.recordOf(M.string(), ChainPoliciesShape),
+ chainPolicies: M.recordOf(M.string(), ChainPolicyShape),
},
{ eventFilter: M.string() },
);
diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts
index ee9a90efffd..30dd64acbbc 100644
--- a/packages/fast-usdc/src/types.ts
+++ b/packages/fast-usdc/src/types.ts
@@ -58,11 +58,14 @@ export interface PoolMetrics extends PoolStats {
}
export interface ChainPolicy {
- nobleContractAddress: EvmHash;
+ /** `msg.sender` of DepositAndBurn to TokenMessenger must be an attenuated wrapper contract that does not contain `replaceDepositForBurn` */
+ attenuatedCttpBridgeAddress: EvmHash;
+ /** @see {@link https://developers.circle.com/stablecoins/evm-smart-contracts} */
cctpTokenMessengerAddress: EvmHash;
- confirmations: number;
+ /** e.g., `1` for ETH mainnet 42161 for Arbitrum One. @see {@link https://chainlist.org/} */
chainId: EvmChainID;
- chainType?: number;
+ /** the number of block confirmations to observe before reporting */
+ confirmations: number;
}
export interface FeedPolicy {
@@ -82,5 +85,14 @@ export type FastUSDCConfig = {
assetInfo: [Denom, DenomDetail & { brandKey?: string }][];
} & CopyRecord;
+/** decoded address hook parameters */
+export type AddressHook = {
+ baseAddress: string;
+ query: {
+ /** end user destination address */
+ EUD: string;
+ };
+};
+
export type * from './constants.js';
export type { LiquidityPoolKit } from './exos/liquidity-pool.js';
diff --git a/packages/fast-usdc/src/utils/address.js b/packages/fast-usdc/src/utils/address.js
deleted file mode 100644
index a84e8f0c5c9..00000000000
--- a/packages/fast-usdc/src/utils/address.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { makeError, q } from '@endo/errors';
-import { M, mustMatch } from '@endo/patterns';
-
-/**
- * @import {Pattern} from '@endo/patterns';
- */
-
-/**
- * Default pattern matcher for `getQueryParams`.
- * Does not assert keys exist, but ensures existing keys are strings.
- */
-const QueryParamsShape = M.splitRecord(
- {},
- {},
- M.recordOf(M.string(), M.string()),
-);
-
-/**
- * Very minimal 'URL query string'-like parser that handles:
- * - Query string delimiter (?)
- * - Key-value separator (=)
- * - Query parameter separator (&)
- *
- * Does not handle:
- * - Subpaths (`agoric1bech32addr/opt/account?k=v`)
- * - URI encoding/decoding (`%20` -> ` `)
- * - note: `decodeURIComponent` seems to be available in XS
- * - Multiple question marks (foo?bar=1?baz=2)
- * - Empty parameters (foo=)
- * - Array parameters (`foo?k=v1&k=v2` -> k: [v1, v2])
- * - Parameters without values (foo&bar=2)
- */
-export const addressTools = {
- /**
- * @param {string} address
- * @returns {boolean}
- */
- hasQueryParams: address => {
- try {
- const params = addressTools.getQueryParams(address);
- return Object.keys(params).length > 0;
- } catch {
- return false;
- }
- },
- /**
- * @param {string} address
- * @param {Pattern} [shape]
- * @returns {Record}
- * @throws {Error} if the address cannot be parsed or params do not match `shape`
- */
- getQueryParams: (address, shape = QueryParamsShape) => {
- const parts = address.split('?');
- if (parts.length !== 2) {
- throw makeError(`Unable to parse query params: ${q(address)}`);
- }
- /** @type {Record} */
- const result = {};
- const paramPairs = parts[1].split('&');
- for (const pair of paramPairs) {
- const [key, value] = pair.split('=');
- if (!key || !value) {
- throw makeError(`Invalid parameter format in pair: ${q(pair)}`);
- }
- result[key] = value;
- }
- harden(result);
- mustMatch(result, shape);
- return result;
- },
-};
diff --git a/packages/fast-usdc/src/utils/deploy-config.js b/packages/fast-usdc/src/utils/deploy-config.js
index 653d95ff293..7b160a7996c 100644
--- a/packages/fast-usdc/src/utils/deploy-config.js
+++ b/packages/fast-usdc/src/utils/deploy-config.js
@@ -64,11 +64,12 @@ export const configurations = {
nobleDomainId: 4,
chainPolicies: {
Arbitrum: {
+ attenuatedCttpBridgeAddress:
+ '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
cctpTokenMessengerAddress:
'0x19330d10D9Cc8751218eaf51E8885D058642E08A',
chainId: 42161,
confirmations: 2,
- nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A',
},
},
},
@@ -92,11 +93,12 @@ export const configurations = {
nobleDomainId: 4,
chainPolicies: {
Arbitrum: {
+ attenuatedCttpBridgeAddress:
+ '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347',
cctpTokenMessengerAddress:
'0x19330d10D9Cc8751218eaf51E8885D058642E08A',
chainId: 42161,
confirmations: 2,
- nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A',
},
},
},
@@ -118,10 +120,10 @@ export const configurations = {
nobleDomainId: 4,
chainPolicies: {
Arbitrum: {
+ attenuatedCttpBridgeAddress: '0xTODO',
cctpTokenMessengerAddress: '0xTODO',
chainId: 421614,
confirmations: 2,
- nobleContractAddress: '0xTODO',
},
},
},
@@ -140,10 +142,10 @@ export const configurations = {
nobleDomainId: 4,
chainPolicies: {
Arbitrum: {
+ attenuatedCttpBridgeAddress: '0xTODO',
cctpTokenMessengerAddress: '0xTODO',
chainId: 421614,
confirmations: 2,
- nobleContractAddress: '0xTODO',
},
},
},
diff --git a/packages/fast-usdc/test/cli/lp-commands.test.ts b/packages/fast-usdc/test/cli/lp-commands.test.ts
index 367dc9a78f6..0ca642aa704 100644
--- a/packages/fast-usdc/test/cli/lp-commands.test.ts
+++ b/packages/fast-usdc/test/cli/lp-commands.test.ts
@@ -32,7 +32,7 @@ const makeTestContext = () => {
const now = () => 1234;
addLPCommands(program, {
- vstorageKit: {
+ smartWalletKit: {
// @ts-expect-error fake brands
agoricNames: { brand: { FastLP, USDC } },
marshaller,
diff --git a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md
index d88e5f3f969..156d050eba9 100644
--- a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md
+++ b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md
@@ -15,7 +15,7 @@ Generated by [AVA](https://avajs.dev).
typeUrl: '/noble.forwarding.v1.MsgRegisterAccount',
value: {
channel: 'channel-test-7',
- recipient: 'agoric123456?EUD=dydx1234',
+ recipient: 'agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423pav3ukg7p3xgengqpq4066gy',
signer: 'noble09876',
},
},
diff --git a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap
index 4bce5856ec4..816eae48527 100644
Binary files a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap and b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap differ
diff --git a/packages/fast-usdc/test/cli/transfer.test.ts b/packages/fast-usdc/test/cli/transfer.test.ts
index 729f40f63cc..28cd3d41569 100644
--- a/packages/fast-usdc/test/cli/transfer.test.ts
+++ b/packages/fast-usdc/test/cli/transfer.test.ts
@@ -1,4 +1,5 @@
import test from 'ava';
+import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import transfer from '../../src/cli/transfer.js';
import {
mockOut,
@@ -63,14 +64,18 @@ test('Transfer registers the noble forwarding account if it does not exist', asy
};
const out = mockOut();
const file = mockFile(path, JSON.stringify(config));
- const agoricSettlementAccount = 'agoric123456';
+ const agoricSettlementAccount =
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek';
const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount';
const vstorageMock = makeVstorageMock({
[settlementAccountVstoragePath]: agoricSettlementAccount,
});
const amount = '150';
- const destination = 'dydx1234';
- const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${agoricSettlementAccount}${encodeURIComponent('?EUD=')}${destination}/`;
+ const EUD = 'dydx1234';
+ const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${encodeAddressHook(
+ agoricSettlementAccount,
+ { EUD },
+ )}/`;
const fetchMock = makeFetchMock({
[nobleFwdAccountQuery]: {
address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h',
@@ -84,7 +89,7 @@ test('Transfer registers the noble forwarding account if it does not exist', asy
await transfer.transfer(
file,
amount,
- destination,
+ EUD,
// @ts-expect-error mocking console
out,
fetchMock.fetch,
@@ -114,14 +119,18 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy
};
const out = mockOut();
const file = mockFile(path, JSON.stringify(config));
- const agoricSettlementAccount = 'agoric123456';
+ const agoricSettlementAccount =
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek';
const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount';
const vstorageMock = makeVstorageMock({
[settlementAccountVstoragePath]: agoricSettlementAccount,
});
const amount = '150';
- const destination = 'dydx1234';
- const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${agoricSettlementAccount}${encodeURIComponent('?EUD=')}${destination}/`;
+ const EUD = 'dydx1234';
+ const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${encodeAddressHook(
+ agoricSettlementAccount,
+ { EUD },
+ )}/`;
const fetchMock = makeFetchMock({
[nobleFwdAccountQuery]: {
address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h',
@@ -135,7 +144,7 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy
await transfer.transfer(
file,
amount,
- destination,
+ EUD,
// @ts-expect-error mocking console
out,
fetchMock.fetch,
diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts
index 908880d3fb4..b91e52485a9 100644
--- a/packages/fast-usdc/test/exos/advancer.test.ts
+++ b/packages/fast-usdc/test/exos/advancer.test.ts
@@ -7,12 +7,15 @@ import { Far } from '@endo/pass-style';
import type { NatAmount } from '@agoric/ertp';
import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js';
import { q } from '@endo/errors';
+import {
+ decodeAddressHook,
+ encodeAddressHook,
+} from '@agoric/cosmic-proto/address-hooks.js';
import { PendingTxStatus } from '../../src/constants.js';
import { prepareAdvancer } from '../../src/exos/advancer.js';
import type { SettlerKit } from '../../src/exos/settler.js';
import { prepareStatusManager } from '../../src/exos/status-manager.js';
import { makeFeeTools } from '../../src/utils/fees.js';
-import { addressTools } from '../../src/utils/address.js';
import { commonSetup } from '../supports.js';
import { MockCctpTxEvidences, intermediateRecipient } from '../fixtures.js';
import {
@@ -20,6 +23,7 @@ import {
makeTestLogger,
prepareMockOrchAccounts,
} from '../mocks.js';
+import type { LiquidityPoolKit } from '../../src/types.js';
const LOCAL_DENOM = `ibc/${denomHash({
denom: 'uusdc',
@@ -62,6 +66,11 @@ const createTestExtensions = (t, common: CommonSetup) => {
// pretend funds move from tmpSeat to poolAccount
localTransferVK.resolver.resolve();
};
+ const rejectLocalTransfeferV = () => {
+ localTransferVK.resolver.reject(
+ new Error('One or more deposits failed: simulated error'),
+ );
+ };
const mockZoeTools = Far('MockZoeTools', {
localTransfer(...args: Parameters) {
console.log('ZoeTools.localTransfer called with', args);
@@ -94,18 +103,17 @@ const createTestExtensions = (t, common: CommonSetup) => {
},
});
+ const mockBorrowerFacetCalls: {
+ borrow: Parameters[];
+ returnToPool: Parameters[];
+ } = { borrow: [], returnToPool: [] };
+
const mockBorrowerF = Far('LiquidityPool Borrow Facet', {
- borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => {
- console.log('LP.borrow called with', amounts);
+ borrow: (seat: ZCFSeat, amount: NatAmount) => {
+ mockBorrowerFacetCalls.borrow.push([seat, amount]);
},
- });
-
- const mockBorrowerErrorF = Far('LiquidityPool Borrow Facet', {
- borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => {
- console.log('LP.borrow called with', amounts);
- throw new Error(
- `Cannot borrow. Requested ${q(amounts.USDC)} must be less than pool balance ${q(usdc.make(1n))}.`,
- );
+ returnToPool: (seat: ZCFSeat, amount: NatAmount) => {
+ mockBorrowerFacetCalls.returnToPool.push([seat, amount]);
},
});
@@ -124,12 +132,13 @@ const createTestExtensions = (t, common: CommonSetup) => {
helpers: {
inspectLogs,
inspectNotifyCalls: () => harden(notifyAdvancingResultCalls),
+ inspectBorrowerFacetCalls: () => harden(mockBorrowerFacetCalls),
},
mocks: {
...mockAccounts,
- mockBorrowerErrorF,
mockNotifyF,
resolveLocalTransferV,
+ rejectLocalTransfeferV,
},
services: {
advancer,
@@ -181,9 +190,23 @@ test('updates status to ADVANCING in happy path', async t => {
'ADVANCED status in happy path',
);
- t.deepEqual(inspectLogs(0), [
- 'Advance transfer fulfilled',
- '{"advanceAmount":{"brand":"[Alleged: USDC brand]","value":"[146999999n]"},"destination":{"chainId":"osmosis-1","encoding":"bech32","value":"osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"},"result":"[undefined]"}',
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ [
+ 'Advance transfer fulfilled',
+ {
+ advanceAmount: {
+ brand: usdc.brand,
+ value: 146999999n,
+ },
+ destination: {
+ chainId: 'osmosis-1',
+ encoding: 'bech32',
+ value: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
+ },
+ result: undefined,
+ },
+ ],
]);
// We expect to see an `Advanced` update, but that is now Settler's job.
@@ -195,8 +218,7 @@ test('updates status to ADVANCING in happy path', async t => {
forwardingAddress: mockEvidence.tx.forwardingAddress,
fullAmount: usdc.make(mockEvidence.tx.amount),
destination: {
- value: addressTools.getQueryParams(mockEvidence.aux.recipientAddress)
- .EUD,
+ value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD,
},
},
true, // indicates transfer succeeded
@@ -206,17 +228,27 @@ test('updates status to ADVANCING in happy path', async t => {
test('updates status to OBSERVED on insufficient pool funds', async t => {
const {
+ brands: { usdc },
bootstrap: { storage },
extensions: {
services: { makeAdvancer, statusManager },
helpers: { inspectLogs },
- mocks: { mockPoolAccount, mockBorrowerErrorF, mockNotifyF },
+ mocks: { mockPoolAccount, mockNotifyF },
},
} = t.context;
+ const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', {
+ borrow: (seat: ZCFSeat, amount: NatAmount) => {
+ throw new Error(
+ `Cannot borrow. Requested ${q(amount)} must be less than pool balance ${q(usdc.make(1n))}.`,
+ );
+ },
+ returnToPool: () => {}, // not expecting this to be called
+ });
+
// make a new advancer that intentionally throws
const advancer = makeAdvancer({
- borrowerFacet: mockBorrowerErrorF,
+ borrowerFacet: mockBorrowerFacet,
notifyFacet: mockNotifyF,
poolAccount: mockPoolAccount.account,
intermediateRecipient,
@@ -232,9 +264,14 @@ test('updates status to OBSERVED on insufficient pool funds', async t => {
'OBSERVED status on insufficient pool funds',
);
- t.deepEqual(inspectLogs(0), [
- 'Advancer error:',
- '"[Error: Cannot borrow. Requested {\\"brand\\":\\"[Alleged: USDC brand]\\",\\"value\\":\\"[294999999n]\\"} must be less than pool balance {\\"brand\\":\\"[Alleged: USDC brand]\\",\\"value\\":\\"[1n]\\"}.]"',
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ [
+ 'Advancer error:',
+ Error(
+ `Cannot borrow. Requested ${q(usdc.make(294999999n))} must be less than pool balance ${q(usdc.make(1n))}.`,
+ ),
+ ],
]);
});
@@ -256,9 +293,12 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => {
'OBSERVED status on makeChainAddress failure',
);
- t.deepEqual(inspectLogs(0), [
- 'Advancer error:',
- '"[Error: Chain info not found for bech32Prefix \\"random\\"]"',
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: random1addr'],
+ [
+ 'Advancer error:',
+ Error('Chain info not found for bech32Prefix "random"'),
+ ],
]);
});
@@ -289,9 +329,9 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t
mockPoolAccount.transferVResolver.reject(new Error('simulated error'));
await eventLoopIteration();
- t.deepEqual(inspectLogs(0), [
- 'Advance transfer rejected',
- '"[Error: simulated error]"',
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ ['Advance transfer rejected', Error('simulated error')],
]);
// We expect to see an `AdvancedFailed` update, but that is now Settler's job.
@@ -306,8 +346,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t
usdc.make(mockEvidence.tx.amount),
),
destination: {
- value: addressTools.getQueryParams(mockEvidence.aux.recipientAddress)
- .EUD,
+ value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD,
},
},
false, // this indicates transfer failed
@@ -334,9 +373,32 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => {
'tx is recorded as OBSERVED',
);
- t.deepEqual(inspectLogs(0), [
- 'Advancer error:',
- '"[Error: Unable to parse query params: \\"agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek\\"]"',
+ t.deepEqual(inspectLogs(), [
+ [
+ 'Advancer error:',
+ Error('query: {} - Must have missing properties ["EUD"]'),
+ ],
+ ]);
+
+ await advancer.handleTransactionEvent({
+ ...MockCctpTxEvidences.AGORIC_NO_PARAMS(
+ encodeAddressHook(
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
+ { EUD: 'osmo1234', extra: 'value' },
+ ),
+ ),
+ txHash:
+ '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799',
+ });
+
+ const [, ...remainingLogs] = inspectLogs();
+ t.deepEqual(remainingLogs, [
+ [
+ 'Advancer error:',
+ Error(
+ 'query: {"EUD":"osmo1234","extra":"value"} - Must not have unexpected properties: ["extra"]',
+ ),
+ ],
]);
});
@@ -347,6 +409,7 @@ test('will not advance same txHash:chainId evidence twice', async t => {
helpers: { inspectLogs },
mocks: { mockPoolAccount, resolveLocalTransferV },
},
+ brands: { usdc },
} = t.context;
const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO();
@@ -357,20 +420,160 @@ test('will not advance same txHash:chainId evidence twice', async t => {
mockPoolAccount.transferVResolver.resolve();
await eventLoopIteration();
- t.deepEqual(inspectLogs(0), [
- 'Advance transfer fulfilled',
- '{"advanceAmount":{"brand":"[Alleged: USDC brand]","value":"[146999999n]"},"destination":{"chainId":"osmosis-1","encoding":"bech32","value":"osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"},"result":"[undefined]"}',
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ [
+ 'Advance transfer fulfilled',
+ {
+ advanceAmount: { brand: usdc.brand, value: 146999999n },
+ destination: {
+ chainId: 'osmosis-1',
+ encoding: 'bech32',
+ value: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
+ },
+ result: undefined,
+ },
+ ],
]);
// Second attempt
void advancer.handleTransactionEvent(mockEvidence);
await eventLoopIteration();
- t.deepEqual(inspectLogs(1), [
- 'txHash already seen:',
- '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702',
+ const [, , ...remainingLogs] = inspectLogs();
+ t.deepEqual(remainingLogs, [
+ [
+ 'txHash already seen:',
+ '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702',
+ ],
]);
});
-test.todo(
- '#10510 zoeTools.localTransfer fails to deposit borrowed USDC to LOA',
-);
+test('returns payment to LP if zoeTools.localTransfer fails', async t => {
+ const {
+ extensions: {
+ services: { advancer },
+ helpers: { inspectLogs, inspectBorrowerFacetCalls, inspectNotifyCalls },
+ mocks: { rejectLocalTransfeferV },
+ },
+ brands: { usdc },
+ } = t.context;
+ const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO();
+
+ void advancer.handleTransactionEvent(mockEvidence);
+ rejectLocalTransfeferV();
+
+ await eventLoopIteration();
+
+ t.deepEqual(
+ inspectLogs(),
+ [
+ ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ [
+ '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP',
+ Error('One or more deposits failed: simulated error'),
+ ],
+ ],
+ 'contract logs report error',
+ );
+
+ const { borrow, returnToPool } = inspectBorrowerFacetCalls();
+
+ const expectedArguments = [
+ Far('MockZCFSeat', {}),
+ usdc.make(146999999n), // net of fees
+ ];
+
+ t.is(borrow.length, 1, 'borrow is called before zt.localTransfer fails');
+ t.deepEqual(borrow[0], expectedArguments, 'borrow arguments match expected');
+
+ t.is(
+ returnToPool.length,
+ 1,
+ 'returnToPool is called after zt.localTransfer fails',
+ );
+ t.deepEqual(
+ returnToPool[0],
+ expectedArguments,
+ 'same amount borrowed is returned to LP',
+ );
+
+ t.like(
+ inspectNotifyCalls(),
+ [
+ [
+ {
+ txHash: mockEvidence.txHash,
+ forwardingAddress: mockEvidence.tx.forwardingAddress,
+ },
+ false, // indicates advance failed
+ ],
+ ],
+ 'Advancing tx is recorded as AdvanceFailed',
+ );
+});
+
+test('alerts if `returnToPool` fallback fails', async t => {
+ const {
+ brands: { usdc },
+ extensions: {
+ services: { makeAdvancer },
+ helpers: { inspectLogs, inspectNotifyCalls },
+ mocks: { mockPoolAccount, mockNotifyF, rejectLocalTransfeferV },
+ },
+ } = t.context;
+
+ const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', {
+ borrow: (seat: ZCFSeat, amount: NatAmount) => {
+ // note: will not be tracked by `inspectBorrowerFacetCalls`
+ },
+ returnToPool: (seat: ZCFSeat, amount: NatAmount) => {
+ throw new Error(
+ `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(amount)}`,
+ );
+ },
+ });
+
+ // make a new advancer that intentionally throws during returnToPool
+ const advancer = makeAdvancer({
+ borrowerFacet: mockBorrowerFacet,
+ notifyFacet: mockNotifyF,
+ poolAccount: mockPoolAccount.account,
+ intermediateRecipient,
+ });
+
+ const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO();
+ void advancer.handleTransactionEvent(mockEvidence);
+ rejectLocalTransfeferV();
+
+ await eventLoopIteration();
+
+ t.deepEqual(inspectLogs(), [
+ ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'],
+ [
+ '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP',
+ Error('One or more deposits failed: simulated error'),
+ ],
+ [
+ '🚨 deposit to localOrchAccount failure recovery failed',
+ Error(
+ `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(usdc.make(146999999n))}`,
+ ),
+ ],
+ ]);
+
+ await eventLoopIteration();
+
+ t.like(
+ inspectNotifyCalls(),
+ [
+ [
+ {
+ txHash: mockEvidence.txHash,
+ forwardingAddress: mockEvidence.tx.forwardingAddress,
+ },
+ false, // indicates advance failed
+ ],
+ ],
+ 'Advancing tx is recorded as AdvanceFailed',
+ );
+});
diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts
index 872bffc2c0a..f7869f3def1 100644
--- a/packages/fast-usdc/test/fast-usdc.contract.test.ts
+++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts
@@ -27,11 +27,14 @@ import { E } from '@endo/far';
import { matches, objectMap } from '@endo/patterns';
import { makePromiseKit } from '@endo/promise-kit';
import path from 'path';
+import {
+ decodeAddressHook,
+ encodeAddressHook,
+} from '@agoric/cosmic-proto/address-hooks.js';
import type { OperatorKit } from '../src/exos/operator-kit.js';
import type { FastUsdcSF } from '../src/fast-usdc.contract.js';
import { PoolMetricsShape } from '../src/type-guards.js';
import type { CctpTxEvidence, FeeConfig, PoolMetrics } from '../src/types.js';
-import { addressTools } from '../src/utils/address.js';
import { makeFeeTools } from '../src/utils/fees.js';
import { MockCctpTxEvidences } from './fixtures.js';
import { commonSetup, uusdcOnAgoric } from './supports.js';
@@ -382,7 +385,7 @@ const makeCustomer = (
return enough;
},
sendFast: async (t: ExecutionContext, amount: bigint, EUD: string) => {
- const recipientAddress = `${settleAddr}?EUD=${EUD}`;
+ const recipientAddress = encodeAddressHook(settleAddr, { EUD });
// KLUDGE: UI would ask noble for a forwardingAddress
// "cctp" here has some noble stuff mixed in.
const tx = cctp.makeTx(amount, recipientAddress);
@@ -411,9 +414,7 @@ const makeCustomer = (
t.deepEqual(bank, []); // no vbank GIVE / GRAB
}
- const { EUD } = addressTools.getQueryParams(
- evidence.aux.recipientAddress,
- );
+ const { EUD } = decodeAddressHook(evidence.aux.recipientAddress).query;
const myMsg = local.find(lm => {
if (lm.type !== 'VLOCALCHAIN_EXECUTE_TX') return false;
@@ -442,7 +443,7 @@ const makeCustomer = (
'C4',
);
t.log(who, 'sees', ibcTransferMsg.token, 'sent to', EUD);
- if (!EUD.startsWith('noble')) {
+ if (!(EUD as string).startsWith('noble')) {
t.like(
JSON.parse(ibcTransferMsg.memo),
{
diff --git a/packages/fast-usdc/test/fixtures.ts b/packages/fast-usdc/test/fixtures.ts
index cbd83ccb657..7ffcedafb73 100644
--- a/packages/fast-usdc/test/fixtures.ts
+++ b/packages/fast-usdc/test/fixtures.ts
@@ -1,7 +1,8 @@
-import type { VTransferIBCEvent } from '@agoric/vats';
+import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js';
import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js';
import type { ChainAddress } from '@agoric/orchestration';
+import type { VTransferIBCEvent } from '@agoric/vats';
import type { CctpTxEvidence } from '../src/types.js';
const mockScenarios = [
@@ -31,7 +32,10 @@ export const MockCctpTxEvidences: Record<
forwardingChannel: 'channel-21',
recipientAddress:
receiverAddress ||
- 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
+ encodeAddressHook(
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
+ { EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' },
+ ),
},
chainId: 1,
}),
@@ -49,7 +53,10 @@ export const MockCctpTxEvidences: Record<
forwardingChannel: 'channel-21',
recipientAddress:
receiverAddress ||
- 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
+ encodeAddressHook(
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
+ { EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' },
+ ),
},
chainId: 1,
}),
@@ -85,7 +92,10 @@ export const MockCctpTxEvidences: Record<
forwardingChannel: 'channel-21',
recipientAddress:
receiverAddress ||
- 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=random1addr',
+ encodeAddressHook(
+ 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
+ { EUD: 'random1addr' },
+ ),
},
chainId: 1,
}),
diff --git a/packages/fast-usdc/test/utils/address.test.ts b/packages/fast-usdc/test/utils/address.test.ts
deleted file mode 100644
index d1c6ea23a3f..00000000000
--- a/packages/fast-usdc/test/utils/address.test.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js';
-import { M } from '@endo/patterns';
-
-import { addressTools } from '../../src/utils/address.js';
-import { EudParamShape } from '../../src/type-guards.js';
-
-const FIXTURES = {
- AGORIC_WITH_DYDX:
- 'agoric1bech32addr?EUD=dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
- AGORIC_WITH_OSMO:
- 'agoric1bech32addr?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
- AGORIC_WITH_MULTIPLE:
- 'agoric1bech32addr?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men&CID=dydx-mainnet-1',
- AGORIC_NO_PARAMS: 'agoric1bech32addr',
- INVALID_MULTIPLE_QUESTION: 'agoric1bech32addr?param1=value1?param2=value2',
- INVALID_PARAM_FORMAT: 'agoric1bech32addr?invalidparam',
-} as const;
-
-// hasQueryParams tests
-test('hasQueryParams: returns true when address has parameters', t => {
- t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_DYDX));
- t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_OSMO));
- t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_MULTIPLE));
-});
-
-test('hasQueryParams: returns false when address has no parameters', t => {
- t.false(addressTools.hasQueryParams(FIXTURES.AGORIC_NO_PARAMS));
-});
-
-test('hasQueryParams: returns false for invalid parameter formats', t => {
- t.false(addressTools.hasQueryParams(FIXTURES.INVALID_MULTIPLE_QUESTION));
- t.false(addressTools.hasQueryParams(FIXTURES.INVALID_PARAM_FORMAT));
-});
-
-// getQueryParams tests - positive cases
-test('getQueryParams: correctly parses address with single EUD parameter', t => {
- const result = addressTools.getQueryParams(
- FIXTURES.AGORIC_WITH_DYDX,
- EudParamShape,
- );
- t.deepEqual(result, {
- EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
- });
-});
-
-test('getQueryParams: correctly parses address with multiple parameters', t => {
- const pattern = harden({ EUD: M.string(), CID: M.string() });
- const result = addressTools.getQueryParams(
- FIXTURES.AGORIC_WITH_MULTIPLE,
- pattern,
- );
- t.deepEqual(result, {
- EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
- CID: 'dydx-mainnet-1',
- });
-});
-
-test('getQueryParams: returns all parameters when no shape is provided', t => {
- const result = addressTools.getQueryParams(FIXTURES.AGORIC_WITH_MULTIPLE);
- t.deepEqual(result, {
- EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
- CID: 'dydx-mainnet-1',
- });
-});
-
-test('getQueryParams: correctly handles address with no parameters', t => {
- t.throws(() => addressTools.getQueryParams(FIXTURES.AGORIC_NO_PARAMS), {
- message: 'Unable to parse query params: "agoric1bech32addr"',
- });
-});
-
-// getQueryParams tests - negative cases
-test('getQueryParams: throws error for multiple question marks', t => {
- t.throws(
- () => addressTools.getQueryParams(FIXTURES.INVALID_MULTIPLE_QUESTION),
- {
- message:
- 'Unable to parse query params: "agoric1bech32addr?param1=value1?param2=value2"',
- },
- );
-});
-
-test('getQueryParams: throws error for invalid parameter format', t => {
- t.throws(() => addressTools.getQueryParams(FIXTURES.INVALID_PARAM_FORMAT), {
- message: 'Invalid parameter format in pair: "invalidparam"',
- });
-});
diff --git a/packages/governance/src/contractHelper.js b/packages/governance/src/contractHelper.js
index c3a0896ea1d..e47b0709f54 100644
--- a/packages/governance/src/contractHelper.js
+++ b/packages/governance/src/contractHelper.js
@@ -250,6 +250,7 @@ const facetHelpers = (zcf, paramManager) => {
* @param {M} paramTypesMap
* @param {ERef} [storageNode]
* @param {ERef} [marshaller]
+ * @param {object} [overrides]
*/
const handleParamGovernance = (
zcf,
@@ -257,6 +258,7 @@ const handleParamGovernance = (
paramTypesMap,
storageNode,
marshaller,
+ overrides,
) => {
/** @type {import('@agoric/notifier').StoredPublisherKit} */
const publisherKit = makeStoredPublisherKit(
@@ -269,6 +271,7 @@ const handleParamGovernance = (
zcf,
{ Electorate: initialPoserInvitation },
paramTypesMap,
+ overrides,
);
return facetHelpers(zcf, paramManager);
diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js
index 6814fbdcc87..76dd57a0c6b 100644
--- a/packages/inter-protocol/src/proposals/add-auction.js
+++ b/packages/inter-protocol/src/proposals/add-auction.js
@@ -1,8 +1,9 @@
import { deeplyFulfilledObject, makeTracer } from '@agoric/internal';
import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js';
-import { E } from '@endo/far';
import { Stable } from '@agoric/internal/src/tokens.js';
+import { E } from '@endo/far';
import { makeGovernedTerms as makeGovernedATerms } from '../auction/params.js';
+import { provideRetiredInstances } from './utils.js';
const trace = makeTracer('NewAuction', true);
@@ -11,6 +12,7 @@ const trace = makeTracer('NewAuction', true);
* auctionUpgradeNewInstance: Instance;
* auctionUpgradeNewGovCreator: any;
* newContractGovBundleId: string;
+ * retiredContractInstances: MapStore;
* }>} interlockPowers
*/
@@ -35,6 +37,7 @@ export const addAuction = async (
economicCommitteeCreatorFacet: electorateCreatorFacet,
governedContractKits: governedContractKitsP,
priceAuthority8400,
+ retiredContractInstances: retiredContractInstancesP,
zoe,
},
produce: {
@@ -42,6 +45,7 @@ export const addAuction = async (
auctionUpgradeNewInstance,
auctionUpgradeNewGovCreator,
newContractGovBundleId,
+ retiredContractInstances: produceRetiredInstances,
},
instance: {
consume: { reserve: reserveInstance },
@@ -79,6 +83,16 @@ export const addAuction = async (
auctioneerInstallationP,
]);
+ const retiredInstances = await provideRetiredInstances(
+ retiredContractInstancesP,
+ produceRetiredInstances,
+ );
+
+ // save the auctioneer instance so we can manage it later
+ const boardID = await E(board).getId(legacyKit.instance);
+ const identifier = `auctioneer-${boardID}`;
+ retiredInstances.init(identifier, legacyKit.instance);
+
// Each field has an extra layer of type + value:
// AuctionStartDelay: { type: 'relativeTime', value: { relValue: 2n, timerBrand: Object [Alleged: timerBrand] {} } }
/** @type {any} */
@@ -210,6 +224,7 @@ export const ADD_AUCTION_MANIFEST = harden({
economicCommitteeCreatorFacet: true,
governedContractKits: true,
priceAuthority8400: true,
+ retiredContractInstances: true,
zoe: true,
},
produce: {
@@ -217,6 +232,7 @@ export const ADD_AUCTION_MANIFEST = harden({
auctionUpgradeNewInstance: true,
auctionUpgradeNewGovCreator: true,
newContractGovBundleId: true,
+ retiredContractInstances: true,
},
instance: {
consume: { reserve: true },
diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js
index f98f62223f2..0ecbea49098 100644
--- a/packages/inter-protocol/src/proposals/deploy-price-feeds.js
+++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js
@@ -5,6 +5,7 @@ import { E } from '@endo/far';
import { unitAmount } from '@agoric/zoe/src/contractSupport/priceQuote.js';
import {
oracleBrandFeedName,
+ provideRetiredInstances,
reserveThenDeposit,
sanitizePathSegment,
} from './utils.js';
@@ -84,7 +85,8 @@ export const ensureOracleBrand = async (
};
/**
- * @param {EconomyBootstrapPowers} powers
+ * @param {EconomyBootstrapPowers &
+ * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers
* @param {{
* AGORIC_INSTANCE_NAME: string;
* contractTerms: import('@agoric/inter-protocol/src/price/fluxAggregatorKit.js').ChainlinkConfig;
@@ -96,6 +98,7 @@ export const ensureOracleBrand = async (
const startPriceAggregatorInstance = async (
{
consume: {
+ agoricNames,
board,
chainStorage,
chainTimerService,
@@ -103,8 +106,10 @@ const startPriceAggregatorInstance = async (
highPrioritySendersManager,
namesByAddressAdmin,
startGovernedUpgradable,
+ retiredContractInstances: retiredContractInstancesP,
},
instance: { produce: produceInstance },
+ produce: { retiredContractInstances: produceRetiredInstances },
},
{ AGORIC_INSTANCE_NAME, contractTerms, brandIn, brandOut },
installation,
@@ -139,6 +144,22 @@ const startPriceAggregatorInstance = async (
// @ts-expect-error GovernableStartFn vs. fluxAggregatorContract.js start
installation,
});
+ const retiredContractInstances = await provideRetiredInstances(
+ retiredContractInstancesP,
+ produceRetiredInstances,
+ );
+
+ // save the instance so we can manage it later
+ const retiringInstance = await E(agoricNames).lookup(
+ 'instance',
+ AGORIC_INSTANCE_NAME,
+ );
+ const boardID = await E(board).getId(retiringInstance);
+ retiredContractInstances.init(
+ `priceFeed-${AGORIC_INSTANCE_NAME}-${boardID}`,
+ retiringInstance,
+ );
+
produceInstance[AGORIC_INSTANCE_NAME].reset();
produceInstance[AGORIC_INSTANCE_NAME].resolve(governedKit.instance);
trace(
@@ -191,7 +212,9 @@ const distributeInvitations = async (
};
/**
- * @param {EconomyBootstrapPowers & NamedVatPowers} powers
+ * @param {EconomyBootstrapPowers &
+ * NamedVatPowers &
+ * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers
* @param {{
* options: PriceFeedConfig & {
* priceAggregatorRef: { bundleID: string };
@@ -300,6 +323,7 @@ export const getManifestForPriceFeeds = async (
namesByAddressAdmin: t,
priceAuthority: t,
priceAuthorityAdmin: t,
+ retiredContractInstances: t,
startGovernedUpgradable: t,
startUpgradable: t,
zoe: t,
@@ -307,9 +331,10 @@ export const getManifestForPriceFeeds = async (
installation: { produce: { priceAggregator: t } },
instance: {
produce: t,
+ consume: t,
},
oracleBrand: { produce: t },
- produce: { priceAuthority8400: t },
+ produce: { priceAuthority8400: t, retiredContractInstances: t },
},
},
options: { ...priceFeedOptions },
diff --git a/packages/inter-protocol/src/proposals/replaceElectorate.js b/packages/inter-protocol/src/proposals/replaceElectorate.js
index cb862be5a67..adde9adf747 100644
--- a/packages/inter-protocol/src/proposals/replaceElectorate.js
+++ b/packages/inter-protocol/src/proposals/replaceElectorate.js
@@ -15,7 +15,7 @@ import {
assertPathSegment,
makeStorageNodeChild,
} from '@agoric/internal/src/lib-chainStorage.js';
-import { reserveThenDeposit } from './utils.js';
+import { provideRetiredInstances, reserveThenDeposit } from './utils.js';
/** @import {EconomyBootstrapPowers} from './econ-behaviors.js' */
/** @import {EconCharterStartResult} from './econ-behaviors.js' */
@@ -181,8 +181,10 @@ const inviteToEconCharter = async (
* Starts a new Economic Committee (EC) by creating an instance with the
* provided committee specifications.
*
- * @param {EconomyBootstrapPowers} powers - The resources and capabilities
- * required to start the committee.
+ * @param {EconomyBootstrapPowers &
+ * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers
+ * - The resources and capabilities required to start the committee.
+ *
* @param {{
* options: {
* committeeName: string;
@@ -196,12 +198,22 @@ const inviteToEconCharter = async (
*/
const startNewEconomicCommittee = async (
{
- consume: { board, chainStorage, startUpgradable },
- produce: { economicCommitteeKit, economicCommitteeCreatorFacet },
+ consume: {
+ board,
+ chainStorage,
+ startUpgradable,
+ retiredContractInstances: retiredInstancesP,
+ },
+ produce: {
+ economicCommitteeKit,
+ economicCommitteeCreatorFacet,
+ retiredContractInstances: produceRetiredInstances,
+ },
installation: {
consume: { committee },
},
instance: {
+ consume: { economicCommittee: economicCommitteeOriginalP },
produce: { economicCommittee },
},
},
@@ -214,6 +226,19 @@ const startNewEconomicCommittee = async (
trace(`committeeName ${committeeName}`);
trace(`committeeSize ${committeeSize}`);
+ const retiredInstances = await provideRetiredInstances(
+ retiredInstancesP,
+ produceRetiredInstances,
+ );
+
+ // Record the retired electorate instance so we can manage it later.
+ const economicCommitteeOriginal = await economicCommitteeOriginalP;
+ const boardID = await E(board).getId(economicCommitteeOriginal);
+ retiredInstances.init(
+ `economicCommittee-${boardID}`,
+ economicCommitteeOriginal,
+ );
+
const committeesNode = await makeStorageNodeChild(
chainStorage,
COMMITTEES_ROOT,
@@ -309,6 +334,7 @@ const startNewEconCharter = async ({
* @typedef {PromiseSpaceOf<{
* auctionUpgradeNewInstance: Instance;
* auctionUpgradeNewGovCreator: any;
+ * retiredContractInstances: MapStore;
* }>} interlockPowers
*/
@@ -485,6 +511,7 @@ export const getManifestForReplaceAllElectorates = async (
manifest: {
[replaceAllElectorates.name]: {
consume: {
+ agoricNames: true,
auctionUpgradeNewGovCreator: true,
auctionUpgradeNewInstance: true,
psmKit: true,
@@ -492,6 +519,7 @@ export const getManifestForReplaceAllElectorates = async (
chainStorage: true,
highPrioritySendersManager: true,
namesByAddressAdmin: true,
+ retiredContractInstances: true,
// Rest of these are designed to be widely shared
board: true,
startUpgradable: true,
@@ -501,6 +529,7 @@ export const getManifestForReplaceAllElectorates = async (
economicCommitteeKit: true,
economicCommitteeCreatorFacet: true,
auctionUpgradeNewGovCreator: true,
+ retiredContractInstances: true,
},
installation: {
consume: {
@@ -514,6 +543,7 @@ export const getManifestForReplaceAllElectorates = async (
economicCommittee: true,
econCommitteeCharter: true,
},
+ consume: { economicCommittee: true },
},
},
},
diff --git a/packages/inter-protocol/src/proposals/utils.js b/packages/inter-protocol/src/proposals/utils.js
index 42894a27148..165731e4838 100644
--- a/packages/inter-protocol/src/proposals/utils.js
+++ b/packages/inter-protocol/src/proposals/utils.js
@@ -3,6 +3,7 @@ import { E } from '@endo/far';
import { WalletName } from '@agoric/internal';
import { getCopyMapEntries, makeCopyMap } from '@agoric/store';
import { assertPathSegment } from '@agoric/internal/src/lib-chainStorage.js';
+import { makeScalarBigMapStore } from '@agoric/vat-data';
/** @import {CopyMap} from '@endo/patterns'; */
@@ -171,3 +172,22 @@ export const sanitizePathSegment = name => {
assertPathSegment(candidate);
return candidate;
};
+
+/**
+ * Idempotently provide an empty MapStore for the `retiredContractInstances`
+ * value in promise space
+ *
+ * @param {Promise} consume
+ * @param {Producer} produce
+ * @returns {Promise}
+ */
+export const provideRetiredInstances = async (consume, produce) => {
+ // Promise space has no way to look for an existing value other than awaiting a promise,
+ // but it does allow extra production so it's safe to do this redundantly.
+ produce.resolve(
+ makeScalarBigMapStore('retiredContractInstances', {
+ durable: true,
+ }),
+ );
+ return consume;
+};
diff --git a/packages/inter-protocol/src/provisionPool.js b/packages/inter-protocol/src/provisionPool.js
index de96cfabaab..ee002f1a011 100644
--- a/packages/inter-protocol/src/provisionPool.js
+++ b/packages/inter-protocol/src/provisionPool.js
@@ -53,6 +53,7 @@ harden(meta);
* storageNode: StorageNode;
* marshaller: Marshal;
* metricsOverride?: import('./provisionPoolKit.js').MetricsNotification;
+ * governedParamOverrides?: Record;
* }} privateArgs
* @param {import('@agoric/vat-data').Baggage} baggage
*/
@@ -74,6 +75,7 @@ export const start = async (zcf, privateArgs, baggage) => {
},
privateArgs.storageNode,
privateArgs.marshaller,
+ privateArgs.governedParamOverrides,
);
const zone = makeDurableZone(baggage);
diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js
index 362ac8950d7..41d151475fd 100644
--- a/packages/orchestration/src/exos/local-orchestration-account.js
+++ b/packages/orchestration/src/exos/local-orchestration-account.js
@@ -690,7 +690,7 @@ export const prepareLocalOrchestrationAccountKit = (
'agoric',
forwardOpts,
);
- trace('got transfer route', q(route).toString());
+ trace('got transfer route', route);
// set a `timeoutTimestamp` if caller does not supply either `timeoutHeight` or `timeoutTimestamp`
// TODO #9324 what's a reasonable default? currently 5 minutes
diff --git a/packages/vats/src/proposals/upgrade-mintHolder-proposal.js b/packages/vats/src/proposals/upgrade-mintHolder-proposal.js
new file mode 100644
index 00000000000..4b231abdc16
--- /dev/null
+++ b/packages/vats/src/proposals/upgrade-mintHolder-proposal.js
@@ -0,0 +1,74 @@
+import { makeTracer } from '@agoric/internal';
+import { E } from '@endo/far';
+
+const trace = makeTracer('upgrade mintHolder', true);
+
+export const upgradeMintHolder = async (
+ {
+ consume: {
+ contractKits: contractKitsP,
+ instancePrivateArgs: instancePrivateArgsP,
+ },
+ },
+ options,
+) => {
+ const { contractRef, labelList } = options.options;
+ assert(contractRef.bundleID, 'mintHolder bundleID not found');
+ assert(labelList, 'mintHolder bank asset label list not found');
+
+ trace(`Start mintHolder contract upgrade`);
+ trace(`Assets: `, labelList);
+
+ const [contractKits, instancePrivateArgs] = await Promise.all([
+ contractKitsP,
+ instancePrivateArgsP,
+ ]);
+
+ for (const assetLabel of labelList) {
+ const mintHolderKit = Array.from(contractKits.values()).find(
+ kit => kit.label && kit.label === assetLabel,
+ );
+ if (!mintHolderKit) {
+ console.error(
+ `ERROR: failed to upgrade ${assetLabel} mintHolder, contractKit not found`,
+ );
+ continue;
+ }
+
+ trace(`${assetLabel} mintHolderKit: `, mintHolderKit);
+
+ const { publicFacet, adminFacet, instance } = mintHolderKit;
+
+ /*
+ * Ensure that publicFacet holds an issuer by verifying that has
+ * the makeEmptyPurse method.
+ */
+ await E(publicFacet).makeEmptyPurse();
+
+ const privateArgs = instancePrivateArgs.get(instance);
+
+ const upgradeResult = await E(adminFacet).upgradeContract(
+ contractRef.bundleID,
+ privateArgs,
+ );
+
+ trace(`${assetLabel} upgrade result: `, upgradeResult);
+ }
+
+ trace(`Finished mintHolder contract upgrade`);
+};
+
+export const getManifestForUpgradingMintHolder = (
+ _powers,
+ { contractRef, labelList },
+) => ({
+ manifest: {
+ [upgradeMintHolder.name]: {
+ consume: {
+ contractKits: true,
+ instancePrivateArgs: true,
+ },
+ },
+ },
+ options: { contractRef, labelList },
+});
diff --git a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js
index a94fd6ef418..c2d8e7c02b9 100644
--- a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js
+++ b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js
@@ -2,7 +2,7 @@ import { E } from '@endo/far';
import { deeplyFulfilled } from '@endo/marshal';
import { makeTracer } from '@agoric/internal';
-const tracer = makeTracer('UpgradeProvisionPool');
+const trace = makeTracer('UpgradeProvisionPool');
/**
* @param {BootstrapPowers & {
@@ -30,7 +30,7 @@ export const upgradeProvisionPool = async (
const { provisionPoolRef } = options.options;
assert(provisionPoolRef.bundleID);
- tracer(`PROVISION POOL BUNDLE ID: `, provisionPoolRef);
+ trace(`PROVISION POOL BUNDLE ID: `, provisionPoolRef);
const [
provisionPoolStartResult,
@@ -49,6 +49,7 @@ export const upgradeProvisionPool = async (
adminFacet,
instance,
creatorFacet: ppCreatorFacet,
+ publicFacet: ppPublicFacet,
} = provisionPoolStartResult;
const { creatorFacet: wfCreatorFacet } = walletFactoryStartResult;
@@ -59,9 +60,16 @@ export const upgradeProvisionPool = async (
E(electorateCreatorFacet).getPoserInvitation(),
]);
+ const params = await E(ppPublicFacet).getGovernedParams();
+ const governedParamOverrides = harden({
+ PerAccountInitialAmount: params.PerAccountInitialAmount.value,
+ });
+ trace('governedParamOverrides: ', { governedParamOverrides });
+
const newPrivateArgs = harden({
...originalPrivateArgs,
initialPoserInvitation: poserInvitation,
+ governedParamOverrides,
});
const upgradeResult = await E(adminFacet).upgradeContract(
@@ -69,7 +77,7 @@ export const upgradeProvisionPool = async (
newPrivateArgs,
);
- tracer('ProvisionPool upgraded: ', upgradeResult);
+ trace('ProvisionPool upgraded: ', upgradeResult);
const references = {
bankManager,
@@ -77,17 +85,17 @@ export const upgradeProvisionPool = async (
walletFactory: wfCreatorFacet,
};
- tracer('Calling setReferences with: ', references);
+ trace('Calling setReferences with: ', references);
await E(ppCreatorFacet).setReferences(references);
- tracer('Creating bridgeHandler...');
+ trace('Creating bridgeHandler...');
const bridgeHandler = await E(ppCreatorFacet).makeHandler();
- tracer('Setting new bridgeHandler...');
+ trace('Setting new bridgeHandler...');
// @ts-expect-error casting
await E(provisionWalletBridgeManager).setHandler(bridgeHandler);
- tracer('Done.');
+ trace('Done.');
};
export const getManifestForUpgradingProvisionPool = (