diff --git a/a3p-integration/proposals/z:acceptance/package.json b/a3p-integration/proposals/z:acceptance/package.json index 44323e31c724..efef02084419 100644 --- a/a3p-integration/proposals/z:acceptance/package.json +++ b/a3p-integration/proposals/z:acceptance/package.json @@ -9,6 +9,7 @@ "type": "module", "license": "Apache-2.0", "dependencies": { + "@agoric/ertp": "0.16.3-u17.1", "@agoric/internal": "0.3.3-dev-5676146.0", "@agoric/synthetic-chain": "^0.3.0", "@endo/errors": "^1.2.2", diff --git a/a3p-integration/proposals/z:acceptance/psm.test.js b/a3p-integration/proposals/z:acceptance/psm.test.js new file mode 100644 index 000000000000..0226d181ec12 --- /dev/null +++ b/a3p-integration/proposals/z:acceptance/psm.test.js @@ -0,0 +1,267 @@ +/** + * @file The goal of this file is to implement a set of tests to make sure PSM works properly + * + * Here are the steps we want to take; + * 1 - Change swap fees and mint limit according to "psmTestSpecs" below + * 2 - Create a new user using agd.keys + * 3 - Fund new user with a stable coin from the VALIDATOR + * - Do not provision manually + * 4 - Make sure new user is able to mint IST from PSM (fees are applied) + * 5 - Make sure new user can pay their debt and get their anchor (fees are applied) + * 6 - Make sure mint limit is adhered + */ + +import test from 'ava'; +import { + adjustBalancesIfNotProvisioned, + agopsPsm, + bankSend, + checkGovParams, + checkSwapExceedMintLimit, + checkSwapSucceeded, + checkUserInitializedSuccessfully, + getPsmMetrics, + implementPsmGovParamChange, + initializeNewUser, + maxMintBelowLimit, +} from './test-lib/psm-lib.js'; +import { + getUser, + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, + waitForBlock, +} from '@agoric/synthetic-chain'; +import { getBalances } from './test-lib/utils.js'; + +// Export these from synthetic-chain? +export const USDC_DENOM = process.env.USDC_DENOM; +export const PSM_PAIR = process.env.PSM_PAIR?.replace('.', '-'); + +const psmTestSpecs = { + govParams: { + giveMintedFeeVal: 10n, // in % + wantMintedFeeVal: 10n, // in % + mintLimit: 500n * 1_000_000n, // in IST + deadline: 1, // in minutes + }, + psmInstance: `psm-${PSM_PAIR}`, + // @ts-expect-error we assume PSM_PAIR is set because of synthetic-chain environment + anchor: PSM_PAIR.split('-')[1], + newUser: { + name: 'new-psm-trader', + fund: { + denom: USDC_DENOM ? USDC_DENOM : 'fake', + value: '300000000', // 300 USDC_grv + }, + }, + otherUser: { + name: 'gov1', + fund: { + denom: USDC_DENOM ? USDC_DENOM : 'fake', + value: '1000000000', // 1000 USDC_grv + }, + toIst: { + value: 500, // in IST + }, + }, + toIst: { + value: 50, // in IST + }, + fromIst: { + value: 50, // in USDC_axl + }, +}; + +test.serial('change gov params', async t => { + await implementPsmGovParamChange( + { + address: GOV1ADDR, + instanceName: psmTestSpecs.psmInstance, + newParams: psmTestSpecs.govParams, + deadline: psmTestSpecs.govParams.deadline, + }, + { committeeAddrs: [GOV1ADDR, GOV2ADDR, GOV3ADDR], position: 0 }, + ); + + // Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in + await waitForBlock(3); + await checkGovParams( + t, + { + GiveMintedFee: { + type: 'ratio', + value: { + numerator: { value: psmTestSpecs.govParams.giveMintedFeeVal * 100n }, // convert to bps + }, + }, + WantMintedFee: { + type: 'ratio', + value: { + numerator: { value: psmTestSpecs.govParams.wantMintedFeeVal * 100n }, // convert to bps + }, + }, + MintLimit: { + type: 'amount', + value: { + value: psmTestSpecs.govParams.mintLimit, + }, + }, + }, + psmTestSpecs.psmInstance.split('-')[2], + ); +}); + +test.serial('initialize new user', async t => { + const { + newUser: { name, fund }, + } = psmTestSpecs; + + await initializeNewUser(name, fund); + // Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in + await waitForBlock(3); + + await checkUserInitializedSuccessfully(t, name, fund); +}); + +test.serial('swap into IST', async t => { + const { + newUser: { name }, + anchor, + toIst, + govParams: { wantMintedFeeVal }, + } = psmTestSpecs; + + const psmTrader = await getUser(name); + + const [metricsBefore, balances] = await Promise.all([ + getPsmMetrics(anchor), + getBalances([psmTrader]), + ]); + + const balancesBefore = await adjustBalancesIfNotProvisioned( + balances, + psmTrader, + ); + t.log('METRICS', metricsBefore); + t.log('BALANCES', balancesBefore); + + await agopsPsm(psmTrader, [ + 'swap', + '--pair', + process.env.PSM_PAIR, + '--wantMinted', + toIst.value, + '--feePct', + wantMintedFeeVal, + ]); + await waitForBlock(5); + + await checkSwapSucceeded(t, metricsBefore, balancesBefore, { + wantMinted: toIst.value, + trader: psmTrader, + fee: Number(wantMintedFeeVal) / 100, // fee has to be between 0 and 1 + }); +}); + +test.serial('swap out of IST', async t => { + const { + newUser: { name }, + anchor, + fromIst, + govParams: { giveMintedFeeVal }, + } = psmTestSpecs; + + const psmTrader = await getUser(name); + + const [metricsBefore, balancesBefore] = await Promise.all([ + getPsmMetrics(anchor), + getBalances([psmTrader]), + ]); + + t.log('METRICS', metricsBefore); + t.log('BALANCES', balancesBefore); + + await agopsPsm(psmTrader, [ + 'swap', + '--pair', + process.env.PSM_PAIR, + '--giveMinted', + fromIst.value, + '--feePct', + giveMintedFeeVal, + ]); + await waitForBlock(5); + + await checkSwapSucceeded(t, metricsBefore, balancesBefore, { + giveMinted: fromIst.value, + trader: psmTrader, + fee: Number(giveMintedFeeVal) / 100, // fee has to be between 0 and 1 + }); +}); + +test.serial('mint limit is adhered', async t => { + const { + otherUser: { + fund: { denom, value }, + name, + }, + govParams, + anchor, + } = psmTestSpecs; + + // Fund other user + const otherAddr = await getUser(name); + await bankSend(otherAddr, `${value}${denom}`); + + // Replace when https://github.com/Agoric/agoric-sdk/pull/10171 is in + await waitForBlock(3); + + const [metricsBefore, balancesBefore] = await Promise.all([ + getPsmMetrics(anchor), + getBalances([otherAddr]), + ]); + + t.log('METRICS', metricsBefore); + t.log('BALANCES', balancesBefore); + + const { maxMintableValue, wantFeeValue } = await maxMintBelowLimit(anchor); + const maxMintFeesAccounted = Math.floor( + maxMintableValue * (1 - wantFeeValue), + ); + t.log({ maxMintableValue, wantFeeValue, maxMintFeesAccounted }); + + // Send a swap, should fail because mint limit is exceeded + await agopsPsm(otherAddr, [ + 'swap', + '--pair', + process.env.PSM_PAIR, + '--wantMinted', + maxMintFeesAccounted / 1000000 + 2, // Make sure we exceed the limit + '--feePct', + govParams.wantMintedFeeVal, + ]); + await waitForBlock(5); + + // Now check if failed with correct error message + await checkSwapExceedMintLimit(t, otherAddr, metricsBefore); + + // Send another swap offer, this time should succeed + await agopsPsm(otherAddr, [ + 'swap', + '--pair', + process.env.PSM_PAIR, + '--wantMinted', + maxMintFeesAccounted / 1000000, + '--feePct', + govParams.wantMintedFeeVal, + ]); + await waitForBlock(5); + + // Make sure swap succeeded + await checkSwapSucceeded(t, metricsBefore, balancesBefore, { + wantMinted: maxMintFeesAccounted / 1000000, + trader: otherAddr, + fee: Number(govParams.wantMintedFeeVal) / 100, // fee has to be between 0 and 1 + }); +}); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js new file mode 100644 index 000000000000..73ffc33afd4f --- /dev/null +++ b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js @@ -0,0 +1,497 @@ +import '@endo/init'; +import { boardSlottingMarshaller, makeFromBoard } from './rpc.js'; +import { + addUser, + agd, + agops, + agoric, + executeOffer, + getUser, + agopsLocation, + executeCommand, + CHAINID, + VALIDATORADDR, + GOV1ADDR, + mkTemp, +} from '@agoric/synthetic-chain'; +import { AmountMath } from '@agoric/ertp'; +import { getBalances } from './utils.js'; +import { PSM_PAIR, USDC_DENOM } from '../psm.test.js'; +import fsp from 'node:fs/promises'; + +const fromBoard = makeFromBoard(); +const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); + +const VOTING_WAIT_MS = 65 * 1000; + +/** + * Import from synthetic-chain once it is updated + * + * @param {string} addr + * @param {string} wanted + * @param {string} [from] + * @returns + */ +export const bankSend = (addr, wanted, from = VALIDATORADDR) => { + const chain = ['--chain-id', CHAINID]; + const fromArg = ['--from', from]; + const testKeyring = ['--keyring-backend', 'test']; + const noise = [...fromArg, ...chain, ...testKeyring, '--yes']; + + return agd.tx('bank', 'send', from, addr, wanted, ...noise); +}; + +/** + * + * @param {{ + * address: string + * instanceName: string + * newParams: Params + * deadline: number + * offerId?: string + * }} QuestionDetails + */ +export const buildProposePSMParamChangeOffer = async ({ + address, + instanceName, + newParams, + deadline, + offerId = Date.now().toString(), +}) => { + const charterAcceptOfferId = await agops.ec( + 'find-continuing-id', + '--for', + `${'charter\\ member\\ invitation'}`, + '--from', + address, + ); + console.log('charterAcceptOfferId', charterAcceptOfferId); + const [brands, instances] = await Promise.all([ + agoric + .follow('-lF', ':published.agoricNames.brand', '-o', 'text') + .then(brandsRaw => + Object.fromEntries(marshaller.fromCapData(JSON.parse(brandsRaw))), + ), + agoric + .follow('-lF', ':published.agoricNames.instance', '-o', 'text') + .then(instancesRaw => + Object.fromEntries(marshaller.fromCapData(JSON.parse(instancesRaw))), + ), + ]); + + console.log('charterAcceptOfferId', charterAcceptOfferId); + console.log('BRANDS', brands); + console.log('INSTANCE', instances); + + /** + * @param {bigint} numValInPercent + */ + const toRatio = numValInPercent => { + const commonDenominator = AmountMath.make(brands.IST, 10_000n); + const numerator = AmountMath.make(brands.IST, numValInPercent * 100n); // Convert to bps + + return { + numerator, + denominator: commonDenominator, + }; + }; + + let params = {}; + if (newParams.giveMintedFeeVal) { + params.GiveMintedFee = toRatio(newParams.giveMintedFeeVal); + } + + if (newParams.wantMintedFeeVal) { + params.WantMintedFee = toRatio(newParams.wantMintedFeeVal); + } + + if (newParams.mintLimit) { + params.MintLimit = AmountMath.make(brands.IST, newParams.mintLimit); + } + + const offerSpec = { + id: offerId, + invitationSpec: { + source: 'continuing', + previousOffer: charterAcceptOfferId, + invitationMakerName: 'VoteOnParamChange', + }, + proposal: {}, + offerArgs: { + instance: instances[instanceName], + params, + deadline: BigInt(deadline * 60 + Math.round(Date.now() / 1000)), + }, + }; + + /** @type {string | object} */ + const spendAction = { + method: 'executeOffer', + offer: offerSpec, + }; + + const offer = JSON.stringify(marshaller.toCapData(harden(spendAction))); + console.log(offerSpec); + console.log(offer); + + return executeOffer(address, offer); +}; + +/** + * + * @param {{ + * committeeAddrs: Array + * position: number | string + * }} VotingDetails + */ +export const voteForNewParams = ({ committeeAddrs, position }) => { + console.log('ACTIONS voting for position', position, 'using', committeeAddrs); + return Promise.all( + committeeAddrs.map(account => + // @ts-expect-error Casting + agops.ec('vote', '--forPosition', position, '--send-from', account), + ), + ); +}; + +/** + * @typedef {{ + * giveMintedFeeVal: bigint; + * wantMintedFeeVal: bigint; + * mintLimit: bigint; + * }} Params + * + * + * @param {{ + * address: string + * instanceName: string + * newParams: Params + * deadline: number + * offerId?: string + * }} question + * + * @param {{ + * committeeAddrs: Array + * position: number + * }} voting + */ +export const implementPsmGovParamChange = async (question, voting) => { + await buildProposePSMParamChangeOffer(question); + await voteForNewParams(voting); + console.log('ACTIONS wait for the vote deadline to pass'); + await new Promise(r => setTimeout(r, VOTING_WAIT_MS)); +}; + +export const checkGovParams = async (t, expected, psmName) => { + const current = await getPsmGovernance(psmName); + + t.log({ + give: current.WantMintedFee.value, + want: current.GiveMintedFee.value, + mintLimit: current.MintLimit, + }); + + t.like(current, expected); +}; + +/** + * + * @param {string} name + * @param {{ + * denom: string, + * value: string + * }} fund + */ +export const initializeNewUser = async (name, fund) => { + const psmTrader = await addUser(name); + await Promise.all([ + bankSend( + psmTrader, + `20000000ubld,${fund.value}${fund.denom}`, + ), + bankSend(psmTrader, `1000000uist`, GOV1ADDR), + ]); +}; + +/** + * + * @param {any} t + * @param {string} userName + * @param {{ + * denom: string, + * value: string + * }} expectedAnchorFunds + */ +export const checkUserInitializedSuccessfully = async ( + t, + userName, + expectedAnchorFunds, +) => { + let userAddress; + await t.notThrowsAsync(async () => { + userAddress = await getUser(userName); + }); + + // @ts-expect-error initialization + const balance = await getBalances([userAddress], expectedAnchorFunds.denom); + t.is(balance >= BigInt(expectedAnchorFunds.value), true); +}; + +/** + * Similar to https://github.com/Agoric/agoric-3-proposals/blob/422b163fecfcf025d53431caebf6d476778b5db3/packages/synthetic-chain/src/lib/commonUpgradeHelpers.ts#L123-L139 + * However, in the case where "address" is not provisioned "agoric wallet send" is needed because + * "agops perf satisfaction" tries to follow ":published.wallet.${address}" which blocks the execution because no such path exists in + * vstorage. In situations like this "agoric wallet send" seems a better choice as it doesn't depend on following user's vstorage wallet path + * + * @param {string} address + * @param {Promise} offerPromise + */ +export const sendOfferAgoric = async (address, offerPromise) => { + const offerPath = await mkTemp('agops.XXX'); + const offer = await offerPromise; + await fsp.writeFile(offerPath, offer); + + await agoric.wallet( + '--keyring-backend=test', + 'send', + '--offer', + offerPath, + '--from', + address, + ); +}; + +/** + * @param {string} address + * @param {Array} params + */ +export const agopsPsm = (address, params) => { + const newParams = ['psm', ...params]; + const offerPromise = executeCommand(agopsLocation, newParams); + return sendOfferAgoric(address, offerPromise); +}; + +const giveAnchor = (base, fee) => { + return Math.ceil(base / (1 - fee)); +}; + +const receiveAnchor = (base, fee) => { + return Math.ceil(base * (1 - fee)); +}; + +const extractBalance = (balances, targetDenom) => { + const balance = balances.find(({ denom }) => denom === targetDenom); + return Number(balance.amount); +}; + +/** + * + * @param {any} t + * @param {any} metricsBefore + * @param {any} balancesBefore + * @param {{trader: string; fee: number} & ( + * | {wantMinted: number} + * | {giveMinted: number} + * )} tradeInfo + */ +export const checkSwapSucceeded = async ( + t, + metricsBefore, + balancesBefore, + tradeInfo, +) => { + + const [metricsAfter, balancesAfter] = await Promise.all([ + agoric + .follow( + '-lF', + `:published.psm.IST.${PSM_PAIR?.split('-')[1]}.metrics`, + '-o', + 'text', + ) + .then(metricsRaw => marshaller.fromCapData(JSON.parse(metricsRaw))), + getBalances([tradeInfo.trader]), + ]); + + t.log('METRICS_AFTER', metricsAfter); + t.log('BALANCES_AFTER', balancesAfter); + + if ('wantMinted' in tradeInfo) { + const anchorPaid = giveAnchor( + tradeInfo.wantMinted * 1000000, + tradeInfo.fee, + ); + const mintedReceived = tradeInfo.wantMinted * 1000000; + const feePaid = anchorPaid - mintedReceived; + + t.deepEqual( + extractBalance(balancesAfter, USDC_DENOM), + extractBalance(balancesBefore, USDC_DENOM) - anchorPaid, + ); + + t.deepEqual( + extractBalance(balancesAfter, 'uist'), + extractBalance(balancesBefore, 'uist') + mintedReceived, + ); + + t.like(metricsAfter, { + anchorPoolBalance: { + value: metricsBefore.anchorPoolBalance.value + BigInt(anchorPaid), + }, + feePoolBalance: { + value: metricsBefore.feePoolBalance.value + BigInt(feePaid), + }, + mintedPoolBalance: { + value: metricsBefore.mintedPoolBalance.value + BigInt(anchorPaid), + }, + totalAnchorProvided: { + value: metricsBefore.totalAnchorProvided.value, + }, + totalMintedProvided: { + value: metricsBefore.totalMintedProvided.value + BigInt(anchorPaid), + }, + }); + } else if ('giveMinted' in tradeInfo) { + const mintedPaid = tradeInfo.giveMinted * 1000000; + const anchorReceived = receiveAnchor( + tradeInfo.giveMinted * 1000000, + tradeInfo.fee, + ); + const feePaid = mintedPaid - anchorReceived; + + t.deepEqual( + extractBalance(balancesAfter, USDC_DENOM), + extractBalance(balancesBefore, USDC_DENOM) + anchorReceived, + ); + + t.deepEqual( + extractBalance(balancesAfter, 'uist'), + extractBalance(balancesBefore, 'uist') - mintedPaid, + ); + + t.like(metricsAfter, { + anchorPoolBalance: { + value: metricsBefore.anchorPoolBalance.value - BigInt(anchorReceived), + }, + feePoolBalance: { + value: metricsBefore.feePoolBalance.value + BigInt(feePaid), + }, + mintedPoolBalance: { + value: metricsBefore.mintedPoolBalance.value - BigInt(anchorReceived), + }, + totalAnchorProvided: { + value: metricsBefore.totalAnchorProvided.value + BigInt(anchorReceived), + }, + totalMintedProvided: { + value: metricsBefore.totalMintedProvided.value, + }, + }); + } +}; + +/** + * + * @param {Array<{ denom: string; amount: string }>} balances + * @param {string} address + */ +export const adjustBalancesIfNotProvisioned = async (balances, address) => { + const { children } = await agd.query( + 'vstorage', + 'children', + 'published.wallet', + '-o', + 'json', + ); + const addressProvisioned = children.includes(address); + + if (addressProvisioned === true) return balances; + + let balancesAdjusted = []; + + balances.forEach(({ denom, amount }) => { + if (denom === 'uist') { + amount = (parseInt(amount) + 250000 - 1_000_000).toString(); // provision sends 250000uist to new accounts and 1 IST is charged + balancesAdjusted.push({ denom, amount }); + } else { + balancesAdjusted.push({ denom, amount }); + } + }); + + return balancesAdjusted; +}; + +/** + * + * @param {any} t + * @param {string} address + * @param {Record} metricsBefore + */ +export const checkSwapExceedMintLimit = async (t, address, metricsBefore) => { + const [offerResult, metricsAfter] = await Promise.all([ + agoric.follow('-lF', `:published.wallet.${address}`), + // @ts-expect-error we assume PSM_PAIR is set because of synthetic-chain environment + getPsmMetrics(PSM_PAIR.split('-')[1]), + ]); + const { status, updated } = offerResult; + + t.is(updated, 'offerStatus'); + t.is(status.error, 'Error: Request would exceed mint limit'); + t.like(metricsBefore, { + mintedPoolBalance: { value: metricsAfter.mintedPoolBalance.value }, + }); +}; + +/** + * @param {string} anchor + */ +export const getPsmMetrics = async anchor => { + const metricsRaw = await agoric.follow( + '-lF', + `:published.psm.IST.${anchor}.metrics`, + '-o', + 'text', + ); + + return marshaller.fromCapData(JSON.parse(metricsRaw)); +}; + +/** + * @param {string} anchor + */ +export const getPsmGovernance = async anchor => { + const governanceRaw = await agoric.follow( + '-lF', + `:published.psm.IST.${anchor}.governance`, + '-o', + 'text', + ); + const { current } = marshaller.fromCapData(JSON.parse(governanceRaw)); + return current; +}; + +/** + * @param {string} anchor + * @returns {Promise<{ maxMintableValue: number; wantFeeValue: number; giveFeeValue: number; }>} + */ +export const maxMintBelowLimit = async anchor => { + const [governance, metrics] = await Promise.all([ + getPsmGovernance(anchor), + getPsmMetrics(anchor), + ]); + + const mintLimitVal = Number(governance.MintLimit.value.value); + const mintedPoolBalanceVal = Number(metrics.mintedPoolBalance.value); + const maxMintableValue = mintLimitVal - mintedPoolBalanceVal - 1; + + const wantFeeRatio = governance.WantMintedFee.value; + const giveFeeRatio = governance.GiveMintedFee.value; + + const wantFeeValue = + Number(wantFeeRatio.numerator.value) / + Number(wantFeeRatio.denominator.value); + const giveFeeValue = + Number(giveFeeRatio.numerator.value) / + Number(giveFeeRatio.denominator.value); + + return { maxMintableValue, wantFeeValue, giveFeeValue }; +}; diff --git a/a3p-integration/proposals/z:acceptance/tsconfig.json b/a3p-integration/proposals/z:acceptance/tsconfig.json index 795ebdd04fc0..bd1c45190fe2 100644 --- a/a3p-integration/proposals/z:acceptance/tsconfig.json +++ b/a3p-integration/proposals/z:acceptance/tsconfig.json @@ -10,6 +10,6 @@ "strictNullChecks": true, "noImplicitThis": true, // XXX synthetic-chain has some errors - "skipLibCheck": true, + "skipLibCheck": true } } diff --git a/a3p-integration/proposals/z:acceptance/yarn.lock b/a3p-integration/proposals/z:acceptance/yarn.lock index 1adfcdbb4503..0072ff0aa7cc 100644 --- a/a3p-integration/proposals/z:acceptance/yarn.lock +++ b/a3p-integration/proposals/z:acceptance/yarn.lock @@ -26,6 +26,40 @@ __metadata: languageName: node linkType: hard +"@agoric/base-zone@npm:0.1.1-upgrade-17-dev-ec448b0.0+ec448b0": + version: 0.1.1-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/base-zone@npm:0.1.1-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/store": "npm:0.9.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/common": "npm:^1.2.5" + "@endo/errors": "npm:^1.2.5" + "@endo/exo": "npm:^1.5.3" + "@endo/far": "npm:^1.1.5" + "@endo/pass-style": "npm:^1.4.3" + "@endo/patterns": "npm:^1.4.3" + checksum: 10c0/b30362368bd2d29b12e19f4809023844a44ed512369cba37a27107b41f66c782d68cc58fde749089465d872bf435b73991792dbcf439c9e85591e2e187c4066f + languageName: node + linkType: hard + +"@agoric/ertp@npm:0.16.3-u17.1": + version: 0.16.3-u17.1 + resolution: "@agoric/ertp@npm:0.16.3-u17.1" + dependencies: + "@agoric/notifier": "npm:^0.7.0-u17.1" + "@agoric/store": "npm:^0.9.3-u17.1" + "@agoric/vat-data": "npm:^0.5.3-u17.1" + "@agoric/zone": "npm:^0.3.0-u17.1" + "@endo/errors": "npm:^1.2.5" + "@endo/eventual-send": "npm:^1.2.5" + "@endo/far": "npm:^1.1.5" + "@endo/marshal": "npm:^1.5.3" + "@endo/nat": "npm:^5.0.10" + "@endo/patterns": "npm:^1.4.3" + "@endo/promise-kit": "npm:^1.1.5" + checksum: 10c0/54a543dea2e4087214da76734146e3e5bfd1bb6f666110495c6e8c6bfe6bc11148e2a507906e255f8140debcb3f95b69a2cf2a960c3cba9b0e3a3ccc204014ab + languageName: node + linkType: hard + "@agoric/internal@npm:0.3.3-dev-5676146.0": version: 0.3.3-dev-5676146.0 resolution: "@agoric/internal@npm:0.3.3-dev-5676146.0" @@ -45,6 +79,41 @@ __metadata: languageName: node linkType: hard +"@agoric/internal@npm:0.4.0-upgrade-17-dev-ec448b0.0+ec448b0": + version: 0.4.0-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/internal@npm:0.4.0-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/common": "npm:^1.2.5" + "@endo/errors": "npm:^1.2.5" + "@endo/far": "npm:^1.1.5" + "@endo/init": "npm:^1.1.4" + "@endo/marshal": "npm:^1.5.3" + "@endo/pass-style": "npm:^1.4.3" + "@endo/patterns": "npm:^1.4.3" + "@endo/promise-kit": "npm:^1.1.5" + "@endo/stream": "npm:^1.2.5" + anylogger: "npm:^0.21.0" + jessie.js: "npm:^0.3.4" + checksum: 10c0/141817835928f890d874aeebbddb59e0f88a8683f15691687a6888bcc44885eb678a931bfee10af5e913f77ae9c7078216eab4252dd14a0ef101c8211e7416ce + languageName: node + linkType: hard + +"@agoric/notifier@npm:^0.7.0-u17.1": + version: 0.7.0-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/notifier@npm:0.7.0-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/internal": "npm:0.4.0-upgrade-17-dev-ec448b0.0+ec448b0" + "@agoric/vat-data": "npm:0.5.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/errors": "npm:^1.2.5" + "@endo/far": "npm:^1.1.5" + "@endo/marshal": "npm:^1.5.3" + "@endo/patterns": "npm:^1.4.3" + "@endo/promise-kit": "npm:^1.1.5" + checksum: 10c0/af93e56e082342facdd87d5265dc7988d641f2d011da03b9c63563c99a9065676dd4d9f869d0a4d83d90bdc6e2c91ce7039aa036c887b8cdd4b454ac17393905 + languageName: node + linkType: hard + "@agoric/store@npm:0.9.3-dev-5676146.0+5676146": version: 0.9.3-dev-5676146.0 resolution: "@agoric/store@npm:0.9.3-dev-5676146.0" @@ -57,6 +126,40 @@ __metadata: languageName: node linkType: hard +"@agoric/store@npm:0.9.3-upgrade-17-dev-ec448b0.0+ec448b0, @agoric/store@npm:^0.9.3-u17.1": + version: 0.9.3-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/store@npm:0.9.3-upgrade-17-dev-ec448b0.0" + dependencies: + "@endo/errors": "npm:^1.2.5" + "@endo/exo": "npm:^1.5.3" + "@endo/marshal": "npm:^1.5.3" + "@endo/pass-style": "npm:^1.4.3" + "@endo/patterns": "npm:^1.4.3" + checksum: 10c0/1ef22b1508979b5cdbed7a705fc84cb3f5d9d1a53afa34446d48c4b633d42a17881e7b8281e7c8458457d34889e9bab6e75acc5878bc4664390cd776dd8364a6 + languageName: node + linkType: hard + +"@agoric/swingset-liveslots@npm:0.10.3-upgrade-17-dev-ec448b0.0+ec448b0": + version: 0.10.3-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/swingset-liveslots@npm:0.10.3-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/internal": "npm:0.4.0-upgrade-17-dev-ec448b0.0+ec448b0" + "@agoric/store": "npm:0.9.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/env-options": "npm:^1.1.6" + "@endo/errors": "npm:^1.2.5" + "@endo/eventual-send": "npm:^1.2.5" + "@endo/exo": "npm:^1.5.3" + "@endo/far": "npm:^1.1.5" + "@endo/init": "npm:^1.1.4" + "@endo/marshal": "npm:^1.5.3" + "@endo/nat": "npm:^5.0.10" + "@endo/pass-style": "npm:^1.4.3" + "@endo/patterns": "npm:^1.4.3" + "@endo/promise-kit": "npm:^1.1.5" + checksum: 10c0/6ac445b9729f737f4a2a3f43f25b255df293e0e6df710920a3879d693da4240e968580cd70b1c2e7a92e38090afc47d2c5d990ed2f2535002734de1e84c63dab + languageName: node + linkType: hard + "@agoric/synthetic-chain@npm:^0.3.0": version: 0.3.0 resolution: "@agoric/synthetic-chain@npm:0.3.0" @@ -72,6 +175,33 @@ __metadata: languageName: node linkType: hard +"@agoric/vat-data@npm:0.5.3-upgrade-17-dev-ec448b0.0+ec448b0, @agoric/vat-data@npm:^0.5.3-u17.1": + version: 0.5.3-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/vat-data@npm:0.5.3-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-upgrade-17-dev-ec448b0.0+ec448b0" + "@agoric/store": "npm:0.9.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@agoric/swingset-liveslots": "npm:0.10.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/errors": "npm:^1.2.5" + "@endo/exo": "npm:^1.5.3" + "@endo/patterns": "npm:^1.4.3" + checksum: 10c0/6b7cf74253187971da6a79ff7e90e0256390233f79f1645f30c9267ab46095e93251bc012b8abde8161ef866904b22ce77aaf67c11976f2d7ce1ab5e0fd13c8e + languageName: node + linkType: hard + +"@agoric/zone@npm:^0.3.0-u17.1": + version: 0.3.0-upgrade-17-dev-ec448b0.0 + resolution: "@agoric/zone@npm:0.3.0-upgrade-17-dev-ec448b0.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-upgrade-17-dev-ec448b0.0+ec448b0" + "@agoric/vat-data": "npm:0.5.3-upgrade-17-dev-ec448b0.0+ec448b0" + "@endo/errors": "npm:^1.2.5" + "@endo/far": "npm:^1.1.5" + "@endo/pass-style": "npm:^1.4.3" + checksum: 10c0/0275010c155aa3e860ffb9d4de18d56db87f06552bbb9f2a81d4c678f9c503ac19c93eebe95fc727221209d889d5dc7853eaa70dc915edadb2943c3af87637d6 + languageName: node + linkType: hard + "@endo/base64@npm:^1.0.7": version: 1.0.7 resolution: "@endo/base64@npm:1.0.7" @@ -90,6 +220,17 @@ __metadata: languageName: node linkType: hard +"@endo/common@npm:^1.2.6": + version: 1.2.6 + resolution: "@endo/common@npm:1.2.6" + dependencies: + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/promise-kit": "npm:^1.1.6" + checksum: 10c0/7cca372677bd1ab535a0f8fc250eca9bfc202ef7dfd24cac6ff1260003aa4512f8db18419dd632b3e57270a589fec54891496904ff2e8a97047f1e187e3f1401 + languageName: node + linkType: hard + "@endo/env-options@npm:^1.1.6": version: 1.1.6 resolution: "@endo/env-options@npm:1.1.6" @@ -97,6 +238,13 @@ __metadata: languageName: node linkType: hard +"@endo/env-options@npm:^1.1.7": + version: 1.1.7 + resolution: "@endo/env-options@npm:1.1.7" + checksum: 10c0/5784bd68790041b08d9ead4f6c29cc7871d2e554c23fc44fff38cb20b6b4e55cdba2f78d844ba5ad4b0818185c32475ff318c1b77890d628690d7c7a6ede9475 + languageName: node + linkType: hard + "@endo/errors@npm:^1.2.2, @endo/errors@npm:^1.2.5": version: 1.2.5 resolution: "@endo/errors@npm:1.2.5" @@ -106,6 +254,15 @@ __metadata: languageName: node linkType: hard +"@endo/errors@npm:^1.2.6": + version: 1.2.6 + resolution: "@endo/errors@npm:1.2.6" + dependencies: + ses: "npm:^1.9.0" + checksum: 10c0/cbc541c2d26fbfeb1567dd1cdf0e1f110ee9866430c5a1b91d87270d6f00bc8293cc8512301217c4eda35e60677ce62a941d11eb32c7da1f72d450a011ad2bb5 + languageName: node + linkType: hard + "@endo/eventual-send@npm:^1.2.5": version: 1.2.5 resolution: "@endo/eventual-send@npm:1.2.5" @@ -115,6 +272,15 @@ __metadata: languageName: node linkType: hard +"@endo/eventual-send@npm:^1.2.6": + version: 1.2.6 + resolution: "@endo/eventual-send@npm:1.2.6" + dependencies: + "@endo/env-options": "npm:^1.1.7" + checksum: 10c0/6983d6b88bf4e99f6c469d4ca037793582b06cc0bfa2da085b5bc7ad67333a1fba6e5e7077b7f279be23ccfba1dff9e06c7f85f9980b09fd002227f89a673c11 + languageName: node + linkType: hard + "@endo/exo@npm:^1.2.1": version: 1.5.3 resolution: "@endo/exo@npm:1.5.3" @@ -130,6 +296,21 @@ __metadata: languageName: node linkType: hard +"@endo/exo@npm:^1.5.3": + version: 1.5.4 + resolution: "@endo/exo@npm:1.5.4" + dependencies: + "@endo/common": "npm:^1.2.6" + "@endo/env-options": "npm:^1.1.7" + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/far": "npm:^1.1.6" + "@endo/pass-style": "npm:^1.4.4" + "@endo/patterns": "npm:^1.4.4" + checksum: 10c0/674d2bfc50f8e7abdf7eb38ba3bb11dac9e84395bdccc3b06eef1076fcab3fd8fe38b9559bfef69f9d78287cd6c2d77533cfec68a57526812d833f1d57151425 + languageName: node + linkType: hard + "@endo/far@npm:^1.0.0, @endo/far@npm:^1.0.4, @endo/far@npm:^1.1.5": version: 1.1.5 resolution: "@endo/far@npm:1.1.5" @@ -141,6 +322,17 @@ __metadata: languageName: node linkType: hard +"@endo/far@npm:^1.1.6": + version: 1.1.6 + resolution: "@endo/far@npm:1.1.6" + dependencies: + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/pass-style": "npm:^1.4.4" + checksum: 10c0/0d001686f717601fd2a4609161e37235603bc2721fe1cc967247019f4d9bb583d6eafc56940a7d95d252ae2064a663f552d36b7fd15528ce207c3cd748f820ec + languageName: node + linkType: hard + "@endo/init@npm:^1.0.4, @endo/init@npm:^1.1.4": version: 1.1.4 resolution: "@endo/init@npm:1.1.4" @@ -176,6 +368,20 @@ __metadata: languageName: node linkType: hard +"@endo/marshal@npm:^1.5.4": + version: 1.5.4 + resolution: "@endo/marshal@npm:1.5.4" + dependencies: + "@endo/common": "npm:^1.2.6" + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/nat": "npm:^5.0.11" + "@endo/pass-style": "npm:^1.4.4" + "@endo/promise-kit": "npm:^1.1.6" + checksum: 10c0/4668a3678567cfbeefc3a47217912ca3f5d8bdb37e0d5d53339953b4ab83950683505f45c0f5c30b415c989bb9df4fa0859849d23b11f5b1064b0da0a13943ab + languageName: node + linkType: hard + "@endo/nat@npm:^5.0.10": version: 5.0.10 resolution: "@endo/nat@npm:5.0.10" @@ -183,6 +389,13 @@ __metadata: languageName: node linkType: hard +"@endo/nat@npm:^5.0.11": + version: 5.0.11 + resolution: "@endo/nat@npm:5.0.11" + checksum: 10c0/50cd9033657dd35288f0333a966984f788213f1c836e6772c0d731361d5854d0ce24b8a7d6f351d56618eb40f6b369e130c1ad939c83d5833246c09119b2e777 + languageName: node + linkType: hard + "@endo/pass-style@npm:^1.2.0, @endo/pass-style@npm:^1.4.3": version: 1.4.3 resolution: "@endo/pass-style@npm:1.4.3" @@ -196,6 +409,19 @@ __metadata: languageName: node linkType: hard +"@endo/pass-style@npm:^1.4.4": + version: 1.4.4 + resolution: "@endo/pass-style@npm:1.4.4" + dependencies: + "@endo/env-options": "npm:^1.1.7" + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/promise-kit": "npm:^1.1.6" + "@fast-check/ava": "npm:^1.1.5" + checksum: 10c0/d6c6268b269d4c14541087ce6b2975f9e31847893d01360c0ea92392ae93316d94fbf59cd7299853a0fb5214176ad7ffc4616b9b2581fd720bdb55ef96d0beeb + languageName: node + linkType: hard + "@endo/patterns@npm:^1.2.0, @endo/patterns@npm:^1.4.3": version: 1.4.3 resolution: "@endo/patterns@npm:1.4.3" @@ -209,6 +435,19 @@ __metadata: languageName: node linkType: hard +"@endo/patterns@npm:^1.4.4": + version: 1.4.4 + resolution: "@endo/patterns@npm:1.4.4" + dependencies: + "@endo/common": "npm:^1.2.6" + "@endo/errors": "npm:^1.2.6" + "@endo/eventual-send": "npm:^1.2.6" + "@endo/marshal": "npm:^1.5.4" + "@endo/promise-kit": "npm:^1.1.6" + checksum: 10c0/3e4c43b916134201b98cb3b17480f01aa15c2ce7a447b574f6ad8b8d1796fd929f2a21e7c541c50ad83afab51044cf03719bef9e48b455a0bec89d940287487b + languageName: node + linkType: hard + "@endo/promise-kit@npm:^1.0.4, @endo/promise-kit@npm:^1.1.5": version: 1.1.5 resolution: "@endo/promise-kit@npm:1.1.5" @@ -218,6 +457,15 @@ __metadata: languageName: node linkType: hard +"@endo/promise-kit@npm:^1.1.6": + version: 1.1.6 + resolution: "@endo/promise-kit@npm:1.1.6" + dependencies: + ses: "npm:^1.9.0" + checksum: 10c0/d60de663e58f9de32b6705268c62c63c4721f1874813d3c10cae7846e921e4ea8a60c8622ef8c937741a3387fbc60110076b25304afedf270727af7b0c3fecb3 + languageName: node + linkType: hard + "@endo/stream@npm:^1.1.0": version: 1.2.5 resolution: "@endo/stream@npm:1.2.5" @@ -229,6 +477,17 @@ __metadata: languageName: node linkType: hard +"@endo/stream@npm:^1.2.5": + version: 1.2.6 + resolution: "@endo/stream@npm:1.2.6" + dependencies: + "@endo/eventual-send": "npm:^1.2.6" + "@endo/promise-kit": "npm:^1.1.6" + ses: "npm:^1.9.0" + checksum: 10c0/76b686aae1614c23aff63ba1b5d5c57a25d331aba98becf4c02ca374e76cb13d455112841d84b1c6274e518f6d855cbcb8556efcb0ac09f8ccec2aa8c393f743 + languageName: node + linkType: hard + "@endo/zip@npm:^1.0.7": version: 1.0.7 resolution: "@endo/zip@npm:1.0.7" @@ -1844,7 +2103,7 @@ __metadata: languageName: node linkType: hard -"jessie.js@npm:^0.3.2": +"jessie.js@npm:^0.3.2, jessie.js@npm:^0.3.4": version: 0.3.4 resolution: "jessie.js@npm:0.3.4" dependencies: @@ -2511,6 +2770,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: + "@agoric/ertp": "npm:0.16.3-u17.1" "@agoric/internal": "npm:0.3.3-dev-5676146.0" "@agoric/synthetic-chain": "npm:^0.3.0" "@endo/errors": "npm:^1.2.2" @@ -2583,6 +2843,15 @@ __metadata: languageName: node linkType: hard +"ses@npm:^1.9.0": + version: 1.9.0 + resolution: "ses@npm:1.9.0" + dependencies: + "@endo/env-options": "npm:^1.1.7" + checksum: 10c0/356f9601b04a87f33403a15fc627caf0c649d86d8d7ee1f4b3c75b947ab05c31b254c94c0aa26e9904862787c73950d5a60f3435deebe5dba23017e20c40b0cb + languageName: node + linkType: hard + "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0"