From 247970e9534ec251f25b60ac5a801938eb5be66b Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 7 Jun 2023 12:27:44 -0700 Subject: [PATCH] test(bootstrap): liq after add-collateral --- packages/inter-protocol/package.json | 1 + packages/inter-protocol/scripts/add-STARS.js | 43 +++++ packages/vats/package.json | 1 + packages/vats/test/bootstrapTests/drivers.js | 12 +- .../vats/test/bootstrapTests/liquidation.js | 71 +++++--- .../test/bootstrapTests/test-liquidation-1.js | 163 ++++++++++++------ .../bootstrapTests/test-liquidation-2b.js | 14 +- 7 files changed, 218 insertions(+), 87 deletions(-) create mode 100644 packages/inter-protocol/scripts/add-STARS.js diff --git a/packages/inter-protocol/package.json b/packages/inter-protocol/package.json index 32ace4e0251..9462af14ee0 100644 --- a/packages/inter-protocol/package.json +++ b/packages/inter-protocol/package.json @@ -10,6 +10,7 @@ "scripts": { "build": "yarn build:bundles", "build:bundles": "node ./scripts/build-bundles.js", + "build:add-STARS-proposal": "agoric run scripts/add-STARS.js", "test": "ava", "test:c8": "c8 $C8_OPTIONS ava --config=ava-nesm.config.js", "test:xs": "exit 0", diff --git a/packages/inter-protocol/scripts/add-STARS.js b/packages/inter-protocol/scripts/add-STARS.js new file mode 100644 index 00000000000..8e6b0025bf4 --- /dev/null +++ b/packages/inter-protocol/scripts/add-STARS.js @@ -0,0 +1,43 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { defaultProposalBuilder as vaultProposalBuilder } from './add-collateral-core.js'; +import { defaultProposalBuilder as oraclesProposalBuilder } from './price-feed-core.js'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */ +export const starsVaultProposalBuilder = async powers => { + return vaultProposalBuilder(powers, { + interchainAssetOptions: { + // Values for the Stargaze token on Osmosis + denom: + 'ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4', + decimalPlaces: 6, + keyword: 'STARS', + oracleBrand: 'STARS', + proposedName: 'STARS', + }, + }); +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').ProposalBuilder} */ +export const starsOraclesProposalBuilder = async powers => { + return oraclesProposalBuilder(powers, { + AGORIC_INSTANCE_NAME: `STARS-USD price feed`, + IN_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', 'STARS'], + IN_BRAND_DECIMALS: 6, + OUT_BRAND_LOOKUP: ['agoricNames', 'oracleBrand', 'USD'], + OUT_BRAND_DECIMALS: 4, + oracleAddresses: [ + // copied from decentral-main-vaults-config.json + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', + ], + }); +}; + +export default async (homeP, endowments) => { + const { writeCoreProposal } = await makeHelpers(homeP, endowments); + await writeCoreProposal('add-STARS', starsVaultProposalBuilder); + await writeCoreProposal('add-STARS-oracles', starsOraclesProposalBuilder); +}; diff --git a/packages/vats/package.json b/packages/vats/package.json index ad128928217..d712ae3fb0b 100644 --- a/packages/vats/package.json +++ b/packages/vats/package.json @@ -14,6 +14,7 @@ "build:boot-viz-sim": "node src/authorityViz.js --sim-chain >docs/boot-sim.dot && dot -Tsvg docs/boot-sim.dot >docs/boot-sim.dot.svg", "build:boot-viz-sim-gov": "node src/authorityViz.js --sim-chain --gov >docs/boot-sim-gov.dot && dot -Tsvg docs/boot-sim-gov.dot >docs/boot-sim-gov.dot.svg", "build:restart-vats-proposal": "agoric run scripts/restart-vats.js", + "build:add-STARS-proposal": "agoric run scripts/add-STARS.js", "prepack": "tsc --build jsconfig.build.json", "postpack": "git clean -f '*.d.ts*'", "test": "ava", diff --git a/packages/vats/test/bootstrapTests/drivers.js b/packages/vats/test/bootstrapTests/drivers.js index 237b2a09999..4bfa1dbb684 100644 --- a/packages/vats/test/bootstrapTests/drivers.js +++ b/packages/vats/test/bootstrapTests/drivers.js @@ -145,28 +145,28 @@ export const makeWalletFactoryDriver = async ( }; /** - * @param {import('@agoric/internal/src/storage-test-utils.js').FakeStorageKit} storage + * @param {string} collateralBrandKey * @param {import('../../tools/board-utils.js').AgoricNamesRemotes} agoricNamesRemotes * @param {Awaited>} walletFactoryDriver * @param {string[]} oracleAddresses */ export const makePriceFeedDriver = async ( - storage, + collateralBrandKey, agoricNamesRemotes, walletFactoryDriver, oracleAddresses, ) => { - // XXX assumes this one feed - const priceFeedName = instanceNameFor('ATOM', 'USD'); + const priceFeedName = instanceNameFor(collateralBrandKey, 'USD'); const oracleWallets = await Promise.all( oracleAddresses.map(addr => walletFactoryDriver.provideSmartWallet(addr)), ); const priceFeedInstance = agoricNamesRemotes.instance[priceFeedName]; - const adminOfferId = 'acceptOracleInvitation'; + priceFeedInstance || Fail`no price feed ${priceFeedName}`; + const adminOfferId = `accept-${collateralBrandKey}-oracleInvitation`; - // accept invitations (TODO move into driver) + // accept invitations await Promise.all( oracleWallets.map(w => w.executeOffer({ diff --git a/packages/vats/test/bootstrapTests/liquidation.js b/packages/vats/test/bootstrapTests/liquidation.js index 8d4b0724021..972212e1928 100644 --- a/packages/vats/test/bootstrapTests/liquidation.js +++ b/packages/vats/test/bootstrapTests/liquidation.js @@ -39,9 +39,15 @@ export const makeLiquidationTestContext = async t => { console.timeLog('DefaultTestContext', 'vaultFactoryKit'); // has to be late enough for agoricNames data to have been published - const agoricNamesRemotes = makeAgoricNamesRemotesFromFakeStorage( - swingsetTestKit.storage, - ); + /** @type {import('../../tools/board-utils.js').AgoricNamesRemotes} */ + const agoricNamesRemotes = {}; + const refreshAgoricNamesRemotes = () => { + Object.assign( + agoricNamesRemotes, + makeAgoricNamesRemotesFromFakeStorage(swingsetTestKit.storage), + ); + }; + refreshAgoricNamesRemotes(); agoricNamesRemotes.brand.ATOM || Fail`ATOM missing from agoricNames`; console.timeLog('DefaultTestContext', 'agoricNamesRemotes'); @@ -65,30 +71,43 @@ export const makeLiquidationTestContext = async t => { ); console.timeLog('DefaultTestContext', 'governanceDriver'); - const priceFeedDriver = await makePriceFeedDriver( - storage, - agoricNamesRemotes, - walletFactoryDriver, - // TODO read from the config file - [ - 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', - 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', - 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', - 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', - 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', - ], - ); + /** @type {Record>>} */ + const priceFeedDrivers = {}; console.timeLog('DefaultTestContext', 'priceFeedDriver'); console.timeEnd('DefaultTestContext'); - const setupStartingState = async () => { + /** + * + * @param {object} opts + * @param {string} opts.collateralBrandKey + * @param {number} opts.managerIndex + */ + const setupStartingState = async ({ collateralBrandKey, managerIndex }) => { + const managerPath = `published.vaultFactory.managers.manager${managerIndex}`; const { advanceTimeBy, readLatest } = swingsetTestKit; + + !priceFeedDrivers[collateralBrandKey] || + Fail`setup for ${collateralBrandKey} already ran`; + priceFeedDrivers[collateralBrandKey] = await makePriceFeedDriver( + collateralBrandKey, + agoricNamesRemotes, + walletFactoryDriver, + // TODO read from the config file + [ + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', + ], + ); + // price feed logic treats zero time as "unset" so advance to nonzero await advanceTimeBy(1, 'seconds'); - await priceFeedDriver.setPrice(12.34); + await priceFeedDrivers[collateralBrandKey].setPrice(12.34); // raise the VaultFactory DebtLimit await governanceDriver.changeParams( @@ -102,7 +121,7 @@ export const makeLiquidationTestContext = async t => { { paramPath: { key: { - collateralBrand: agoricNamesRemotes.brand.ATOM, + collateralBrand: agoricNamesRemotes.brand[collateralBrandKey], }, }, }, @@ -120,7 +139,7 @@ export const makeLiquidationTestContext = async t => { ); // confirm Relevant Governance Parameter Assumptions - t.like(readLatest('published.vaultFactory.managers.manager0.governance'), { + t.like(readLatest(`${managerPath}.governance`), { current: { DebtLimit: { value: { value: DebtLimitValue } }, InterestRate: { @@ -168,11 +187,16 @@ export const makeLiquidationTestContext = async t => { }; const check = { - vaultNotification(vaultIndex, partial) { + /** + * @param {number} managerIndex + * @param {number} vaultIndex + * @param {Record} partial + */ + vaultNotification(managerIndex, vaultIndex, partial) { const { readLatest } = swingsetTestKit; const notification = readLatest( - `published.vaultFactory.managers.manager0.vaults.vault${vaultIndex}`, + `published.vaultFactory.managers.manager${managerIndex}.vaults.vault${vaultIndex}`, ); t.like(notification, partial); }, @@ -183,7 +207,8 @@ export const makeLiquidationTestContext = async t => { agoricNamesRemotes, check, governanceDriver, - priceFeedDriver, + priceFeedDrivers, + refreshAgoricNamesRemotes, setupStartingState, walletFactoryDriver, }; diff --git a/packages/vats/test/bootstrapTests/test-liquidation-1.js b/packages/vats/test/bootstrapTests/test-liquidation-1.js index ecb397d649d..906e69cef63 100644 --- a/packages/vats/test/bootstrapTests/test-liquidation-1.js +++ b/packages/vats/test/bootstrapTests/test-liquidation-1.js @@ -1,6 +1,6 @@ // @ts-check /** - * @file Bootstrap test integration vaults with smart-wallet + * @file Bootstrap test of liquidation across multiple collaterals */ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; @@ -9,6 +9,7 @@ import { makeParseAmount, Offers, } from '@agoric/inter-protocol/src/clientSupport.js'; +import process from 'process'; import { likePayouts, makeLiquidationTestContext, @@ -20,9 +21,6 @@ import { */ const test = anyTest; -// presently all these tests use one collateral manager -const collateralBrandKey = 'ATOM'; - //#region Product spec const setup = /** @type {const} */ ({ vaults: [ @@ -92,6 +90,7 @@ const outcome = /** @type {const} */ ({ reserve: { allocations: { ATOM: 0.309852, + STARS: 0.309852, }, shortfall: 0, }, @@ -129,24 +128,38 @@ test.after.always(t => { }); // Reference: Flow 1 from https://github.com/Agoric/agoric-sdk/issues/7123 -test.serial('scenario: Flow 1', async t => { +const checkFlow1 = async ( + t, + { collateralBrandKey, managerIndex }, + _expected, +) => { + // fail if there are any unhandled rejections + process.on('unhandledRejection', error => { + t.fail(/** @type {Error} */ (error).message); + }); + const { advanceTimeBy, advanceTimeTo, agoricNamesRemotes, check, setupStartingState, - priceFeedDriver, + priceFeedDrivers, readLatest, walletFactoryDriver, } = t.context; - await setupStartingState(); + const metricsPath = `published.vaultFactory.managers.manager${managerIndex}.metrics`; + + await setupStartingState({ + collateralBrandKey, + managerIndex, + }); const minter = await walletFactoryDriver.provideSmartWallet('agoric1minter'); for (let i = 0; i < setup.vaults.length; i += 1) { - const offerId = `open-vault${i}`; + const offerId = `open-${collateralBrandKey}-vault${i}`; await minter.executeOfferMaker(Offers.vaults.OpenVault, { offerId, collateralBrandKey, @@ -161,7 +174,7 @@ test.serial('scenario: Flow 1', async t => { // Verify starting balances for (let i = 0; i < setup.vaults.length; i += 1) { - check.vaultNotification(i, { + check.vaultNotification(managerIndex, i, { debtSnapshot: { debt: { value: scale6(setup.vaults[i].debt) } }, locked: { value: scale6(setup.vaults[i].atom) }, vaultState: 'active', @@ -180,18 +193,18 @@ test.serial('scenario: Flow 1', async t => { agoricNamesRemotes.instance['psm-IST-USDC_axl'], agoricNamesRemotes.brand, { - offerId: 'print-ist', + offerId: `print-${collateralBrandKey}-ist`, wantMinted: 1_000, pair: ['IST', 'USDC_axl'], }, ), ); - const maxBuy = '10000ATOM'; + const maxBuy = `10000${collateralBrandKey}`; // bids are long-lasting offers so we can't wait here for completion await buyer.sendOfferMaker(Offers.auction.Bid, { - offerId: 'bid1', + offerId: `${collateralBrandKey}-bid1`, ...setup.bids[0], maxBuy, parseAmount, @@ -199,33 +212,33 @@ test.serial('scenario: Flow 1', async t => { t.like(readLatest('published.wallet.agoric1buyer'), { status: { - id: 'bid1', + id: `${collateralBrandKey}-bid1`, result: 'Your bid has been accepted', payouts: undefined, }, }); await buyer.sendOfferMaker(Offers.auction.Bid, { - offerId: 'bid2', + offerId: `${collateralBrandKey}-bid2`, ...setup.bids[1], maxBuy, parseAmount, }); t.like(readLatest('published.wallet.agoric1buyer'), { status: { - id: 'bid2', + id: `${collateralBrandKey}-bid2`, result: 'Your bid has been accepted', payouts: undefined, }, }); await buyer.sendOfferMaker(Offers.auction.Bid, { - offerId: 'bid3', + offerId: `${collateralBrandKey}-bid3`, ...setup.bids[2], maxBuy, parseAmount, }); t.like(readLatest('published.wallet.agoric1buyer'), { status: { - id: 'bid3', + id: `${collateralBrandKey}-bid3`, result: 'Your bid has been accepted', payouts: undefined, }, @@ -237,22 +250,21 @@ test.serial('scenario: Flow 1', async t => { // Change price to trigger liquidation // --------------- - await priceFeedDriver.setPrice(9.99); + await priceFeedDrivers[collateralBrandKey].setPrice(9.99); // check nothing liquidating yet /** @type {import('@agoric/inter-protocol/src/auction/scheduler.js').ScheduleNotification} */ const liveSchedule = readLatest('published.auction.schedule'); t.is(liveSchedule.activeStartTime, null); - t.like(readLatest('published.vaultFactory.managers.manager0.metrics'), { + t.like(readLatest(metricsPath), { numActiveVaults: setup.vaults.length, numLiquidatingVaults: 0, - lockedQuote: null, }); // advance time to start an auction - console.log('step 0 of 10'); + console.log(collateralBrandKey, 'step 1 of 10'); await advanceTimeTo(NonNullish(liveSchedule.nextDescendingStepTime)); - t.like(readLatest('published.vaultFactory.managers.manager0.metrics'), { + t.like(readLatest(metricsPath), { numActiveVaults: 0, numLiquidatingVaults: setup.vaults.length, liquidatingCollateral: { @@ -262,24 +274,24 @@ test.serial('scenario: Flow 1', async t => { lockedQuote: null, }); - console.log('step 1 of 10'); + console.log(collateralBrandKey, 'step 2 of 10'); await advanceTimeBy(3, 'minutes'); - t.like(readLatest('published.auction.book0'), { + 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('step 2 of 10'); + console.log(collateralBrandKey, 'step 3 of 10'); await advanceTimeBy(3, 'minutes'); - console.log('step 3 of 10'); + console.log(collateralBrandKey, 'step 4 of 10'); await advanceTimeBy(3, 'minutes'); // XXX updates for bid1 and bid2 are appended in the same turn so readLatest gives bid2 // NB: console output shows 8897786n payout which matches spec 8.897ATOM // t.like(readLatest('published.wallet.agoric1buyer'), { // status: { - // id: 'bid1', + // id: `${collateralBrandKey}-bid1`, // payouts: { // Bid: { value: 0n }, // Collateral: { value: scale6(outcome.bids[0].payouts.Collateral) }, @@ -289,30 +301,30 @@ test.serial('scenario: Flow 1', async t => { t.like(readLatest('published.wallet.agoric1buyer'), { status: { - id: 'bid2', + id: `${collateralBrandKey}-bid2`, payouts: likePayouts(outcome.bids[1].payouts), }, }); - console.log('step 4 of 10'); + console.log(collateralBrandKey, 'step 5 of 10'); await advanceTimeBy(3, 'minutes'); - console.log('step 5 of 10'); + console.log(collateralBrandKey, 'step 6 of 10'); await advanceTimeBy(3, 'minutes'); - t.like(readLatest('published.auction.book0'), { + t.like(readLatest(`published.auction.book${managerIndex}`), { collateralAvailable: { value: 9659301n }, }); - console.log('step 6 of 10'); + console.log(collateralBrandKey, 'step 7 of 10'); await advanceTimeBy(3, 'minutes'); - console.log('step 7 of 10'); + console.log(collateralBrandKey, 'step 8 of 10'); await advanceTimeBy(3, 'minutes'); - console.log('step 8 of 10'); + console.log(collateralBrandKey, 'step 9 of 10'); await advanceTimeBy(3, 'minutes'); // Not part of product spec - t.like(readLatest('published.vaultFactory.managers.manager0.metrics'), { + t.like(readLatest(metricsPath), { numActiveVaults: 0, numLiquidationsCompleted: setup.vaults.length, numLiquidatingVaults: 0, @@ -325,36 +337,37 @@ test.serial('scenario: Flow 1', async t => { totalShortfallReceived: { value: 0n }, }); - console.log('step 9 of 10'); - await advanceTimeBy(3, 'minutes'); - - console.log('step 10 of 10'); - await advanceTimeBy(3, 'minutes'); - - console.log('step 11 of 10'); - await advanceTimeBy(3, 'minutes'); + console.log(collateralBrandKey, 'step 10 of 10'); + // continuing after now would start a new auction + { + /** @type {Record} */ + const { nextDescendingStepTime, nextStartTime } = readLatest( + 'published.auction.schedule', + ); + t.is(nextDescendingStepTime.absValue, nextStartTime.absValue); + } // bid3 still live because it's not fully satisfied const { liveOffers } = readLatest('published.wallet.agoric1buyer.current'); - t.is(liveOffers[0][1].id, 'bid3'); + t.is(liveOffers[0][1].id, `${collateralBrandKey}-bid3`); // exit to get payouts - await buyer.tryExitOffer('bid3'); + await buyer.tryExitOffer(`${collateralBrandKey}-bid3`); t.like(readLatest('published.wallet.agoric1buyer'), { status: { - id: 'bid3', + id: `${collateralBrandKey}-bid3`, payouts: likePayouts(outcome.bids[2].payouts), }, }); // TODO express spec up top in a way it can be passed in here - check.vaultNotification(0, { + check.vaultNotification(managerIndex, 0, { debt: undefined, vaultState: 'liquidated', locked: { value: scale6(outcome.vaultsActual[0].locked), }, }); - check.vaultNotification(1, { + check.vaultNotification(managerIndex, 1, { debt: undefined, vaultState: 'liquidated', locked: { @@ -366,10 +379,58 @@ test.serial('scenario: Flow 1', async t => { // check reserve balances t.like(readLatest('published.reserve.metrics'), { allocations: { - ATOM: { value: scale6(outcome.reserve.allocations.ATOM) }, - // not part of product spec - Fee: { value: scale6(1.54) }, + [collateralBrandKey]: { + value: scale6(outcome.reserve.allocations[collateralBrandKey]), + }, }, shortfallBalance: { value: scale6(outcome.reserve.shortfall) }, }); +}; + +test.serial( + 'liquidate ATOM', + checkFlow1, + { collateralBrandKey: 'ATOM', managerIndex: 0 }, + {}, +); + +test.serial('add STARS collateral', async t => { + const { controller, buildProposal } = t.context; + + t.log('building proposal'); + const proposal = await buildProposal({ + package: 'inter-protocol', + packageScriptName: 'build:add-STARS-proposal', + }); + + for await (const bundle of proposal.bundles) { + await controller.validateAndInstallBundle(bundle); + } + t.log('installed', proposal.bundles.length, 'bundles'); + + t.log('launching proposal'); + const bridgeMessage = { + type: 'CORE_EVAL', + evals: proposal.evals, + }; + t.log({ bridgeMessage }); + + const { EV } = t.context.runUtils; + /** @type {ERef} */ + const coreEvalBridgeHandler = await EV.vat('bootstrap').consumeItem( + 'coreEvalBridgeHandler', + ); + await EV(coreEvalBridgeHandler).fromBridge(bridgeMessage); + + t.context.refreshAgoricNamesRemotes(); + + t.log('restart-vats proposal executed'); + t.pass(); // reached here without throws }); + +test.serial( + 'liquidate STARS', + checkFlow1, + { collateralBrandKey: 'STARS', managerIndex: 1 }, + {}, +); diff --git a/packages/vats/test/bootstrapTests/test-liquidation-2b.js b/packages/vats/test/bootstrapTests/test-liquidation-2b.js index 354dd2b6b7e..c958c5e3076 100644 --- a/packages/vats/test/bootstrapTests/test-liquidation-2b.js +++ b/packages/vats/test/bootstrapTests/test-liquidation-2b.js @@ -127,12 +127,12 @@ test.serial('scenario: Flow 2b', async t => { agoricNamesRemotes, check, setupStartingState, - priceFeedDriver, + priceFeedDrivers, readLatest, walletFactoryDriver, } = t.context; - await setupStartingState(); + await setupStartingState({ collateralBrandKey: 'ATOM', managerIndex: 0 }); const minter = await walletFactoryDriver.provideSmartWallet('agoric1minter'); @@ -152,7 +152,7 @@ test.serial('scenario: Flow 2b', async t => { // Verify starting balances for (let i = 0; i < setup.vaults.length; i += 1) { - check.vaultNotification(i, { + check.vaultNotification(0, i, { debtSnapshot: { debt: { value: scale6(setup.vaults[i].debt) } }, locked: { value: scale6(setup.vaults[i].atom) }, vaultState: 'active', @@ -204,7 +204,7 @@ test.serial('scenario: Flow 2b', async t => { // Change price to trigger liquidation // --------------- - await priceFeedDriver.setPrice(9.99); + await priceFeedDrivers.ATOM.setPrice(9.99); // check nothing liquidating yet /** @type {import('@agoric/inter-protocol/src/auction/scheduler.js').ScheduleNotification} */ @@ -269,21 +269,21 @@ test.serial('scenario: Flow 2b', async t => { await advanceTimeBy(3, 'minutes'); // TODO express spec up top in a way it can be passed in here - check.vaultNotification(0, { + check.vaultNotification(0, 0, { debt: undefined, vaultState: 'active', locked: { value: scale6(outcome.vaultsActual[0].locked), }, }); - check.vaultNotification(1, { + check.vaultNotification(0, 1, { debt: undefined, vaultState: 'active', locked: { value: scale6(outcome.vaultsActual[1].locked), }, }); - check.vaultNotification(2, { + check.vaultNotification(0, 2, { debt: undefined, vaultState: 'liquidated', locked: {