From fd91f781ad721033d67485d1732272af0c689ae7 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Thu, 29 Aug 2024 14:15:41 -0700 Subject: [PATCH 1/7] feat: coreEval to update priceFeeds, auction, and vaultManager The primary goal is to stop using the original priceFeeds and scaledPriceAuthorities that are retaining old quotePayments. (see In order to do so, we also replace the auctioneer, and upgrade the vaultManager, since they have no mechanism for dynamically finding out about new priceAuthorities. There are bootstrap tests and a3p-integration/ tests here to demonstrate that after the upgrades and replacements, all these well-known vats are in touch with one another and liquidation still works. --- .../f:replace-price-feeds/.yarnrc.yml | 1 + .../proposals/f:replace-price-feeds/README.md | 10 + .../f:replace-price-feeds/agd-tools.js | 23 + .../f:replace-price-feeds/agoric-tools.js | 95 + .../proposals/f:replace-price-feeds/eval.sh | 15 + .../f:replace-price-feeds/package.json | 28 + .../priceFeedUpdate.test.js | 152 ++ .../resetChargingPeriod.js | 41 + .../proposals/f:replace-price-feeds/test.sh | 6 + .../proposals/f:replace-price-feeds/yarn.lock | 2345 +++++++++++++++++ .../priceFeed-follower-auction.test.js | 5 +- a3p-integration/scripts/build-submission.sh | 3 +- .../bootstrapTests/price-feed-replace.test.ts | 200 ++ .../updateGovernedParams.test.ts | 159 ++ packages/boot/test/tools/changeVaultParams.ts | 47 + packages/boot/tools/drivers.ts | 44 +- packages/boot/tools/liquidation.ts | 30 +- .../inter-protocol/updatePriceFeeds.js | 83 + .../builders/scripts/vats/priceFeedSupport.js | 53 +- .../src/econCommitteeCharter.js | 2 +- .../src/proposals/add-auction.js | 6 +- .../src/proposals/addAssetToVault.js | 22 +- .../src/proposals/deploy-price-feeds.js | 310 +++ .../src/proposals/price-feed-proposal.js | 3 +- .../replace-scaledPriceAuthorities.js | 119 + .../src/proposals/upgrade-vaults.js | 68 +- .../inter-protocol/src/proposals/utils.js | 8 + packages/vats/src/core/types-ambient.d.ts | 3 + .../contractSupport/priceAuthorityInitial.js | 2 +- .../priceAuthorityTransform.js | 2 +- .../zoe/src/contracts/scaledPriceAuthority.js | 4 +- 31 files changed, 3799 insertions(+), 90 deletions(-) create mode 100644 a3p-integration/proposals/f:replace-price-feeds/.yarnrc.yml create mode 100644 a3p-integration/proposals/f:replace-price-feeds/README.md create mode 100644 a3p-integration/proposals/f:replace-price-feeds/agd-tools.js create mode 100644 a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js create mode 100755 a3p-integration/proposals/f:replace-price-feeds/eval.sh create mode 100644 a3p-integration/proposals/f:replace-price-feeds/package.json create mode 100644 a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js create mode 100755 a3p-integration/proposals/f:replace-price-feeds/resetChargingPeriod.js create mode 100755 a3p-integration/proposals/f:replace-price-feeds/test.sh create mode 100644 a3p-integration/proposals/f:replace-price-feeds/yarn.lock create mode 100644 packages/boot/test/bootstrapTests/price-feed-replace.test.ts create mode 100644 packages/boot/test/bootstrapTests/updateGovernedParams.test.ts create mode 100644 packages/boot/test/tools/changeVaultParams.ts create mode 100644 packages/builders/scripts/inter-protocol/updatePriceFeeds.js create mode 100644 packages/inter-protocol/src/proposals/deploy-price-feeds.js create mode 100644 packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js diff --git a/a3p-integration/proposals/f:replace-price-feeds/.yarnrc.yml b/a3p-integration/proposals/f:replace-price-feeds/.yarnrc.yml new file mode 100644 index 00000000000..3186f3f0795 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/a3p-integration/proposals/f:replace-price-feeds/README.md b/a3p-integration/proposals/f:replace-price-feeds/README.md new file mode 100644 index 00000000000..414bb07fe81 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/README.md @@ -0,0 +1,10 @@ +# CoreEvalProposal to replace existing price_feed and scaledPriceAuthority vats +# with new contracts. Auctions will need to be replaced, and Vaults will need to +# get at least a null upgrade in order to make use of the new prices. Oracle +# operators will need to accept new invitations, and sync to the roundId (0) of +# the new contracts in order to feed the new pipelines. + +The `submission` for this proposal is automatically generated during `yarn build` +in [a3p-integration](../..) using the code in agoric-sdk through +[build-all-submissions.sh](../../scripts/build-all-submissions.sh) and +[build-submission.sh](../../scripts/build-submission.sh). diff --git a/a3p-integration/proposals/f:replace-price-feeds/agd-tools.js b/a3p-integration/proposals/f:replace-price-feeds/agd-tools.js new file mode 100644 index 00000000000..c94718bc1ba --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/agd-tools.js @@ -0,0 +1,23 @@ +import { agd } from '@agoric/synthetic-chain'; + +export const BID_OFFER_ID = 'bid-vaultUpgrade-test3'; + +/** @param {string} path */ +export const queryVstorage = path => + agd.query('vstorage', 'data', '--output', 'json', path); + +export const getOracleInstance = async price => { + const instanceRec = await queryVstorage(`published.agoricNames.instance`); + + const value = JSON.parse(instanceRec.value); + const body = JSON.parse(value.values.at(-1)); + + const feeds = JSON.parse(body.body.substring(1)); + const feedName = `${price}-USD price feed`; + + const key = Object.keys(feeds).find(k => feeds[k][0] === feedName); + if (key) { + return body.slots[key]; + } + return null; +}; diff --git a/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js b/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js new file mode 100644 index 00000000000..0f85fd52122 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js @@ -0,0 +1,95 @@ +import assert from 'node:assert'; +import { agops, agoric, executeOffer } from '@agoric/synthetic-chain'; + +export const generateVaultDirectorParamChange = async ( + previousOfferId, + voteDur, + params, + paramsPath, +) => { + const voteDurSec = BigInt(voteDur); + const toSec = ms => BigInt(Math.round(ms / 1000)); + + const id = `propose-${Date.now()}`; + const deadline = toSec(Date.now()) + voteDurSec; + + const zip = (xs, ys) => xs.map((x, i) => [x, ys[i]]); + const fromSmallCapsEntries = txt => { + const { body, slots } = JSON.parse(txt); + const theEntries = zip(JSON.parse(body.slice(1)), slots).map( + ([[name, ref], boardID]) => { + const iface = ref.replace(/^\$\d+\./, ''); + return [name, { iface, boardID }]; + }, + ); + return Object.fromEntries(theEntries); + }; + + const slots = []; // XXX global mutable state + const smallCaps = { + Nat: n => `+${n}`, + // XXX mutates obj + ref: obj => { + if (obj.ix) return obj.ix; + const ix = slots.length; + slots.push(obj.boardID); + obj.ix = `$${ix}.Alleged: ${obj.iface}`; + return obj.ix; + }, + }; + + await null; + const instance = fromSmallCapsEntries( + await agoric.follow('-lF', ':published.agoricNames.instance', '-o', 'text'), + ); + assert(instance.VaultFactory); + + const body = { + method: 'executeOffer', + offer: { + id, + invitationSpec: { + invitationMakerName: 'VoteOnParamChange', + previousOffer: previousOfferId, + source: 'continuing', + }, + offerArgs: { + deadline: smallCaps.Nat(deadline), + instance: smallCaps.ref(instance.VaultFactory), + params, + path: paramsPath, + }, + proposal: {}, + }, + }; + + const capData = { body: `#${JSON.stringify(body)}`, slots }; + return JSON.stringify(capData); +}; + +export const proposeVaultDirectorParamChange = async ( + address, + params, + path, +) => { + const charterAcceptOfferId = await agops.ec( + 'find-continuing-id', + '--for', + `${'charter\\ member\\ invitation'}`, + '--from', + address, + ); + + return executeOffer( + address, + generateVaultDirectorParamChange(charterAcceptOfferId, 30, params, path), + ); +}; + +export const voteForNewParams = (accounts, position) => { + return Promise.all( + accounts.map(account => + agops.ec('vote', '--forPosition', position, '--send-from', account), + ), + ); +}; diff --git a/a3p-integration/proposals/f:replace-price-feeds/eval.sh b/a3p-integration/proposals/f:replace-price-feeds/eval.sh new file mode 100755 index 00000000000..c44d11c5a35 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/eval.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Exit when any command fails +set -uxeo pipefail + +# The upgrade-vaults proposal needs to know the existing vaultDirector +# parameters in order to cleanly upgrade the contract. The governance notifier +# it relies on doesn't give the most recent value if there were no updates to +# the parameters, so we'll do a governance action to reset them to their current +# values so the notifier will work. + +./resetChargingPeriod.js + +cp /usr/src/upgrade-test-scripts/eval_submission.js . +./eval_submission.js diff --git a/a3p-integration/proposals/f:replace-price-feeds/package.json b/a3p-integration/proposals/f:replace-price-feeds/package.json new file mode 100644 index 00000000000..696ed9ca904 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/package.json @@ -0,0 +1,28 @@ +{ + "agoricProposal": { + "source": "subdir", + "sdk-generate": [ + "inter-protocol/updatePriceFeeds.js submission UNRELEASED_A3P_INTEGRATION", + "vats/add-auction.js", + "vats/upgradeVaults.js" + ], + "type": "/agoric.swingset.CoreEvalProposal" + }, + "type": "module", + "license": "Apache-2.0", + "dependencies": { + "@agoric/synthetic-chain": "^0.3.0", + "ava": "^5.3.1" + }, + "ava": { + "concurrency": 1, + "timeout": "2m", + "files": [ + "!submission" + ] + }, + "scripts": { + "agops": "yarn --cwd /usr/src/agoric-sdk/ --silent agops" + }, + "packageManager": "yarn@4.2.2" +} diff --git a/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js b/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js new file mode 100644 index 00000000000..19f4bea6cd3 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js @@ -0,0 +1,152 @@ +import test from 'ava'; + +import { + agops, + ATOM_DENOM, + bankSend, + createBid, + generateOracleMap, + getDetailsMatchingVats, + getInstanceBoardId, + getISTBalance, + getLiveOffers, + getPriceQuote, + getVaultPrices, + getVatDetails, + openVault, + pushPrices, + registerOraclesForBrand, + USER1ADDR, +} from '@agoric/synthetic-chain'; + +import { BID_OFFER_ID } from './agd-tools.js'; + +export const checkForOracle = async (t, name) => { + const instanceName = `${name}-USD price feed`; + const instance = await getInstanceBoardId(instanceName); + t.truthy(instance); +}; + +const checkPriceFeedVatsUpdated = async t => { + const atomDetails = await getVatDetails('ATOM-USD_price_feed'); + // both the original and the new ATOM vault are incarnation 0 + t.is(atomDetails.incarnation, 0); + const stAtomDetails = await getVatDetails('stATOM'); + t.is(stAtomDetails.incarnation, 0); + await checkForOracle(t, 'ATOM'); + await checkForOracle(t, 'stATOM'); +}; + +console.log('adding oracle for each brand'); +const oraclesByBrand = generateOracleMap('f-priceFeeds', ['ATOM', 'stATOM']); +await registerOraclesForBrand('ATOM', oraclesByBrand); +await registerOraclesForBrand('stATOM', oraclesByBrand); + +let roundId = 1; + +const tryPushPrices = async t => { + // There are no old prices for the other currencies. + // const atomOutPre = await getPriceQuote('ATOM'); + // t.is(atomOutPre, '+12010000'); + // const stAtomOutPre = await getPriceQuote('stATOM'); + // t.is(stAtomOutPre, '+12010000'); + + t.log('pushing new prices'); + await pushPrices(13.4, 'ATOM', oraclesByBrand, roundId); + await pushPrices(13.7, 'stATOM', oraclesByBrand, roundId); + roundId += 1; + + t.log('awaiting new quotes'); + const atomOut = await getPriceQuote('ATOM'); + t.is(atomOut, '+13400000'); + const stAtomOut = await getPriceQuote('stATOM'); + t.is(stAtomOut, '+13700000'); +}; + +const createNewBid = async t => { + await createBid('20', USER1ADDR, BID_OFFER_ID); + const liveOffer = await getLiveOffers(USER1ADDR); + t.true(liveOffer[0].includes(BID_OFFER_ID)); +}; + +const openMarginalVault = async t => { + let user1IST = await getISTBalance(USER1ADDR); + await bankSend(USER1ADDR, `20000000${ATOM_DENOM}`); + const currentVaults = await agops.vaults('list', '--from', USER1ADDR); + + t.log('opening a vault'); + await openVault(USER1ADDR, 5, 10); + user1IST += 5; + const istBalanceAfterVaultOpen = await getISTBalance(USER1ADDR); + t.is(istBalanceAfterVaultOpen, user1IST); + + const activeVaultsAfter = await agops.vaults('list', '--from', USER1ADDR); + t.log(currentVaults, activeVaultsAfter); + t.true( + activeVaultsAfter.length > currentVaults.length, + `vaults count should increase, ${activeVaultsAfter.length}, ${currentVaults.length}`, + ); +}; + +const triggerAuction = async t => { + await pushPrices(5.2, 'ATOM', oraclesByBrand, roundId); + + const atomOut = await getPriceQuote('ATOM'); + t.is(atomOut, '+5200000'); +}; + +const checkNewAuctionVat = async t => { + const details = await getDetailsMatchingVats('auctioneer'); + // This query matches both the auction and its governor, so double the count + t.true(Object.keys(details).length > 2); +}; + +const countPriceFeedVats = async t => { + // price_feed and governor, old and new for two tokens + const priceFeedDetails = await getDetailsMatchingVats('price_feed'); + t.is(Object.keys(priceFeedDetails).length, 8); + + // Two old SPAs, and two new ones + const details = await getDetailsMatchingVats('scaledPriceAuthority'); + t.is(Object.keys(details).length, 4); + + const atomDetails = await getDetailsMatchingVats('-ATOM-USD_price_feed'); + t.is(Object.keys(atomDetails).length, 4); + + const stAtomDetails = await getVatDetails('stATOM'); + t.is(Object.keys(stAtomDetails).length, 4); + await Promise.all([checkForOracle(t, 'ATOM'), checkForOracle(t, 'stATOM')]); +}; + +const verifyVaultPriceUpdate = async t => { + const quote = await getVaultPrices(0); + t.true(quote.value[0].amountIn.brand.includes(' ATOM ')); + t.is(quote.value[0].amountOut.value, '+5200000'); +}; + +// test.serial() isn't guaranteed to run tests in order, so we run the intended tests here +test('liquidation post upgrade', async t => { + t.log('starting upgrade vaults test'); + await checkPriceFeedVatsUpdated(t); + + t.log('starting pushPrices'); + await tryPushPrices(t); + + t.log('create a new Bid for the auction'); + await createNewBid(t); + + t.log('open a marginal vault'); + await openMarginalVault(t); + + t.log('trigger Auction'); + await triggerAuction(t); + + t.log('check new auction'); + await checkNewAuctionVat(t); + + t.log('count vats'); + await countPriceFeedVats(t); + + t.log('verify Vault priceUpdate'); + await verifyVaultPriceUpdate(t); +}); diff --git a/a3p-integration/proposals/f:replace-price-feeds/resetChargingPeriod.js b/a3p-integration/proposals/f:replace-price-feeds/resetChargingPeriod.js new file mode 100755 index 00000000000..c77494dddc6 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/resetChargingPeriod.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +/* global setTimeout */ + +import { + getQuoteBody, + GOV1ADDR, + GOV2ADDR, + GOV3ADDR, +} from '@agoric/synthetic-chain'; +import { + proposeVaultDirectorParamChange, + voteForNewParams, +} from './agoric-tools.js'; + +const GOV_ADDRESSES = [GOV1ADDR, GOV2ADDR, GOV3ADDR]; + +const readChargingPeriod = async () => { + const governanceBody = await getQuoteBody( + 'published.vaultFactory.governance', + ); + const period = + governanceBody.current.ChargingPeriod.value.match(/\+?(\d+)/)[1]; + return `+${period}`; +}; + +const setChargingPeriod = async period => { + const params = { + ChargingPeriod: period, + }; + + const path = { paramPath: { key: 'governedParams' } }; + + await proposeVaultDirectorParamChange(GOV1ADDR, params, path); + await voteForNewParams(GOV_ADDRESSES, 0); + + await new Promise(r => setTimeout(r, 65000)); +}; + +const period = await readChargingPeriod(); +await setChargingPeriod(period); diff --git a/a3p-integration/proposals/f:replace-price-feeds/test.sh b/a3p-integration/proposals/f:replace-price-feeds/test.sh new file mode 100755 index 00000000000..23a194f7f79 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Place here any test that should be executed using the proposal. +# The effects of this step are not persisted in further layers. + +yarn ava ./*.test.js diff --git a/a3p-integration/proposals/f:replace-price-feeds/yarn.lock b/a3p-integration/proposals/f:replace-price-feeds/yarn.lock new file mode 100644 index 00000000000..ee7a03e8e81 --- /dev/null +++ b/a3p-integration/proposals/f:replace-price-feeds/yarn.lock @@ -0,0 +1,2345 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@agoric/synthetic-chain@npm:^0.3.0": + version: 0.3.0 + resolution: "@agoric/synthetic-chain@npm:0.3.0" + dependencies: + "@endo/zip": "npm:^1.0.7" + better-sqlite3: "npm:^9.6.0" + chalk: "npm:^5.3.0" + cosmjs-types: "npm:^0.9.0" + execa: "npm:^9.3.1" + bin: + synthetic-chain: dist/cli/cli.js + checksum: 10c0/17c6241bdc48b8a2a7608c9d4d7c0a0c76fb10d4ee44a31a1150104a792bcd1133f4b1a7e8ab26673a07450b3ceabccd9911999117568221b49221b6ee4306a1 + languageName: node + linkType: hard + +"@endo/zip@npm:^1.0.7": + version: 1.0.7 + resolution: "@endo/zip@npm:1.0.7" + checksum: 10c0/a1c0d155448ce877012b34c8fe8cd3a58de9eb807514c81cddeebb802ee8e552b27d8a9a40fab3f3e4c49e0cb7fea6902fa1dd12a23ff6f30b56161fc3edc1f8 + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^2.0.0": + version: 2.2.2 + resolution: "@npmcli/agent@npm:2.2.2" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10c0/325e0db7b287d4154ecd164c0815c08007abfb07653cc57bceded17bb7fd240998a3cbdbe87d700e30bef494885eccc725ab73b668020811d56623d145b524ae + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.1 + resolution: "@npmcli/fs@npm:3.1.1" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/c37a5b4842bfdece3d14dfdb054f73fe15ed2d3da61b34ff76629fb5b1731647c49166fd2a8bf8b56fcfa51200382385ea8909a3cbecdad612310c114d3f6c99 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd + languageName: node + linkType: hard + +"@sec-ant/readable-stream@npm:^0.4.1": + version: 0.4.1 + resolution: "@sec-ant/readable-stream@npm:0.4.1" + checksum: 10c0/64e9e9cf161e848067a5bf60cdc04d18495dc28bb63a8d9f8993e4dd99b91ad34e4b563c85de17d91ffb177ec17a0664991d2e115f6543e73236a906068987af + languageName: node + linkType: hard + +"@sindresorhus/merge-streams@npm:^4.0.0": + version: 4.0.0 + resolution: "@sindresorhus/merge-streams@npm:4.0.0" + checksum: 10c0/482ee543629aa1933b332f811a1ae805a213681ecdd98c042b1c1b89387df63e7812248bb4df3910b02b3cc5589d3d73e4393f30e197c9dde18046ccd471fc6b + languageName: node + linkType: hard + +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.2.0": + version: 8.3.4 + resolution: "acorn-walk@npm:8.3.4" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/76537ac5fb2c37a64560feaf3342023dadc086c46da57da363e64c6148dc21b57d49ace26f949e225063acb6fb441eabffd89f7a3066de5ad37ab3e328927c62 + languageName: node + linkType: hard + +"acorn@npm:^8.11.0, acorn@npm:^8.8.2": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" + bin: + acorn: bin/acorn + checksum: 10c0/51fb26cd678f914e13287e886da2d7021f8c2bc0ccc95e03d3e0447ee278dd3b40b9c57dc222acd5881adcf26f3edc40901a4953403232129e3876793cd17386 + languageName: node + linkType: hard + +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: "npm:^4.3.4" + checksum: 10c0/e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 + languageName: node + linkType: hard + +"aggregate-error@npm:^4.0.0": + version: 4.0.1 + resolution: "aggregate-error@npm:4.0.1" + dependencies: + clean-stack: "npm:^4.0.0" + indent-string: "npm:^5.0.0" + checksum: 10c0/75fd739f5c4c60a667cce35ccaf0edf135e147ef0be9a029cab75de14ac9421779b15339d562e58d25b233ea0ef2bbd4c916f149fdbcb73c2b9a62209e611343 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.1.0 + resolution: "ansi-regex@npm:6.1.0" + checksum: 10c0/a91daeddd54746338478eef88af3439a7edf30f8e23196e2d6ed182da9add559c601266dbef01c2efa46a958ad6f1f8b176799657616c702b5b02e799e7fd8dc + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c + languageName: node + linkType: hard + +"anymatch@npm:~3.1.2": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" + dependencies: + normalize-path: "npm:^3.0.0" + picomatch: "npm:^2.0.4" + checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac + languageName: node + linkType: hard + +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: "npm:~1.0.2" + checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de + languageName: node + linkType: hard + +"array-find-index@npm:^1.0.1": + version: 1.0.2 + resolution: "array-find-index@npm:1.0.2" + checksum: 10c0/86b9485c74ddd324feab807e10a6de3f9c1683856267236fac4bb4d4667ada6463e106db3f6c540ae6b720e0442b590ec701d13676df4c6af30ebf4da09b4f57 + languageName: node + linkType: hard + +"arrgv@npm:^1.0.2": + version: 1.0.2 + resolution: "arrgv@npm:1.0.2" + checksum: 10c0/7e6e782e6b749923ac7cbc4048ef6fe0844c4a59bfc8932fcd4c44566ba25eed46501f94dd7cf3c7297da88f3f599ca056bfb77d0c2484aebc92f04239f69124 + languageName: node + linkType: hard + +"arrify@npm:^3.0.0": + version: 3.0.0 + resolution: "arrify@npm:3.0.0" + checksum: 10c0/2e26601b8486f29780f1f70f7ac05a226755814c2a3ab42e196748f650af1dc310cd575a11dd4b9841c70fd7460b2dd2b8fe6fb7a3375878e2660706efafa58e + languageName: node + linkType: hard + +"ava@npm:^5.3.1": + version: 5.3.1 + resolution: "ava@npm:5.3.1" + dependencies: + acorn: "npm:^8.8.2" + acorn-walk: "npm:^8.2.0" + ansi-styles: "npm:^6.2.1" + arrgv: "npm:^1.0.2" + arrify: "npm:^3.0.0" + callsites: "npm:^4.0.0" + cbor: "npm:^8.1.0" + chalk: "npm:^5.2.0" + chokidar: "npm:^3.5.3" + chunkd: "npm:^2.0.1" + ci-info: "npm:^3.8.0" + ci-parallel-vars: "npm:^1.0.1" + clean-yaml-object: "npm:^0.1.0" + cli-truncate: "npm:^3.1.0" + code-excerpt: "npm:^4.0.0" + common-path-prefix: "npm:^3.0.0" + concordance: "npm:^5.0.4" + currently-unhandled: "npm:^0.4.1" + debug: "npm:^4.3.4" + emittery: "npm:^1.0.1" + figures: "npm:^5.0.0" + globby: "npm:^13.1.4" + ignore-by-default: "npm:^2.1.0" + indent-string: "npm:^5.0.0" + is-error: "npm:^2.2.2" + is-plain-object: "npm:^5.0.0" + is-promise: "npm:^4.0.0" + matcher: "npm:^5.0.0" + mem: "npm:^9.0.2" + ms: "npm:^2.1.3" + p-event: "npm:^5.0.1" + p-map: "npm:^5.5.0" + picomatch: "npm:^2.3.1" + pkg-conf: "npm:^4.0.0" + plur: "npm:^5.1.0" + pretty-ms: "npm:^8.0.0" + resolve-cwd: "npm:^3.0.0" + stack-utils: "npm:^2.0.6" + strip-ansi: "npm:^7.0.1" + supertap: "npm:^3.0.1" + temp-dir: "npm:^3.0.0" + write-file-atomic: "npm:^5.0.1" + yargs: "npm:^17.7.2" + peerDependencies: + "@ava/typescript": "*" + peerDependenciesMeta: + "@ava/typescript": + optional: true + bin: + ava: entrypoints/cli.mjs + checksum: 10c0/262cbdb9e8c3ce7177be91b92ba521e9d5aef577dcc8095cc591f86baaa291b91c88925928f5d26832c4d1b381a6ae99f2e8804077c592d0d32322c1212605cc + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf + languageName: node + linkType: hard + +"better-sqlite3@npm:^9.6.0": + version: 9.6.0 + resolution: "better-sqlite3@npm:9.6.0" + dependencies: + bindings: "npm:^1.5.0" + node-gyp: "npm:latest" + prebuild-install: "npm:^7.1.1" + checksum: 10c0/8db9b38f414e26a56d4c40fc16e94a253118491dae0e2c054338a9e470f1a883c7eb4cb330f2f5737db30f704d4f2e697c59071ca04e03364ee9fe04375aa9c8 + languageName: node + linkType: hard + +"binary-extensions@npm:^2.0.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 + languageName: node + linkType: hard + +"bindings@npm:^1.5.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: "npm:1.0.0" + checksum: 10c0/3dab2491b4bb24124252a91e656803eac24292473e56554e35bbfe3cc1875332cfa77600c3bac7564049dc95075bf6fcc63a4609920ff2d64d0fe405fcf0d4ba + languageName: node + linkType: hard + +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: "npm:^5.5.0" + inherits: "npm:^2.0.4" + readable-stream: "npm:^3.4.0" + checksum: 10c0/02847e1d2cb089c9dc6958add42e3cdeaf07d13f575973963335ac0fdece563a50ac770ac4c8fa06492d2dd276f6cc3b7f08c7cd9c7a7ad0f8d388b2a28def5f + languageName: node + linkType: hard + +"blueimp-md5@npm:^2.10.0": + version: 2.19.0 + resolution: "blueimp-md5@npm:2.19.0" + checksum: 10c0/85d04343537dd99a288c62450341dcce7380d3454c81f8e5a971ddd80307d6f9ef51b5b92ad7d48aaaa92fd6d3a1f6b2f4fada068faae646887f7bfabc17a346 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f + languageName: node + linkType: hard + +"braces@npm:^3.0.3, braces@npm:~3.0.2": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 + languageName: node + linkType: hard + +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.1.13" + checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + languageName: node + linkType: hard + +"cacache@npm:^18.0.0": + version: 18.0.4 + resolution: "cacache@npm:18.0.4" + dependencies: + "@npmcli/fs": "npm:^3.1.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^4.0.0" + ssri: "npm:^10.0.0" + tar: "npm:^6.1.11" + unique-filename: "npm:^3.0.0" + checksum: 10c0/6c055bafed9de4f3dcc64ac3dc7dd24e863210902b7c470eb9ce55a806309b3efff78033e3d8b4f7dcc5d467f2db43c6a2857aaaf26f0094b8a351d44c42179f + languageName: node + linkType: hard + +"callsites@npm:^4.0.0": + version: 4.2.0 + resolution: "callsites@npm:4.2.0" + checksum: 10c0/8f7e269ec09fc0946bb22d838a8bc7932e1909ab4a833b964749f4d0e8bdeaa1f253287c4f911f61781f09620b6925ccd19a5ea4897489c4e59442c660c312a3 + languageName: node + linkType: hard + +"cbor@npm:^8.1.0": + version: 8.1.0 + resolution: "cbor@npm:8.1.0" + dependencies: + nofilter: "npm:^3.1.0" + checksum: 10c0/a836e2e7ea0efb1b9c4e5a4be906c57113d730cc42293a34072e0164ed110bb8ac035dc7dca2e3ebb641bd4b37e00fdbbf09c951aa864b3d4888a6ed8c6243f7 + languageName: node + linkType: hard + +"chalk@npm:^5.2.0, chalk@npm:^5.3.0": + version: 5.3.0 + resolution: "chalk@npm:5.3.0" + checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 + languageName: node + linkType: hard + +"chokidar@npm:^3.5.3": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" + dependencies: + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" + dependenciesMeta: + fsevents: + optional: true + checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 + languageName: node + linkType: hard + +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 + languageName: node + linkType: hard + +"chunkd@npm:^2.0.1": + version: 2.0.1 + resolution: "chunkd@npm:2.0.1" + checksum: 10c0/4e0c5aac6048ecedfa4cd0a5f6c4f010c70a7b7645aeca7bfeb47cb0733c3463054f0ced3f2667b2e0e67edd75d68a8e05481b01115ba3f8a952a93026254504 + languageName: node + linkType: hard + +"ci-info@npm:^3.8.0": + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 10c0/6f0109e36e111684291d46123d491bc4e7b7a1934c3a20dea28cba89f1d4a03acd892f5f6a81ed3855c38647e285a150e3c9ba062e38943bef57fee6c1554c3a + languageName: node + linkType: hard + +"ci-parallel-vars@npm:^1.0.1": + version: 1.0.1 + resolution: "ci-parallel-vars@npm:1.0.1" + checksum: 10c0/80952f699cbbc146092b077b4f3e28d085620eb4e6be37f069b4dbb3db0ee70e8eec3beef4ebe70ff60631e9fc743b9d0869678489f167442cac08b260e5ac08 + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 + languageName: node + linkType: hard + +"clean-stack@npm:^4.0.0": + version: 4.2.0 + resolution: "clean-stack@npm:4.2.0" + dependencies: + escape-string-regexp: "npm:5.0.0" + checksum: 10c0/2bdf981a0fef0a23c14255df693b30eb9ae27eedf212470d8c400a0c0b6fb82fbf1ff8c5216ccd5721e3670b700389c886b1dce5070776dc9fbcc040957758c0 + languageName: node + linkType: hard + +"clean-yaml-object@npm:^0.1.0": + version: 0.1.0 + resolution: "clean-yaml-object@npm:0.1.0" + checksum: 10c0/a6505310590038afb9f0adc7f17a4c66787719c94d23f8491267ea4d9c405cdd378bd576ae1926169b6d997d4c59a8b86516bf4d16ba228280cf615598c58e05 + languageName: node + linkType: hard + +"cli-truncate@npm:^3.1.0": + version: 3.1.0 + resolution: "cli-truncate@npm:3.1.0" + dependencies: + slice-ansi: "npm:^5.0.0" + string-width: "npm:^5.0.0" + checksum: 10c0/a19088878409ec0e5dc2659a5166929629d93cfba6d68afc9cde2282fd4c751af5b555bf197047e31c87c574396348d011b7aa806fec29c4139ea4f7f00b324c + languageName: node + linkType: hard + +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 + languageName: node + linkType: hard + +"code-excerpt@npm:^4.0.0": + version: 4.0.0 + resolution: "code-excerpt@npm:4.0.0" + dependencies: + convert-to-spaces: "npm:^2.0.1" + checksum: 10c0/b6c5a06e039cecd2ab6a0e10ee0831de8362107d1f298ca3558b5f9004cb8e0260b02dd6c07f57b9a0e346c76864d2873311ee1989809fdeb05bd5fbbadde773 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: 10c0/c4a74294e1b1570f4a8ab435285d185a03976c323caa16359053e749db4fde44e3e6586c29cd051100335e11895767cbbd27ea389108e327d62f38daf4548fdb + languageName: node + linkType: hard + +"concordance@npm:^5.0.4": + version: 5.0.4 + resolution: "concordance@npm:5.0.4" + dependencies: + date-time: "npm:^3.1.0" + esutils: "npm:^2.0.3" + fast-diff: "npm:^1.2.0" + js-string-escape: "npm:^1.0.1" + lodash: "npm:^4.17.15" + md5-hex: "npm:^3.0.1" + semver: "npm:^7.3.2" + well-known-symbols: "npm:^2.0.0" + checksum: 10c0/59b440f330df3a7c9aa148ba588b3e99aed86acab225b4f01ffcea34ace4cf11f817e31153254e8f38ed48508998dad40b9106951a743c334d751f7ab21afb8a + languageName: node + linkType: hard + +"convert-to-spaces@npm:^2.0.1": + version: 2.0.1 + resolution: "convert-to-spaces@npm:2.0.1" + checksum: 10c0/d90aa0e3b6a27f9d5265a8d32def3c5c855b3e823a9db1f26d772f8146d6b91020a2fdfd905ce8048a73fad3aaf836fef8188c67602c374405e2ae8396c4ac46 + languageName: node + linkType: hard + +"cosmjs-types@npm:^0.9.0": + version: 0.9.0 + resolution: "cosmjs-types@npm:0.9.0" + checksum: 10c0/bc20f4293fb34629d7c5f96bafe533987f753df957ff68eb078d0128ae5a418320cb945024441769a07bb9bc5dde9d22b972fd40d485933e5706ea191c43727b + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3": + version: 7.0.3 + resolution: "cross-spawn@npm:7.0.3" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 + languageName: node + linkType: hard + +"currently-unhandled@npm:^0.4.1": + version: 0.4.1 + resolution: "currently-unhandled@npm:0.4.1" + dependencies: + array-find-index: "npm:^1.0.1" + checksum: 10c0/32d197689ec32f035910202c1abb0dc6424dce01d7b51779c685119b380d98535c110ffff67a262fc7e367612a7dfd30d3d3055f9a6634b5a9dd1302de7ef11c + languageName: node + linkType: hard + +"date-time@npm:^3.1.0": + version: 3.1.0 + resolution: "date-time@npm:3.1.0" + dependencies: + time-zone: "npm:^1.0.0" + checksum: 10c0/aa3e2e930d74b0b9e90f69de7a16d3376e30f21f1f4ce9a2311d8fec32d760e776efea752dafad0ce188187265235229013036202be053fc2d7979813bfb6ded + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.4": + version: 4.3.7 + resolution: "debug@npm:4.3.7" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/1471db19c3b06d485a622d62f65947a19a23fbd0dd73f7fd3eafb697eec5360cde447fb075919987899b1a2096e85d35d4eb5a4de09a57600ac9cf7e6c8e768b + languageName: node + linkType: hard + +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e + languageName: node + linkType: hard + +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.0": + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 10c0/88095bda8f90220c95f162bf92cad70bd0e424913e655c20578600e35b91edc261af27531cf160a331e185c0ced93944bc7e09939143225f56312d7fd800fdb7 + languageName: node + linkType: hard + +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: "npm:^4.0.0" + checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 + languageName: node + linkType: hard + +"emittery@npm:^1.0.1": + version: 1.0.3 + resolution: "emittery@npm:1.0.3" + checksum: 10c0/91605d044f3891dd1f8ab731aeb94b520488b21e707f7064dcbcf5303bac3b4e7133dfa23c343ede1fc970340bd78a9b1aed522b805bc15104606bba630dd71e + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.4 + resolution: "end-of-stream@npm:1.4.4" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 + languageName: node + linkType: hard + +"escalade@npm:^3.1.1": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"escape-string-regexp@npm:5.0.0, escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 10c0/2530479fe8db57eace5e8646c9c2a9c80fa279614986d16dcc6bcaceb63ae77f05a851ba6c43756d816c61d7f4534baf56e3c705e3e0d884818a46808811c507 + languageName: node + linkType: hard + +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 + languageName: node + linkType: hard + +"esutils@npm:^2.0.3": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + languageName: node + linkType: hard + +"execa@npm:^9.3.1": + version: 9.4.0 + resolution: "execa@npm:9.4.0" + dependencies: + "@sindresorhus/merge-streams": "npm:^4.0.0" + cross-spawn: "npm:^7.0.3" + figures: "npm:^6.1.0" + get-stream: "npm:^9.0.0" + human-signals: "npm:^8.0.0" + is-plain-obj: "npm:^4.1.0" + is-stream: "npm:^4.0.1" + npm-run-path: "npm:^6.0.0" + pretty-ms: "npm:^9.0.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^4.0.0" + yoctocolors: "npm:^2.0.0" + checksum: 10c0/6ad06c627b5d7bb007bc7b6cc35d7e32b5a3365375ffc8ddbcc12d2423651fa9928ba0c447cc9e60079e505e9b24fbe0a57f80371511d7d20302c04c2d3ce95e + languageName: node + linkType: hard + +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 10c0/1c9e7afe9acadf9d373301d27f6a47b34e89b3391b1ef38b7471d381812537ef2457e620ae7f819d2642ce9c43b189b3583813ec395e2938319abe356a9b2f51 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 + languageName: node + linkType: hard + +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 + languageName: node + linkType: hard + +"fast-glob@npm:^3.3.0": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10c0/42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845 + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.17.1 + resolution: "fastq@npm:1.17.1" + dependencies: + reusify: "npm:^1.0.4" + checksum: 10c0/1095f16cea45fb3beff558bb3afa74ca7a9250f5a670b65db7ed585f92b4b48381445cd328b3d87323da81e43232b5d5978a8201bde84e0cd514310f1ea6da34 + languageName: node + linkType: hard + +"figures@npm:^5.0.0": + version: 5.0.0 + resolution: "figures@npm:5.0.0" + dependencies: + escape-string-regexp: "npm:^5.0.0" + is-unicode-supported: "npm:^1.2.0" + checksum: 10c0/ce0f17d4ea8b0fc429c5207c343534a2f5284ecfb22aa08607da7dc84ed9e1cf754f5b97760e8dcb98d3c9d1a1e4d3d578fe3b5b99c426f05d0f06c7ba618e16 + languageName: node + linkType: hard + +"figures@npm:^6.1.0": + version: 6.1.0 + resolution: "figures@npm:6.1.0" + dependencies: + is-unicode-supported: "npm:^2.0.0" + checksum: 10c0/9159df4264d62ef447a3931537de92f5012210cf5135c35c010df50a2169377581378149abfe1eb238bd6acbba1c0d547b1f18e0af6eee49e30363cedaffcfe4 + languageName: node + linkType: hard + +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: 10c0/3b545e3a341d322d368e880e1c204ef55f1d45cdea65f7efc6c6ce9e0c4d22d802d5629320eb779d006fe59624ac17b0e848d83cc5af7cd101f206cb704f5519 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 + languageName: node + linkType: hard + +"find-up@npm:^6.0.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: "npm:^7.1.0" + path-exists: "npm:^5.0.0" + checksum: 10c0/07e0314362d316b2b13f7f11ea4692d5191e718ca3f7264110127520f3347996349bf9e16805abae3e196805814bc66ef4bff2b8904dc4a6476085fc9b0eba07 + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.3.0 + resolution: "foreground-child@npm:3.3.0" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2 + languageName: node + linkType: hard + +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 10c0/a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"get-caller-file@npm:^2.0.5": + version: 2.0.5 + resolution: "get-caller-file@npm:2.0.5" + checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde + languageName: node + linkType: hard + +"get-stream@npm:^9.0.0": + version: 9.0.1 + resolution: "get-stream@npm:9.0.1" + dependencies: + "@sec-ant/readable-stream": "npm:^0.4.1" + is-stream: "npm:^4.0.1" + checksum: 10c0/d70e73857f2eea1826ac570c3a912757dcfbe8a718a033fa0c23e12ac8e7d633195b01710e0559af574cbb5af101009b42df7b6f6b29ceec8dbdf7291931b948 + languageName: node + linkType: hard + +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 10c0/737ee3f52d0a27e26332cde85b533c21fcdc0b09fb716c3f8e522cfaa9c600d4a631dec9fcde179ec9d47cca89017b7848ed4d6ae6b6b78f936c06825b1fcc12 + languageName: node + linkType: hard + +"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee + languageName: node + linkType: hard + +"glob@npm:^10.2.2, glob@npm:^10.3.10": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e + languageName: node + linkType: hard + +"globby@npm:^13.1.4": + version: 13.2.2 + resolution: "globby@npm:13.2.2" + dependencies: + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.3.0" + ignore: "npm:^5.2.4" + merge2: "npm:^1.4.1" + slash: "npm:^4.0.0" + checksum: 10c0/a8d7cc7cbe5e1b2d0f81d467bbc5bc2eac35f74eaded3a6c85fc26d7acc8e6de22d396159db8a2fc340b8a342e74cac58de8f4aee74146d3d146921a76062664 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c + languageName: node + linkType: hard + +"human-signals@npm:^8.0.0": + version: 8.0.0 + resolution: "human-signals@npm:8.0.0" + checksum: 10c0/e4dac4f7d3eb791ed04129fc6a85bd454a9102d3e3b76c911d0db7057ebd60b2956b435b5b5712aec18960488ede3c21ef7c56e42cdd70760c0d84d3c05cd92e + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + languageName: node + linkType: hard + +"ignore-by-default@npm:^2.1.0": + version: 2.1.0 + resolution: "ignore-by-default@npm:2.1.0" + checksum: 10c0/3a6040dac25ed9da39dee73bf1634fdd1e15b0eb7cf52a6bdec81c310565782d8811c104ce40acb3d690d61c5fc38a91c78e6baee830a8a2232424dbc6b66981 + languageName: node + linkType: hard + +"ignore@npm:^5.2.4": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f + languageName: node + linkType: hard + +"indent-string@npm:^5.0.0": + version: 5.0.0 + resolution: "indent-string@npm:5.0.0" + checksum: 10c0/8ee77b57d92e71745e133f6f444d6fa3ed503ad0e1bcd7e80c8da08b42375c07117128d670589725ed07b1978065803fa86318c309ba45415b7fe13e7f170220 + languageName: node + linkType: hard + +"inherits@npm:^2.0.3, inherits@npm:^2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc + languageName: node + linkType: hard + +"irregular-plurals@npm:^3.3.0": + version: 3.5.0 + resolution: "irregular-plurals@npm:3.5.0" + checksum: 10c0/7c033bbe7325e5a6e0a26949cc6863b6ce273403d4cd5b93bd99b33fecb6605b0884097c4259c23ed0c52c2133bf7d1cdcdd7a0630e8c325161fe269b3447918 + languageName: node + linkType: hard + +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" + dependencies: + binary-extensions: "npm:^2.0.0" + checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 + languageName: node + linkType: hard + +"is-error@npm:^2.2.2": + version: 2.2.2 + resolution: "is-error@npm:2.2.2" + checksum: 10c0/475d3463968bf16e94485555d7cb7a879ed68685e08d365a3370972e626054f1846ebbb3934403091e06682445568601fe919e41646096e5007952d0c1f4fd9b + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^4.0.0": + version: 4.0.0 + resolution: "is-fullwidth-code-point@npm:4.0.0" + checksum: 10c0/df2a717e813567db0f659c306d61f2f804d480752526886954a2a3e2246c7745fd07a52b5fecf2b68caf0a6c79dcdace6166fdf29cc76ed9975cc334f0a018b8 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 10c0/85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 + languageName: node + linkType: hard + +"is-plain-obj@npm:^4.1.0": + version: 4.1.0 + resolution: "is-plain-obj@npm:4.1.0" + checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e + languageName: node + linkType: hard + +"is-plain-object@npm:^5.0.0": + version: 5.0.0 + resolution: "is-plain-object@npm:5.0.0" + checksum: 10c0/893e42bad832aae3511c71fd61c0bf61aa3a6d853061c62a307261842727d0d25f761ce9379f7ba7226d6179db2a3157efa918e7fe26360f3bf0842d9f28942c + languageName: node + linkType: hard + +"is-promise@npm:^4.0.0": + version: 4.0.0 + resolution: "is-promise@npm:4.0.0" + checksum: 10c0/ebd5c672d73db781ab33ccb155fb9969d6028e37414d609b115cc534654c91ccd061821d5b987eefaa97cf4c62f0b909bb2f04db88306de26e91bfe8ddc01503 + languageName: node + linkType: hard + +"is-stream@npm:^4.0.1": + version: 4.0.1 + resolution: "is-stream@npm:4.0.1" + checksum: 10c0/2706c7f19b851327ba374687bc4a3940805e14ca496dc672b9629e744d143b1ad9c6f1b162dece81c7bfbc0f83b32b61ccc19ad2e05aad2dd7af347408f60c7f + languageName: node + linkType: hard + +"is-unicode-supported@npm:^1.2.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10c0/b8674ea95d869f6faabddc6a484767207058b91aea0250803cbf1221345cb0c56f466d4ecea375dc77f6633d248d33c47bd296fb8f4cdba0b4edba8917e83d8a + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10c0/a0f53e9a7c1fdbcf2d2ef6e40d4736fdffff1c9f8944c75e15425118ff3610172c87bf7bc6c34d3903b04be59790bb2212ddbe21ee65b5a97030fc50370545a5 + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 + languageName: node + linkType: hard + +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 + languageName: node + linkType: hard + +"js-string-escape@npm:^1.0.1": + version: 1.0.1 + resolution: "js-string-escape@npm:1.0.1" + checksum: 10c0/2c33b9ff1ba6b84681c51ca0997e7d5a1639813c95d5b61cb7ad47e55cc28fa4a0b1935c3d218710d8e6bcee5d0cd8c44755231e3a4e45fc604534d9595a3628 + languageName: node + linkType: hard + +"js-yaml@npm:^3.14.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: "npm:^1.0.7" + esprima: "npm:^4.0.0" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/6746baaaeac312c4db8e75fa22331d9a04cccb7792d126ed8ce6a0bbcfef0cedaddd0c5098fade53db067c09fe00aa1c957674b4765610a8b06a5a189e46433b + languageName: node + linkType: hard + +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 + languageName: node + linkType: hard + +"load-json-file@npm:^7.0.0": + version: 7.0.1 + resolution: "load-json-file@npm:7.0.1" + checksum: 10c0/7117459608a0b6329c7f78e6e1f541b3162dd901c29dd5af721fec8b270177d2e3d7999c971f344fff04daac368d052732e2c7146014bc84d15e0b636975e19a + languageName: node + linkType: hard + +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: "npm:^6.0.0" + checksum: 10c0/139e8a7fe11cfbd7f20db03923cacfa5db9e14fa14887ea121345597472b4a63c1a42a8a5187defeeff6acf98fd568da7382aa39682d38f0af27433953a97751 + languageName: node + linkType: hard + +"lodash@npm:^4.17.15": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb + languageName: node + linkType: hard + +"make-fetch-happen@npm:^13.0.0": + version: 13.0.1 + resolution: "make-fetch-happen@npm:13.0.1" + dependencies: + "@npmcli/agent": "npm:^2.0.0" + cacache: "npm:^18.0.0" + http-cache-semantics: "npm:^4.1.1" + is-lambda: "npm:^1.0.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^3.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^0.6.3" + proc-log: "npm:^4.2.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^10.0.0" + checksum: 10c0/df5f4dbb6d98153b751bccf4dc4cc500de85a96a9331db9805596c46aa9f99d9555983954e6c1266d9f981ae37a9e4647f42b9a4bb5466f867f4012e582c9e7e + languageName: node + linkType: hard + +"map-age-cleaner@npm:^0.1.3": + version: 0.1.3 + resolution: "map-age-cleaner@npm:0.1.3" + dependencies: + p-defer: "npm:^1.0.0" + checksum: 10c0/7495236c7b0950956c144fd8b4bc6399d4e78072a8840a4232fe1c4faccbb5eb5d842e5c0a56a60afc36d723f315c1c672325ca03c1b328650f7fcc478f385fd + languageName: node + linkType: hard + +"matcher@npm:^5.0.0": + version: 5.0.0 + resolution: "matcher@npm:5.0.0" + dependencies: + escape-string-regexp: "npm:^5.0.0" + checksum: 10c0/eda5471fc9d5b7264d63c81727824adc3585ddb5cfdc5fce5a9b7c86f946ff181610735d330b1c37a84811df872d1290bf4e9401d2be2a414204343701144b18 + languageName: node + linkType: hard + +"md5-hex@npm:^3.0.1": + version: 3.0.1 + resolution: "md5-hex@npm:3.0.1" + dependencies: + blueimp-md5: "npm:^2.10.0" + checksum: 10c0/ee2b4d8da16b527b3a3fe4d7a96720f43afd07b46a82d49421208b5a126235fb75cfb30b80d4029514772c8844273f940bddfbf4155c787f968f3be4060d01e4 + languageName: node + linkType: hard + +"mem@npm:^9.0.2": + version: 9.0.2 + resolution: "mem@npm:9.0.2" + dependencies: + map-age-cleaner: "npm:^0.1.3" + mimic-fn: "npm:^4.0.0" + checksum: 10c0/c2c56141399e520d8f0e50186bb7e4b49300b33984dc919682f3f13e53dec0e6608fbd327d5ae99494f45061a3a05a8ee04ccba6dcf795c3c215b5aa906eb41f + languageName: node + linkType: hard + +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb + languageName: node + linkType: hard + +"micromatch@npm:^4.0.4": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + +"mimic-fn@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-fn@npm:4.0.0" + checksum: 10c0/de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf + languageName: node + linkType: hard + +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + languageName: node + linkType: hard + +"minimist@npm:^1.2.0, minimist@npm:^1.2.3": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.5 + resolution: "minipass-fetch@npm:3.0.5" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^2.1.2" + dependenciesMeta: + encoding: + optional: true + checksum: 10c0/9d702d57f556274286fdd97e406fc38a2f5c8d15e158b498d7393b1105974b21249289ec571fa2b51e038a4872bfc82710111cf75fae98c662f3d6f95e72152b + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c + languageName: node + linkType: hard + +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 + languageName: node + linkType: hard + +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 10c0/95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 + languageName: node + linkType: hard + +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf + languageName: node + linkType: hard + +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"napi-build-utils@npm:^1.0.1": + version: 1.0.2 + resolution: "napi-build-utils@npm:1.0.2" + checksum: 10c0/37fd2cd0ff2ad20073ce78d83fd718a740d568b225924e753ae51cb69d68f330c80544d487e5e5bd18e28702ed2ca469c2424ad948becd1862c1b0209542b2e9 + languageName: node + linkType: hard + +"negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 + languageName: node + linkType: hard + +"node-abi@npm:^3.3.0": + version: 3.67.0 + resolution: "node-abi@npm:3.67.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/72ce2edbdfb84745bc201a4e48aa7146fd88a0d2c80046b6b17f28439c9a7683eab846f40f1e819349c31f7d9331ed5c50d1e741208d938dd5f38b29cab2275e + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 10.2.0 + resolution: "node-gyp@npm:10.2.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^13.0.0" + nopt: "npm:^7.0.0" + proc-log: "npm:^4.1.0" + semver: "npm:^7.3.5" + tar: "npm:^6.2.1" + which: "npm:^4.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/00630d67dbd09a45aee0a5d55c05e3916ca9e6d427ee4f7bc392d2d3dc5fad7449b21fc098dd38260a53d9dcc9c879b36704a1994235d4707e7271af7e9a835b + languageName: node + linkType: hard + +"nofilter@npm:^3.1.0": + version: 3.1.0 + resolution: "nofilter@npm:3.1.0" + checksum: 10c0/92459f3864a067b347032263f0b536223cbfc98153913b5dce350cb39c8470bc1813366e41993f22c33cc6400c0f392aa324a4b51e24c22040635c1cdb046499 + languageName: node + linkType: hard + +"nopt@npm:^7.0.0": + version: 7.2.1 + resolution: "nopt@npm:7.2.1" + dependencies: + abbrev: "npm:^2.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/a069c7c736767121242037a22a788863accfa932ab285a1eb569eb8cd534b09d17206f68c37f096ae785647435e0c5a5a0a67b42ec743e481a455e5ae6a6df81 + languageName: node + linkType: hard + +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 + languageName: node + linkType: hard + +"npm-run-path@npm:^6.0.0": + version: 6.0.0 + resolution: "npm-run-path@npm:6.0.0" + dependencies: + path-key: "npm:^4.0.0" + unicorn-magic: "npm:^0.3.0" + checksum: 10c0/b223c8a0dcd608abf95363ea5c3c0ccc3cd877daf0102eaf1b0f2390d6858d8337fbb7c443af2403b067a7d2c116d10691ecd22ab3c5273c44da1ff8d07753bd + languageName: node + linkType: hard + +"once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + languageName: node + linkType: hard + +"p-defer@npm:^1.0.0": + version: 1.0.0 + resolution: "p-defer@npm:1.0.0" + checksum: 10c0/ed603c3790e74b061ac2cb07eb6e65802cf58dce0fbee646c113a7b71edb711101329ad38f99e462bd2e343a74f6e9366b496a35f1d766c187084d3109900487 + languageName: node + linkType: hard + +"p-event@npm:^5.0.1": + version: 5.0.1 + resolution: "p-event@npm:5.0.1" + dependencies: + p-timeout: "npm:^5.0.2" + checksum: 10c0/2317171489537f316661fa863f3bb711b2ceb89182937238422cec10223cbb958c432d6c26a238446a622d788187bdd295b1d8ecedbe2e467e045930d60202b0 + languageName: node + linkType: hard + +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: "npm:^1.0.0" + checksum: 10c0/a56af34a77f8df2ff61ddfb29431044557fcbcb7642d5a3233143ebba805fc7306ac1d448de724352861cb99de934bc9ab74f0d16fe6a5460bdbdf938de875ad + languageName: node + linkType: hard + +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: "npm:^4.0.0" + checksum: 10c0/d72fa2f41adce59c198270aa4d3c832536c87a1806e0f69dffb7c1a7ca998fb053915ca833d90f166a8c082d3859eabfed95f01698a3214c20df6bb8de046312 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 + languageName: node + linkType: hard + +"p-map@npm:^5.5.0": + version: 5.5.0 + resolution: "p-map@npm:5.5.0" + dependencies: + aggregate-error: "npm:^4.0.0" + checksum: 10c0/410bce846b1e3db6bb2ccab6248372ecf4e635fc2b31331c8f56478e73fec9e146e8b4547585e635703160a3d252a6a65b8f855834aebc2c3408eb5789630cc4 + languageName: node + linkType: hard + +"p-timeout@npm:^5.0.2": + version: 5.1.0 + resolution: "p-timeout@npm:5.1.0" + checksum: 10c0/1b026cf9d5878c64bec4341ca9cda8ec6b8b3aea8a57885ca0fe2b35753a20d767fb6f9d3aa41e1252f42bc95432c05ea33b6b18f271fb10bfb0789591850a41 + languageName: node + linkType: hard + +"package-json-from-dist@npm:^1.0.0": + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033 + languageName: node + linkType: hard + +"parse-ms@npm:^3.0.0": + version: 3.0.0 + resolution: "parse-ms@npm:3.0.0" + checksum: 10c0/056b4a32a9d3749f3f4cfffefb45c45540491deaa8e1d8ad43c2ddde7ba04edd076bd1b298f521238bb5fb084a9b2c4a2ebb78aefa651afbc4c2b0af4232fc54 + languageName: node + linkType: hard + +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16 + languageName: node + linkType: hard + +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 10c0/b170f3060b31604cde93eefdb7392b89d832dfbc1bed717c9718cbe0f230c1669b7e75f87e19901da2250b84d092989a0f9e44d2ef41deb09aa3ad28e691a40a + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 + languageName: node + linkType: hard + +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c + languageName: node + linkType: hard + +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + languageName: node + linkType: hard + +"pkg-conf@npm:^4.0.0": + version: 4.0.0 + resolution: "pkg-conf@npm:4.0.0" + dependencies: + find-up: "npm:^6.0.0" + load-json-file: "npm:^7.0.0" + checksum: 10c0/27d027609f27228edcde121f6f707b4ba1f5488e95e98f2e58652ae4e99792081bd1de67d591f4a0f05b02c0b66d745591d49f82041cbc8d41e2238ef5d73eb4 + languageName: node + linkType: hard + +"plur@npm:^5.1.0": + version: 5.1.0 + resolution: "plur@npm:5.1.0" + dependencies: + irregular-plurals: "npm:^3.3.0" + checksum: 10c0/26bb622b8545fcfd47bbf56fbcca66c08693708a232e403fa3589e00003c56c14231ac57c7588ca5db83ef4be1f61383402c4ea954000768f779f8aef6eb6da8 + languageName: node + linkType: hard + +"prebuild-install@npm:^7.1.1": + version: 7.1.2 + resolution: "prebuild-install@npm:7.1.2" + dependencies: + detect-libc: "npm:^2.0.0" + expand-template: "npm:^2.0.3" + github-from-package: "npm:0.0.0" + minimist: "npm:^1.2.3" + mkdirp-classic: "npm:^0.5.3" + napi-build-utils: "npm:^1.0.1" + node-abi: "npm:^3.3.0" + pump: "npm:^3.0.0" + rc: "npm:^1.2.7" + simple-get: "npm:^4.0.0" + tar-fs: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + bin: + prebuild-install: bin.js + checksum: 10c0/e64868ba9ef2068fd7264f5b03e5298a901e02a450acdb1f56258d88c09dea601eefdb3d1dfdff8513fdd230a92961712be0676192626a3b4d01ba154d48bdd3 + languageName: node + linkType: hard + +"pretty-ms@npm:^8.0.0": + version: 8.0.0 + resolution: "pretty-ms@npm:8.0.0" + dependencies: + parse-ms: "npm:^3.0.0" + checksum: 10c0/e960d633ecca45445cf5c6dffc0f5e4bef6744c92449ab0e8c6c704800675ab71e181c5e02ece5265e02137a33e313d3f3e355fbf8ea30b4b5b23de423329f8d + languageName: node + linkType: hard + +"pretty-ms@npm:^9.0.0": + version: 9.1.0 + resolution: "pretty-ms@npm:9.1.0" + dependencies: + parse-ms: "npm:^4.0.0" + checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9 + languageName: node + linkType: hard + +"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": + version: 4.2.0 + resolution: "proc-log@npm:4.2.0" + checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 + languageName: node + linkType: hard + +"pump@npm:^3.0.0": + version: 3.0.2 + resolution: "pump@npm:3.0.2" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/5ad655cb2a7738b4bcf6406b24ad0970d680649d996b55ad20d1be8e0c02394034e4c45ff7cd105d87f1e9b96a0e3d06fd28e11fae8875da26e7f7a8e2c9726f + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 + languageName: node + linkType: hard + +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 + languageName: node + linkType: hard + +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: "npm:^2.2.1" + checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b + languageName: node + linkType: hard + +"require-directory@npm:^2.1.1": + version: 2.1.1 + resolution: "require-directory@npm:2.1.1" + checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 + languageName: node + linkType: hard + +"resolve-cwd@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-cwd@npm:3.0.0" + dependencies: + resolve-from: "npm:^5.0.0" + checksum: 10c0/e608a3ebd15356264653c32d7ecbc8fd702f94c6703ea4ac2fb81d9c359180cba0ae2e6b71faa446631ed6145454d5a56b227efc33a2d40638ac13f8beb20ee4 + languageName: node + linkType: hard + +"resolve-from@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107 + languageName: node + linkType: hard + +"root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + dependencies: + "@agoric/synthetic-chain": "npm:^0.3.0" + ava: "npm:^5.3.1" + languageName: unknown + linkType: soft + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: "npm:^1.2.2" + checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"semver@npm:^7.3.2, semver@npm:^7.3.5": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + languageName: node + linkType: hard + +"serialize-error@npm:^7.0.1": + version: 7.0.1 + resolution: "serialize-error@npm:7.0.1" + dependencies: + type-fest: "npm:^0.13.1" + checksum: 10c0/7982937d578cd901276c8ab3e2c6ed8a4c174137730f1fb0402d005af209a0e84d04acc874e317c936724c7b5b26c7a96ff7e4b8d11a469f4924a4b0ea814c05 + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 + languageName: node + linkType: hard + +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 10c0/62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: "npm:^6.0.0" + once: "npm:^1.3.1" + simple-concat: "npm:^1.0.0" + checksum: 10c0/b0649a581dbca741babb960423248899203165769747142033479a7dc5e77d7b0fced0253c731cd57cf21e31e4d77c9157c3069f4448d558ebc96cf9e1eebcf0 + languageName: node + linkType: hard + +"slash@npm:^4.0.0": + version: 4.0.0 + resolution: "slash@npm:4.0.0" + checksum: 10c0/b522ca75d80d107fd30d29df0549a7b2537c83c4c4ecd12cd7d4ea6c8aaca2ab17ada002e7a1d78a9d736a0261509f26ea5b489082ee443a3a810586ef8eff18 + languageName: node + linkType: hard + +"slice-ansi@npm:^5.0.0": + version: 5.0.0 + resolution: "slice-ansi@npm:5.0.0" + dependencies: + ansi-styles: "npm:^6.0.0" + is-fullwidth-code-point: "npm:^4.0.0" + checksum: 10c0/2d4d40b2a9d5cf4e8caae3f698fe24ae31a4d778701724f578e984dcb485ec8c49f0c04dab59c401821e80fcdfe89cace9c66693b0244e40ec485d72e543914f + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.4 + resolution: "socks-proxy-agent@npm:8.0.4" + dependencies: + agent-base: "npm:^7.1.1" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/345593bb21b95b0508e63e703c84da11549f0a2657d6b4e3ee3612c312cb3a907eac10e53b23ede3557c6601d63252103494caa306b66560f43af7b98f53957a + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.3 + resolution: "socks@npm:2.8.3" + dependencies: + ip-address: "npm:^9.0.5" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 + languageName: node + linkType: hard + +"sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec + languageName: node + linkType: hard + +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.6 + resolution: "ssri@npm:10.0.6" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/e5a1e23a4057a86a97971465418f22ea89bd439ac36ade88812dd920e4e61873e8abd6a9b72a03a67ef50faa00a2daf1ab745c5a15b46d03e0544a0296354227 + languageName: node + linkType: hard + +"stack-utils@npm:^2.0.6": + version: 2.0.6 + resolution: "stack-utils@npm:2.0.6" + dependencies: + escape-string-regexp: "npm:^2.0.0" + checksum: 10c0/651c9f87667e077584bbe848acaecc6049bc71979f1e9a46c7b920cad4431c388df0f51b8ad7cfd6eed3db97a2878d0fc8b3122979439ea8bac29c61c95eec8a + languageName: node + linkType: hard + +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b + languageName: node + linkType: hard + +"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 + languageName: node + linkType: hard + +"strip-final-newline@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-final-newline@npm:4.0.0" + checksum: 10c0/b0cf2b62d597a1b0e3ebc42b88767f0a0d45601f89fd379a928a1812c8779440c81abba708082c946445af1d6b62d5f16e2a7cf4f30d9d6587b89425fae801ff + languageName: node + linkType: hard + +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + +"supertap@npm:^3.0.1": + version: 3.0.1 + resolution: "supertap@npm:3.0.1" + dependencies: + indent-string: "npm:^5.0.0" + js-yaml: "npm:^3.14.1" + serialize-error: "npm:^7.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/8164674f2e280cab875f0fef5bb36c15553c13e29697ff92f4e0d6bc62149f0303a89eee47535413ed145ea72e14a24d065bab233059d48a499ec5ebb4566b0f + languageName: node + linkType: hard + +"tar-fs@npm:^2.0.0": + version: 2.1.1 + resolution: "tar-fs@npm:2.1.1" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.1.4" + checksum: 10c0/871d26a934bfb7beeae4c4d8a09689f530b565f79bd0cf489823ff0efa3705da01278160da10bb006d1a793fa0425cf316cec029b32a9159eacbeaff4965fb6d + languageName: node + linkType: hard + +"tar-stream@npm:^2.1.4": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + dependencies: + bl: "npm:^4.0.3" + end-of-stream: "npm:^1.4.1" + fs-constants: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.1.1" + checksum: 10c0/2f4c910b3ee7196502e1ff015a7ba321ec6ea837667220d7bcb8d0852d51cb04b87f7ae471008a6fb8f5b1a1b5078f62f3a82d30c706f20ada1238ac797e7692 + languageName: node + linkType: hard + +"tar@npm:^6.1.11, tar@npm:^6.2.1": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 + languageName: node + linkType: hard + +"temp-dir@npm:^3.0.0": + version: 3.0.0 + resolution: "temp-dir@npm:3.0.0" + checksum: 10c0/a86978a400984cd5f315b77ebf3fe53bb58c61f192278cafcb1f3fb32d584a21dc8e08b93171d7874b7cc972234d3455c467306cc1bfc4524b622e5ad3bfd671 + languageName: node + linkType: hard + +"time-zone@npm:^1.0.0": + version: 1.0.0 + resolution: "time-zone@npm:1.0.0" + checksum: 10c0/d00ebd885039109011b6e2423ebbf225160927333c2ade6d833e9cc4676db20759f1f3855fafde00d1bd668c243a6aa68938ce71fe58aab0d514e820d59c1d81 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + languageName: node + linkType: hard + +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 10c0/4c7a1b813e7beae66fdbf567a65ec6d46313643753d0beefb3c7973d66fcec3a1e7f39759f0a0b4465883499c6dc8b0750ab8b287399af2e583823e40410a17a + languageName: node + linkType: hard + +"type-fest@npm:^0.13.1": + version: 0.13.1 + resolution: "type-fest@npm:0.13.1" + checksum: 10c0/0c0fa07ae53d4e776cf4dac30d25ad799443e9eef9226f9fddbb69242db86b08584084a99885cfa5a9dfe4c063ebdc9aa7b69da348e735baede8d43f1aeae93b + languageName: node + linkType: hard + +"unicorn-magic@npm:^0.3.0": + version: 0.3.0 + resolution: "unicorn-magic@npm:0.3.0" + checksum: 10c0/0a32a997d6c15f1c2a077a15b1c4ca6f268d574cf5b8975e778bb98e6f8db4ef4e86dfcae4e158cd4c7e38fb4dd383b93b13eefddc7f178dea13d3ac8a603271 + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: "npm:^4.0.0" + checksum: 10c0/6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10c0/cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + languageName: node + linkType: hard + +"well-known-symbols@npm:^2.0.0": + version: 2.0.0 + resolution: "well-known-symbols@npm:2.0.0" + checksum: 10c0/cb6c12e98877e8952ec28d13ae6f4fdb54ae1cb49b16a728720276dadd76c930e6cb0e174af3a4620054dd2752546f842540122920c6e31410208abd4958ee6b + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10c0/449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 + languageName: node + linkType: hard + +"write-file-atomic@npm:^5.0.1": + version: 5.0.1 + resolution: "write-file-atomic@npm:5.0.1" + dependencies: + imurmurhash: "npm:^0.1.4" + signal-exit: "npm:^4.0.1" + checksum: 10c0/e8c850a8e3e74eeadadb8ad23c9d9d63e4e792bd10f4836ed74189ef6e996763959f1249c5650e232f3c77c11169d239cbfc8342fc70f3fe401407d23810505d + languageName: node + linkType: hard + +"y18n@npm:^5.0.5": + version: 5.0.8 + resolution: "y18n@npm:5.0.8" + checksum: 10c0/4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a + languageName: node + linkType: hard + +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 + languageName: node + linkType: hard + +"yargs@npm:^17.7.2": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 + languageName: node + linkType: hard + +"yocto-queue@npm:^1.0.0": + version: 1.1.1 + resolution: "yocto-queue@npm:1.1.1" + checksum: 10c0/cb287fe5e6acfa82690acb43c283de34e945c571a78a939774f6eaba7c285bacdf6c90fbc16ce530060863984c906d2b4c6ceb069c94d1e0a06d5f2b458e2a92 + languageName: node + linkType: hard + +"yoctocolors@npm:^2.0.0": + version: 2.1.1 + resolution: "yoctocolors@npm:2.1.1" + checksum: 10c0/85903f7fa96f1c70badee94789fade709f9d83dab2ec92753d612d84fcea6d34c772337a9f8914c6bed2f5fc03a428ac5d893e76fab636da5f1236ab725486d0 + languageName: node + linkType: hard diff --git a/a3p-integration/proposals/n:upgrade-next/priceFeed-follower-auction.test.js b/a3p-integration/proposals/n:upgrade-next/priceFeed-follower-auction.test.js index 30ae903b075..1dc0df73472 100644 --- a/a3p-integration/proposals/n:upgrade-next/priceFeed-follower-auction.test.js +++ b/a3p-integration/proposals/n:upgrade-next/priceFeed-follower-auction.test.js @@ -3,6 +3,7 @@ import { getDetailsMatchingVats } from './vatDetails.js'; test('new auction vat', async t => { const details = await getDetailsMatchingVats('auctioneer'); - // This query matches both the auction and its governor, so 2*2 - t.is(Object.keys(details).length, 4); + // This query matches both the auction and its governor, so 2*3 for the + // original, the vaults&auctions coreEval, and the priceFeed coreEval. + t.is(Object.keys(details).length, 6); }); diff --git a/a3p-integration/scripts/build-submission.sh b/a3p-integration/scripts/build-submission.sh index 2c90949ef42..3470c24cf52 100755 --- a/a3p-integration/scripts/build-submission.sh +++ b/a3p-integration/scripts/build-submission.sh @@ -9,8 +9,9 @@ a3pProposalDir=$1 builderScript=$2 submissionDirName=${3:-submission} submissionDir="./a3p-integration/$a3pProposalDir/$submissionDirName" +extraParams=${4:-} -yarn agoric run "packages/builders/scripts/$builderScript" +yarn agoric run "packages/builders/scripts/$builderScript" $extraParams mkdir -p "$submissionDir" plans=*-plan.json diff --git a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts new file mode 100644 index 00000000000..b4844fd984f --- /dev/null +++ b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts @@ -0,0 +1,200 @@ +/** + * @file The goal of this test is to see that the + * upgrade scripts re-wire all the contracts so new auctions and + * price feeds are connected to vaults correctly. + * + * 1. enter a bid + * 2. force prices to drop so a vault liquidates + * 3. verify that the bidder gets the liquidated assets. + */ +import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import type { TestFn } from 'ava'; +import { ScheduleNotification } from '@agoric/inter-protocol/src/auction/scheduler.js'; +import { NonNullish } from '@agoric/internal'; +import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; +import { Fail } from '@endo/errors'; + +import { + LiquidationTestContext, + likePayouts, + makeLiquidationTestContext, + scale6, + LiquidationSetup, +} from '../../tools/liquidation.js'; +import { + updateVaultDirectorParams, + updateVaultManagerParams, +} from '../tools/changeVaultParams'; + +const test = anyTest as TestFn; +test.before( + async t => + (t.context = await makeLiquidationTestContext(t, { env: process.env })), +); +test.after.always(t => t.context.shutdown()); + +const collateralBrandKey = 'ATOM'; +const managerIndex = 0; + +const setup: LiquidationSetup = { + vaults: [{ atom: 15, ist: 100, debt: 100.5 }], + bids: [{ give: '20IST', discount: 0.1 }], + price: { + starting: 12.34, + trigger: 9.99, + }, + auction: { + start: { collateral: 15, debt: 100.5 }, + end: { collateral: 9.659301, debt: 0 }, + }, +}; + +const outcome = { + bids: [{ payouts: { Bid: 0, Collateral: 2.224446 } }], +}; + +test.serial('setupVaults; run replace-price-feeds proposals', async t => { + const { + agoricNamesRemotes, + buildProposal, + evalProposal, + priceFeedDrivers, + refreshAgoricNamesRemotes, + setupVaults, + governanceDriver: gd, + } = t.context; + + await setupVaults(collateralBrandKey, managerIndex, setup); + + const instancePre = agoricNamesRemotes.instance['ATOM-USD price feed']; + + const priceFeedBuilder = + '@agoric/builders/scripts/inter-protocol/updatePriceFeeds.js'; + t.log('building', priceFeedBuilder); + const brandName = collateralBrandKey; + + const { ATOM } = agoricNamesRemotes.brand; + ATOM || Fail`ATOM missing from agoricNames`; + await updateVaultManagerParams(t, gd, ATOM, 50_000_000n); + + const SOME_GUI = 'someGUIHASH'; + await updateVaultDirectorParams(t, gd, SOME_GUI); + + t.log('building all relevant CoreEvals'); + const coreEvals = await Promise.all([ + buildProposal(priceFeedBuilder, ['UNRELEASED_main']), + buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), + buildProposal('@agoric/builders/scripts/vats/add-auction.js'), + ]); + const combined = { + evals: coreEvals.flatMap(e => e.evals), + bundles: coreEvals.flatMap(e => e.bundles), + }; + t.log('evaluating', coreEvals.length, 'scripts'); + await evalProposal(combined); + + refreshAgoricNamesRemotes(); + const instancePost = agoricNamesRemotes.instance['ATOM-USD price feed']; + t.not(instancePre, instancePost); + + await priceFeedDrivers[collateralBrandKey].refreshInvitations(); +}); + +test.serial('1. place bid', async t => { + const { placeBids, readLatest } = t.context; + await placeBids(collateralBrandKey, 'agoric1buyer', setup, 0); + + t.like(readLatest('published.wallet.agoric1buyer.current'), { + liveOffers: [['ATOM-bid1', { id: 'ATOM-bid1' }]], + }); +}); + +test.serial('2. trigger liquidation by changing price', async t => { + const { priceFeedDrivers, readLatest } = t.context; + + await priceFeedDrivers[collateralBrandKey].setPrice(9.99); + + t.log(readLatest('published.priceFeed.ATOM-USD_price_feed'), { + // aka 9.99 + amountIn: { value: 1000000n }, + amountOut: { value: 9990000n }, + }); + + // check nothing liquidating yet + const liveSchedule: ScheduleNotification = readLatest( + 'published.auction.schedule', + ); + t.is(liveSchedule.activeStartTime, null); + const metricsPath = `published.vaultFactory.managers.manager${managerIndex}.metrics`; + + t.like(readLatest(metricsPath), { + numActiveVaults: setup.vaults.length, + numLiquidatingVaults: 0, + }); +}); + +test.serial('3. verify liquidation', async t => { + const { advanceTimeBy, advanceTimeTo, readLatest } = t.context; + + const liveSchedule: ScheduleNotification = readLatest( + 'published.auction.schedule', + ); + const metricsPath = `published.vaultFactory.managers.manager${managerIndex}.metrics`; + + // advance time to start an auction + console.log(collateralBrandKey, 'step 1 of 10'); + await advanceTimeTo(NonNullish(liveSchedule.nextDescendingStepTime)); + await eventLoopIteration(); // let promises to update vstorage settle + + // vaultFactory sent collateral for liquidation + t.like(readLatest(metricsPath), { + numActiveVaults: 0, + numLiquidatingVaults: setup.vaults.length, + liquidatingCollateral: { + value: scale6(setup.auction.start.collateral), + }, + liquidatingDebt: { value: scale6(setup.auction.start.debt) }, + lockedQuote: null, + }); + + console.log(collateralBrandKey, 'step 2 of 10'); + await advanceTimeBy(3, 'minutes'); + t.like(readLatest(`published.auction.book${managerIndex}`), { + collateralAvailable: { value: scale6(setup.auction.start.collateral) }, + startCollateral: { value: scale6(setup.auction.start.collateral) }, + startProceedsGoal: { value: scale6(setup.auction.start.debt) }, + }); + + console.log(collateralBrandKey, 'step 3 of 10'); + await advanceTimeBy(3, 'minutes'); + + console.log(collateralBrandKey, 'step 4 of 10'); + await advanceTimeBy(3, 'minutes'); + + console.log(collateralBrandKey, 'step 5 of 10'); + await advanceTimeBy(3, 'minutes'); + + console.log(collateralBrandKey, 'step 6 of 10'); + await advanceTimeBy(3, 'minutes'); + t.like(readLatest(`published.auction.book${managerIndex}`), { + // 15_000_000 - ( 20_000_000 / 8.991 ) + collateralAvailable: { value: 12775554n }, + }); + + console.log(collateralBrandKey, 'step 7 of 10'); + await advanceTimeBy(3, 'minutes'); + + console.log(collateralBrandKey, 'step 8 of 10'); + await advanceTimeBy(3, 'minutes'); + + console.log(collateralBrandKey, 'step 9 of 10'); + await advanceTimeBy(3, 'minutes'); + + t.like(readLatest('published.wallet.agoric1buyer'), { + status: { + id: `${collateralBrandKey}-bid1`, + payouts: likePayouts(outcome.bids[0].payouts), + }, + }); +}); diff --git a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts new file mode 100644 index 00000000000..8e3f0ffb332 --- /dev/null +++ b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts @@ -0,0 +1,159 @@ +/** + * @file The goal of this test is to see that the + * upgrade scripts re-wire all the contracts so new auctions and + * price feeds are connected to vaults correctly. + * + * 1. enter a bid + * 2. force prices to drop so a vault liquidates + * 3. verify that the bidder gets the liquidated assets. + */ +import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import type { TestFn } from 'ava'; +import { makeAgoricNamesRemotesFromFakeStorage } from '@agoric/vats/tools/board-utils'; +import { Fail } from '@endo/errors'; + +import { makeSwingsetTestKit } from '../../tools/supports.js'; +import { + makeGovernanceDriver, + makeWalletFactoryDriver, +} from '../../tools/drivers.js'; +import { + updateVaultDirectorParams, + updateVaultManagerParams, +} from '../tools/changeVaultParams'; + +const makeDefaultTestContext = async t => { + console.time('DefaultTestContext'); + const swingsetTestKit = await makeSwingsetTestKit(t.log); + + const { runUtils, storage } = swingsetTestKit; + console.timeLog('DefaultTestContext', 'swingsetTestKit'); + const { EV } = runUtils; + + // Wait for ATOM to make it into agoricNames + await EV.vat('bootstrap').consumeItem('vaultFactoryKit'); + console.timeLog('DefaultTestContext', 'vaultFactoryKit'); + + // has to be late enough for agoricNames data to have been published + const agoricNamesRemotes = makeAgoricNamesRemotesFromFakeStorage( + swingsetTestKit.storage, + ); + agoricNamesRemotes.brand.ATOM || Fail`ATOM missing from agoricNames`; + console.timeLog('DefaultTestContext', 'agoricNamesRemotes'); + + const walletFactoryDriver = await makeWalletFactoryDriver( + runUtils, + storage, + agoricNamesRemotes, + ); + console.timeLog('DefaultTestContext', 'walletFactoryDriver'); + + console.timeEnd('DefaultTestContext'); + + const gd = await makeGovernanceDriver( + swingsetTestKit, + agoricNamesRemotes, + walletFactoryDriver, + [ + 'agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce', + 'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang', + 'agoric1w8wktaur4zf8qmmtn3n7x3r0jhsjkjntcm3u6h', + ], + ); + + return { ...swingsetTestKit, agoricNamesRemotes, gd }; +}; + +const test = anyTest as TestFn< + Awaited> +>; + +test.before(async t => { + t.context = await makeDefaultTestContext(t); +}); +test.after.always(t => { + return t.context.shutdown && t.context.shutdown(); +}); + +const outcome = { + bids: [{ payouts: { Bid: 0, Collateral: 1.800828 } }], +}; + +test('modify manager & director params; update vats, check', async t => { + const { agoricNamesRemotes, evalProposal, buildProposal, gd } = t.context; + + const { ATOM } = agoricNamesRemotes.brand; + ATOM || Fail`ATOM missing from agoricNames`; + + const { EV } = t.context.runUtils; + const zoe: ZoeService = await EV.vat('bootstrap').consumeItem('zoe'); + const vaultFactoryKit = + await EV.vat('bootstrap').consumeItem('vaultFactoryKit'); + const brands = await EV(zoe).getBrands(vaultFactoryKit.instance); + + // /// Modify Manager params /////////////// + t.log('modify manager params'); + const getDebtLimitValue = async () => { + const params = await EV(vaultFactoryKit.publicFacet).getGovernedParams({ + collateralBrand: brands.ATOM, + }); + + // @ts-expect-error getGovernedParams doesn't declare these fields + return params.DebtLimit.value.value; + }; + + t.is(await getDebtLimitValue(), 1_000_000_000n); + await updateVaultManagerParams(t, gd, ATOM, 50_000_000n); + + t.is(await getDebtLimitValue(), 50_000_000n); + + // /// Modify Director params /////////////// + t.log('modify director params'); + const directorPF = vaultFactoryKit.publicFacet; + const subscriptionPre = await EV(directorPF).getElectorateSubscription(); + + const iteratorP = await EV(subscriptionPre)[Symbol.asyncIterator](); + let next = await EV(iteratorP).next(); + + const ORIGINAL_GUI = + 'bafybeidvpbtlgefi3ptuqzr2fwfyfjqfj6onmye63ij7qkrb4yjxekdh3e'; + + t.is(next.value.current.ReferencedUI.value, ORIGINAL_GUI); + + const SOME_GUI = 'someGUIHASH'; + await updateVaultDirectorParams(t, gd, SOME_GUI); + + next = await EV(iteratorP).next(); + t.is(next.value.current.ReferencedUI.value, SOME_GUI); + + const ANOTHER_GUI = 'anotherGUIHASH'; + await updateVaultDirectorParams(t, gd, ANOTHER_GUI); + + next = await EV(iteratorP).next(); + t.is(next.value.current.ReferencedUI.value, ANOTHER_GUI); + + // /// run the coreEval /////////////// + t.log('upgrade priceFeeds, vaults, and auctions'); + const priceFeedBuilder = + '@agoric/builders/scripts/inter-protocol/updatePriceFeeds.js'; + const coreEvals = await Promise.all([ + buildProposal(priceFeedBuilder, ['UNRELEASED_main']), + buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), + buildProposal('@agoric/builders/scripts/vats/add-auction.js'), + ]); + const combined = { + evals: coreEvals.flatMap(e => e.evals), + bundles: coreEvals.flatMap(e => e.bundles), + }; + t.log('evaluating', coreEvals.length, 'scripts'); + await evalProposal(combined); + + // verify manager params restored to latest value + t.is(await getDebtLimitValue(), 50_000_000n); + + // verify director params restored to latest value + const subscriptionPost = await EV(directorPF).getElectorateSubscription(); + const { head } = await EV(subscriptionPost).subscribeAfter(); + t.is(head.value.current.ReferencedUI.value, ANOTHER_GUI); +}); diff --git a/packages/boot/test/tools/changeVaultParams.ts b/packages/boot/test/tools/changeVaultParams.ts new file mode 100644 index 00000000000..4cff2fc526a --- /dev/null +++ b/packages/boot/test/tools/changeVaultParams.ts @@ -0,0 +1,47 @@ +import { ParamChangesOfferArgs } from '@agoric/inter-protocol/src/econCommitteeCharter'; + +export const updateVaultManagerParams = async (t, gd, brand, newDebtLimit) => { + const { agoricNamesRemotes } = t.context; + + const vaults = agoricNamesRemotes.instance.VaultFactory; + const timerBrand = agoricNamesRemotes.brand.timer; + assert(timerBrand); + + /* XXX @type {Partial} */ + const params = { + DebtLimit: { brand: agoricNamesRemotes.brand.IST, value: newDebtLimit }, + }; + + const offerArgs: ParamChangesOfferArgs = { + deadline: 1000n, + params, + instance: vaults, + path: { paramPath: { key: { collateralBrand: brand } } }, + }; + + await gd.changeParams(vaults, params, offerArgs.path); + + return newDebtLimit; +}; +export const updateVaultDirectorParams = async (t, gd, referenceUI) => { + const { agoricNamesRemotes } = t.context; + + const vaults = agoricNamesRemotes.instance.VaultFactory; + const timerBrand = agoricNamesRemotes.brand.timer; + assert(timerBrand); + + const params = { + ReferencedUI: referenceUI, + }; + + const offerArgs: ParamChangesOfferArgs = { + deadline: 1000n, + params, + instance: vaults, + path: { paramPath: { key: 'governedParams' } }, + }; + + await gd.changeParams(vaults, params, offerArgs.path); + + return referenceUI; +}; diff --git a/packages/boot/tools/drivers.ts b/packages/boot/tools/drivers.ts index b1877c0a31c..c042ec0f4ec 100644 --- a/packages/boot/tools/drivers.ts +++ b/packages/boot/tools/drivers.ts @@ -155,24 +155,28 @@ export const makePriceFeedDriver = async ( oracleAddresses.map(addr => walletFactoryDriver.provideSmartWallet(addr)), ); - const priceFeedInstance = agoricNamesRemotes.instance[priceFeedName]; - priceFeedInstance || Fail`no price feed ${priceFeedName}`; - const adminOfferId = `accept-${collateralBrandKey}-oracleInvitation`; - - // accept invitations - await Promise.all( - oracleWallets.map(w => - w.executeOffer({ - id: adminOfferId, - invitationSpec: { - source: 'purse', - instance: priceFeedInstance, - description: 'oracle invitation', - }, - proposal: {}, - }), - ), - ); + let nonce = 0; + let adminOfferId; + const acceptInvitations = async () => { + const priceFeedInstance = agoricNamesRemotes.instance[priceFeedName]; + priceFeedInstance || Fail`no price feed ${priceFeedName}`; + nonce += 1; + adminOfferId = `accept-${collateralBrandKey}-oracleInvitation${nonce}`; + return Promise.all( + oracleWallets.map(w => + w.executeOffer({ + id: adminOfferId, + invitationSpec: { + source: 'purse', + instance: priceFeedInstance, + description: 'oracle invitation', + }, + proposal: {}, + }), + ), + ); + }; + await acceptInvitations(); // zero is the initial lastReportedRoundId so causes an error: cannot report on previous rounds let roundId = 1n; @@ -196,6 +200,10 @@ export const makePriceFeedDriver = async ( roundId += 1n; // TODO confirm the new price is written to storage }, + async refreshInvitations() { + roundId = 1n; + await acceptInvitations(); + }, }; }; harden(makePriceFeedDriver); diff --git a/packages/boot/tools/liquidation.ts b/packages/boot/tools/liquidation.ts index 221f98e7260..1945abdc9fe 100644 --- a/packages/boot/tools/liquidation.ts +++ b/packages/boot/tools/liquidation.ts @@ -53,6 +53,17 @@ export type LiquidationSetup = { }; }; +// TODO read from the config file +export const atomConfig = { + oracleAddresses: [ + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', + ], +}; + export const scale6 = x => BigInt(Math.round(x * 1_000_000)); const DebtLimitValue = scale6(100_000); @@ -103,14 +114,7 @@ export const makeLiquidationTestKit = async ({ collateralBrandKey, agoricNamesRemotes, walletFactoryDriver, - // TODO read from the config file - [ - 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', - 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', - 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', - 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', - 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', - ], + atomConfig.oracleAddresses, ); } @@ -304,8 +308,14 @@ export const makeLiquidationTestKit = async ({ }; }; -export const makeLiquidationTestContext = async t => { - const swingsetTestKit = await makeSwingsetTestKit(t.log); +export const makeLiquidationTestContext = async ( + t, + io: { env?: Record } = {}, +) => { + const { env = {} } = io; + const swingsetTestKit = await makeSwingsetTestKit(t.log, undefined, { + slogFile: env.SLOGFILE, + }); console.time('DefaultTestContext'); const { runUtils, storage } = swingsetTestKit; diff --git a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js new file mode 100644 index 00000000000..264c04ee522 --- /dev/null +++ b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js @@ -0,0 +1,83 @@ +/* global process */ + +import { makeHelpers } from '@agoric/deploy-script-support'; +import { getManifestForPriceFeeds } from '@agoric/inter-protocol/src/proposals/deploy-price-feeds.js'; + +/** @import {PriceFeedConfig} from '@agoric/inter-protocol/src/proposals/deploy-price-feeds.js'; */ + +/** @type {Record} */ +const configurations = { + UNRELEASED_A3P_INTEGRATION: { + oracleAddresses: [ + 'agoric1ee9hr0jyrxhy999y755mp862ljgycmwyp4pl7q', // GOV1 + 'agoric1wrfh296eu2z34p6pah7q04jjuyj3mxu9v98277', // GOV2 + 'agoric1ydzxwh6f893jvpaslmaz6l8j2ulup9a7x8qvvq', // GOV3 + ], + inBrandNames: ['ATOM', 'stATOM'], + }, + UNRELEASED_main: { + oracleAddresses: [ + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', // DSRV + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', // Stakin + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', // 01node + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', // Simply Staking + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', // P2P + ], + inBrandNames: ['ATOM', 'stATOM', 'stOSMO', 'stTIA', 'stkATOM'], + contractTerms: { minSubmissionCount: 3 }, + }, + UNRELEASED_devnet: { + oracleAddresses: [ + 'agoric1lw4e4aas9q84tq0q92j85rwjjjapf8dmnllnft', // DSRV + 'agoric1zj6vrrrjq4gsyr9lw7dplv4vyejg3p8j2urm82', // Stakin + 'agoric1ra0g6crtsy6r3qnpu7ruvm7qd4wjnznyzg5nu4', // 01node + 'agoric1qj07c7vfk3knqdral0sej7fa6eavkdn8vd8etf', // Simply Staking + 'agoric10vjkvkmpp9e356xeh6qqlhrny2htyzp8hf88fk', // P2P + ], + inBrandNames: ['ATOM', 'stTIA', 'stkATOM'], + }, +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }, opts) => { + return harden({ + sourceSpec: '@agoric/inter-protocol/src/proposals/deploy-price-feeds.js', + getManifestCall: [ + getManifestForPriceFeeds.name, + { + ...opts, + priceAggregatorRef: publishRef( + install( + '@agoric/inter-protocol/src/price/fluxAggregatorContract.js', + '../bundles/bundle-fluxAggregatorKit.js', + ), + ), + scaledPARef: publishRef( + install( + '@agoric/zoe/src/contracts/scaledPriceAuthority.js', + '../bundles/bundle-scaledPriceAuthority.js', + ), + ), + }, + ], + }); +}; + +const { keys } = Object; +const Usage = `agoric run updatePriceFeed.js ${keys(configurations).join(' | ')}`; + +export default async (homeP, endowments) => { + const { scriptArgs } = endowments; + const config = configurations[scriptArgs?.[0]]; + if (!config) { + console.error(Usage); + process.exit(1); + } + console.log('UPPrices', scriptArgs, config); + + const { writeCoreEval } = await makeHelpers(homeP, endowments); + + await writeCoreEval('gov-price-feeds', (utils, opts) => + defaultProposalBuilder(utils, { ...opts, ...config }), + ); +}; diff --git a/packages/builders/scripts/vats/priceFeedSupport.js b/packages/builders/scripts/vats/priceFeedSupport.js index 5f916d3c793..8a975bfdcc0 100644 --- a/packages/builders/scripts/vats/priceFeedSupport.js +++ b/packages/builders/scripts/vats/priceFeedSupport.js @@ -1,8 +1,32 @@ /* global process */ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { M, mustMatch } from '@agoric/store'; import { DEFAULT_CONTRACT_TERMS } from '../inter-protocol/price-feed-core.js'; -const { Fail } = assert; +/** @import {TypedPattern} from '@agoric/internal'; */ +/** + * @typedef {{ + * AGORIC_INSTANCE_NAME: string, + * ORACLE_ADDRESSES: string[], + * IN_BRAND_LOOKUP?: string[], + * IN_BRAND_NAME?: string, + * } & ({ IN_BRAND_LOOKUP: string[] } + * | { IN_BRAND_NAME: string }) + * } PriceFeedOptions + */ + +/** @type {TypedPattern} */ +const PriceFeedOptionsShape = M.and( + M.splitRecord({ + AGORIC_INSTANCE_NAME: M.string(), + ORACLE_ADDRESSES: M.arrayOf(M.string()), + }), + M.or( + M.splitRecord({ IN_BRAND_LOOKUP: M.arrayOf(M.string()) }), + M.splitRecord({ IN_BRAND_NAME: M.string() }), + ), +); /** * modified copy of ../inter-protocol/price-feed-core.js @@ -13,22 +37,16 @@ export const strictPriceFeedProposalBuilder = async ( { publishRef, install }, options, ) => { + mustMatch(options, PriceFeedOptionsShape); const { AGORIC_INSTANCE_NAME, IN_BRAND_LOOKUP, + // @ts-expect-error yes, IN_BRAND_LOOKUP may be undefined, but then IN_BRAND_LOOKUP must be defined IN_BRAND_NAME = IN_BRAND_LOOKUP[IN_BRAND_LOOKUP.length - 1], ORACLE_ADDRESSES, } = options; const oracleAddresses = ORACLE_ADDRESSES; - Array.isArray(oracleAddresses) || - Fail`ORACLE_ADDRESSES array is required; got ${oracleAddresses}`; - - AGORIC_INSTANCE_NAME || - Fail`AGORIC_INSTANCE_NAME is required; got ${AGORIC_INSTANCE_NAME}`; - - Array.isArray(IN_BRAND_LOOKUP) || - Fail`IN_BRAND_NAME array is required; got ${IN_BRAND_LOOKUP}`; return harden({ sourceSpec: '@agoric/inter-protocol/src/proposals/price-feed-proposal.js', @@ -88,3 +106,20 @@ export const deprecatedPriceFeedProposalBuilder = async (powers, options) => { * @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ export const priceFeedProposalBuilder = deprecatedPriceFeedProposalBuilder; + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + + const { scriptArgs } = endowments; + if (scriptArgs.length !== 1) throw RangeError('arg 0 must be JSON opts'); + let opts; + try { + opts = JSON.parse(scriptArgs[0]); + } catch (cause) { + throw RangeError('expected JSON', { cause }); + } + + await writeCoreEval('atomPriceFeed', powers => + strictPriceFeedProposalBuilder(powers, opts), + ); +}; diff --git a/packages/inter-protocol/src/econCommitteeCharter.js b/packages/inter-protocol/src/econCommitteeCharter.js index b718e4d9337..468fe413c4c 100644 --- a/packages/inter-protocol/src/econCommitteeCharter.js +++ b/packages/inter-protocol/src/econCommitteeCharter.js @@ -25,7 +25,7 @@ export const INVITATION_MAKERS_DESC = 'charter member invitation'; * @property {bigint} deadline * @property {Instance} instance * @property {Record} params - * @property {{ paramPath: { key: string } }} [path] + * @property {{ paramPath: unknown }} [path] paramPath is determined by contract */ const ParamChangesOfferArgsShape = M.splitRecord( { diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js index ca5bb004759..6bfad088ee6 100644 --- a/packages/inter-protocol/src/proposals/add-auction.js +++ b/packages/inter-protocol/src/proposals/add-auction.js @@ -27,7 +27,7 @@ export const addAuction = async ( chainTimerService, economicCommitteeCreatorFacet: electorateCreatorFacet, econCharterKit, - priceAuthority, + priceAuthority8400, zoe, }, produce: { auctioneerKit: produceAuctioneerKit, auctionUpgradeNewInstance }, @@ -95,7 +95,7 @@ export const addAuction = async ( const auctionTerms = makeGovernedATerms( { storageNode, marshaller }, chainTimerService, - priceAuthority, + priceAuthority8400, reservePublicFacet, { ...params, @@ -197,7 +197,7 @@ export const ADD_AUCTION_MANIFEST = harden({ chainTimerService: true, econCharterKit: true, economicCommitteeCreatorFacet: true, - priceAuthority: true, + priceAuthority8400: true, zoe: true, }, produce: { diff --git a/packages/inter-protocol/src/proposals/addAssetToVault.js b/packages/inter-protocol/src/proposals/addAssetToVault.js index 7bd27147cbd..2173895349b 100644 --- a/packages/inter-protocol/src/proposals/addAssetToVault.js +++ b/packages/inter-protocol/src/proposals/addAssetToVault.js @@ -129,7 +129,7 @@ export const publishInterchainAssetFromBank = async ( * @param {object} config.options * @param {InterchainAssetOptions} config.options.interchainAssetOptions */ -export const registerScaledPriceAuthority = async ( +export const startScaledPriceAuthority = async ( { consume: { agoricNamesAdmin, @@ -137,7 +137,6 @@ export const registerScaledPriceAuthority = async ( priceAuthorityAdmin, priceAuthority, }, - instance: { produce: produceInstance }, }, { options: { interchainAssetOptions } }, ) => { @@ -231,6 +230,25 @@ export const registerScaledPriceAuthority = async ( true, // force ); + return spaKit; +}; + +/** + * @param {BootstrapPowers} powers + * @param {object} config + * @param {object} config.options + */ +export const registerScaledPriceAuthority = async (powers, { options }) => { + const { + instance: { produce: produceInstance }, + } = powers; + + const { keyword, issuerName = keyword } = options.interchainAssetOptions; + + const spaKit = await startScaledPriceAuthority(powers, { options }); + + const label = scaledPriceFeedName(issuerName); + // publish into agoricNames so that others can await its presence. // This must stay after registerPriceAuthority above so it's evidence of registration. // eslint-disable-next-line no-restricted-syntax -- computed property diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js new file mode 100644 index 00000000000..070136cfd3b --- /dev/null +++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js @@ -0,0 +1,310 @@ +import { makeTracer } from '@agoric/internal'; +import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js'; +import { E } from '@endo/far'; + +import { unitAmount } from '@agoric/zoe/src/contractSupport/priceQuote.js'; +import { + oracleBrandFeedName, + reserveThenDeposit, + sanitizePathSegment, +} from './utils.js'; +import { replaceScaledPriceAuthorities } from './replace-scaledPriceAuthorities.js'; + +const STORAGE_PATH = 'priceFeed'; + +/** @type {ChainlinkConfig} */ +export const DEFAULT_CONTRACT_TERMS = { + maxSubmissionCount: 1000, + minSubmissionCount: 2, + restartDelay: 1n, // the number of rounds an Oracle has to wait before they can initiate another round + timeout: 10, // in seconds according to chainTimerService + minSubmissionValue: 1, + maxSubmissionValue: 2 ** 256, +}; + +/** @import {EconomyBootstrapPowers} from './econ-behaviors.js'; */ +/** @import {ChainlinkConfig} from '@agoric/inter-protocol/src/price/fluxAggregatorKit.js'; */ +/** @typedef {typeof import('@agoric/inter-protocol/src/price/fluxAggregatorContract.js').start} FluxStartFn */ + +const trace = makeTracer('DeployPriceFeed', true); + +/** + * @typedef {{ + * oracleAddresses: string[]; + * inBrandNames: string[]; + * contractTerms?: Partial; + * }} PriceFeedConfig + */ + +/** + * @param {EconomyBootstrapPowers} powers + * @param {string} bundleID + */ +const installPriceAggregator = async ( + { + consume: { zoe }, + installation: { + produce: { priceAggregator }, + }, + }, + bundleID, +) => { + /** @type {Installation} */ + const installation = await E(zoe).installBundleID(bundleID); + priceAggregator.reset(); + priceAggregator.resolve(installation); + trace('installed priceAggregator', bundleID.slice(0, 'b1-1234567'.length)); + return installation; +}; + +/** + * Create inert brands (no mint or issuer) referred to by price oracles. + * + * @param {EconomyBootstrapPowers & NamedVatPowers} space + * @param {{ name: string; decimalPlaces: number }} opt + * @returns {Promise>} + */ +export const ensureOracleBrand = async ( + { + namedVat: { + consume: { agoricNames }, + }, + oracleBrand: { produce: oracleBrandProduce }, + }, + { name, decimalPlaces }, +) => { + const brand = E(agoricNames).provideInertBrand(name, { + assetKind: 'nat', + decimalPlaces, + }); + + oracleBrandProduce[name].reset(); + oracleBrandProduce[name].resolve(brand); + return brand; +}; + +/** + * @param {EconomyBootstrapPowers} powers + * @param {{ + * AGORIC_INSTANCE_NAME: string; + * contractTerms: import('@agoric/inter-protocol/src/price/fluxAggregatorKit.js').ChainlinkConfig; + * brandIn: Brand<'nat'>; + * brandOut: Brand<'nat'>; + * }} config + * @param {Installation} installation + */ +const startPriceAggegatorInstance = async ( + { + consume: { + board, + chainStorage, + chainTimerService, + econCharterKit, + highPrioritySendersManager, + namesByAddressAdmin, + startGovernedUpgradable, + }, + instance: { produce: produceInstance }, + }, + { AGORIC_INSTANCE_NAME, contractTerms, brandIn, brandOut }, + installation, +) => { + trace('startPriceAggregatorInstance', AGORIC_INSTANCE_NAME); + const label = sanitizePathSegment(AGORIC_INSTANCE_NAME); + + const feedsStorage = await makeStorageNodeChild(chainStorage, STORAGE_PATH); + const storageNode = await E(feedsStorage).makeChildNode(label); + const marshaller = await E(board).getReadonlyMarshaller(); + + const terms = harden({ + ...contractTerms, + description: AGORIC_INSTANCE_NAME, + brandIn, + brandOut, + timer: await chainTimerService, + unitAmountIn: await unitAmount(brandIn), + }); + const privateArgs = { + highPrioritySendersManager: await highPrioritySendersManager, + marshaller, + namesByAddressAdmin, + storageNode, + }; + const governedKit = await E(startGovernedUpgradable)({ + governedParams: {}, + privateArgs, + terms, + label, + // @ts-expect-error GovernableStartFn vs. fluxAggregatorContract.js start + installation, + }); + produceInstance[AGORIC_INSTANCE_NAME].reset(); + produceInstance[AGORIC_INSTANCE_NAME].resolve(governedKit.instance); + trace( + 'new instance', + label, + { terms, privateArgs, installation }, + governedKit, + ); + + await E(E.get(econCharterKit).creatorFacet).addInstance( + governedKit.instance, + governedKit.governorCreatorFacet, + AGORIC_INSTANCE_NAME, + ); + trace('added', label, 'instance to econCharter'); + + /** @type {import('@agoric/zoe/src/zoeService/utils.js').StartedInstanceKit} */ + // @ts-expect-error + const { instance, publicFacet, creatorFacet } = governedKit; + + return harden({ instance, publicFacet, creatorFacet }); +}; + +/** + * Send invitations to oracle operators for a price feed. + * + * @param {EconomyBootstrapPowers} powers + * @param {{ oracleAddresses: string[]; AGORIC_INSTANCE_NAME: string }} config + * @param {any} creatorFacet + */ +const distributeInvitations = async ( + { consume: { namesByAddressAdmin } }, + { oracleAddresses, AGORIC_INSTANCE_NAME }, + creatorFacet, +) => { + /** @param {string} addr */ + const addOracle = async addr => { + const invitation = await E(creatorFacet).makeOracleInvitation(addr); + const debugName = `${AGORIC_INSTANCE_NAME} member ${addr}`; + await reserveThenDeposit(debugName, namesByAddressAdmin, addr, [ + invitation, + ]).catch(err => console.error(`failed deposit to ${debugName}`, err)); + }; + + trace('distributing invitations', oracleAddresses); + // This doesn't resolve until oracle operators create their smart wallets. + // Don't block bootstrap on it. + void Promise.all(oracleAddresses.map(addOracle)); + trace('createPriceFeed complete'); +}; + +/** + * @param {EconomyBootstrapPowers & NamedVatPowers} powers + * @param {{ + * options: PriceFeedConfig & { + * priceAggregatorRef: { bundleID: string }; + * scaledPARef: { bundleID: string }; + * inBrandsDecimals?: number; + * contractTerms?: ChainlinkConfig; + * outBrandName?: string; + * outBrandDecimals?: number; + * }; + * }} config + */ +export const deployPriceFeeds = async (powers, config) => { + const { + inBrandNames, + oracleAddresses, + contractTerms, + priceAggregatorRef, + scaledPARef, + inBrandsDecimals = 6, + outBrandName = 'USD', + outBrandDecimals = 6, + } = config.options; + await null; + + const installation = await installPriceAggregator( + powers, + priceAggregatorRef.bundleID, + ); + + const { priceAuthorityAdmin, priceAuthority } = powers.consume; + for (const inBrandName of inBrandNames) { + const AGORIC_INSTANCE_NAME = oracleBrandFeedName(inBrandName, outBrandName); + const brandIn = await ensureOracleBrand(powers, { + name: inBrandName, + decimalPlaces: inBrandsDecimals, + }); + const brandOut = await ensureOracleBrand(powers, { + name: outBrandName, + decimalPlaces: outBrandDecimals, + }); + const kit = await startPriceAggegatorInstance( + powers, + { + AGORIC_INSTANCE_NAME, + brandIn, + brandOut, + contractTerms: { ...DEFAULT_CONTRACT_TERMS, ...contractTerms }, + }, + installation, + ); + + const forceReplace = true; + await E(priceAuthorityAdmin).registerPriceAuthority( + E(kit.publicFacet).getPriceAuthority(), + brandIn, + brandOut, + forceReplace, + ); + + await distributeInvitations( + powers, + { oracleAddresses, AGORIC_INSTANCE_NAME }, + kit.creatorFacet, + ); + } + + // @ts-expect-error replaceScaledPriceAuthorities uses a subset of the powers. + await replaceScaledPriceAuthorities(powers, { + options: { scaledPARef }, + }); + + // cf. #8400 QuotePayments storage leak + powers.produce.priceAuthority8400.resolve(priceAuthority); +}; + +const t = 'priceFeed'; + +/** + * Thread price feed upgrade options through from builder to core-eval. + * + * @param {object} utils + * @param {any} utils.restoreRef + * @param {PriceFeedConfig & { priceAggregatorRef: any }} priceFeedOptions + */ +export const getManifestForPriceFeeds = async ( + { restoreRef: _restoreRef }, + priceFeedOptions, +) => ({ + manifest: { + [deployPriceFeeds.name]: { + namedVat: t, + consume: { + agoricNamesAdmin: t, + board: t, + chainStorage: t, + chainTimerService: t, + contractKits: t, + econCharterKit: t, + highPrioritySendersManager: t, + instancePrivateArgs: t, + namesByAddressAdmin: t, + priceAuthority: t, + priceAuthorityAdmin: t, + startGovernedUpgradable: t, + startUpgradable: t, + zoe: t, + }, + installation: { produce: { priceAggregator: t } }, + instance: { + produce: t, + }, + oracleBrand: { produce: t }, + produce: { priceAuthority8400: t }, + }, + }, + options: { ...priceFeedOptions }, +}); diff --git a/packages/inter-protocol/src/proposals/price-feed-proposal.js b/packages/inter-protocol/src/proposals/price-feed-proposal.js index ef0808cea6e..ffe124dbd4d 100644 --- a/packages/inter-protocol/src/proposals/price-feed-proposal.js +++ b/packages/inter-protocol/src/proposals/price-feed-proposal.js @@ -227,7 +227,8 @@ export const createPriceFeed = async ( // being after the above awaits means that when this resolves, the consumer // gets notified that the authority is in the registry and its instance is in - // agoricNames. + // agoricNames. reset() in case we're replacing an existing feed. + produceInstance[AGORIC_INSTANCE_NAME].reset(); produceInstance[AGORIC_INSTANCE_NAME].resolve(faKit.instance); E(E.get(econCharterKit).creatorFacet).addInstance( diff --git a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js new file mode 100644 index 00000000000..6ceceb74ff8 --- /dev/null +++ b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js @@ -0,0 +1,119 @@ +import { makeTracer } from '@agoric/internal'; +import { E } from '@endo/far'; +import { deeplyFulfilled } from '@endo/marshal'; + +import { startScaledPriceAuthority } from './addAssetToVault.js'; +import { scaledPriceFeedName } from './utils.js'; + +const trace = makeTracer('replaceScaledPA', true); + +/** + * @param {BootstrapPowers} powers + * @param {object} config + * @param {object} config.options + */ +export const replaceScaledPriceAuthority = async (powers, { options }) => { + const { + instance: { produce: produceInstance }, + } = powers; + const { keyword, issuerName = keyword } = options.interchainAssetOptions; + + const spaKit = await startScaledPriceAuthority(powers, { options }); + + const label = scaledPriceFeedName(issuerName); + produceInstance[label].reset(); + + // publish into agoricNames so that others can await its presence. + // This must stay after registerPriceAuthority above so it's evidence of registration. + produceInstance[label].resolve(spaKit.instance); +}; + +/** + * Look up the existing assets known to auctions, and replace the corresponding + * scaledPriceAuthorities. The existing contracts will be left behind to be + * cleaned up later. + * + * @param {ChainBootstrapSpace & BootstrapPowers} powers + * @param {{ options: { scaledPARef: { bundleID: string } } }} options + */ +export const replaceScaledPriceAuthorities = async (powers, { options }) => { + trace('start'); + const { + consume: { agoricNamesAdmin, contractKits: contractKitsP, zoe }, + } = powers; + + const { scaledPARef } = options; + + const installationsAdmin = E(agoricNamesAdmin).lookupAdmin('installation'); + const [spaInstallation, contractKits] = await Promise.all([ + E(E(installationsAdmin).readonly()).lookup('scaledPriceAuthority'), + contractKitsP, + ]); + + const bundleID = scaledPARef.bundleID; + if (scaledPARef && bundleID) { + await E.when( + E(zoe).installBundleID(bundleID), + installation => + E(installationsAdmin).update('scaledPriceAuthority', installation), + err => + console.error( + `🚨 failed to update scaledPriceAuthority installation`, + err, + ), + ); + trace('installed scaledPriceAuthority bundle', bundleID); + } + + // Ask Zoe for the installation for each kit's instance, and return all the + // kits where that matches the given installation. + async function selectKitsWithInstallation(kits) { + /** @type {StartedInstanceKit[]} */ + const scaledPAKitMapP = Array.from(kits.values()).map(kit => [ + kit, + E(zoe).getInstallationForInstance(kit.instance), + ]); + const scaledPAKitMap = await deeplyFulfilled(harden(scaledPAKitMapP)); + const scaledPAKitEntries = []; + for (const [instance, installation] of scaledPAKitMap) { + if (spaInstallation === installation) { + scaledPAKitEntries.push(instance); + } + } + return scaledPAKitEntries; + } + const scaledPAKitEntries = await selectKitsWithInstallation(contractKits); + + for (const kitEntry of scaledPAKitEntries) { + trace({ kitEntry }); + + const keyword = kitEntry.label.match(/scaledPriceAuthority-(.*)/)[1]; + const interchainAssetOptions = { keyword }; + await replaceScaledPriceAuthority(powers, { + options: { interchainAssetOptions }, + }); + } +}; + +const t = 'replaceScaledPriceAuthority'; +export const getManifestForReplaceScaledPriceAuthorities = async ( + _ign, + upgradeSPAOptions, +) => ({ + manifest: { + [replaceScaledPriceAuthorities.name]: { + consume: { + agoricNamesAdmin: t, + contractKits: t, + priceAuthority: t, + priceAuthorityAdmin: t, + zoe: t, + startUpgradable: t, + }, + instance: { + produce: t, + }, + }, + }, + options: { ...upgradeSPAOptions }, +}); diff --git a/packages/inter-protocol/src/proposals/upgrade-vaults.js b/packages/inter-protocol/src/proposals/upgrade-vaults.js index 2088aac9e67..8befdd0c5a3 100644 --- a/packages/inter-protocol/src/proposals/upgrade-vaults.js +++ b/packages/inter-protocol/src/proposals/upgrade-vaults.js @@ -1,6 +1,5 @@ import { E } from '@endo/far'; import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; -import { AmountMath } from '@agoric/ertp/src/index.js'; import { makeTracer } from '@agoric/internal/src/index.js'; import { Fail } from '@endo/errors'; import { TimeMath } from '@agoric/time'; @@ -9,6 +8,7 @@ const trace = makeTracer('upgrade Vaults proposal'); /** * @typedef {PromiseSpaceOf<{ + * priceAuthority8400: Instance; * auctionUpgradeNewInstance: Instance; * }>} interlockPowers */ @@ -27,6 +27,7 @@ export const upgradeVaults = async ( reserveKit, vaultFactoryKit, zoe, + priceAuthority8400, }, produce: { auctionUpgradeNewInstance: auctionUpgradeNewInstanceProducer }, installation: { @@ -44,6 +45,8 @@ export const upgradeVaults = async ( const allBrands = await E(zoe).getBrands(directorInstance); const { Minted: _istBrand, ...vaultBrands } = allBrands; + await priceAuthority8400; + const bundleID = vaultsRef.bundleID; console.log(`upgradeVaults: bundleId`, bundleID); /** @@ -77,24 +80,21 @@ export const upgradeVaults = async ( const subscription = E(directorPF).getElectorateSubscription(); const notifier = makeNotifierFromAsyncIterable(subscription); - let { value, updateCount } = await notifier.getUpdateSince(0n); - // @ts-expect-error It's an amount. - while (AmountMath.isEmpty(value.current.MinInitialDebt.value)) { - ({ value, updateCount } = await notifier.getUpdateSince(updateCount)); - trace( - `minInitialDebt was empty, retried`, - value.current.MinInitialDebt.value, - ); - } + const { updateCount } = await notifier.getUpdateSince(); + + // subscribeAfter() retrieves the latest value. + const after = await E(subscription).subscribeAfter(updateCount); + const { current } = after.head.value; return harden({ - MinInitialDebt: value.current.MinInitialDebt.value, - ReferencedUI: value.current.ReferencedUI.value, - RecordingPeriod: value.current.RecordingPeriod.value, - ChargingPeriod: value.current.ChargingPeriod.value, + MinInitialDebt: current.MinInitialDebt.value, + ReferencedUI: current.ReferencedUI.value, + RecordingPeriod: current.RecordingPeriod.value, + ChargingPeriod: current.ChargingPeriod.value, }); }; const directorParamOverrides = await readCurrentDirectorParams(); + trace({ directorParamOverrides }); const readManagerParams = async () => { const { publicFacet: directorPF } = kit; @@ -104,34 +104,22 @@ export const upgradeVaults = async ( const params = {}; for (const kwd of Object.keys(vaultBrands)) { const collateralBrand = vaultBrands[kwd]; - const subscription = E(directorPF).getSubscription({ + + /** @type {any} */ + const governedParams = await E(directorPF).getGovernedParams({ collateralBrand, }); - const notifier = makeNotifierFromAsyncIterable(subscription); - let { value, updateCount } = await notifier.getUpdateSince(0n); - // @ts-expect-error It's an amount. - if (AmountMath.isEmpty(value.current.DebtLimit.value)) { - // The parameters might have been empty at start, and the notifier might - // give the first state before the current state. - trace(`debtLimit was empty, retrying`, value.current.DebtLimit.value); - ({ value, updateCount } = await notifier.getUpdateSince(updateCount)); - - // @ts-expect-error It's an amount. - if (AmountMath.isEmpty(value.current.DebtLimit.value)) { - trace('debtLimit was empty after retrying'); - throw Error('🚨Governed parameters empty after retry, Giving up'); - } - } - trace(kwd, 'params at', updateCount, 'are', value.current); + trace({ kwd, governedParams }); params[kwd] = harden({ brand: collateralBrand, - debtLimit: value.current.DebtLimit.value, - interestRate: value.current.InterestRate.value, - liquidationMargin: value.current.LiquidationMargin.value, - liquidationPadding: value.current.LiquidationPadding.value, - liquidationPenalty: value.current.LiquidationPenalty.value, - mintFee: value.current.MintFee.value, + debtLimit: governedParams.DebtLimit.value, + interestRate: governedParams.InterestRate.value, + liquidationMargin: governedParams.LiquidationMargin.value, + liquidationPadding: governedParams.LiquidationPadding.value, + liquidationPenalty: governedParams.LiquidationPenalty.value, + mintFee: governedParams.MintFee.value, }); + trace(kwd, params[kwd]); } return params; }; @@ -167,12 +155,11 @@ export const upgradeVaults = async ( trace('upgraded vaultFactory.', upgradeResult); }; - await upgradeVaultFactory(); // @ts-expect-error It's saved in econ-behaviors.js:startVaultFactory() const vaultFactoryPrivateArgs = kit.privateArgs; - console.log('UPGV upgraded vaults, restarting governor'); + trace('restarting governor'); const ecf = await electorateCreatorFacet; // restart vaultFactory governor @@ -183,7 +170,7 @@ export const upgradeVaults = async ( }), ); - console.log('UPGV restarted governor'); + trace('restarted governor'); }; const uV = 'upgradeVaults'; @@ -200,6 +187,7 @@ export const getManifestForUpgradeVaults = async ( manifest: { [upgradeVaults.name]: { consume: { + priceAuthority8400: uV, auctionUpgradeNewInstance: uV, chainTimerService: uV, economicCommitteeCreatorFacet: uV, diff --git a/packages/inter-protocol/src/proposals/utils.js b/packages/inter-protocol/src/proposals/utils.js index f0c00e9e18e..c191824468f 100644 --- a/packages/inter-protocol/src/proposals/utils.js +++ b/packages/inter-protocol/src/proposals/utils.js @@ -2,6 +2,7 @@ import { Fail } from '@endo/errors'; 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 {CopyMap} from '@endo/patterns'; */ @@ -163,3 +164,10 @@ export const oracleBrandFeedName = (inBrandName, outBrandName) => export const scaledPriceFeedName = issuerName => `scaledPriceAuthority-${issuerName}`; + +/** @type {(name: string) => string} */ +export const sanitizePathSegment = name => { + const candidate = name.replace(/ /g, '_'); + assertPathSegment(candidate); + return candidate; +}; diff --git a/packages/vats/src/core/types-ambient.d.ts b/packages/vats/src/core/types-ambient.d.ts index db262a6f4de..333898e6481 100644 --- a/packages/vats/src/core/types-ambient.d.ts +++ b/packages/vats/src/core/types-ambient.d.ts @@ -230,6 +230,7 @@ type WellKnownContracts = { mintHolder: typeof import('@agoric/vats/src/mintHolder.js').start; psm: typeof import('@agoric/inter-protocol/src/psm/psm.js').start; provisionPool: typeof import('@agoric/inter-protocol/src/provisionPool.js').start; + priceAggregator: typeof import('@agoric/inter-protocol/src/price/fluxAggregatorContract.js').start; reserve: typeof import('@agoric/inter-protocol/src/reserve/assetReserve.js').start; VaultFactory: typeof import('@agoric/inter-protocol/src/vaultFactory/vaultFactory.js').start; // no typeof because walletFactory is exporting `start` as a type @@ -377,6 +378,8 @@ type ChainBootstrapSpaceT = { powerStore: MapStore; priceAuthorityVat: Awaited; priceAuthority: import('@agoric/zoe/tools/types.js').PriceAuthority; + // signal that price feeds have #8400 QuotePayments storage leak fixed + priceAuthority8400: import('@agoric/zoe/tools/types.js').PriceAuthority; priceAuthorityAdmin: import('@agoric/vats/src/priceAuthorityRegistry').PriceAuthorityRegistryAdmin; provisioning: Awaited | undefined; provisionBridgeManager: diff --git a/packages/zoe/src/contractSupport/priceAuthorityInitial.js b/packages/zoe/src/contractSupport/priceAuthorityInitial.js index b5378654542..fc19c7747fb 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityInitial.js +++ b/packages/zoe/src/contractSupport/priceAuthorityInitial.js @@ -109,7 +109,7 @@ export const makeInitialTransform = ( : quoteP; }; - return Far('PriceAuthority', { + return Far('PriceAuthorityWithInitialValue', { ...priceAuthority, makeQuoteNotifier, quoteGiven, diff --git a/packages/zoe/src/contractSupport/priceAuthorityTransform.js b/packages/zoe/src/contractSupport/priceAuthorityTransform.js index ce2d79217b9..ac6425c2b9f 100644 --- a/packages/zoe/src/contractSupport/priceAuthorityTransform.js +++ b/packages/zoe/src/contractSupport/priceAuthorityTransform.js @@ -182,7 +182,7 @@ export const makePriceAuthorityTransform = async ({ }; /** @type {PriceAuthority} */ - const priceAuthority = Far('PriceAuthority', { + const priceAuthority = Far('ScaledPriceAuthority', { getQuoteIssuer(brandIn, brandOut) { assertBrands(brandIn, brandOut); return quoteIssuer; diff --git a/packages/zoe/src/contracts/scaledPriceAuthority.js b/packages/zoe/src/contracts/scaledPriceAuthority.js index b558a315c16..2b43bff8fcf 100644 --- a/packages/zoe/src/contracts/scaledPriceAuthority.js +++ b/packages/zoe/src/contracts/scaledPriceAuthority.js @@ -52,7 +52,9 @@ export const prepare = async (zcf, privateArgs, baggage) => { const priceAuthority = makePriceAuthorityTransform({ quoteMint, - sourcePriceAuthority, + // If the priceAuthority is overridden in privateArgs, use that version + sourcePriceAuthority: + privateArgs?.newPriceAuthority || sourcePriceAuthority, sourceBrandIn, sourceBrandOut, actualBrandIn, From 03cd5853e911993f0b604be73b24ad1220496316 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Mon, 7 Oct 2024 13:07:58 -0700 Subject: [PATCH 2/7] chore: minor clean-ups --- .../proposals/f:replace-price-feeds/agoric-tools.js | 1 + .../proposals/f:replace-price-feeds/package.json | 2 +- .../f:replace-price-feeds/priceFeedUpdate.test.js | 7 +++++-- .../test/bootstrapTests/price-feed-replace.test.ts | 6 +++--- .../test/bootstrapTests/updateGovernedParams.test.ts | 2 +- .../scripts/inter-protocol/updatePriceFeeds.js | 6 +++--- .../src/price/fluxAggregatorContract.js | 2 ++ .../src/proposals/deploy-price-feeds.js | 11 ++++++----- .../inter-protocol/src/vaultFactory/vaultManager.js | 1 + 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js b/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js index 0f85fd52122..1c6e10ac8f6 100644 --- a/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js +++ b/a3p-integration/proposals/f:replace-price-feeds/agoric-tools.js @@ -14,6 +14,7 @@ export const generateVaultDirectorParamChange = async ( const deadline = toSec(Date.now()) + voteDurSec; const zip = (xs, ys) => xs.map((x, i) => [x, ys[i]]); + // KLUDGE: partial deconstruction of smallCaps values const fromSmallCapsEntries = txt => { const { body, slots } = JSON.parse(txt); const theEntries = zip(JSON.parse(body.slice(1)), slots).map( diff --git a/a3p-integration/proposals/f:replace-price-feeds/package.json b/a3p-integration/proposals/f:replace-price-feeds/package.json index 696ed9ca904..84abe583e48 100644 --- a/a3p-integration/proposals/f:replace-price-feeds/package.json +++ b/a3p-integration/proposals/f:replace-price-feeds/package.json @@ -2,7 +2,7 @@ "agoricProposal": { "source": "subdir", "sdk-generate": [ - "inter-protocol/updatePriceFeeds.js submission UNRELEASED_A3P_INTEGRATION", + "inter-protocol/updatePriceFeeds.js submission A3P_INTEGRATION", "vats/add-auction.js", "vats/upgradeVaults.js" ], diff --git a/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js b/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js index 19f4bea6cd3..5cbacd019ad 100644 --- a/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js +++ b/a3p-integration/proposals/f:replace-price-feeds/priceFeedUpdate.test.js @@ -98,7 +98,7 @@ const triggerAuction = async t => { const checkNewAuctionVat = async t => { const details = await getDetailsMatchingVats('auctioneer'); // This query matches both the auction and its governor, so double the count - t.true(Object.keys(details).length > 2); + t.is(Object.keys(details).length, 3 * 2); }; const countPriceFeedVats = async t => { @@ -110,6 +110,8 @@ const countPriceFeedVats = async t => { const details = await getDetailsMatchingVats('scaledPriceAuthority'); t.is(Object.keys(details).length, 4); + // ATOM vat name is something like zcf-DEADBEEF-ATOM_USD_price_feed + // initial '-' distinguishes this from stAOM const atomDetails = await getDetailsMatchingVats('-ATOM-USD_price_feed'); t.is(Object.keys(atomDetails).length, 4); @@ -119,7 +121,8 @@ const countPriceFeedVats = async t => { }; const verifyVaultPriceUpdate = async t => { - const quote = await getVaultPrices(0); + const ATOMManagerIndex = 0; + const quote = await getVaultPrices(ATOMManagerIndex); t.true(quote.value[0].amountIn.brand.includes(' ATOM ')); t.is(quote.value[0].amountOut.value, '+5200000'); }; diff --git a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts index b4844fd984f..c137ba91017 100644 --- a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts +++ b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts @@ -25,7 +25,7 @@ import { import { updateVaultDirectorParams, updateVaultManagerParams, -} from '../tools/changeVaultParams'; +} from '../tools/changeVaultParams.js'; const test = anyTest as TestFn; test.before( @@ -54,7 +54,7 @@ const outcome = { bids: [{ payouts: { Bid: 0, Collateral: 2.224446 } }], }; -test.serial('setupVaults; run replace-price-feeds proposals', async t => { +test.serial('setupVaults; run updatePriceFeeds proposals', async t => { const { agoricNamesRemotes, buildProposal, @@ -83,7 +83,7 @@ test.serial('setupVaults; run replace-price-feeds proposals', async t => { t.log('building all relevant CoreEvals'); const coreEvals = await Promise.all([ - buildProposal(priceFeedBuilder, ['UNRELEASED_main']), + buildProposal(priceFeedBuilder, ['main']), 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 8e3f0ffb332..140e4ae70bc 100644 --- a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts +++ b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts @@ -138,7 +138,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, ['UNRELEASED_main']), + buildProposal(priceFeedBuilder, ['main']), buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), buildProposal('@agoric/builders/scripts/vats/add-auction.js'), ]); diff --git a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js index 264c04ee522..eefb2e54a47 100644 --- a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js +++ b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js @@ -7,7 +7,7 @@ import { getManifestForPriceFeeds } from '@agoric/inter-protocol/src/proposals/d /** @type {Record} */ const configurations = { - UNRELEASED_A3P_INTEGRATION: { + A3P_INTEGRATION: { oracleAddresses: [ 'agoric1ee9hr0jyrxhy999y755mp862ljgycmwyp4pl7q', // GOV1 'agoric1wrfh296eu2z34p6pah7q04jjuyj3mxu9v98277', // GOV2 @@ -15,7 +15,7 @@ const configurations = { ], inBrandNames: ['ATOM', 'stATOM'], }, - UNRELEASED_main: { + main: { oracleAddresses: [ 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', // DSRV 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', // Stakin @@ -26,7 +26,7 @@ const configurations = { inBrandNames: ['ATOM', 'stATOM', 'stOSMO', 'stTIA', 'stkATOM'], contractTerms: { minSubmissionCount: 3 }, }, - UNRELEASED_devnet: { + devnet: { oracleAddresses: [ 'agoric1lw4e4aas9q84tq0q92j85rwjjjapf8dmnllnft', // DSRV 'agoric1zj6vrrrjq4gsyr9lw7dplv4vyejg3p8j2urm82', // Stakin diff --git a/packages/inter-protocol/src/price/fluxAggregatorContract.js b/packages/inter-protocol/src/price/fluxAggregatorContract.js index 0eb968edd2b..37eb8f077f0 100644 --- a/packages/inter-protocol/src/price/fluxAggregatorContract.js +++ b/packages/inter-protocol/src/price/fluxAggregatorContract.js @@ -195,3 +195,5 @@ export const start = async (zcf, privateArgs, baggage) => { }); }; harden(start); + +/** @typedef {typeof start} FluxStartFn */ diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js index 070136cfd3b..f2ab8a8bbfa 100644 --- a/packages/inter-protocol/src/proposals/deploy-price-feeds.js +++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js @@ -24,7 +24,7 @@ export const DEFAULT_CONTRACT_TERMS = { /** @import {EconomyBootstrapPowers} from './econ-behaviors.js'; */ /** @import {ChainlinkConfig} from '@agoric/inter-protocol/src/price/fluxAggregatorKit.js'; */ -/** @typedef {typeof import('@agoric/inter-protocol/src/price/fluxAggregatorContract.js').start} FluxStartFn */ +/** @import {FluxStartFn} from '@agoric/inter-protocol/src/price/fluxAggregatorContract.js'; */ const trace = makeTracer('DeployPriceFeed', true); @@ -58,7 +58,7 @@ const installPriceAggregator = async ( }; /** - * Create inert brands (no mint or issuer) referred to by price oracles. + * Provide (find/create) inert brands (no mint or issuer) referred to by oracles * * @param {EconomyBootstrapPowers & NamedVatPowers} space * @param {{ name: string; decimalPlaces: number }} opt @@ -93,7 +93,7 @@ export const ensureOracleBrand = async ( * }} config * @param {Installation} installation */ -const startPriceAggegatorInstance = async ( +const startPriceAggregatorInstance = async ( { consume: { board, @@ -121,6 +121,7 @@ const startPriceAggegatorInstance = async ( description: AGORIC_INSTANCE_NAME, brandIn, brandOut, + // XXX powerful TimerService, see #6003 timer: await chainTimerService, unitAmountIn: await unitAmount(brandIn), }); @@ -184,7 +185,7 @@ const distributeInvitations = async ( trace('distributing invitations', oracleAddresses); // This doesn't resolve until oracle operators create their smart wallets. - // Don't block bootstrap on it. + // Don't block completion on it. void Promise.all(oracleAddresses.map(addOracle)); trace('createPriceFeed complete'); }; @@ -231,7 +232,7 @@ export const deployPriceFeeds = async (powers, config) => { name: outBrandName, decimalPlaces: outBrandDecimals, }); - const kit = await startPriceAggegatorInstance( + const kit = await startPriceAggregatorInstance( powers, { AGORIC_INSTANCE_NAME, diff --git a/packages/inter-protocol/src/vaultFactory/vaultManager.js b/packages/inter-protocol/src/vaultFactory/vaultManager.js index 20ffb29ab71..474d7843927 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultManager.js +++ b/packages/inter-protocol/src/vaultFactory/vaultManager.js @@ -455,6 +455,7 @@ export const prepareVaultManagerKit = ( // will throw. See https://github.com/Agoric/agoric-sdk/issues/4317 const quoteWatcher = harden({ onFulfilled(value) { + trace('watcher updated price', value); ephemera.storedCollateralQuote = value; }, onRejected() { From 0b047f0b6a16b076d283764b65771bfb1c2571c3 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 8 Oct 2024 14:00:19 -0700 Subject: [PATCH 3/7] refactor: match scaledPriceAuthority with AgoricNames using brands --- .../src/proposals/deploy-price-feeds.js | 1 + .../replace-scaledPriceAuthorities.js | 50 +++++++++---------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js index f2ab8a8bbfa..a80c50edf43 100644 --- a/packages/inter-protocol/src/proposals/deploy-price-feeds.js +++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js @@ -285,6 +285,7 @@ export const getManifestForPriceFeeds = async ( namedVat: t, consume: { agoricNamesAdmin: t, + agoricNames: t, board: t, chainStorage: t, chainTimerService: t, diff --git a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js index 6ceceb74ff8..1fff5d373bc 100644 --- a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js +++ b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js @@ -1,6 +1,5 @@ import { makeTracer } from '@agoric/internal'; import { E } from '@endo/far'; -import { deeplyFulfilled } from '@endo/marshal'; import { startScaledPriceAuthority } from './addAssetToVault.js'; import { scaledPriceFeedName } from './utils.js'; @@ -16,15 +15,15 @@ export const replaceScaledPriceAuthority = async (powers, { options }) => { const { instance: { produce: produceInstance }, } = powers; - const { keyword, issuerName = keyword } = options.interchainAssetOptions; + const { issuerName } = options.interchainAssetOptions; const spaKit = await startScaledPriceAuthority(powers, { options }); const label = scaledPriceFeedName(issuerName); produceInstance[label].reset(); - // publish into agoricNames so that others can await its presence. - // This must stay after registerPriceAuthority above so it's evidence of registration. + // publish into agoricNames. This must stay after registerPriceAuthority, + // which is called by startScaledPriceAuthority() produceInstance[label].resolve(spaKit.instance); }; @@ -39,7 +38,12 @@ export const replaceScaledPriceAuthority = async (powers, { options }) => { export const replaceScaledPriceAuthorities = async (powers, { options }) => { trace('start'); const { - consume: { agoricNamesAdmin, contractKits: contractKitsP, zoe }, + consume: { + agoricNamesAdmin, + agoricNames, + contractKits: contractKitsP, + zoe, + }, } = powers; const { scaledPARef } = options; @@ -67,30 +71,25 @@ export const replaceScaledPriceAuthorities = async (powers, { options }) => { // Ask Zoe for the installation for each kit's instance, and return all the // kits where that matches the given installation. - async function selectKitsWithInstallation(kits) { - /** @type {StartedInstanceKit[]} */ - const scaledPAKitMapP = Array.from(kits.values()).map(kit => [ - kit, - E(zoe).getInstallationForInstance(kit.instance), - ]); - const scaledPAKitMap = await deeplyFulfilled(harden(scaledPAKitMapP)); - const scaledPAKitEntries = []; - for (const [instance, installation] of scaledPAKitMap) { - if (spaInstallation === installation) { - scaledPAKitEntries.push(instance); - } - } - return scaledPAKitEntries; + async function maybeSPAKit(kit) { + const installation = await E(zoe).getInstallationForInstance(kit.instance); + return spaInstallation === installation ? [kit] : []; } - const scaledPAKitEntries = await selectKitsWithInstallation(contractKits); + const scaledPAKits = ( + await Promise.all([...contractKits.values()].map(maybeSPAKit)) + ).flat(); - for (const kitEntry of scaledPAKitEntries) { - trace({ kitEntry }); + const namedBrands = await E(E(agoricNames).lookup('brand')).entries(); - const keyword = kitEntry.label.match(/scaledPriceAuthority-(.*)/)[1]; - const interchainAssetOptions = { keyword }; + for (const kitEntry of scaledPAKits) { + const { instance } = kitEntry; + const terms = await E(powers.consume.zoe).getTerms(instance); + const { brand } = terms.scaleIn.denominator; + const entry = namedBrands.find(([_k, v]) => v === brand); + assert(entry, 'unable to find issuerName for ', brand); + const issuerName = entry[0]; await replaceScaledPriceAuthority(powers, { - options: { interchainAssetOptions }, + options: { interchainAssetOptions: { issuerName } }, }); } }; @@ -104,6 +103,7 @@ export const getManifestForReplaceScaledPriceAuthorities = async ( [replaceScaledPriceAuthorities.name]: { consume: { agoricNamesAdmin: t, + agoricNames: t, contractKits: t, priceAuthority: t, priceAuthorityAdmin: t, From 841cf20d5d5dbd06b7e4e5201d09820e6a032abe Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 8 Oct 2024 14:03:01 -0700 Subject: [PATCH 4/7] chore: revert unneeded changes to priceFeedSupport.js --- .../builders/scripts/vats/priceFeedSupport.js | 53 ++++--------------- 1 file changed, 9 insertions(+), 44 deletions(-) diff --git a/packages/builders/scripts/vats/priceFeedSupport.js b/packages/builders/scripts/vats/priceFeedSupport.js index 8a975bfdcc0..5f916d3c793 100644 --- a/packages/builders/scripts/vats/priceFeedSupport.js +++ b/packages/builders/scripts/vats/priceFeedSupport.js @@ -1,32 +1,8 @@ /* global process */ -import { makeHelpers } from '@agoric/deploy-script-support'; -import { M, mustMatch } from '@agoric/store'; import { DEFAULT_CONTRACT_TERMS } from '../inter-protocol/price-feed-core.js'; -/** @import {TypedPattern} from '@agoric/internal'; */ -/** - * @typedef {{ - * AGORIC_INSTANCE_NAME: string, - * ORACLE_ADDRESSES: string[], - * IN_BRAND_LOOKUP?: string[], - * IN_BRAND_NAME?: string, - * } & ({ IN_BRAND_LOOKUP: string[] } - * | { IN_BRAND_NAME: string }) - * } PriceFeedOptions - */ - -/** @type {TypedPattern} */ -const PriceFeedOptionsShape = M.and( - M.splitRecord({ - AGORIC_INSTANCE_NAME: M.string(), - ORACLE_ADDRESSES: M.arrayOf(M.string()), - }), - M.or( - M.splitRecord({ IN_BRAND_LOOKUP: M.arrayOf(M.string()) }), - M.splitRecord({ IN_BRAND_NAME: M.string() }), - ), -); +const { Fail } = assert; /** * modified copy of ../inter-protocol/price-feed-core.js @@ -37,16 +13,22 @@ export const strictPriceFeedProposalBuilder = async ( { publishRef, install }, options, ) => { - mustMatch(options, PriceFeedOptionsShape); const { AGORIC_INSTANCE_NAME, IN_BRAND_LOOKUP, - // @ts-expect-error yes, IN_BRAND_LOOKUP may be undefined, but then IN_BRAND_LOOKUP must be defined IN_BRAND_NAME = IN_BRAND_LOOKUP[IN_BRAND_LOOKUP.length - 1], ORACLE_ADDRESSES, } = options; const oracleAddresses = ORACLE_ADDRESSES; + Array.isArray(oracleAddresses) || + Fail`ORACLE_ADDRESSES array is required; got ${oracleAddresses}`; + + AGORIC_INSTANCE_NAME || + Fail`AGORIC_INSTANCE_NAME is required; got ${AGORIC_INSTANCE_NAME}`; + + Array.isArray(IN_BRAND_LOOKUP) || + Fail`IN_BRAND_NAME array is required; got ${IN_BRAND_LOOKUP}`; return harden({ sourceSpec: '@agoric/inter-protocol/src/proposals/price-feed-proposal.js', @@ -106,20 +88,3 @@ export const deprecatedPriceFeedProposalBuilder = async (powers, options) => { * @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ export const priceFeedProposalBuilder = deprecatedPriceFeedProposalBuilder; - -export default async (homeP, endowments) => { - const { writeCoreEval } = await makeHelpers(homeP, endowments); - - const { scriptArgs } = endowments; - if (scriptArgs.length !== 1) throw RangeError('arg 0 must be JSON opts'); - let opts; - try { - opts = JSON.parse(scriptArgs[0]); - } catch (cause) { - throw RangeError('expected JSON', { cause }); - } - - await writeCoreEval('atomPriceFeed', powers => - strictPriceFeedProposalBuilder(powers, opts), - ); -}; From 95b2b1d2a268e846e02c400e10000c4e18c149b5 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 8 Oct 2024 14:13:57 -0700 Subject: [PATCH 5/7] chore: add comments in powers for replaceScaledPriceAuthorities --- .../src/proposals/replace-scaledPriceAuthorities.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js index 1fff5d373bc..8723af3ce7b 100644 --- a/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js +++ b/packages/inter-protocol/src/proposals/replace-scaledPriceAuthorities.js @@ -102,15 +102,20 @@ export const getManifestForReplaceScaledPriceAuthorities = async ( manifest: { [replaceScaledPriceAuthorities.name]: { consume: { - agoricNamesAdmin: t, + // //// Widely known //// agoricNames: t, - contractKits: t, priceAuthority: t, - priceAuthorityAdmin: t, - zoe: t, startUpgradable: t, + zoe: t, + + // //// closely held, powerful //// + agoricNamesAdmin: t, + contractKits: t, + priceAuthorityAdmin: t, }, instance: { + // This is a right to add/replace any instance. That we update only the + // relevant ones must be verified by inspection. produce: t, }, }, From 5405d47945e95295d411a01b76254849b1e4b9e8 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Tue, 8 Oct 2024 14:33:05 -0700 Subject: [PATCH 6/7] chore: update comment & lint fixes --- .../test/bootstrapTests/updateGovernedParams.test.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts index 140e4ae70bc..7fe5c25f582 100644 --- a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts +++ b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts @@ -1,7 +1,7 @@ /** - * @file The goal of this test is to see that the - * upgrade scripts re-wire all the contracts so new auctions and - * price feeds are connected to vaults correctly. + * @file The goal of this test is to ensure that governance can update params + * after an upgrade. There was a point when the contractGovernor kept trying to + * use the old paramManager which was ephemeral and no longer useable. * * 1. enter a bid * 2. force prices to drop so a vault liquidates @@ -21,7 +21,7 @@ import { import { updateVaultDirectorParams, updateVaultManagerParams, -} from '../tools/changeVaultParams'; +} from '../tools/changeVaultParams.js'; const makeDefaultTestContext = async t => { console.time('DefaultTestContext'); @@ -76,10 +76,6 @@ test.after.always(t => { return t.context.shutdown && t.context.shutdown(); }); -const outcome = { - bids: [{ payouts: { Bid: 0, Collateral: 1.800828 } }], -}; - test('modify manager & director params; update vats, check', async t => { const { agoricNamesRemotes, evalProposal, buildProposal, gd } = t.context; From eb941d442717e9ed3b8c7641b69d8c1c74945480 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 9 Oct 2024 10:32:54 -0700 Subject: [PATCH 7/7] test: update new acceptance tests for results of priceFeed update --- .../z:acceptance/test-lib/sync-tools.js | 70 +++++++++++++++++++ .../proposals/z:acceptance/vaults.test.js | 40 +++++++++++ 2 files changed, 110 insertions(+) create mode 100644 a3p-integration/proposals/z:acceptance/test-lib/sync-tools.js diff --git a/a3p-integration/proposals/z:acceptance/test-lib/sync-tools.js b/a3p-integration/proposals/z:acceptance/test-lib/sync-tools.js new file mode 100644 index 00000000000..70ffbee37db --- /dev/null +++ b/a3p-integration/proposals/z:acceptance/test-lib/sync-tools.js @@ -0,0 +1,70 @@ +/** + * @file These tools mostly duplicate code that will be added in other PRs + * and eventually migrated to synthetic-chain. Sorry for the duplication. + */ + +/** + * @typedef {object} RetryOptions + * @property {number} [maxRetries] + * @property {number} [retryIntervalMs] + * @property {(...arg0: string[]) => void} [log] + * @property {(object) => void} [setTimeout] + * @property {string} [errorMessage=Error] + */ + +const ambientSetTimeout = globalThis.setTimeout; + +/** + * From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L10 + * + * @param {number} ms + * @param {*} sleepOptions + */ +const sleep = (ms, { log = () => {}, setTimeout = ambientSetTimeout }) => + new Promise(resolve => { + log(`Sleeping for ${ms}ms...`); + setTimeout(resolve, ms); + }); + +/** + * From https://github.com/Agoric/agoric-sdk/blob/442f07c8f0af03281b52b90e90c27131eef6f331/multichain-testing/tools/sleep.ts#L24 + * + * @param {() => Promise} operation + * @param {(result: any) => boolean} condition + * @param {string} message + * @param {RetryOptions} options + */ +export const retryUntilCondition = async ( + operation, + condition, + message, + { maxRetries = 6, retryIntervalMs = 3500, log, setTimeout }, +) => { + console.log({ maxRetries, retryIntervalMs, message }); + let retries = 0; + + await null; + while (retries < maxRetries) { + try { + const result = await operation(); + log('RESULT', result); + if (condition(result)) { + return result; + } + } catch (error) { + if (error instanceof Error) { + log(`Error: ${error.message}`); + } else { + log(`Unknown error: ${String(error)}`); + } + } + + retries += 1; + console.log( + `Retry ${retries}/${maxRetries} - Waiting for ${retryIntervalMs}ms for ${message}...`, + ); + await sleep(retryIntervalMs, { log, setTimeout }); + } + + throw Error(`${message} condition failed after ${maxRetries} retries.`); +}; diff --git a/a3p-integration/proposals/z:acceptance/vaults.test.js b/a3p-integration/proposals/z:acceptance/vaults.test.js index eea9b5899e9..a33ac7319b8 100644 --- a/a3p-integration/proposals/z:acceptance/vaults.test.js +++ b/a3p-integration/proposals/z:acceptance/vaults.test.js @@ -7,12 +7,52 @@ import { adjustVault, closeVault, getISTBalance, + getPriceQuote, + pushPrices, getContractInfo, ATOM_DENOM, USER1ADDR, waitForBlock, + registerOraclesForBrand, + generateOracleMap, } from '@agoric/synthetic-chain'; import { getBalances, agopsVaults } from './test-lib/utils.js'; +import { retryUntilCondition } from './test-lib/sync-tools.js'; + +export const scale6 = x => BigInt(x * 1_000_000); + +// There may be a new vaultFactory that doesn't have prices yet, so we publish +// prices now +test.before(async t => { + const pushPriceRetryOpts = { + maxRetries: 5, // arbitrary + retryIntervalMs: 5000, // in ms + }; + t.context = { + roundId: 1, + retryOpts: { + pushPriceRetryOpts, + }, + }; + const oraclesByBrand = generateOracleMap('z-acc', ['ATOM']); + await registerOraclesForBrand('ATOM', oraclesByBrand); + + const price = 15.2; + // @ts-expect-error t.context is fine + await pushPrices(price, 'ATOM', oraclesByBrand, t.context.roundId); + + await retryUntilCondition( + () => getPriceQuote('ATOM'), + res => res === `+${scale6(price).toString()}`, + 'price not pushed yet', + { + log: t.log, + setTimeout: globalThis.setTimeout, + // @ts-expect-error t.context is fine + ...t.context.pushPriceRetryOpts, + }, + ); +}); test.serial('attempt to open vaults under the minimum amount', async t => { const activeVaultsBefore = await agopsVaults(USER1ADDR);