From 9cedbdc37a7c896cb3caa451be40e872aaaa766c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 2 May 2022 14:32:34 -0700 Subject: [PATCH 01/39] chore(vault): type VaultUIState -> VaultTitleState --- packages/run-protocol/src/runStake/runStakeKit.js | 2 +- packages/run-protocol/src/vaultFactory/types.js | 2 +- packages/run-protocol/src/vaultFactory/vault.js | 6 +++--- packages/run-protocol/src/vaultFactory/vaultTitle.js | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/run-protocol/src/runStake/runStakeKit.js b/packages/run-protocol/src/runStake/runStakeKit.js index d21d513d03d..6c877fcfc8c 100644 --- a/packages/run-protocol/src/runStake/runStakeKit.js +++ b/packages/run-protocol/src/runStake/runStakeKit.js @@ -166,7 +166,7 @@ const helperBehavior = { snapshotState: ({ state, facets }, newActive) => { const { debtSnapshot: debt, interestSnapshot: interest, manager } = state; const { helper } = facets; - /** @type {VaultUIState} */ + /** @type {VaultTitleState} */ const result = harden({ // TODO move manager state to a separate notifer https://github.com/Agoric/agoric-sdk/issues/4540 interestRate: manager.getInterestRate(), diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index e0a1d6c2850..387e810e990 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -1,6 +1,6 @@ // @ts-check -/** @typedef {import('./vault').VaultUIState} VaultUIState */ +/** @typedef {import('./vault').VaultTitleState} VaultTitleState */ /** @typedef {import('./vault').Vault} Vault */ /** @typedef {import('./vaultKit').VaultKit} VaultKit */ /** @typedef {import('./vaultManager').VaultManager} VaultManager */ diff --git a/packages/run-protocol/src/vaultFactory/vault.js b/packages/run-protocol/src/vaultFactory/vault.js index fd74b0d2c62..fd4783defb9 100644 --- a/packages/run-protocol/src/vaultFactory/vault.js +++ b/packages/run-protocol/src/vaultFactory/vault.js @@ -66,7 +66,7 @@ const validTransitions = { /** * @typedef {Phase[keyof typeof Phase]} TitlePhase * - * @typedef {object} VaultUIState + * @typedef {object} VaultTitleState * @property {Amount<'nat'>} locked Amount of Collateral locked * @property {{debt: Amount<'nat'>, interest: Ratio}} debtSnapshot 'debt' at the point the compounded interest was 'interest' * @property {Ratio} interestRate Annual interest rate charge @@ -101,7 +101,7 @@ const validTransitions = { * * @typedef {{ * interestSnapshot: Ratio, - * outerUpdater: IterationObserver | null, + * outerUpdater: IterationObserver | null, * phase: VaultPhase, * debtSnapshot: Amount<'nat'>, * }} MutableState @@ -302,7 +302,7 @@ const helperBehavior = { */ getStateSnapshot: ({ state, facets }, newPhase) => { const { debtSnapshot: debt, interestSnapshot: interest } = state; - /** @type {VaultUIState} */ + /** @type {VaultTitleState} */ return harden({ // TODO move manager state to a separate notifer https://github.com/Agoric/agoric-sdk/issues/4540 interestRate: state.manager.getGovernedParams().getInterestRate(), diff --git a/packages/run-protocol/src/vaultFactory/vaultTitle.js b/packages/run-protocol/src/vaultFactory/vaultTitle.js index 43b541351ae..01adfccc841 100644 --- a/packages/run-protocol/src/vaultFactory/vaultTitle.js +++ b/packages/run-protocol/src/vaultFactory/vaultTitle.js @@ -10,8 +10,8 @@ const { details: X } = assert; /** * @typedef {{ - * notifier: NotifierRecord['notifier'], - * updater: NotifierRecord['updater'], + * notifier: NotifierRecord['notifier'], + * updater: NotifierRecord['updater'], * vault: Vault | null, * }} State * @typedef {Readonly<{ @@ -29,7 +29,7 @@ const { details: X } = assert; * @returns {State} */ const initState = vault => { - /** @type {NotifierRecord} */ + /** @type {NotifierRecord} */ const { updater, notifier } = makeNotifierKit(); return { notifier, updater, vault }; From 53346723a0faaf27a87a5824a9271d5e645c8922 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 3 May 2022 16:09:12 -0700 Subject: [PATCH 02/39] chore(zoe): type setupZCFTest --- packages/zoe/test/unitTests/zcf/setupZcfTest.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/zoe/test/unitTests/zcf/setupZcfTest.js b/packages/zoe/test/unitTests/zcf/setupZcfTest.js index 3a02315d7ae..e7d85d5bbaf 100644 --- a/packages/zoe/test/unitTests/zcf/setupZcfTest.js +++ b/packages/zoe/test/unitTests/zcf/setupZcfTest.js @@ -14,6 +14,12 @@ const dirname = path.dirname(filename); const contractRoot = `${dirname}/zcfTesterContract.js`; +/** + * Test setup utility + * + * @param {IssuerKeywordRecord} [issuerKeywordRecord] + * @param {Record} [terms] + */ export const setupZCFTest = async (issuerKeywordRecord, terms) => { /** @type {ZCF} */ let zcf; From af797d9ec9434b9b5a635cfa8b8b38b1f6c6f1bb Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 3 May 2022 16:38:43 -0700 Subject: [PATCH 03/39] chore(vault): disambiguate VaultManager type (facet naming confusion) --- packages/run-protocol/src/vaultFactory/types.js | 3 ++- packages/run-protocol/src/vaultFactory/vault.js | 1 + .../run-protocol/src/vaultFactory/vaultDirector.js | 13 ++++++++++--- .../run-protocol/src/vaultFactory/vaultManager.js | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index 387e810e990..08ab13f8006 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -4,6 +4,7 @@ /** @typedef {import('./vault').Vault} Vault */ /** @typedef {import('./vaultKit').VaultKit} VaultKit */ /** @typedef {import('./vaultManager').VaultManager} VaultManager */ +/** @typedef {import('./vaultManager').VaultManagerObject} VaultManagerObject */ /** @typedef {import('./vaultManager').CollateralManager} CollateralManager */ /** @@ -37,7 +38,7 @@ * @param {Issuer} collateralIssuer * @param {Keyword} collateralKeyword * @param {VaultManagerParamValues} params - * @returns {Promise} + * @returns {Promise} */ /** diff --git a/packages/run-protocol/src/vaultFactory/vault.js b/packages/run-protocol/src/vaultFactory/vault.js index fd4783defb9..6208ce475f4 100644 --- a/packages/run-protocol/src/vaultFactory/vault.js +++ b/packages/run-protocol/src/vaultFactory/vault.js @@ -74,6 +74,7 @@ const validTransitions = { * @property {TitlePhase} vaultState */ +// XXX masks typedef from types.js, but using that causes circular def problems /** * @typedef {object} VaultManager * @property {() => Notifier} getNotifier diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 56bca7005b2..1750ec0c485 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -33,7 +33,7 @@ const { details: X } = assert; /** * @typedef {Readonly<{ * debtMint: ZCFMint<'nat'>, - * collateralTypes: Store, + * collateralTypes: Store, * electionManager: Instance, * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager<{VaultDirectorParams}>, * mintSeat: ZCFSeat, @@ -119,7 +119,7 @@ const makeVaultInvitation = ({ state }) => { }. ${requestedAmount.value} is too small`, ); - /** @type {VaultManager} */ + /** @type {VaultManagerObject} */ const mgr = collateralTypes.get(brandIn); return mgr.makeVaultKit(seat); }; @@ -160,6 +160,13 @@ const getLiquidationConfig = directorParamManager => ({ terms: directorParamManager.getLiquidationTerms(), }); +/** + * + * @param {ImmutableState['directorParamManager']} govParams + * @param {VaultManagerObject} vaultManager + * @param {*} oldInstall + * @param {*} oldTerms + */ const watchGovernance = (govParams, vaultManager, oldInstall, oldTerms) => { const subscription = govParams.getSubscription(); observeIteration(subscription, { @@ -353,7 +360,7 @@ const publicBehavior = { collateralTypes.has(brandIn), X`Not a supported collateral type ${brandIn}`, ); - /** @type {VaultManager} */ + /** @type {VaultManagerObject} */ return collateralTypes.get(brandIn).getPublicFacet(); }, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 5cf73cf0c1d..dea881cb1a1 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -636,5 +636,6 @@ const makeVaultManagerKit = defineKindMulti( */ export const makeVaultManager = pickFacet(makeVaultManagerKit, 'self'); -/** @typedef {ReturnType} VaultManager */ -/** @typedef {ReturnType} CollateralManager */ +/** @typedef {ReturnType['manager']} VaultManager */ +/** @typedef {ReturnType} VaultManagerObject */ +/** @typedef {ReturnType} CollateralManager */ From b4a5fcff00c74bc295c282f7083cdcaf04b3ce09 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 29 Apr 2022 15:19:45 -0700 Subject: [PATCH 04/39] feat(vault): vaultDirector econ notifier --- .../run-protocol/src/vaultFactory/types.js | 1 + .../src/vaultFactory/vaultDirector.js | 41 +++++++++- .../test/vaultFactory/test-vaultFactory.js | 81 +++++++++++++++---- 3 files changed, 104 insertions(+), 19 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index 08ab13f8006..bef3eb39095 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -49,6 +49,7 @@ * @property {() => Allocation} getPenaltyAllocation * @property {() => Instance} getContractGovernor * @property {() => Promise} makeCollectFeesInvitation + * @property {() => void} notifyEcon */ /** diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 1750ec0c485..2db8f9bd2f0 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -18,7 +18,7 @@ import { Far } from '@endo/marshal'; import { AmountMath } from '@agoric/ertp'; import { assertKeywordName } from '@agoric/zoe/src/cleanProposal.js'; import { defineKindMulti } from '@agoric/vat-data'; -import { observeIteration } from '@agoric/notifier'; +import { makeNotifierKit, observeIteration } from '@agoric/notifier'; import { makeVaultManager } from './vaultManager.js'; import { makeMakeCollectFeesInvitation } from '../collectFees.js'; import { @@ -31,6 +31,12 @@ import { const { details: X } = assert; /** + * @typedef {{ + * collaterals: Brand[], + * penaltyPoolAllocation: AmountKeywordRecord, + * rewardPoolAllocation: AmountKeywordRecord, + * }} EconState + * * @typedef {Readonly<{ * debtMint: ZCFMint<'nat'>, * collateralTypes: Store, @@ -40,6 +46,8 @@ const { details: X } = assert; * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, * vaultParamManagers: Store, + * econNotifier: Notifier + * econUpdater: IterationObserver * zcf: import('./vaultFactory.js').VaultFactoryZCF, * }>} ImmutableState * @@ -70,13 +78,17 @@ const initState = (zcf, directorParamManager, debtMint) => { const vaultParamManagers = makeScalarMap('brand'); + const { notifier: econNotifier, updater: econUpdater } = makeNotifierKit(); + return { collateralTypes, debtMint, directorParamManager, + econNotifier, + econUpdater, mintSeat, - rewardPoolSeat, penaltyPoolSeat, + rewardPoolSeat, vaultParamManagers, zcf, }; @@ -154,7 +166,9 @@ const getCollaterals = async ({ state }) => { ), ); }; - +/** + * @param {ImmutableState['directorParamManager']} directorParamManager + */ const getLiquidationConfig = directorParamManager => ({ install: directorParamManager.getLiquidationInstall(), terms: directorParamManager.getLiquidationTerms(), @@ -194,7 +208,7 @@ const machineBehavior = { * @param {VaultManagerParamValues} initialParamValues */ addVaultType: async ( - { state }, + { state, facets }, collateralIssuer, collateralKeyword, initialParamValues, @@ -259,6 +273,7 @@ const machineBehavior = { } // TODO add aggregate debt tracking at the vaultFactory level #4482 // totalDebt = AmountMath.add(totalDebt, toMint); + facets.machine.notifyEcon(); }; /** @@ -295,6 +310,7 @@ const machineBehavior = { const { install, terms } = getLiquidationConfig(directorParamManager); await vm.setupLiquidator(install, terms); watchGovernance(directorParamManager, vm, install, terms); + facets.machine.notifyEcon(); return vm; }, getCollaterals, @@ -310,6 +326,16 @@ const machineBehavior = { }, /** @param {MethodContext} context */ getContractGovernor: ({ state }) => state.zcf.getTerms().electionManager, + /** @param {MethodContext} context */ + notifyEcon: ({ state }) => { + /** @type {EconState} */ + const econState = harden({ + collaterals: Array.from(state.collateralTypes.keys()), + penaltyPoolAllocation: state.penaltyPoolSeat.getCurrentAllocation(), + rewardPoolAllocation: state.rewardPoolSeat.getCurrentAllocation(), + }); + state.econUpdater.updateState(econState); + }, // XXX accessors for tests /** @param {MethodContext} context */ @@ -363,6 +389,13 @@ const publicBehavior = { /** @type {VaultManagerObject} */ return collateralTypes.get(brandIn).getPublicFacet(); }, + /** + * @param {MethodContext} context + */ + getPublicNotifiers: ({ state }) => { + const { econNotifier } = state; + return { econ: econNotifier }; + }, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ makeLoanInvitation: makeVaultInvitation, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 11d18c8e7c9..b0dd67da4e1 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -293,12 +293,12 @@ async function setupServices( const governorCreatorFacet = consume.vaultFactoryGovernorCreator; /** @type {Promise>} */ - const vaultFactoryCreatorFacet = /** @type { any } */ ( + const vaultFactoryCreatorFacetP = /** @type { any } */ ( E(governorCreatorFacet).getCreatorFacet() ); // Add a vault that will lend on aeth collateral - const aethVaultManagerP = E(vaultFactoryCreatorFacet).addVaultType( + const aethVaultManagerP = E(vaultFactoryCreatorFacetP).addVaultType( aethIssuer, 'AEth', rates, @@ -307,18 +307,23 @@ async function setupServices( // @ts-expect-error cast const [ governorInstance, - vaultFactory, + vaultFactoryCreator, lender, aethVaultManager, priceAuthority, ] = await Promise.all([ E(consume.agoricNames).lookup('instance', 'VaultFactoryGovernor'), - vaultFactoryCreatorFacet, + vaultFactoryCreatorFacetP, E(governorCreatorFacet).getPublicFacet(), aethVaultManagerP, pa, ]); - trace(t, 'pa', { governorInstance, vaultFactory, lender, priceAuthority }); + trace(t, 'pa', { + governorInstance, + vaultFactory: vaultFactoryCreator, + lender, + priceAuthority, + }); const { g, v } = { g: { @@ -327,7 +332,7 @@ async function setupServices( governorCreatorFacet, }, v: { - vaultFactory, + vaultFactoryCreator, lender, aethVaultManager, }, @@ -364,7 +369,11 @@ test('first', async t => { undefined, 500n, ); - const { vaultFactory, lender, aethVaultManager } = services.vaultFactory; + const { + vaultFactoryCreator: vaultFactory, + lender, + aethVaultManager, + } = services.vaultFactory; trace(t, 'services', { services, vaultFactory, lender }); // Create a loan for 470 RUN with 1100 aeth collateral @@ -496,7 +505,7 @@ test('price drop', async t => { trace(t, 'setup'); const { - vaultFactory: { vaultFactory, lender }, + vaultFactory: { vaultFactoryCreator: vaultFactory, lender }, priceAuthority, } = services; @@ -636,7 +645,7 @@ test('price falls precipitously', async t => { undefined, 1500n, ); - const { vaultFactory, lender } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; // Create a loan for 370 RUN with 400 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 400n); @@ -784,7 +793,7 @@ test('vaultFactory display collateral', async t => { 500n, ); - const { vaultFactory } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; const collaterals = await E(vaultFactory).getCollaterals(); t.deepEqual(collaterals[0], { brand: aethBrand, @@ -823,7 +832,7 @@ test('interest on multiple vaults', async t => { SECONDS_PER_DAY, 500n, ); - const { vaultFactory, lender } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; // Create a loan for Alice for 4700 RUN with 1100 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 1100n); @@ -1413,7 +1422,7 @@ test('overdeposit', async t => { undefined, 500n, ); - const { vaultFactory, lender } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; // Alice's loan ///////////////////////////////////// @@ -1792,7 +1801,7 @@ test('collect fees from loan and AMM', async t => { undefined, 500n, ); - const { vaultFactory, lender } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; // Create a loan for 470 RUN with 1100 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 1100n); @@ -2279,7 +2288,7 @@ test('addVaultType: invalid args do not modify state', async t => { 500n, ); - const { vaultFactory } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; const failsForSameReason = async p => p @@ -2316,7 +2325,7 @@ test('addVaultType: extra, unexpected params', async t => { 500n, ); - const { vaultFactory } = services.vaultFactory; + const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; const params = { ...defaultParamValues(aethBrand), shoeSize: 10 }; const extraParams = { ...params, shoeSize: 10 }; @@ -2337,3 +2346,45 @@ test('addVaultType: extra, unexpected params', async t => { ); t.true(matches(actual, M.remotable()), 'unexpected params are ignored'); }); + +test('director notifiers', async t => { + const { + aethKit: { brand: aethBrand }, + } = t.context; + const services = await setupServices( + t, + [500n, 15n], + AmountMath.make(aethBrand, 900n), + undefined, + undefined, + 500n, + ); + + const { lender, vaultFactoryCreator } = services.vaultFactory; + + const { econ } = await E(lender).getPublicNotifiers(); + + let state = await E(econ).getUpdateSince(); + t.deepEqual(state.value, { + collaterals: [aethBrand], + penaltyPoolAllocation: {}, + rewardPoolAllocation: {}, + }); + + // add a vault type + const chit = makeIssuerKit('chit'); + await E(vaultFactoryCreator).addVaultType( + chit.issuer, + 'Chit', + defaultParamValues(chit.brand), + ); + state = await E(econ).getUpdateSince(state.updateCount); + t.deepEqual(state.value, { + collaterals: [aethBrand, chit.brand], + penaltyPoolAllocation: {}, + rewardPoolAllocation: {}, + }); + + // Not testing penaltyPoolAllocation and rewardPoolAllocation contents because those are simply those values. + // We could refactor the tests of those allocations to use the data now exposed by a notifier. +}); From 696b65149e560f322d189d1b8bbd1a3a36f22721 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 2 May 2022 16:00:10 -0700 Subject: [PATCH 05/39] feat(vault): vaultManager econNotifier --- .../src/vaultFactory/vaultManager.js | 44 ++++++++++++++-- .../test/vaultFactory/test-liquidator.js | 2 +- .../test/vaultFactory/test-vaultFactory.js | 50 ++++++++++++++++++- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index dea881cb1a1..803af4c6c15 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -34,11 +34,15 @@ const trace = makeTracer('VM', false); * compoundedInterest: Ratio, * interestRate: Ratio, * latestInterestUpdate: bigint, + * }} AssetState + * + * @typedef {{ + * numVaults: number, + * totalCollateral: Amount<'nat'>, * totalDebt: Amount<'nat'>, * liquidatorInstance?: Instance, - * }} AssetState */ - -/** + * }} EconState + * * @typedef {{ * getChargingPeriod: () => bigint, * getRecordingPeriod: () => bigint, @@ -70,9 +74,12 @@ const trace = makeTracer('VM', false); * assetNotifier: Notifier, * assetUpdater: IterationObserver, * compoundedInterest: Ratio, + * econNotifier: Notifier, + * econUpdater: IterationObserver, * latestInterestUpdate: bigint, * liquidator?: Liquidator * liquidatorInstance?: Instance + * totalCollateral: Amount<'nat'>, * totalDebt: Amount<'nat'>, * vaultCounter: number, * }} MutableState @@ -138,6 +145,7 @@ const initState = ( zcf, }; + const totalCollateral = AmountMath.makeEmpty(fixed.collateralBrand, 'nat'); const totalDebt = AmountMath.makeEmpty(fixed.debtBrand, 'nat'); const compoundedInterest = makeRatio(100n, fixed.debtBrand); // starts at 1.0, no interest // timestamp of most recent update to interest @@ -148,8 +156,14 @@ const initState = ( compoundedInterest, interestRate: fixed.factoryPowers.getGovernedParams().getInterestRate(), latestInterestUpdate, + }), + ); + + const { updater: econUpdater, notifier: econNotifier } = makeNotifierKit( + harden({ + numVaults: 0, + totalCollateral, totalDebt, - liquidationInstance: undefined, }), ); @@ -159,9 +173,12 @@ const initState = ( assetNotifier, assetUpdater, debtBrand: fixed.debtBrand, + econNotifier, + econUpdater, vaultCounter: 0, liquidator: undefined, liquidatorInstance: undefined, + totalCollateral, totalDebt, compoundedInterest, latestInterestUpdate, @@ -243,6 +260,17 @@ const helperBehavior = { state.assetUpdater.updateState(payload); }, + /** @param {MethodContext} context */ + econNotify: ({ state }) => { + /** @type {EconState} */ + const payload = harden({ + numVaults: state.prioritizedVaults.getSize(), + totalCollateral: state.totalCollateral, + totalDebt: state.totalDebt, + }); + state.econUpdater.updateState(payload); + }, + /** * When any Vault's debt ratio is higher than the current high-water level, * call `reschedulePriceCheck()` to request a fresh notification from the @@ -464,7 +492,9 @@ const collateralBehavior = { makeVaultInvitation: ({ state: { zcf }, facets: { self } }) => zcf.makeInvitation(self.makeVaultKit, 'MakeVault'), /** @param {MethodContext} context */ - getNotifier: ({ state }) => state.assetNotifier, + getAssetNotifier: ({ state }) => state.assetNotifier, + /** @param {MethodContext} context */ + getPublicNotifiers: ({ state }) => ({ econ: state.econNotifier }), /** @param {MethodContext} context */ getCompoundedInterest: ({ state }) => state.compoundedInterest, }; @@ -510,6 +540,10 @@ const selfBehavior = { // TODO `await` is allowed until the above ordering is fixed // eslint-disable-next-line @jessie.js/no-nested-await const vaultKit = await vault.initVaultKit(seat); + state.totalCollateral = AmountMath.add( + state.totalCollateral, + vaultKit.vault.getCollateralAmount(), + ); seat.exit(); return vaultKit; } catch (err) { diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index bd0e3e7e822..6fc6d9a1f96 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -342,7 +342,7 @@ const makeDriver = async (t, initialPrice, priceBase) => { } = services; const managerNotifier = await E( E(lender).getCollateralManager(aethBrand), - ).getNotifier(); + ).getAssetNotifier(); let managerNotification = await E(managerNotifier).getUpdateSince(); /** @type {UserSeat} */ diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index b0dd67da4e1..15ea8b1fb40 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -298,13 +298,12 @@ async function setupServices( ); // Add a vault that will lend on aeth collateral + /** @type {Promise} */ const aethVaultManagerP = E(vaultFactoryCreatorFacetP).addVaultType( aethIssuer, 'AEth', rates, ); - /** @type {[any, VaultFactory, VFC['publicFacet']]} */ - // @ts-expect-error cast const [ governorInstance, vaultFactoryCreator, @@ -2388,3 +2387,50 @@ test('director notifiers', async t => { // Not testing penaltyPoolAllocation and rewardPoolAllocation contents because those are simply those values. // We could refactor the tests of those allocations to use the data now exposed by a notifier. }); + +test('manager notifiers', async t => { + const { aethKit, runKit } = t.context; + const services = await setupServices( + t, + [500n, 15n], + AmountMath.make(aethKit.brand, 900n), + undefined, + undefined, + 500n, + ); + + const { aethVaultManager, lender } = services.vaultFactory; + const cm = await E(aethVaultManager).getPublicFacet(); + + const { econ } = await E(cm).getPublicNotifiers(); + let state = await E(econ).getUpdateSince(); + t.deepEqual(state.value, { + numVaults: 0, + totalCollateral: AmountMath.makeEmpty(aethKit.brand), + totalDebt: AmountMath.makeEmpty(t.context.runKit.brand), + }); + + // Create a loan for 470 RUN with 1100 aeth collateral + const collateralAmount = AmountMath.make(aethKit.brand, 1100n); + const loanAmount = AmountMath.make(runKit.brand, 470n); + /** @type {UserSeat} */ + const vaultSeat = await E(services.zoe).offer( + await E(lender).makeVaultInvitation(), + harden({ + give: { Collateral: collateralAmount }, + want: { RUN: loanAmount }, + }), + harden({ + Collateral: t.context.aethKit.mint.mintPayment(collateralAmount), + }), + ); + + await E(vaultSeat).getOfferResult(); + + state = await E(econ).getUpdateSince(state.updateCount); + t.deepEqual(state.value, { + numVaults: 1, + totalCollateral: collateralAmount, + totalDebt: AmountMath.make(runKit.brand, 494n), // 470 plus fee + }); +}); From 8fc22d7d46155fe58606e22e5ef5e4ac1038c3bb Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 2 May 2022 16:09:25 -0700 Subject: [PATCH 06/39] feat(vault): number of vaults per manager in EconState --- .../src/vaultFactory/prioritizedVaults.js | 1 + .../run-protocol/src/vaultFactory/vaultManager.js | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/prioritizedVaults.js b/packages/run-protocol/src/vaultFactory/prioritizedVaults.js index f38074536e7..5dfa3c0ad5f 100644 --- a/packages/run-protocol/src/vaultFactory/prioritizedVaults.js +++ b/packages/run-protocol/src/vaultFactory/prioritizedVaults.js @@ -174,6 +174,7 @@ export const makePrioritizedVaults = (reschedulePriceCheck = () => {}) => { addVault, entries: vaults.entries, entriesPrioritizedGTE, + getSize: vaults.getSize, highestRatio: firstDebtRatio, refreshVaultPriority, removeVault, diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 803af4c6c15..178a44bbbd1 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -34,13 +34,13 @@ const trace = makeTracer('VM', false); * compoundedInterest: Ratio, * interestRate: Ratio, * latestInterestUpdate: bigint, + * liquidatorInstance?: Instance, * }} AssetState * * @typedef {{ * numVaults: number, * totalCollateral: Amount<'nat'>, * totalDebt: Amount<'nat'>, - * liquidatorInstance?: Instance, * }} EconState * * @typedef {{ @@ -240,12 +240,13 @@ const helperBehavior = { updateTime, ); Object.assign(state, stateUpdates); - facets.helper.notify(); + facets.helper.assetNotify(); trace('chargeAllVaults complete'); facets.helper.reschedulePriceCheck(); }, - notify: ({ state }) => { + /** @param {MethodContext} context */ + assetNotify: ({ state }) => { const interestRate = state.factoryPowers .getGovernedParams() .getInterestRate(); @@ -254,7 +255,7 @@ const helperBehavior = { compoundedInterest: state.compoundedInterest, interestRate, latestInterestUpdate: state.latestInterestUpdate, - totalDebt: state.totalDebt, + // XXX move to EconState and type as present with null liquidatorInstance: state.liquidatorInstance, }); state.assetUpdater.updateState(payload); @@ -521,7 +522,7 @@ const selfBehavior = { * @param {MethodContext} context * @param {ZCFSeat} seat */ - makeVaultKit: async ({ state, facets: { manager } }, seat) => { + makeVaultKit: async ({ state, facets: { helper, manager } }, seat) => { const { prioritizedVaults, zcf } = state; assertProposalShape(seat, { give: { Collateral: null }, @@ -545,6 +546,7 @@ const selfBehavior = { vaultKit.vault.getCollateralAmount(), ); seat.exit(); + helper.econNotify(); return vaultKit; } catch (err) { // remove it from prioritizedVaults @@ -594,7 +596,7 @@ const selfBehavior = { }); state.liquidatorInstance = instance; state.liquidator = creatorFacet; - facets.helper.notify(); + facets.helper.assetNotify(); }, /** @param {MethodContext} context */ From 4a0d2d64dc26d60a41fe7c4e4714ae8827aee266 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 09:35:35 -0700 Subject: [PATCH 07/39] style: fix 'object' type casing --- packages/run-protocol/test/vaultFactory/test-liquidator.js | 2 +- packages/vats/src/core/types.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index 6fc6d9a1f96..1026371aef3 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -382,7 +382,7 @@ const makeDriver = async (t, initialPrice, priceBase) => { /** * * @param {Vault.Phase} phase - * @param {Object} likeExpected + * @param {object} likeExpected * @param {undefined|AT_NEXT|number} optSince */ notified: async (phase, likeExpected, optSince) => { diff --git a/packages/vats/src/core/types.js b/packages/vats/src/core/types.js index 122afd3b614..680e7c7bd77 100644 --- a/packages/vats/src/core/types.js +++ b/packages/vats/src/core/types.js @@ -78,7 +78,7 @@ */ /** - * @typedef {Object} Producer + * @typedef {object} Producer * @property {(v: ERef) => void} resolve * @property {(r: unknown) => void} reject * @property {() => void} reset From a6f5d8bbd2f298301bbf1fb5a7c39fb415256037 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 09:48:18 -0700 Subject: [PATCH 08/39] fixup! chore(vault): type VaultUIState -> VaultTitleState --- packages/run-protocol/src/runStake/runStakeKit.js | 2 +- packages/run-protocol/src/vaultFactory/types.js | 2 +- packages/run-protocol/src/vaultFactory/vault.js | 6 +++--- packages/run-protocol/src/vaultFactory/vaultTitle.js | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/run-protocol/src/runStake/runStakeKit.js b/packages/run-protocol/src/runStake/runStakeKit.js index 6c877fcfc8c..5b44f9aff57 100644 --- a/packages/run-protocol/src/runStake/runStakeKit.js +++ b/packages/run-protocol/src/runStake/runStakeKit.js @@ -166,7 +166,7 @@ const helperBehavior = { snapshotState: ({ state, facets }, newActive) => { const { debtSnapshot: debt, interestSnapshot: interest, manager } = state; const { helper } = facets; - /** @type {VaultTitleState} */ + /** @type {VaultNotification} */ const result = harden({ // TODO move manager state to a separate notifer https://github.com/Agoric/agoric-sdk/issues/4540 interestRate: manager.getInterestRate(), diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index bef3eb39095..6257544d3cb 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -1,6 +1,6 @@ // @ts-check -/** @typedef {import('./vault').VaultTitleState} VaultTitleState */ +/** @typedef {import('./vault').VaultNotification} VaultNotification */ /** @typedef {import('./vault').Vault} Vault */ /** @typedef {import('./vaultKit').VaultKit} VaultKit */ /** @typedef {import('./vaultManager').VaultManager} VaultManager */ diff --git a/packages/run-protocol/src/vaultFactory/vault.js b/packages/run-protocol/src/vaultFactory/vault.js index 6208ce475f4..65ca8db0ee1 100644 --- a/packages/run-protocol/src/vaultFactory/vault.js +++ b/packages/run-protocol/src/vaultFactory/vault.js @@ -66,7 +66,7 @@ const validTransitions = { /** * @typedef {Phase[keyof typeof Phase]} TitlePhase * - * @typedef {object} VaultTitleState + * @typedef {object} VaultNotification * @property {Amount<'nat'>} locked Amount of Collateral locked * @property {{debt: Amount<'nat'>, interest: Ratio}} debtSnapshot 'debt' at the point the compounded interest was 'interest' * @property {Ratio} interestRate Annual interest rate charge @@ -102,7 +102,7 @@ const validTransitions = { * * @typedef {{ * interestSnapshot: Ratio, - * outerUpdater: IterationObserver | null, + * outerUpdater: IterationObserver | null, * phase: VaultPhase, * debtSnapshot: Amount<'nat'>, * }} MutableState @@ -303,7 +303,7 @@ const helperBehavior = { */ getStateSnapshot: ({ state, facets }, newPhase) => { const { debtSnapshot: debt, interestSnapshot: interest } = state; - /** @type {VaultTitleState} */ + /** @type {VaultNotification} */ return harden({ // TODO move manager state to a separate notifer https://github.com/Agoric/agoric-sdk/issues/4540 interestRate: state.manager.getGovernedParams().getInterestRate(), diff --git a/packages/run-protocol/src/vaultFactory/vaultTitle.js b/packages/run-protocol/src/vaultFactory/vaultTitle.js index 01adfccc841..c51da929168 100644 --- a/packages/run-protocol/src/vaultFactory/vaultTitle.js +++ b/packages/run-protocol/src/vaultFactory/vaultTitle.js @@ -10,8 +10,8 @@ const { details: X } = assert; /** * @typedef {{ - * notifier: NotifierRecord['notifier'], - * updater: NotifierRecord['updater'], + * notifier: NotifierRecord['notifier'], + * updater: NotifierRecord['updater'], * vault: Vault | null, * }} State * @typedef {Readonly<{ @@ -29,7 +29,7 @@ const { details: X } = assert; * @returns {State} */ const initState = vault => { - /** @type {NotifierRecord} */ + /** @type {NotifierRecord} */ const { updater, notifier } = makeNotifierKit(); return { notifier, updater, vault }; From ae03243b52d77c54b0a8bf04adc456f4e315eb0e Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 09:52:38 -0700 Subject: [PATCH 09/39] 'econ' -> 'metrics' (will squash) --- .../src/vaultFactory/vaultDirector.js | 23 ++++++------ .../src/vaultFactory/vaultManager.js | 37 ++++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 2db8f9bd2f0..c8daf084290 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -35,7 +35,7 @@ const { details: X } = assert; * collaterals: Brand[], * penaltyPoolAllocation: AmountKeywordRecord, * rewardPoolAllocation: AmountKeywordRecord, - * }} EconState + * }} MetricsNotification * * @typedef {Readonly<{ * debtMint: ZCFMint<'nat'>, @@ -46,8 +46,8 @@ const { details: X } = assert; * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, * vaultParamManagers: Store, - * econNotifier: Notifier - * econUpdater: IterationObserver + * metricsNotifier: Notifier + * metricsUpdater: IterationObserver * zcf: import('./vaultFactory.js').VaultFactoryZCF, * }>} ImmutableState * @@ -78,14 +78,15 @@ const initState = (zcf, directorParamManager, debtMint) => { const vaultParamManagers = makeScalarMap('brand'); - const { notifier: econNotifier, updater: econUpdater } = makeNotifierKit(); + const { notifier: metricsNotifier, updater: metricsUpdater } = + makeNotifierKit(); return { collateralTypes, debtMint, directorParamManager, - econNotifier, - econUpdater, + metricsNotifier, + metricsUpdater, mintSeat, penaltyPoolSeat, rewardPoolSeat, @@ -328,13 +329,13 @@ const machineBehavior = { getContractGovernor: ({ state }) => state.zcf.getTerms().electionManager, /** @param {MethodContext} context */ notifyEcon: ({ state }) => { - /** @type {EconState} */ - const econState = harden({ + /** @type {MetricsNotification} */ + const metrics = harden({ collaterals: Array.from(state.collateralTypes.keys()), penaltyPoolAllocation: state.penaltyPoolSeat.getCurrentAllocation(), rewardPoolAllocation: state.rewardPoolSeat.getCurrentAllocation(), }); - state.econUpdater.updateState(econState); + state.metricsUpdater.updateState(metrics); }, // XXX accessors for tests @@ -393,8 +394,8 @@ const publicBehavior = { * @param {MethodContext} context */ getPublicNotifiers: ({ state }) => { - const { econNotifier } = state; - return { econ: econNotifier }; + const { metricsNotifier } = state; + return { metrics: metricsNotifier }; }, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ makeLoanInvitation: makeVaultInvitation, diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 178a44bbbd1..48f0feee94d 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -41,7 +41,7 @@ const trace = makeTracer('VM', false); * numVaults: number, * totalCollateral: Amount<'nat'>, * totalDebt: Amount<'nat'>, - * }} EconState + * }} MetricsNotification * * @typedef {{ * getChargingPeriod: () => bigint, @@ -74,8 +74,8 @@ const trace = makeTracer('VM', false); * assetNotifier: Notifier, * assetUpdater: IterationObserver, * compoundedInterest: Ratio, - * econNotifier: Notifier, - * econUpdater: IterationObserver, + * metricsNotifier: Notifier, + * metricsUpdater: IterationObserver, * latestInterestUpdate: bigint, * liquidator?: Liquidator * liquidatorInstance?: Instance @@ -159,13 +159,14 @@ const initState = ( }), ); - const { updater: econUpdater, notifier: econNotifier } = makeNotifierKit( - harden({ - numVaults: 0, - totalCollateral, - totalDebt, - }), - ); + const { updater: metricsUpdater, notifier: metricsNotifier } = + makeNotifierKit( + harden({ + numVaults: 0, + totalCollateral, + totalDebt, + }), + ); /** @type {MutableState & ImmutableState} */ const state = { @@ -173,8 +174,8 @@ const initState = ( assetNotifier, assetUpdater, debtBrand: fixed.debtBrand, - econNotifier, - econUpdater, + metricsNotifier, + metricsUpdater, vaultCounter: 0, liquidator: undefined, liquidatorInstance: undefined, @@ -255,21 +256,21 @@ const helperBehavior = { compoundedInterest: state.compoundedInterest, interestRate, latestInterestUpdate: state.latestInterestUpdate, - // XXX move to EconState and type as present with null + // XXX move to governance and type as present with null liquidatorInstance: state.liquidatorInstance, }); state.assetUpdater.updateState(payload); }, /** @param {MethodContext} context */ - econNotify: ({ state }) => { - /** @type {EconState} */ + metricsNotify: ({ state }) => { + /** @type {MetricsNotification} */ const payload = harden({ numVaults: state.prioritizedVaults.getSize(), totalCollateral: state.totalCollateral, totalDebt: state.totalDebt, }); - state.econUpdater.updateState(payload); + state.metricsUpdater.updateState(payload); }, /** @@ -495,7 +496,7 @@ const collateralBehavior = { /** @param {MethodContext} context */ getAssetNotifier: ({ state }) => state.assetNotifier, /** @param {MethodContext} context */ - getPublicNotifiers: ({ state }) => ({ econ: state.econNotifier }), + getPublicNotifiers: ({ state }) => ({ metrics: state.metricsNotifier }), /** @param {MethodContext} context */ getCompoundedInterest: ({ state }) => state.compoundedInterest, }; @@ -546,7 +547,7 @@ const selfBehavior = { vaultKit.vault.getCollateralAmount(), ); seat.exit(); - helper.econNotify(); + helper.metricsNotify(); return vaultKit; } catch (err) { // remove it from prioritizedVaults From d0c76129696a3ba81cf429bf2fd65f1b27d30199 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 10:02:02 -0700 Subject: [PATCH 10/39] fixup! chore(vault): disambiguate VaultManager type (facet naming confusion) --- packages/run-protocol/src/vaultFactory/types.js | 4 ++-- packages/run-protocol/src/vaultFactory/vaultDirector.js | 8 ++++---- packages/run-protocol/src/vaultFactory/vaultManager.js | 6 +++--- .../run-protocol/test/vaultFactory/test-vaultFactory.js | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index 6257544d3cb..dd6aa67a6f7 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -3,8 +3,8 @@ /** @typedef {import('./vault').VaultNotification} VaultNotification */ /** @typedef {import('./vault').Vault} Vault */ /** @typedef {import('./vaultKit').VaultKit} VaultKit */ +/** @typedef {import('./vaultManager').VaultKitManager} VaultKitManager */ /** @typedef {import('./vaultManager').VaultManager} VaultManager */ -/** @typedef {import('./vaultManager').VaultManagerObject} VaultManagerObject */ /** @typedef {import('./vaultManager').CollateralManager} CollateralManager */ /** @@ -38,7 +38,7 @@ * @param {Issuer} collateralIssuer * @param {Keyword} collateralKeyword * @param {VaultManagerParamValues} params - * @returns {Promise} + * @returns {Promise} */ /** diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index c8daf084290..2d2c54b2227 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -39,7 +39,7 @@ const { details: X } = assert; * * @typedef {Readonly<{ * debtMint: ZCFMint<'nat'>, - * collateralTypes: Store, + * collateralTypes: Store, * electionManager: Instance, * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager<{VaultDirectorParams}>, * mintSeat: ZCFSeat, @@ -132,7 +132,7 @@ const makeVaultInvitation = ({ state }) => { }. ${requestedAmount.value} is too small`, ); - /** @type {VaultManagerObject} */ + /** @type {VaultManager} */ const mgr = collateralTypes.get(brandIn); return mgr.makeVaultKit(seat); }; @@ -178,7 +178,7 @@ const getLiquidationConfig = directorParamManager => ({ /** * * @param {ImmutableState['directorParamManager']} govParams - * @param {VaultManagerObject} vaultManager + * @param {VaultManager} vaultManager * @param {*} oldInstall * @param {*} oldTerms */ @@ -387,7 +387,7 @@ const publicBehavior = { collateralTypes.has(brandIn), X`Not a supported collateral type ${brandIn}`, ); - /** @type {VaultManagerObject} */ + /** @type {VaultManager} */ return collateralTypes.get(brandIn).getPublicFacet(); }, /** diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 48f0feee94d..555fd8708c7 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -673,6 +673,6 @@ const makeVaultManagerKit = defineKindMulti( */ export const makeVaultManager = pickFacet(makeVaultManagerKit, 'self'); -/** @typedef {ReturnType['manager']} VaultManager */ -/** @typedef {ReturnType} VaultManagerObject */ -/** @typedef {ReturnType} CollateralManager */ +/** @typedef {ReturnType['manager']} VaultKitManager */ +/** @typedef {ReturnType} VaultManager */ +/** @typedef {ReturnType} CollateralManager */ diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 15ea8b1fb40..541db535040 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -298,7 +298,7 @@ async function setupServices( ); // Add a vault that will lend on aeth collateral - /** @type {Promise} */ + /** @type {Promise} */ const aethVaultManagerP = E(vaultFactoryCreatorFacetP).addVaultType( aethIssuer, 'AEth', From c5bd54da1e03271b487fcd29e4cf572cf28711c8 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 10:06:56 -0700 Subject: [PATCH 11/39] size -> count --- packages/run-protocol/src/vaultFactory/prioritizedVaults.js | 2 +- packages/run-protocol/src/vaultFactory/vaultManager.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/prioritizedVaults.js b/packages/run-protocol/src/vaultFactory/prioritizedVaults.js index 5dfa3c0ad5f..4baad985d2c 100644 --- a/packages/run-protocol/src/vaultFactory/prioritizedVaults.js +++ b/packages/run-protocol/src/vaultFactory/prioritizedVaults.js @@ -174,7 +174,7 @@ export const makePrioritizedVaults = (reschedulePriceCheck = () => {}) => { addVault, entries: vaults.entries, entriesPrioritizedGTE, - getSize: vaults.getSize, + getCount: vaults.getSize, highestRatio: firstDebtRatio, refreshVaultPriority, removeVault, diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 555fd8708c7..bbaee2c95f1 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -266,7 +266,7 @@ const helperBehavior = { metricsNotify: ({ state }) => { /** @type {MetricsNotification} */ const payload = harden({ - numVaults: state.prioritizedVaults.getSize(), + numVaults: state.prioritizedVaults.getCount(), totalCollateral: state.totalCollateral, totalDebt: state.totalDebt, }); From e4401c12a4cfd745d0ef1cf77488317c34606bd0 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 11:35:28 -0700 Subject: [PATCH 12/39] undo name change in test --- .../src/vaultFactory/vaultDirector.js | 2 +- .../test/vaultFactory/test-vaultFactory.js | 34 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 2d2c54b2227..ead8cd079f1 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -41,7 +41,7 @@ const { details: X } = assert; * debtMint: ZCFMint<'nat'>, * collateralTypes: Store, * electionManager: Instance, - * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager<{VaultDirectorParams}>, + * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager, * mintSeat: ZCFSeat, * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 541db535040..e5bfa7f2232 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -292,10 +292,8 @@ async function setupServices( await startVaultFactory(space, { loanParams: loanTiming }, minInitialDebt); const governorCreatorFacet = consume.vaultFactoryGovernorCreator; - /** @type {Promise>} */ - const vaultFactoryCreatorFacetP = /** @type { any } */ ( - E(governorCreatorFacet).getCreatorFacet() - ); + /** @type {Promise>} */ + const vaultFactoryCreatorFacetP = E(governorCreatorFacet).getCreatorFacet(); // Add a vault that will lend on aeth collateral /** @type {Promise} */ @@ -306,7 +304,7 @@ async function setupServices( ); const [ governorInstance, - vaultFactoryCreator, + vaultFactory, // creator lender, aethVaultManager, priceAuthority, @@ -319,7 +317,7 @@ async function setupServices( ]); trace(t, 'pa', { governorInstance, - vaultFactory: vaultFactoryCreator, + vaultFactory, lender, priceAuthority, }); @@ -331,7 +329,7 @@ async function setupServices( governorCreatorFacet, }, v: { - vaultFactoryCreator, + vaultFactory, lender, aethVaultManager, }, @@ -368,11 +366,7 @@ test('first', async t => { undefined, 500n, ); - const { - vaultFactoryCreator: vaultFactory, - lender, - aethVaultManager, - } = services.vaultFactory; + const { vaultFactory, lender, aethVaultManager } = services.vaultFactory; trace(t, 'services', { services, vaultFactory, lender }); // Create a loan for 470 RUN with 1100 aeth collateral @@ -504,7 +498,7 @@ test('price drop', async t => { trace(t, 'setup'); const { - vaultFactory: { vaultFactoryCreator: vaultFactory, lender }, + vaultFactory: { vaultFactory, lender }, priceAuthority, } = services; @@ -644,7 +638,7 @@ test('price falls precipitously', async t => { undefined, 1500n, ); - const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; + const { vaultFactory, lender } = services.vaultFactory; // Create a loan for 370 RUN with 400 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 400n); @@ -792,7 +786,7 @@ test('vaultFactory display collateral', async t => { 500n, ); - const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; + const { vaultFactory } = services.vaultFactory; const collaterals = await E(vaultFactory).getCollaterals(); t.deepEqual(collaterals[0], { brand: aethBrand, @@ -831,7 +825,7 @@ test('interest on multiple vaults', async t => { SECONDS_PER_DAY, 500n, ); - const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; + const { vaultFactory, lender } = services.vaultFactory; // Create a loan for Alice for 4700 RUN with 1100 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 1100n); @@ -1421,7 +1415,7 @@ test('overdeposit', async t => { undefined, 500n, ); - const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; + const { vaultFactory, lender } = services.vaultFactory; // Alice's loan ///////////////////////////////////// @@ -1800,7 +1794,7 @@ test('collect fees from loan and AMM', async t => { undefined, 500n, ); - const { vaultFactoryCreator: vaultFactory, lender } = services.vaultFactory; + const { vaultFactory, lender } = services.vaultFactory; // Create a loan for 470 RUN with 1100 aeth collateral const collateralAmount = AmountMath.make(aethBrand, 1100n); @@ -2287,7 +2281,7 @@ test('addVaultType: invalid args do not modify state', async t => { 500n, ); - const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; + const { vaultFactory } = services.vaultFactory; const failsForSameReason = async p => p @@ -2324,7 +2318,7 @@ test('addVaultType: extra, unexpected params', async t => { 500n, ); - const { vaultFactoryCreator: vaultFactory } = services.vaultFactory; + const { vaultFactory } = services.vaultFactory; const params = { ...defaultParamValues(aethBrand), shoeSize: 10 }; const extraParams = { ...params, shoeSize: 10 }; From 424776fa6c9eb4a749ed116e3fbeda4b89035ef1 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 9 May 2022 11:46:47 -0700 Subject: [PATCH 13/39] lint --- packages/run-protocol/src/vaultFactory/vaultDirector.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index ead8cd079f1..f0abe83c832 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -41,7 +41,7 @@ const { details: X } = assert; * debtMint: ZCFMint<'nat'>, * collateralTypes: Store, * electionManager: Instance, - * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager, + * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager, * mintSeat: ZCFSeat, * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, @@ -171,7 +171,9 @@ const getCollaterals = async ({ state }) => { * @param {ImmutableState['directorParamManager']} directorParamManager */ const getLiquidationConfig = directorParamManager => ({ + // @ts-expect-error VaultDirectoryParams isn't right install: directorParamManager.getLiquidationInstall(), + // @ts-expect-error VaultDirectoryParams isn't right terms: directorParamManager.getLiquidationTerms(), }); From d9c0607ac7a0169cd75c1fa148d85e4780a40b7c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 May 2022 14:11:51 -0700 Subject: [PATCH 14/39] handleFooOffer style per https://github.com/Agoric/agoric-sdk/pull/5179 --- .../run-protocol/src/vaultFactory/liquidateIncrementally.js | 5 +++-- packages/run-protocol/src/vaultFactory/liquidateMinimum.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index b6256ab7116..1e487d5efb3 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -242,7 +242,7 @@ const start = async zcf => { trace('offerResult', { amounts }); } - const debtorHook = async (debtorSeat, { debt: originalDebt }) => { + const handleLiquidateOffer = async (debtorSeat, { debt: originalDebt }) => { trace('LIQ', originalDebt); assertProposalShape(debtorSeat, { give: { In: null }, @@ -284,7 +284,8 @@ const start = async zcf => { * @type {ERef} */ const creatorFacet = Far('debtorInvitationCreator', { - makeLiquidateInvitation: () => zcf.makeInvitation(debtorHook, 'Liquidate'), + makeLiquidateInvitation: () => + zcf.makeInvitation(handleLiquidateOffer, 'Liquidate'), }); return harden({ creatorFacet }); diff --git a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js index fa22347b583..d88298c5626 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js +++ b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js @@ -28,7 +28,7 @@ const start = async zcf => { * @param {ZCFSeat} debtorSeat * @param {{ debt: Amount<'nat'> }} options */ - const debtorHook = async (debtorSeat, { debt }) => { + const handleLiquidationOffer = async (debtorSeat, { debt }) => { const debtBrand = debt.brand; const { give: { In: amountIn }, @@ -63,7 +63,8 @@ const start = async zcf => { * @type {ERef} */ const creatorFacet = Far('debtorInvitationCreator', { - makeLiquidateInvitation: () => zcf.makeInvitation(debtorHook, 'Liquidate'), + makeLiquidateInvitation: () => + zcf.makeInvitation(handleLiquidationOffer, 'Liquidate'), }); return harden({ creatorFacet }); From 024c205313b4f98acc14b52baa133983f5b2e8ed Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 May 2022 14:25:39 -0700 Subject: [PATCH 15/39] chore(zoe): more typing offerTo and Invitation --- .../src/vaultFactory/liquidateIncrementally.js | 4 ++++ packages/run-protocol/src/vaultFactory/types.js | 2 +- packages/zoe/src/contractSupport/zoeHelpers.js | 9 ++++++--- packages/zoe/src/types.js | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index 1e487d5efb3..fc0df279b89 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -242,6 +242,10 @@ const start = async zcf => { trace('offerResult', { amounts }); } + /** + * @param {ZCFSeat} debtorSeat + * @param {{ debt: Amount<'nat'> }} options + */ const handleLiquidateOffer = async (debtorSeat, { debt: originalDebt }) => { trace('LIQ', originalDebt); assertProposalShape(debtorSeat, { diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index e0a1d6c2850..fc24013cb8c 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -112,7 +112,7 @@ /** * @typedef {object} Liquidator - * @property {() => Promise} makeLiquidateInvitation + * @property {() => Promise }, void>>} makeLiquidateInvitation */ /** diff --git a/packages/zoe/src/contractSupport/zoeHelpers.js b/packages/zoe/src/contractSupport/zoeHelpers.js index 6a4df1e4049..702059959b5 100644 --- a/packages/zoe/src/contractSupport/zoeHelpers.js +++ b/packages/zoe/src/contractSupport/zoeHelpers.js @@ -283,10 +283,13 @@ const reverse = (keywordRecord = {}) => { * contract instance (contractA) and depositing the payouts in another * seat in the current contract instance (contractA). * + * @template {object=} A Offer args + * @template {object=} R Offer result + * * @param {ZCF} zcf * Zoe Contract Facet for contractA * - * @param {ERef} invitation + * @param {ERef>} invitation * Invitation to contractB * * @param {KeywordKeywordRecord=} keywordMapping @@ -304,10 +307,10 @@ const reverse = (keywordRecord = {}) => { * The seat in contractA to deposit the payout of the offer to. * If `toSeat` is not provided, this defaults to the `fromSeat`. * - * @param {object=} offerArgs + * @param {A} [offerArgs] * Aditional contract-specific optional arguments in a record. * - * @returns {Promise<{userSeatPromise: Promise, deposited: Promise}>} + * @returns {Promise<{userSeatPromise: Promise>, deposited: Promise}>} * A promise for the userSeat for the offer to the other contract, and a * promise (`deposited`) which resolves when the payout for the offer has been * deposited to the `toSeat` diff --git a/packages/zoe/src/types.js b/packages/zoe/src/types.js index 0e0a6c5df6a..7b6bfe65e66 100644 --- a/packages/zoe/src/types.js +++ b/packages/zoe/src/types.js @@ -43,6 +43,7 @@ */ /** + * @template [OfferArgs] * @template [OfferResult] * @typedef {Payment<'set'>} Invitation */ From 0cb7b4bf98678c9df4c89f0eb70e7f437a51837d Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 May 2022 16:14:12 -0700 Subject: [PATCH 16/39] plan --- .../src/vaultFactory/liquidateIncrementally.js | 4 ++-- .../run-protocol/src/vaultFactory/liquidation.js | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index fc0df279b89..f3135b5a667 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -39,8 +39,6 @@ const trace = makeTracer('LiqI', false); * Selling uses the `oracleLimit as the `want` as the limit to allowed * slippage, and provides the remaining `debt` as the `stopAfter` so * that we sell no more than is needed to pay off the debt. - * - * TODO integrate the reserve, including the above Reserve strategies. */ /** @@ -74,6 +72,8 @@ const start = async zcf => { const asFloat = (numerator, denominator) => Number(numerator) / Number(denominator); + const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); + /** * Compute the tranche size whose sale on the AMM would have * a price impact of MAX_IMPACT_BP. diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index 5e74f839b2c..3c951957fc2 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -58,9 +58,9 @@ const liquidate = async ( trace('liquidate start', vault); vault.liquidating(); + // -> CONTRACT const debtBeforePenalty = vault.getCurrentDebt(); const penalty = ceilMultiplyBy(debtBeforePenalty, penaltyRate); - const debt = AmountMath.add(debtBeforePenalty, penalty); const vaultZcfSeat = vault.getVaultSeat(); @@ -81,13 +81,16 @@ const liquidate = async ( }), vaultZcfSeat, vaultZcfSeat, - harden({ debt }), + harden({ debt }), // + penaltyRate ); trace(` offeredTo`, collateralToSell, debt); // await deposited, but we don't need the value. await Promise.all([deposited, E(liqSeat).getOfferResult()]); + // all the proceeds from AMM sale are on the vault seat instead of a staging seat + // ??? & okay? + // -> CONTRACT // Now we need to know how much was sold so we can pay off the debt. // We can use this because only liquidation adds RUN to the vaultSeat. const { debtPaid, penaltyProceeds, runToBurn } = partitionProceeds( @@ -98,12 +101,17 @@ const liquidate = async ( trace({ debt, debtPaid, penaltyProceeds, runToBurn }); + // -> CONTRACT + // penaltyPoolSeat is up to the contract (give it Reserve so it can make it) // Allocate penalty portion of proceeds to a seat that will be transferred to reserve penaltyPoolSeat.incrementBy( vaultZcfSeat.decrementBy(harden({ RUN: penaltyProceeds })), ); zcf.reallocate(penaltyPoolSeat, vaultZcfSeat); + // STAYS + // runToBurn is simply min(proceeds, debt) + // whatever's remaining stays on the vault seat burnLosses(runToBurn, vaultZcfSeat); // Accounting complete. Update the vault state. From b13aba1c177f230b51a1926047521f7608cc460a Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 May 2022 16:17:21 -0700 Subject: [PATCH 17/39] factored penalties into liquidation contracts --- .../vaultFactory/liquidateIncrementally.js | 34 ++++++++++-- .../src/vaultFactory/liquidateMinimum.js | 42 ++++++++++++--- .../src/vaultFactory/liquidation.js | 52 +++++-------------- .../test/vaultFactory/test-vaultFactory.js | 6 +-- 4 files changed, 80 insertions(+), 54 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index f3135b5a667..15b73f164df 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -13,6 +13,7 @@ import { import { AmountMath } from '@agoric/ertp'; import { Far } from '@endo/marshal'; import { makeTracer } from '../makeTracer.js'; +import { partitionProceeds } from './liquidation.js'; const { details: X } = assert; const trace = makeTracer('LiqI', false); @@ -39,6 +40,8 @@ const trace = makeTracer('LiqI', false); * Selling uses the `oracleLimit as the `want` as the limit to allowed * slippage, and provides the remaining `debt` as the `stopAfter` so * that we sell no more than is needed to pay off the debt. + * + * TODO integrate the reserve, including the above Reserve strategies. */ /** @@ -72,6 +75,7 @@ const start = async zcf => { const asFloat = (numerator, denominator) => Number(numerator) / Number(denominator); + // TODO distribute penalties to the reserve const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); /** @@ -244,10 +248,14 @@ const start = async zcf => { /** * @param {ZCFSeat} debtorSeat - * @param {{ debt: Amount<'nat'> }} options + * @param {object} options + * @param {Amount<'nat'>} options.debt Debt before penalties + * @param {Ratio} options.penaltyRate */ - const handleLiquidateOffer = async (debtorSeat, { debt: originalDebt }) => { - trace('LIQ', originalDebt); + const handleLiquidateOffer = async ( + debtorSeat, + { debt: originalDebt, penaltyRate }, + ) => { assertProposalShape(debtorSeat, { give: { In: null }, }); @@ -255,7 +263,11 @@ const start = async zcf => { originalDebt.brand === debtBrand, X`Cannot liquidate to ${originalDebt.brand}`, ); - for await (const t of processTranches(debtorSeat, originalDebt)) { + const penalty = ceilMultiplyBy(originalDebt, penaltyRate); + const debtWithPenalty = AmountMath.add(originalDebt, penalty); + trace('LIQ', { originalDebt, debtWithPenalty }); + + for await (const t of processTranches(debtorSeat, debtWithPenalty)) { const { collateral, oracleLimit, ammProceeds, debt } = t; trace(`OFFER TO DEBT: `, { collateral, @@ -280,6 +292,18 @@ const start = async zcf => { }); } } + + // Now we need to know how much was sold so we can pay off the debt. + // We can use this because only liquidation adds debt brand to the seat. + const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand); + const penaltyPaid = AmountMath.min(penalty, debtPaid); + + // Allocate penalty portion of proceeds to a seat that will be transferred to reserve + penaltyPoolSeat.incrementBy( + debtorSeat.decrementBy(harden({ Out: penaltyPaid })), + ); + zcf.reallocate(penaltyPoolSeat, debtorSeat); + debtorSeat.exit(); trace('exit seat'); }; @@ -287,7 +311,7 @@ const start = async zcf => { /** * @type {ERef} */ - const creatorFacet = Far('debtorInvitationCreator', { + const creatorFacet = Far('debtorInvitationCreator (incrementally)', { makeLiquidateInvitation: () => zcf.makeInvitation(handleLiquidateOffer, 'Liquidate'), }); diff --git a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js index d88298c5626..eb3bbf9289d 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js +++ b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js @@ -1,14 +1,19 @@ // @ts-check import { E } from '@endo/eventual-send'; -import { offerTo } from '@agoric/zoe/src/contractSupport/index.js'; +import { + ceilMultiplyBy, + offerTo, +} from '@agoric/zoe/src/contractSupport/index.js'; import { AmountMath } from '@agoric/ertp'; import { Far } from '@endo/marshal'; import { makeTracer } from '../makeTracer.js'; +import { partitionProceeds } from './liquidation.js'; const trace = makeTracer('LiqMin', false); +// ??? is this contract used only for tests and demo purposes? /** * This contract liquidates the minimum amount of vault's collateral necessary * to satisfy the debt. It uses the AMM's swapOut, which sells no more than @@ -26,10 +31,19 @@ const start = async zcf => { /** * @param {ZCFSeat} debtorSeat - * @param {{ debt: Amount<'nat'> }} options + * @param {object} options + * @param {Amount<'nat'>} options.debt Debt before penalties + * @param {Ratio} options.penaltyRate */ - const handleLiquidationOffer = async (debtorSeat, { debt }) => { - const debtBrand = debt.brand; + const handleLiquidationOffer = async ( + debtorSeat, + { debt: originalDebt, penaltyRate }, + ) => { + // ??? distribute penalties to the reserve + const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); + const penalty = ceilMultiplyBy(originalDebt, penaltyRate); + const debtWithPenalty = AmountMath.add(originalDebt, penalty); + const debtBrand = originalDebt.brand; const { give: { In: amountIn }, } = debtorSeat.getProposal(); @@ -39,7 +53,7 @@ const start = async zcf => { give: { In: amountIn }, want: { Out: AmountMath.makeEmpty(debtBrand) }, }); - trace(`OFFER TO DEBT: `, debt, amountIn); + trace(`OFFER TO DEBT: `, debtWithPenalty, amountIn); const { deposited } = await offerTo( zcf, swapInvitation, @@ -47,22 +61,34 @@ const start = async zcf => { liqProposal, debtorSeat, debtorSeat, - { stopAfter: debt }, + { stopAfter: debtWithPenalty }, ); const amounts = await deposited; trace(`Liq results`, { - debt, + debtWithPenalty, amountIn, paid: debtorSeat.getCurrentAllocation(), amounts, }); + + // Now we need to know how much was sold so we can pay off the debt. + // We can use this because only liquidation adds debt brand to the seat. + const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand); + const penaltyPaid = AmountMath.min(penalty, debtPaid); + + // Allocate penalty portion of proceeds to a seat that will be transferred to reserve + penaltyPoolSeat.incrementBy( + debtorSeat.decrementBy(harden({ Out: penaltyPaid })), + ); + zcf.reallocate(penaltyPoolSeat, debtorSeat); + debtorSeat.exit(); }; /** * @type {ERef} */ - const creatorFacet = Far('debtorInvitationCreator', { + const creatorFacet = Far('debtorInvitationCreator (minimum)', { makeLiquidateInvitation: () => zcf.makeInvitation(handleLiquidationOffer, 'Liquidate'), }); diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index 3c951957fc2..ca85ba3fa6f 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -3,11 +3,7 @@ import { E } from '@endo/eventual-send'; import { AmountMath } from '@agoric/ertp'; -import { - ceilMultiplyBy, - makeRatio, - offerTo, -} from '@agoric/zoe/src/contractSupport/index.js'; +import { makeRatio, offerTo } from '@agoric/zoe/src/contractSupport/index.js'; import { makeTracer } from '../makeTracer.js'; const trace = makeTracer('LIQ'); @@ -58,10 +54,7 @@ const liquidate = async ( trace('liquidate start', vault); vault.liquidating(); - // -> CONTRACT - const debtBeforePenalty = vault.getCurrentDebt(); - const penalty = ceilMultiplyBy(debtBeforePenalty, penaltyRate); - const debt = AmountMath.add(debtBeforePenalty, penalty); + const debt = vault.getCurrentDebt(); const vaultZcfSeat = vault.getVaultSeat(); @@ -69,7 +62,7 @@ const liquidate = async ( 'Collateral', collateralBrand, ); - trace(`liq prep`, collateralToSell, debtBeforePenalty, debt); + trace(`liq prep`, { collateralToSell, debt, liquidator }); const { deposited, userSeatPromise: liqSeat } = await offerTo( zcf, @@ -81,41 +74,24 @@ const liquidate = async ( }), vaultZcfSeat, vaultZcfSeat, - harden({ debt }), // + penaltyRate + harden({ debt, penaltyRate }), ); - trace(` offeredTo`, collateralToSell, debt); + trace(` offeredTo`, { collateralToSell, debt }); - // await deposited, but we don't need the value. - await Promise.all([deposited, E(liqSeat).getOfferResult()]); + // await deposited and offer result, but ignore the latter + const [proceeds] = await Promise.all([ + deposited, + E(liqSeat).getOfferResult(), + ]); // all the proceeds from AMM sale are on the vault seat instead of a staging seat - // ??? & okay? - - // -> CONTRACT - // Now we need to know how much was sold so we can pay off the debt. - // We can use this because only liquidation adds RUN to the vaultSeat. - const { debtPaid, penaltyProceeds, runToBurn } = partitionProceeds( - vaultZcfSeat.getAmountAllocated('RUN', debt.brand), - debt, - penalty, - ); - - trace({ debt, debtPaid, penaltyProceeds, runToBurn }); - - // -> CONTRACT - // penaltyPoolSeat is up to the contract (give it Reserve so it can make it) - // Allocate penalty portion of proceeds to a seat that will be transferred to reserve - penaltyPoolSeat.incrementBy( - vaultZcfSeat.decrementBy(harden({ RUN: penaltyProceeds })), - ); - zcf.reallocate(penaltyPoolSeat, vaultZcfSeat); + // ??? ^ okay? - // STAYS - // runToBurn is simply min(proceeds, debt) - // whatever's remaining stays on the vault seat + const runToBurn = AmountMath.min(proceeds.RUN, debt); + trace('before burn', { debt, proceeds, runToBurn }); burnLosses(runToBurn, vaultZcfSeat); // Accounting complete. Update the vault state. - vault.liquidated(AmountMath.subtract(debt, debtPaid)); + vault.liquidated(AmountMath.subtract(debt, runToBurn)); // remaining funds are left on the vault for the user to close and claim return vault; diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 11d18c8e7c9..115a8604764 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -460,9 +460,9 @@ test('first', async t => { 'unused collateral remains after liquidation', ); - t.deepEqual(await E(vaultFactory).getPenaltyAllocation(), { - RUN: AmountMath.make(runBrand, 30n), - }); + // ??? remove penalty pool from vault factory + // used to be funded from liquidation penalty + t.deepEqual(await E(vaultFactory).getPenaltyAllocation(), {}); t.deepEqual(await E(vaultFactory).getRewardAllocation(), { RUN: AmountMath.make(runBrand, 24n), }); From 58d8555fec54bcac8b064a45b7dd072e9c1618fb Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 11 May 2022 12:06:10 -0700 Subject: [PATCH 18/39] rm obsolete partitionProceeds --- .../vaultFactory/liquidateIncrementally.js | 1 - .../src/vaultFactory/liquidateMinimum.js | 1 - .../src/vaultFactory/liquidation.js | 18 +-------- .../vaultFactory/test-liquidation-helpers.js | 39 ------------------- 4 files changed, 1 insertion(+), 58 deletions(-) delete mode 100644 packages/run-protocol/test/vaultFactory/test-liquidation-helpers.js diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index 15b73f164df..a20665f292f 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -13,7 +13,6 @@ import { import { AmountMath } from '@agoric/ertp'; import { Far } from '@endo/marshal'; import { makeTracer } from '../makeTracer.js'; -import { partitionProceeds } from './liquidation.js'; const { details: X } = assert; const trace = makeTracer('LiqI', false); diff --git a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js index eb3bbf9289d..59560a726d1 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js +++ b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js @@ -9,7 +9,6 @@ import { AmountMath } from '@agoric/ertp'; import { Far } from '@endo/marshal'; import { makeTracer } from '../makeTracer.js'; -import { partitionProceeds } from './liquidation.js'; const trace = makeTracer('LiqMin', false); diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index ca85ba3fa6f..ac618923ae4 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -8,21 +8,6 @@ import { makeTracer } from '../makeTracer.js'; const trace = makeTracer('LIQ'); -/** - * @param {Amount<'nat'>} proceeds - * @param {Amount<'nat'>} debt - after incurring penalty - * @param {Amount<'nat'>} penaltyPortion - */ -const partitionProceeds = (proceeds, debt, penaltyPortion) => { - const debtPaid = AmountMath.min(proceeds, debt); - - // Pay as much of the penalty as possible - const penaltyProceeds = AmountMath.min(penaltyPortion, debtPaid); - const runToBurn = AmountMath.subtract(debtPaid, penaltyProceeds); - - return { debtPaid, penaltyProceeds, runToBurn }; -}; - /** * Liquidates a Vault, using the strategy to parameterize the particular * contract being used. The strategy provides a KeywordMapping and proposal @@ -105,7 +90,6 @@ const liquidationDetailTerms = debtBrand => }); harden(liquidate); -harden(partitionProceeds); harden(liquidationDetailTerms); -export { liquidate, partitionProceeds, liquidationDetailTerms }; +export { liquidate, liquidationDetailTerms }; diff --git a/packages/run-protocol/test/vaultFactory/test-liquidation-helpers.js b/packages/run-protocol/test/vaultFactory/test-liquidation-helpers.js deleted file mode 100644 index b681c99421b..00000000000 --- a/packages/run-protocol/test/vaultFactory/test-liquidation-helpers.js +++ /dev/null @@ -1,39 +0,0 @@ -// @ts-check -// Must be first to set up globals -import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; - -import { AmountMath } from '@agoric/ertp'; -import { Far } from '@endo/marshal'; -import { partitionProceeds } from '../../src/vaultFactory/liquidation.js'; - -export const mockBrand = Far('brand'); - -const amount = n => AmountMath.make(mockBrand, BigInt(n)); - -const partitionTest = ( - [proceeds, debt, penaltyPortion], - [debtPaid, penaltyProceeds, runToBurn], -) => { - test(`partitionProceeds: (${proceeds} for ${debt} with ${penaltyPortion} penalty)`, t => { - const result = partitionProceeds( - amount(proceeds), - amount(debt), - amount(penaltyPortion), - ); - t.deepEqual(result, { - debtPaid: amount(debtPaid), - penaltyProceeds: amount(penaltyProceeds), - runToBurn: amount(runToBurn), - }); - }); -}; - -// no proceeds -partitionTest([0, 0, 0], [0, 0, 0]); -partitionTest([0, 100, 10], [0, 0, 0]); -// proceeds gte debt -partitionTest([100, 100, 10], [100, 10, 90]); -partitionTest([200, 100, 10], [100, 10, 90]); -// proceeds less than debt -partitionTest([100, 200, 10], [100, 10, 90]); -partitionTest([100, 200, 200], [100, 100, 0]); From 276c94c3bf206976ef04f247efe6140524142d98 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 May 2022 14:15:28 -0700 Subject: [PATCH 19/39] lint and comments --- packages/run-protocol/src/vaultFactory/liquidateMinimum.js | 3 +-- packages/zoe/src/contracts/otcDesk.js | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js index 59560a726d1..bb314eff82e 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js +++ b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js @@ -12,7 +12,6 @@ import { makeTracer } from '../makeTracer.js'; const trace = makeTracer('LiqMin', false); -// ??? is this contract used only for tests and demo purposes? /** * This contract liquidates the minimum amount of vault's collateral necessary * to satisfy the debt. It uses the AMM's swapOut, which sells no more than @@ -38,7 +37,7 @@ const start = async zcf => { debtorSeat, { debt: originalDebt, penaltyRate }, ) => { - // ??? distribute penalties to the reserve + // XXX does not distribute penalties anywhere const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); const penalty = ceilMultiplyBy(originalDebt, penaltyRate); const debtWithPenalty = AmountMath.add(originalDebt, penalty); diff --git a/packages/zoe/src/contracts/otcDesk.js b/packages/zoe/src/contracts/otcDesk.js index 8523e4bfd33..4147ebca83c 100644 --- a/packages/zoe/src/contracts/otcDesk.js +++ b/packages/zoe/src/contracts/otcDesk.js @@ -66,6 +66,7 @@ const start = zcf => { * @returns {Promise} */ const makeQuote = async (price, assets, timeAuthority, deadline) => { + /** @type {{ creatorInvitation: Invitation} } */ const { creatorInvitation } = await E(zoe).startInstance( coveredCallInstallation, zcf.getTerms().issuers, From c44cd1ea90dad05198a98ac66d7ec0af9fc812bc Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 May 2022 16:24:34 -0700 Subject: [PATCH 20/39] named parameters for makeGovernedTerms() --- packages/run-protocol/src/econ-behaviors.js | 19 +++++------ .../run-protocol/src/vaultFactory/params.js | 32 ++++++++++--------- .../run-protocol/test/swingsetTests/setup.js | 23 ++++++------- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/packages/run-protocol/src/econ-behaviors.js b/packages/run-protocol/src/econ-behaviors.js index b0e559d40a2..36037e94ac9 100644 --- a/packages/run-protocol/src/econ-behaviors.js +++ b/packages/run-protocol/src/econ-behaviors.js @@ -247,7 +247,7 @@ export const startVaultFactory = async ( { consume: { chainTimerService, - priceAuthority, + priceAuthority: priceAuthorityP, zoe, feeMintAccess: feeMintAccessP, // ISSUE: why doeszn't Zoe await this? economicCommitteeCreatorFacet: electorateCreatorFacet, @@ -304,19 +304,20 @@ export const startVaultFactory = async ( ]); const ammPublicFacet = await E(zoe).getPublicFacet(ammInstance); const feeMintAccess = await feeMintAccessP; - const pa = await priceAuthority; + const priceAuthority = await priceAuthorityP; const timer = await chainTimerService; - const vaultFactoryTerms = makeGovernedTerms( - pa, - loanParams, - installations.liquidate, + const vaultFactoryTerms = makeGovernedTerms({ + priceAuthority, + loanTiming: loanParams, + liquidationInstall: installations.liquidate, timer, invitationAmount, vaultManagerParams, ammPublicFacet, - liquidationDetailTerms(centralBrand), - AmountMath.make(centralBrand, minInitialDebt), - ); + liquidationTerms: liquidationDetailTerms(centralBrand), + minInitialDebt: AmountMath.make(centralBrand, minInitialDebt), + bootstrapPaymentValue: 0n, + }); const governorTerms = harden({ timer, diff --git a/packages/run-protocol/src/vaultFactory/params.js b/packages/run-protocol/src/vaultFactory/params.js index 85e9aa158f2..9cb58ada56a 100644 --- a/packages/run-protocol/src/vaultFactory/params.js +++ b/packages/run-protocol/src/vaultFactory/params.js @@ -1,3 +1,4 @@ +/* eslint-disable no-useless-rename */ // @ts-check import './types.js'; @@ -107,29 +108,30 @@ const makeVaultDirectorParamManager = async ( }; /** - * @param {ERef} priceAuthority - * @param {LoanTiming} loanTiming - * @param {Installation} liquidationInstall - * @param {ERef} timerService - * @param {Amount} invitationAmount - * @param {VaultManagerParamValues} vaultManagerParams - * @param {XYKAMMPublicFacet} ammPublicFacet - * @param {object} liquidationTerms - * @param {Amount} minInitialDebt - * @param {bigint=} bootstrapPaymentValue + * @param {object} opts + * @param {ERef} opts.priceAuthority + * @param {LoanTiming} opts.loanTiming + * @param {Installation} opts.liquidationInstall + * @param {ERef} opts.timer + * @param {Amount} opts.invitationAmount + * @param {VaultManagerParamValues} opts.vaultManagerParams + * @param {XYKAMMPublicFacet} opts.ammPublicFacet + * @param {object} opts.liquidationTerms + * @param {Amount} opts.minInitialDebt + * @param {bigint} opts.bootstrapPaymentValue */ -const makeGovernedTerms = ( +const makeGovernedTerms = ({ priceAuthority, loanTiming, liquidationInstall, - timerService, + timer, invitationAmount, vaultManagerParams, ammPublicFacet, liquidationTerms, minInitialDebt, - bootstrapPaymentValue = 0n, -) => { + bootstrapPaymentValue, +}) => { const loanTimingParams = makeParamManagerSync({ [CHARGING_PERIOD_KEY]: ['nat', loanTiming.chargingPeriod], [RECORDING_PERIOD_KEY]: ['nat', loanTiming.recordingPeriod], @@ -142,7 +144,7 @@ const makeGovernedTerms = ( priceAuthority, loanParams, loanTimingParams, - timerService, + timerService: timer, governedParams: makeVaultDirectorParams( invitationAmount, liquidationInstall, diff --git a/packages/run-protocol/test/swingsetTests/setup.js b/packages/run-protocol/test/swingsetTests/setup.js index 1fbcdb18802..dfc9eda71be 100644 --- a/packages/run-protocol/test/swingsetTests/setup.js +++ b/packages/run-protocol/test/swingsetTests/setup.js @@ -184,7 +184,7 @@ const buildOwner = async ( const [moolaIssuer] = issuers; const runBrand = await E(E(zoe).getFeeIssuer()).getBrand(); - const rates = makeRates(runBrand); + const vaultManagerParams = makeRates(runBrand); const loanTiming = { chargingPeriod: SECONDS_PER_DAY, @@ -199,18 +199,19 @@ const buildOwner = async ( E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), ]); - const terms = makeGovernedTerms( - priceAuthorityKit.priceAuthority, + const terms = makeGovernedTerms({ + priceAuthority: priceAuthorityKit.priceAuthority, loanTiming, - installations.liquidateMinimum, + liquidationInstall: installations.liquidateMinimum, timer, - poserInvitationAmount, - rates, + electorateInvitation: poserInvitationAmount, + vaultManagerParams, // @ts-expect-error It's not a real AMM public facet - ammMock, - liquidationDetailTerms(runBrand), - AmountMath.make(runBrand, 100n), - ); + ammPublicFacet: ammMock, + liquidationTerms: liquidationDetailTerms(runBrand), + minInitialDebt: AmountMath.make(runBrand, 100n), + bootstrapPaymentValue: 0n, + }); const privateVaultFactoryArgs = { feeMintAccess, initialPoserInvitation }; @@ -235,7 +236,7 @@ const buildOwner = async ( await E(E(governorFacets.creatorFacet).getCreatorFacet()).addVaultType( moolaIssuer, 'Moola', - rates, + vaultManagerParams, ); const QUOTE_INTERVAL = 24n * 60n * 60n; From 6a3349eee5e7d9a6fab1f7202091973da20c9e68 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 13:07:35 -0700 Subject: [PATCH 21/39] wire reservePublicFacet into vaultFactory terms --- packages/run-protocol/src/econ-behaviors.js | 3 ++ packages/run-protocol/src/reserve/types.js | 1 + .../vaultFactory/liquidateIncrementally.js | 3 ++ .../src/vaultFactory/liquidation.js | 1 + .../run-protocol/src/vaultFactory/params.js | 42 ++++++++++--------- .../src/vaultFactory/vaultDirector.js | 13 +++++- .../src/vaultFactory/vaultFactory.js | 6 ++- .../src/vaultFactory/vaultManager.js | 10 +++-- packages/run-protocol/test/reserve/setup.js | 2 +- .../run-protocol/test/swingsetTests/setup.js | 4 +- .../test/vaultFactory/test-liquidator.js | 23 +++++++--- .../test/vaultFactory/test-vaultFactory.js | 21 +++++++--- 12 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 packages/run-protocol/src/reserve/types.js diff --git a/packages/run-protocol/src/econ-behaviors.js b/packages/run-protocol/src/econ-behaviors.js index 36037e94ac9..040f9414ab2 100644 --- a/packages/run-protocol/src/econ-behaviors.js +++ b/packages/run-protocol/src/econ-behaviors.js @@ -248,6 +248,7 @@ export const startVaultFactory = async ( consume: { chainTimerService, priceAuthority: priceAuthorityP, + reservePublicFacet: reservePublicFacetP, zoe, feeMintAccess: feeMintAccessP, // ISSUE: why doeszn't Zoe await this? economicCommitteeCreatorFacet: electorateCreatorFacet, @@ -305,9 +306,11 @@ export const startVaultFactory = async ( const ammPublicFacet = await E(zoe).getPublicFacet(ammInstance); const feeMintAccess = await feeMintAccessP; const priceAuthority = await priceAuthorityP; + const reservePublicFacet = await reservePublicFacetP; const timer = await chainTimerService; const vaultFactoryTerms = makeGovernedTerms({ priceAuthority, + reservePublicFacet, loanTiming: loanParams, liquidationInstall: installations.liquidate, timer, diff --git a/packages/run-protocol/src/reserve/types.js b/packages/run-protocol/src/reserve/types.js new file mode 100644 index 00000000000..38c8447269b --- /dev/null +++ b/packages/run-protocol/src/reserve/types.js @@ -0,0 +1 @@ +/** @typedef {import('../reserve/assetReserve.js').AssetReservePublicFacet} AssetReservePublicFacet */ diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index a20665f292f..52355490a44 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -47,6 +47,7 @@ const trace = makeTracer('LiqI', false); * @typedef {{ * amm: XYKAMMPublicFacet, * priceAuthority: PriceAuthority, + * reservePublicFacet: AssetReservePublicFacet, * timerService: TimerService, * debtBrand: Brand, * MaxImpactBP: NatValue, @@ -59,6 +60,7 @@ const start = async zcf => { const { amm, priceAuthority, + reservePublicFacet, timerService, debtBrand, MaxImpactBP, @@ -75,6 +77,7 @@ const start = async zcf => { Number(numerator) / Number(denominator); // TODO distribute penalties to the reserve + assert(reservePublicFacet, 'Missing reservePublicFacet'); const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); /** diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index ac618923ae4..2db9ae11d52 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -88,6 +88,7 @@ const liquidationDetailTerms = debtBrand => OracleTolerance: makeRatio(30n, debtBrand), AMMMaxSlippage: makeRatio(30n, debtBrand), }); +/** @typedef {ReturnType} LiquidationTerms */ harden(liquidate); harden(liquidationDetailTerms); diff --git a/packages/run-protocol/src/vaultFactory/params.js b/packages/run-protocol/src/vaultFactory/params.js index 9cb58ada56a..82388d5d76e 100644 --- a/packages/run-protocol/src/vaultFactory/params.js +++ b/packages/run-protocol/src/vaultFactory/params.js @@ -27,7 +27,7 @@ export const MIN_INITIAL_DEBT_KEY = 'MinInitialDebt'; /** * @param {Amount} electorateInvitationAmount * @param {Installation} liquidationInstall - * @param {object} liquidationTerms + * @param {import('./liquidation.js').LiquidationTerms} liquidationTerms * @param {Amount} minInitialDebt */ const makeVaultDirectorParams = ( @@ -108,29 +108,32 @@ const makeVaultDirectorParamManager = async ( }; /** - * @param {object} opts - * @param {ERef} opts.priceAuthority - * @param {LoanTiming} opts.loanTiming - * @param {Installation} opts.liquidationInstall - * @param {ERef} opts.timer - * @param {Amount} opts.invitationAmount - * @param {VaultManagerParamValues} opts.vaultManagerParams - * @param {XYKAMMPublicFacet} opts.ammPublicFacet - * @param {object} opts.liquidationTerms - * @param {Amount} opts.minInitialDebt - * @param {bigint} opts.bootstrapPaymentValue + * @param {{ + * invitationAmount: Amount, + * minInitialDebt: Amount, + * bootstrapPaymentValue: bigint, + * priceAuthority: ERef, + * timer: ERef, + * reservePublicFacet: AssetReservePublicFacet, + * liquidationInstall: Installation, + * loanTiming: LoanTiming, + * liquidationTerms: import('./liquidation.js').LiquidationTerms, + * vaultManagerParams: VaultManagerParamValues, + * ammPublicFacet: XYKAMMPublicFacet, + * }} opts */ const makeGovernedTerms = ({ - priceAuthority, - loanTiming, - liquidationInstall, - timer, - invitationAmount, - vaultManagerParams, ammPublicFacet, + bootstrapPaymentValue, + invitationAmount, + liquidationInstall, liquidationTerms, + loanTiming, minInitialDebt, - bootstrapPaymentValue, + priceAuthority, + reservePublicFacet, + timer, + vaultManagerParams, }) => { const loanTimingParams = makeParamManagerSync({ [CHARGING_PERIOD_KEY]: ['nat', loanTiming.chargingPeriod], @@ -144,6 +147,7 @@ const makeGovernedTerms = ({ priceAuthority, loanParams, loanTimingParams, + reservePublicFacet, timerService: timer, governedParams: makeVaultDirectorParams( invitationAmount, diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 3824f72c81b..1923a80dc21 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -153,11 +153,21 @@ const getCollaterals = async ({ state }) => { ); }; +/** + * @param {import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager} directorParamManager + */ const getLiquidationConfig = directorParamManager => ({ install: directorParamManager.getLiquidationInstall(), terms: directorParamManager.getLiquidationTerms(), }); +/** + * + * @param {*} govParams + * @param {VaultManager} vaultManager + * @param {*} oldInstall + * @param {*} oldTerms + */ const watchGovernance = (govParams, vaultManager, oldInstall, oldTerms) => { const subscription = govParams.getSubscription(); observeIteration(subscription, { @@ -412,10 +422,11 @@ const behavior = { * ammPublicFacet: AutoswapPublicFacet, * liquidationInstall: Installation, * loanTimingParams: {ChargingPeriod: ParamRecord<'nat'>, RecordingPeriod: ParamRecord<'nat'>}, + * reservePublicFacet: AssetReservePublicFacet, * timerService: TimerService, * priceAuthority: ERef * }>} zcf - * @param {import('./params.js').VaultDirectorParams} directorParamManager + * @param {import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager} directorParamManager * @param {ZCFMint<"nat">} debtMint */ const makeVaultDirector = defineKindMulti('VaultDirector', initState, behavior); diff --git a/packages/run-protocol/src/vaultFactory/vaultFactory.js b/packages/run-protocol/src/vaultFactory/vaultFactory.js index 2c7a756990a..4a471f94851 100644 --- a/packages/run-protocol/src/vaultFactory/vaultFactory.js +++ b/packages/run-protocol/src/vaultFactory/vaultFactory.js @@ -33,9 +33,11 @@ import { makeVaultDirector } from './vaultDirector.js'; * ammPublicFacet: AutoswapPublicFacet, * liquidationInstall: Installation, * loanTimingParams: {ChargingPeriod: ParamRecord<'nat'>, RecordingPeriod: ParamRecord<'nat'>}, - * timerService: TimerService, * minInitialDebt: Amount, - * priceAuthority: ERef}>} VaultFactoryZCF + * priceAuthority: ERef, + * reservePublicFacet: AssetReservePublicFacet, + * timerService: TimerService, + * }>} VaultFactoryZCF */ /** diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 5cf73cf0c1d..9bd92129761 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -61,7 +61,7 @@ const trace = makeTracer('VM', false); * poolIncrementSeat: ZCFSeat, * priceAuthority: ERef, * prioritizedVaults: ReturnType, - * zcf: ZCF, + * zcf: import('./vaultFactory.js').VaultFactoryZCF, * }>} ImmutableState */ @@ -97,7 +97,7 @@ let outstandingQuote = null; /** * Create state for the Vault Manager kind * - * @param {ZCF} zcf + * @param {import('./vaultFactory.js').VaultFactoryZCF} zcf * @param {ZCFMint<'nat'>} debtMint * @param {Brand} collateralBrand * @param {ERef} priceAuthority @@ -532,7 +532,8 @@ const selfBehavior = { liquidationTerms, ) => { const { zcf, debtBrand, collateralBrand } = state; - const { ammPublicFacet, priceAuthority, timerService } = zcf.getTerms(); + const { ammPublicFacet, priceAuthority, reservePublicFacet, timerService } = + zcf.getTerms(); const zoe = zcf.getZoeService(); const collateralIssuer = zcf.getIssuerForBrand(collateralBrand); const debtIssuer = zcf.getIssuerForBrand(debtBrand); @@ -548,9 +549,10 @@ const selfBehavior = { harden({ ...liquidationTerms, amm: ammPublicFacet, + debtBrand, + reservePublicFacet, priceAuthority, timerService, - debtBrand, }), ); trace('setup liquidator complete', { diff --git a/packages/run-protocol/test/reserve/setup.js b/packages/run-protocol/test/reserve/setup.js index 7d141443a0c..54c6674c84b 100644 --- a/packages/run-protocol/test/reserve/setup.js +++ b/packages/run-protocol/test/reserve/setup.js @@ -54,7 +54,7 @@ const setupReserveBootstrap = async ( /** * NOTE: called separately by each test so contracts don't interfere * - * @param {*} t + * @param {import("ava").ExecutionContext} t * @param {{ committeeName: string, committeeSize: number}} electorateTerms * @param {ManualTimer | undefined=} timer * @returns {{ diff --git a/packages/run-protocol/test/swingsetTests/setup.js b/packages/run-protocol/test/swingsetTests/setup.js index dfc9eda71be..6e6d8a0a4ed 100644 --- a/packages/run-protocol/test/swingsetTests/setup.js +++ b/packages/run-protocol/test/swingsetTests/setup.js @@ -5,7 +5,7 @@ import { makeIssuerKit, AmountMath } from '@agoric/ertp'; import { makeRatio } from '@agoric/zoe/src/contractSupport/index.js'; import buildManualTimer from '@agoric/zoe/tools/manualTimer'; -import { makeGovernedTerms } from '../../src/vaultFactory/params'; +import { makeGovernedTerms as makeVaultFactoryTerms } from '../../src/vaultFactory/params'; import { ammMock } from './mockAmm'; import { liquidationDetailTerms } from '../../src/vaultFactory/liquidation'; @@ -199,7 +199,7 @@ const buildOwner = async ( E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), ]); - const terms = makeGovernedTerms({ + const terms = makeVaultFactoryTerms({ priceAuthority: priceAuthorityKit.priceAuthority, loanTiming, liquidationInstall: installations.liquidateMinimum, diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index 066ed903542..620158e4a35 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -32,6 +32,7 @@ import { waitForPromisesToSettle, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; +import { setupReserveServices } from '../reserve/setup.js'; // #region Support @@ -82,15 +83,18 @@ test.before(async t => { const runIssuer = E(zoe).getFeeIssuer(); const runBrand = await E(runIssuer).getBrand(); const aethKit = makeIssuerKit('aEth'); - const loader = await unsafeMakeBundleCache('./bundles/'); // package-relative + const bundleCache = await unsafeMakeBundleCache('./bundles/'); // package-relative // note that the liquidation might be a different bundle name // Collect.mapValues(contractRoots, (root, k) => loader.load(root, k)), const bundles = await Collect.allValues({ - faucet: loader.load(contractRoots.faucet, 'faucet'), - liquidate: loader.load(contractRoots.liquidate, 'liquidateIncrementally'), - VaultFactory: loader.load(contractRoots.VaultFactory, 'VaultFactory'), - amm: loader.load(contractRoots.amm, 'amm'), + faucet: bundleCache.load(contractRoots.faucet, 'faucet'), + liquidate: bundleCache.load( + contractRoots.liquidate, + 'liquidateIncrementally', + ), + VaultFactory: bundleCache.load(contractRoots.VaultFactory, 'VaultFactory'), + amm: bundleCache.load(contractRoots.amm, 'amm'), }); const installation = Collect.mapValues(bundles, bundle => E(zoe).install(bundle), @@ -112,7 +116,7 @@ test.before(async t => { aethInitialLiquidity: AmountMath.make(aethKit.brand, 900_000_000n), }; const frozenCtx = await deeplyFulfilled(harden(contextPs)); - t.context = { ...frozenCtx }; + t.context = { ...frozenCtx, bundleCache }; trace(t, 'CONTEXT'); }); @@ -270,6 +274,13 @@ async function setupServices( }); produce.priceAuthority.resolve(priceAuthority); + const { reserve } = await setupReserveServices( + t, + t.context.electorateTerms, + timer, + ); + produce.reservePublicFacet.resolve(reserve.reservePublicFacet); + const { installation: { produce: iProduce }, } = space; diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 115a8604764..6780f40c301 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -40,6 +40,7 @@ import { installGovernance, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; +import { setupReserveServices } from '../reserve/setup.js'; // #region Support @@ -92,13 +93,14 @@ test.before(async t => { const runIssuer = E(zoe).getFeeIssuer(); const runBrand = E(runIssuer).getBrand(); const aethKit = makeIssuerKit('aEth'); - const loader = await unsafeMakeBundleCache('./bundles/'); // package-relative + + const bundleCache = await unsafeMakeBundleCache('./bundles/'); // package-relative // note that the liquidation might be a different bundle name const bundles = await Collect.allValues({ - faucet: loader.load(contractRoots.faucet, 'faucet'), - liquidate: loader.load(contractRoots.liquidate, 'liquidateMinimum'), - VaultFactory: loader.load(contractRoots.VaultFactory, 'VaultFactory'), - amm: loader.load(contractRoots.amm, 'amm'), + faucet: bundleCache.load(contractRoots.faucet, 'faucet'), + liquidate: bundleCache.load(contractRoots.liquidate, 'liquidateMinimum'), + VaultFactory: bundleCache.load(contractRoots.VaultFactory, 'VaultFactory'), + amm: bundleCache.load(contractRoots.amm, 'amm'), }); const installation = Collect.mapValues(bundles, bundle => E(zoe).install(bundle), @@ -121,7 +123,7 @@ test.before(async t => { aethInitialLiquidity: AmountMath.make(aethKit.brand, 300n), }; const frozenCtx = await deeplyFulfilled(harden(contextPs)); - t.context = { ...frozenCtx }; + t.context = { ...frozenCtx, bundleCache }; trace(t, 'CONTEXT'); }); @@ -284,6 +286,13 @@ async function setupServices( }); produce.priceAuthority.resolve(pa); + const { reserve } = await setupReserveServices( + t, + t.context.electorateTerms, + timer, + ); + produce.reservePublicFacet.resolve(reserve.reservePublicFacet); + const { installation: { produce: iProduce }, } = space; From 86dea15432cf30d39919538ed989183d6fbe42a9 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 13:24:43 -0700 Subject: [PATCH 22/39] rm obsolete penaltyPoolSeat --- .../src/vaultFactory/liquidateIncrementally.js | 2 +- packages/run-protocol/src/vaultFactory/liquidation.js | 2 -- packages/run-protocol/src/vaultFactory/types.js | 1 - packages/run-protocol/src/vaultFactory/vaultDirector.js | 8 -------- packages/run-protocol/src/vaultFactory/vaultManager.js | 8 +------- 5 files changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index 52355490a44..ceca675025b 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -76,7 +76,7 @@ const start = async zcf => { const asFloat = (numerator, denominator) => Number(numerator) / Number(denominator); - // TODO distribute penalties to the reserve + // TODO(before merge) distribute penalties to the reserve assert(reservePublicFacet, 'Missing reservePublicFacet'); const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index 2db9ae11d52..4f04fabda48 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -23,7 +23,6 @@ const trace = makeTracer('LIQ'); * ) => void} burnLosses * @param {Liquidator} liquidator * @param {Brand} collateralBrand - * @param {ZCFSeat} penaltyPoolSeat * @param {Ratio} penaltyRate * @returns {Promise} */ @@ -33,7 +32,6 @@ const liquidate = async ( burnLosses, liquidator, collateralBrand, - penaltyPoolSeat, penaltyRate, ) => { trace('liquidate start', vault); diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index fc24013cb8c..f4249479162 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -45,7 +45,6 @@ * @property {AddVaultType} addVaultType * @property {() => Promise>} getCollaterals * @property {() => Allocation} getRewardAllocation - * @property {() => Allocation} getPenaltyAllocation * @property {() => Instance} getContractGovernor * @property {() => Promise} makeCollectFeesInvitation */ diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 1923a80dc21..0ee764c7d9a 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -37,7 +37,6 @@ const { details: X } = assert; * electionManager: Instance, * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager, * mintSeat: ZCFSeat, - * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, * vaultParamManagers: Store, * zcf: import('./vaultFactory.js').VaultFactoryZCF, @@ -64,7 +63,6 @@ const initState = (zcf, directorParamManager, debtMint) => { /** For temporary staging of newly minted tokens */ const { zcfSeat: mintSeat } = zcf.makeEmptySeatKit(); const { zcfSeat: rewardPoolSeat } = zcf.makeEmptySeatKit(); - const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); const collateralTypes = makeScalarMap('brand'); @@ -76,7 +74,6 @@ const initState = (zcf, directorParamManager, debtMint) => { directorParamManager, mintSeat, rewardPoolSeat, - penaltyPoolSeat, vaultParamManagers, zcf, }; @@ -204,7 +201,6 @@ const machineBehavior = { debtMint, collateralTypes, mintSeat, - penaltyPoolSeat, rewardPoolSeat, vaultParamManagers, directorParamManager, @@ -289,7 +285,6 @@ const machineBehavior = { zcf.getTerms().priceAuthority, factoryPowers, timerService, - penaltyPoolSeat, startTimeStamp, ); collateralTypes.init(collateralBrand, vm); @@ -316,9 +311,6 @@ const machineBehavior = { /** @param {MethodContext} context */ getRewardAllocation: ({ state }) => state.rewardPoolSeat.getCurrentAllocation(), - /** @param {MethodContext} context */ - getPenaltyAllocation: ({ state }) => - state.penaltyPoolSeat.getCurrentAllocation(), }; const creatorBehavior = { diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index 9bd92129761..1e75b4a9c8f 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -56,7 +56,6 @@ const trace = makeTracer('VM', false); * debtBrand: Brand<'nat'>, * debtMint: ZCFMint<'nat'>, * factoryPowers: import('./vaultDirector.js').FactoryPowersFacet, - * penaltyPoolSeat: ZCFSeat, * periodNotifier: ERef>, * poolIncrementSeat: ZCFSeat, * priceAuthority: ERef, @@ -103,7 +102,6 @@ let outstandingQuote = null; * @param {ERef} priceAuthority * @param {import('./vaultDirector.js').FactoryPowersFacet} factoryPowers * @param {ERef} timerService - * @param {ZCFSeat} penaltyPoolSeat * @param {Timestamp} startTimeStamp */ const initState = ( @@ -113,7 +111,6 @@ const initState = ( priceAuthority, factoryPowers, timerService, - penaltyPoolSeat, startTimeStamp, ) => { const periodNotifier = E(timerService).makeNotifier( @@ -127,7 +124,6 @@ const initState = ( debtBrand: debtMint.getIssuerRecord().brand, debtMint, factoryPowers, - penaltyPoolSeat, periodNotifier, poolIncrementSeat: zcf.makeEmptySeatKit().zcfSeat, priceAuthority, @@ -354,7 +350,7 @@ const helperBehavior = { * @param {[key: string, vaultKit: Vault]} record */ liquidateAndRemove: ({ state, facets }, [key, vault]) => { - const { factoryPowers, penaltyPoolSeat, prioritizedVaults, zcf } = state; + const { factoryPowers, prioritizedVaults, zcf } = state; trace('liquidating', vault.getVaultSeat().getProposal()); // Start liquidation (vaultState: LIQUIDATING) @@ -367,7 +363,6 @@ const helperBehavior = { (amount, seat) => facets.manager.burnAndRecord(amount, seat), liquidator, state.collateralBrand, - penaltyPoolSeat, factoryPowers.getGovernedParams().getLiquidationPenalty(), ) .then(() => { @@ -633,7 +628,6 @@ const makeVaultManagerKit = defineKindMulti( * @param {ERef} priceAuthority * @param {import('./vaultDirector.js').FactoryPowersFacet} factoryPowers * @param {ERef} timerService - * @param {ZCFSeat} penaltyPoolSeat * @param {Timestamp} startTimeStamp */ export const makeVaultManager = pickFacet(makeVaultManagerKit, 'self'); From db7194b2fe1cec0155558c3cd9f6c906422cf869 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 14:34:45 -0700 Subject: [PATCH 23/39] fixup! wire reservePublicFacet into vaultFactory terms --- packages/run-protocol/src/core-proposal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/run-protocol/src/core-proposal.js b/packages/run-protocol/src/core-proposal.js index 92668634296..302dae65c9b 100644 --- a/packages/run-protocol/src/core-proposal.js +++ b/packages/run-protocol/src/core-proposal.js @@ -50,6 +50,7 @@ const SHARED_MAIN_MANIFEST = harden({ chainTimerService: 'timer', zoe: 'zoe', priceAuthority: 'priceAuthority', + reservePublicFacet: 'reservePublicFacet', economicCommitteeCreatorFacet: 'economicCommittee', }, produce: { From db9e40656895015b5f8108229693d6641c2ebe91 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 14:35:02 -0700 Subject: [PATCH 24/39] fixup! rm obsolete penaltyPoolSeat --- packages/run-protocol/test/vaultFactory/test-vaultFactory.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 6780f40c301..9f657f327e7 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -469,9 +469,6 @@ test('first', async t => { 'unused collateral remains after liquidation', ); - // ??? remove penalty pool from vault factory - // used to be funded from liquidation penalty - t.deepEqual(await E(vaultFactory).getPenaltyAllocation(), {}); t.deepEqual(await E(vaultFactory).getRewardAllocation(), { RUN: AmountMath.make(runBrand, 24n), }); From 4c928599405144788e0aa5669d42499d77cc698c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 15:36:31 -0700 Subject: [PATCH 25/39] consume reserve instance instead of facet --- packages/run-protocol/src/core-proposal.js | 7 +++++-- packages/run-protocol/src/econ-behaviors.js | 20 +++++++++++-------- .../test/vaultFactory/test-liquidator.js | 14 ++++++------- .../test/vaultFactory/test-vaultFactory.js | 15 +++++++------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/packages/run-protocol/src/core-proposal.js b/packages/run-protocol/src/core-proposal.js index 302dae65c9b..3a3839a6a92 100644 --- a/packages/run-protocol/src/core-proposal.js +++ b/packages/run-protocol/src/core-proposal.js @@ -50,7 +50,6 @@ const SHARED_MAIN_MANIFEST = harden({ chainTimerService: 'timer', zoe: 'zoe', priceAuthority: 'priceAuthority', - reservePublicFacet: 'reservePublicFacet', economicCommitteeCreatorFacet: 'economicCommittee', }, produce: { @@ -68,7 +67,11 @@ const SHARED_MAIN_MANIFEST = harden({ }, }, instance: { - consume: { amm: 'amm', economicCommittee: 'economicCommittee' }, + consume: { + amm: 'amm', + economicCommittee: 'economicCommittee', + reserve: 'reserve', + }, produce: { VaultFactory: 'VaultFactory', Treasury: 'VaultFactory', diff --git a/packages/run-protocol/src/econ-behaviors.js b/packages/run-protocol/src/econ-behaviors.js index 040f9414ab2..39ac4c2bb32 100644 --- a/packages/run-protocol/src/econ-behaviors.js +++ b/packages/run-protocol/src/econ-behaviors.js @@ -248,7 +248,6 @@ export const startVaultFactory = async ( consume: { chainTimerService, priceAuthority: priceAuthorityP, - reservePublicFacet: reservePublicFacetP, zoe, feeMintAccess: feeMintAccessP, // ISSUE: why doeszn't Zoe await this? economicCommitteeCreatorFacet: electorateCreatorFacet, @@ -297,16 +296,21 @@ export const startVaultFactory = async ( loanFee: makeRatio(0n, centralBrand, BASIS_POINTS), }; - const [ammInstance, electorateInstance, contractGovernorInstall] = - await Promise.all([ - instance.consume.amm, - instance.consume.economicCommittee, - contractGovernor, - ]); + const [ + ammInstance, + electorateInstance, + contractGovernorInstall, + reserveInstance, + ] = await Promise.all([ + instance.consume.amm, + instance.consume.economicCommittee, + contractGovernor, + instance.consume.reserve, + ]); const ammPublicFacet = await E(zoe).getPublicFacet(ammInstance); const feeMintAccess = await feeMintAccessP; const priceAuthority = await priceAuthorityP; - const reservePublicFacet = await reservePublicFacetP; + const reservePublicFacet = await E(zoe).getPublicFacet(reserveInstance); const timer = await chainTimerService; const vaultFactoryTerms = makeGovernedTerms({ priceAuthority, diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index 620158e4a35..d8ffd7435cd 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -20,6 +20,7 @@ import { startEconomicCommittee, startVaultFactory, setupAmm, + setupReserve, } from '../../src/econ-behaviors.js'; import '../../src/vaultFactory/types.js'; import * as Collect from '../../src/collect.js'; @@ -32,7 +33,6 @@ import { waitForPromisesToSettle, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; -import { setupReserveServices } from '../reserve/setup.js'; // #region Support @@ -95,6 +95,7 @@ test.before(async t => { ), VaultFactory: bundleCache.load(contractRoots.VaultFactory, 'VaultFactory'), amm: bundleCache.load(contractRoots.amm, 'amm'), + reserve: bundleCache.load(contractRoots.reserve, 'reserve'), }); const installation = Collect.mapValues(bundles, bundle => E(zoe).install(bundle), @@ -274,16 +275,13 @@ async function setupServices( }); produce.priceAuthority.resolve(priceAuthority); - const { reserve } = await setupReserveServices( - t, - t.context.electorateTerms, - timer, - ); - produce.reservePublicFacet.resolve(reserve.reservePublicFacet); - const { installation: { produce: iProduce }, } = space; + // make the installation available for setupReserve + iProduce.reserve.resolve(t.context.installation.reserve); + // produce the reserve instance in the space + await setupReserve(space); iProduce.VaultFactory.resolve(t.context.installation.VaultFactory); iProduce.liquidate.resolve(t.context.installation.liquidate); await startVaultFactory(space, { loanParams: loanTiming }, minInitialDebt); diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 9f657f327e7..e216a52c6ee 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -28,6 +28,7 @@ import { startEconomicCommittee, startVaultFactory, setupAmm, + setupReserve, } from '../../src/econ-behaviors.js'; import '../../src/vaultFactory/types.js'; import * as Collect from '../../src/collect.js'; @@ -40,7 +41,6 @@ import { installGovernance, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; -import { setupReserveServices } from '../reserve/setup.js'; // #region Support @@ -50,6 +50,7 @@ const contractRoots = { liquidate: './src/vaultFactory/liquidateMinimum.js', VaultFactory: './src/vaultFactory/vaultFactory.js', amm: './src/vpool-xyk-amm/multipoolMarketMaker.js', + reserve: './src/reserve/assetReserve.js', }; /** @typedef {import('../../src/vaultFactory/vaultFactory').VaultFactoryContract} VFC */ @@ -101,6 +102,7 @@ test.before(async t => { liquidate: bundleCache.load(contractRoots.liquidate, 'liquidateMinimum'), VaultFactory: bundleCache.load(contractRoots.VaultFactory, 'VaultFactory'), amm: bundleCache.load(contractRoots.amm, 'amm'), + reserve: bundleCache.load(contractRoots.reserve, 'reserve'), }); const installation = Collect.mapValues(bundles, bundle => E(zoe).install(bundle), @@ -286,16 +288,13 @@ async function setupServices( }); produce.priceAuthority.resolve(pa); - const { reserve } = await setupReserveServices( - t, - t.context.electorateTerms, - timer, - ); - produce.reservePublicFacet.resolve(reserve.reservePublicFacet); - const { installation: { produce: iProduce }, } = space; + // make the installation available for setupReserve + iProduce.reserve.resolve(t.context.installation.reserve); + // produce the reserve instance in the space + await setupReserve(space); iProduce.VaultFactory.resolve(t.context.installation.VaultFactory); iProduce.liquidate.resolve(t.context.installation.liquidate); await startVaultFactory(space, { loanParams: loanTiming }, minInitialDebt); From fff80b0a89f4be70ba526cd25b9e3b5ed7b7faed Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 15:49:57 -0700 Subject: [PATCH 26/39] typecheck liquidator,vaultFactory tests --- .../test/vaultFactory/test-liquidator.js | 18 +++++++------ .../test/vaultFactory/test-vaultFactory.js | 26 ++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index d8ffd7435cd..23845c48b5f 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -1,6 +1,6 @@ -// @ts-nocheck +// @ts-check -import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; +import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import '@agoric/zoe/exported.js'; import { E } from '@endo/eventual-send'; @@ -34,6 +34,9 @@ import { } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; +/** @type {import('ava').TestInterface} */ +const test = unknownTest; + // #region Support // TODO path resolve these so refactors detect @@ -147,7 +150,6 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { t.context.committee = makeVoterTool( zoe, space.consume.economicCommitteeCreatorFacet, - // @ts-expect-error TODO: add vaultFactoryGovernorCreator to vats/src/types.js space.consume.vaultFactoryGovernorCreator, counter, ); @@ -190,7 +192,7 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { /** * - * @param {ExecutionContext} t + * @param {import('ava').ExecutionContext} t * @param {bigint} runInitialLiquidity */ const getRunFromFaucet = async (t, runInitialLiquidity) => { @@ -223,7 +225,7 @@ const getRunFromFaucet = async (t, runInitialLiquidity) => { /** * NOTE: called separately by each test so AMM/zoe/priceAuthority don't interfere * - * @param {ExecutionContext} t + * @param {import('ava').ExecutionContext} t * @param {Amount} initialPrice * @param {Amount} priceBase * @param {TimerService} timer @@ -392,9 +394,9 @@ const makeDriver = async (t, initialPrice, priceBase) => { }, /** * - * @param {Vault.Phase} phase - * @param {object} likeExpected - * @param {undefined|AT_NEXT|number} optSince + * @param {import('../../src/vaultFactory/vault.js').VaultPhase} phase + * @param {object} [likeExpected] + * @param {AT_NEXT|number} [optSince] */ notified: async (phase, likeExpected, optSince) => { // optSince can be AT_NEXT in order to wait for the diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index e216a52c6ee..b490e01dd73 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -1,6 +1,6 @@ -// @ts-nocheck +// @ts-check -import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; +import { test as unknownTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import '@agoric/zoe/exported.js'; import { E } from '@endo/eventual-send'; @@ -42,6 +42,9 @@ import { } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; +/** @type {import('ava').TestInterface} */ +const test = unknownTest; + // #region Support // TODO path resolve these so refactors detect @@ -187,7 +190,7 @@ const setupAmmAndElectorate = async (t, aethLiquidity, runLiquidity) => { /** * - * @param {ExecutionContext} t + * @param {import('ava').ExecutionContext} t * @param {bigint} runInitialLiquidity */ const getRunFromFaucet = async (t, runInitialLiquidity) => { @@ -199,6 +202,7 @@ const getRunFromFaucet = async (t, runInitialLiquidity) => { } = t.context; /** @type {Promise>} */ // On-chain, there will be pre-existing RUN. The faucet replicates that + // @ts-expect-error const { creatorFacet: faucetCreator } = await E(zoe).startInstance( installation, {}, @@ -221,8 +225,8 @@ const getRunFromFaucet = async (t, runInitialLiquidity) => { /** * NOTE: called separately by each test so AMM/zoe/priceAuthority don't interfere * - * @param {ExecutionContext} t - * @param {Array | Ratio} priceOrList + * @param {import('ava').ExecutionContext} t + * @param {Array | Ratio} priceOrList * @param {Amount} unitAmountIn * @param {TimerService} timer * @param {unknown} quoteInterval @@ -306,12 +310,13 @@ async function setupServices( ); // Add a vault that will lend on aeth collateral + /** @type {Promise} */ const aethVaultManagerP = E(vaultFactoryCreatorFacet).addVaultType( aethIssuer, 'AEth', rates, ); - /** @type {[any, VaultFactory, VFC['publicFacet']]} */ + /** @type {[any, VaultFactory, VFC['publicFacet'], VaultManager, PriceAuthority]} */ // @ts-expect-error cast const [ governorInstance, @@ -551,11 +556,13 @@ test('price drop', async t => { ); trace(t, 'pa2', priceAuthority); + // @ts-expect-error mock priceAuthority.setPrice(makeRatio(677n, runBrand, 900n, aethBrand)); trace(t, 'price dropped a little'); notification = await E(vaultNotifier).getUpdateSince(); t.is(notification.value.vaultState, Phase.ACTIVE); + // @ts-expect-error mock await E(priceAuthority).setPrice(makeRatio(636n, runBrand, 900n, aethBrand)); notification = await E(vaultNotifier).getUpdateSince( notification.updateCount, @@ -575,6 +582,7 @@ test('price drop', async t => { ); trace(t, 'debt remains', AmountMath.make(runBrand, 284n)); + // @ts-expect-error mock await E(priceAuthority).setPrice(makeRatio(1000n, runBrand, 900n, aethBrand)); trace(t, 'debt gone'); notification = await E(vaultNotifier).getUpdateSince( @@ -1696,6 +1704,7 @@ test('mutable liquidity triggers and interest', async t => { t.deepEqual(aliceUpdate.value.debtSnapshot.debt, aliceRunDebtLevel); trace(t, 'alice reduce collateral'); + // @ts-expect-error mock await E(priceAuthority).setPrice(makeRatio(7n, runBrand, 1n, aethBrand)); trace(t, 'changed price to 7'); @@ -2296,9 +2305,7 @@ test('addVaultType: invalid args do not modify state', async t => { .addVaultType(chit.issuer, kw, null), ); await failsForSameReason( - E(vaultFactory) - // @ts-expect-error bad args on purpose for test - .addVaultType(chit.issuer, 'bogus kw', params), + E(vaultFactory).addVaultType(chit.issuer, 'bogus kw', params), ); // The keyword in the vault manager is not "stuck"; it's still available: @@ -2331,6 +2338,7 @@ test('addVaultType: extra, unexpected params', async t => { }; await t.throwsAsync( + // @ts-expect-error bad args E(vaultFactory).addVaultType(chit.issuer, 'Chit', missingParams), { message: /Must have same property names/ }, ); From 9e3018318c0f0b3b698fe225addc236d56dc4de0 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 15:50:51 -0700 Subject: [PATCH 27/39] fix test typo tsc caught --- packages/run-protocol/test/vaultFactory/test-liquidator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index 23845c48b5f..4ea24fa193a 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -488,7 +488,7 @@ const makeDriver = async (t, initialPrice, priceBase) => { }, managerNotified: async (likeExpected, optSince) => { managerNotification = await E(managerNotifier).getUpdateSince( - optSince === AT_NEXT ? managerNotifier.updateCount : optSince, + optSince === AT_NEXT ? managerNotification.updateCount : optSince, ); trace(t, 'manager notifier', managerNotification); if (likeExpected) { From d8fba65ef4aac98585a25272bc9fdd0295917837 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 16:01:31 -0700 Subject: [PATCH 28/39] fix invitation param and typecheck that would have caught it --- .../governance/src/contractGovernance/paramManager.js | 6 +++++- packages/run-protocol/src/vaultFactory/params.js | 1 - packages/run-protocol/test/swingsetTests/mockAmm.js | 1 + packages/run-protocol/test/swingsetTests/setup.js | 8 ++++++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/governance/src/contractGovernance/paramManager.js b/packages/governance/src/contractGovernance/paramManager.js index fa294758c96..1eea5de7329 100644 --- a/packages/governance/src/contractGovernance/paramManager.js +++ b/packages/governance/src/contractGovernance/paramManager.js @@ -17,7 +17,7 @@ import { } from './assertions.js'; import { CONTRACT_ELECTORATE } from './governParam.js'; -const { details: X } = assert; +const { details: X, quote: q } = assert; /** * @param {ParamManagerBase} paramManager @@ -29,6 +29,10 @@ const assertElectorateMatches = (paramManager, governedParams) => { const { [CONTRACT_ELECTORATE]: { value: paramElectorate }, } = governedParams; + assert( + paramElectorate, + X`Missing ${q(CONTRACT_ELECTORATE)} term in ${q(governedParams)}`, + ); assert( keyEQ(managerElectorate, paramElectorate), X`Electorate in manager (${managerElectorate})} incompatible with terms (${paramElectorate}`, diff --git a/packages/run-protocol/src/vaultFactory/params.js b/packages/run-protocol/src/vaultFactory/params.js index 82388d5d76e..047124a9023 100644 --- a/packages/run-protocol/src/vaultFactory/params.js +++ b/packages/run-protocol/src/vaultFactory/params.js @@ -1,4 +1,3 @@ -/* eslint-disable no-useless-rename */ // @ts-check import './types.js'; diff --git a/packages/run-protocol/test/swingsetTests/mockAmm.js b/packages/run-protocol/test/swingsetTests/mockAmm.js index 5bd6497441f..3468cc5a884 100644 --- a/packages/run-protocol/test/swingsetTests/mockAmm.js +++ b/packages/run-protocol/test/swingsetTests/mockAmm.js @@ -2,6 +2,7 @@ import { Far } from '@endo/marshal'; +/** @type {any} */ export const ammMock = Far('mock AMM', { getInputPrice(amountIn, amountOut) { return { amountIn, amountOut }; diff --git a/packages/run-protocol/test/swingsetTests/setup.js b/packages/run-protocol/test/swingsetTests/setup.js index 6e6d8a0a4ed..4aa67757589 100644 --- a/packages/run-protocol/test/swingsetTests/setup.js +++ b/packages/run-protocol/test/swingsetTests/setup.js @@ -199,18 +199,22 @@ const buildOwner = async ( E(E(zoe).getInvitationIssuer()).getAmountOf(poserInvitationP), ]); + /** @type {AssetReservePublicFacet} */ + // @ts-expect-error cast, never used + const reservePublicFacet = null; + const terms = makeVaultFactoryTerms({ priceAuthority: priceAuthorityKit.priceAuthority, loanTiming, liquidationInstall: installations.liquidateMinimum, timer, - electorateInvitation: poserInvitationAmount, + invitationAmount: poserInvitationAmount, vaultManagerParams, - // @ts-expect-error It's not a real AMM public facet ammPublicFacet: ammMock, liquidationTerms: liquidationDetailTerms(runBrand), minInitialDebt: AmountMath.make(runBrand, 100n), bootstrapPaymentValue: 0n, + reservePublicFacet, }); const privateVaultFactoryArgs = { feeMintAccess, initialPoserInvitation }; From 74460d25d351d09e50bf51998c8381c8fa62f705 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 May 2022 16:17:00 -0700 Subject: [PATCH 29/39] update comment docs --- .../run-protocol/src/vaultFactory/liquidateIncrementally.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index ceca675025b..6959b491352 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -23,6 +23,10 @@ const trace = makeTracer('LiqI', false); * price impact on the AMM of any one sale. Each block it will compute * a tranche of collateral to sell, where the size is a function of * the amount of that collateral in the AMM pool and the desired price impact. + * It presently consults the AMM and Oracle for whether to sell. + * + * The next revision of this will work as follows... + * * It then gets 3 prices for the current tranche: * - AMM quote - compute XYK locally based on the pool sizes * - Reserve quote - based on a low price at which the Reserve will purchase @@ -76,7 +80,7 @@ const start = async zcf => { const asFloat = (numerator, denominator) => Number(numerator) / Number(denominator); - // TODO(before merge) distribute penalties to the reserve + // TODO(5467)) distribute penalties to the reserve assert(reservePublicFacet, 'Missing reservePublicFacet'); const { zcfSeat: penaltyPoolSeat } = zcf.makeEmptySeatKit(); From bbb4ea9fbbf712175675e9916a50a8e45f3dc138 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 08:35:47 -0700 Subject: [PATCH 30/39] work around type resolution shortcomings --- packages/run-protocol/src/reserve/types.js | 1 - packages/run-protocol/src/vaultFactory/types.js | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) delete mode 100644 packages/run-protocol/src/reserve/types.js diff --git a/packages/run-protocol/src/reserve/types.js b/packages/run-protocol/src/reserve/types.js deleted file mode 100644 index 38c8447269b..00000000000 --- a/packages/run-protocol/src/reserve/types.js +++ /dev/null @@ -1 +0,0 @@ -/** @typedef {import('../reserve/assetReserve.js').AssetReservePublicFacet} AssetReservePublicFacet */ diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index f4249479162..22a8cad0392 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -1,10 +1,14 @@ // @ts-check -/** @typedef {import('./vault').VaultUIState} VaultUIState */ -/** @typedef {import('./vault').Vault} Vault */ -/** @typedef {import('./vaultKit').VaultKit} VaultKit */ -/** @typedef {import('./vaultManager').VaultManager} VaultManager */ -/** @typedef {import('./vaultManager').CollateralManager} CollateralManager */ +/** + * @typedef {import('./vault').VaultUIState} VaultUIState + * @typedef {import('./vault').Vault} Vault + * @typedef {import('./vaultKit').VaultKit} VaultKit + * @typedef {import('./vaultManager').VaultManager} VaultManager + * @typedef {import('./vaultManager').CollateralManager} CollateralManager + * @typedef {import('../reserve/assetReserve.js').AssetReserveCreatorFacet} AssetReserveCreatorFacet + * @typedef {import('../reserve/assetReserve.js').AssetReservePublicFacet} AssetReservePublicFacet + */ /** * @typedef {object} AutoswapLocal From 01c3fe609b6dfea498c3f4e71168410e277b5421 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 09:52:03 -0700 Subject: [PATCH 31/39] better comments --- .../run-protocol/src/vaultFactory/liquidateIncrementally.js | 4 ++-- packages/run-protocol/src/vaultFactory/liquidateMinimum.js | 4 ++-- packages/run-protocol/src/vaultFactory/liquidation.js | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js index 6959b491352..ebba37704cb 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js +++ b/packages/run-protocol/src/vaultFactory/liquidateIncrementally.js @@ -300,11 +300,11 @@ const start = async zcf => { } // Now we need to know how much was sold so we can pay off the debt. - // We can use this because only liquidation adds debt brand to the seat. + // We can use this seat because only liquidation adds debt brand to it.. const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand); const penaltyPaid = AmountMath.min(penalty, debtPaid); - // Allocate penalty portion of proceeds to a seat that will be transferred to reserve + // Allocate penalty portion of proceeds to a seat that will hold it for transfer to reserve penaltyPoolSeat.incrementBy( debtorSeat.decrementBy(harden({ Out: penaltyPaid })), ); diff --git a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js index bb314eff82e..88c9772f0df 100644 --- a/packages/run-protocol/src/vaultFactory/liquidateMinimum.js +++ b/packages/run-protocol/src/vaultFactory/liquidateMinimum.js @@ -70,11 +70,11 @@ const start = async zcf => { }); // Now we need to know how much was sold so we can pay off the debt. - // We can use this because only liquidation adds debt brand to the seat. + // We can use this seat because only liquidation adds debt brand to it.. const debtPaid = debtorSeat.getAmountAllocated('Out', debtBrand); const penaltyPaid = AmountMath.min(penalty, debtPaid); - // Allocate penalty portion of proceeds to a seat that will be transferred to reserve + // Allocate penalty portion of proceeds to a seat that will hold it for transfer to reserve penaltyPoolSeat.incrementBy( debtorSeat.decrementBy(harden({ Out: penaltyPaid })), ); diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index 4f04fabda48..98ed7bb8723 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -66,8 +66,7 @@ const liquidate = async ( deposited, E(liqSeat).getOfferResult(), ]); - // all the proceeds from AMM sale are on the vault seat instead of a staging seat - // ??? ^ okay? + // NB: all the proceeds from AMM sale are on the vault seat instead of a staging seat const runToBurn = AmountMath.min(proceeds.RUN, debt); trace('before burn', { debt, proceeds, runToBurn }); From 58f8d9d9c9301dc02f0e108c6bae0239326bee9a Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 14:10:43 -0700 Subject: [PATCH 32/39] fixup undo vaultFactoryCreator --- packages/run-protocol/test/vaultFactory/test-vaultFactory.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index a5d30af31ad..8c24f35d8a7 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -2353,7 +2353,7 @@ test('director notifiers', async t => { 500n, ); - const { lender, vaultFactoryCreator } = services.vaultFactory; + const { lender, vaultFactory } = services.vaultFactory; const { econ } = await E(lender).getPublicNotifiers(); @@ -2366,7 +2366,7 @@ test('director notifiers', async t => { // add a vault type const chit = makeIssuerKit('chit'); - await E(vaultFactoryCreator).addVaultType( + await E(vaultFactory).addVaultType( chit.issuer, 'Chit', defaultParamValues(chit.brand), From 3fe00a4fdf8695cc0d302ec3804fa258258bffe4 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 14:10:47 -0700 Subject: [PATCH 33/39] getMetrics --- packages/run-protocol/src/vaultFactory/types.js | 2 +- .../run-protocol/src/vaultFactory/vaultDirector.js | 12 +++++------- .../run-protocol/src/vaultFactory/vaultManager.js | 2 +- .../test/vaultFactory/test-vaultFactory.js | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/types.js b/packages/run-protocol/src/vaultFactory/types.js index dd6aa67a6f7..306b7f02617 100644 --- a/packages/run-protocol/src/vaultFactory/types.js +++ b/packages/run-protocol/src/vaultFactory/types.js @@ -49,7 +49,7 @@ * @property {() => Allocation} getPenaltyAllocation * @property {() => Instance} getContractGovernor * @property {() => Promise} makeCollectFeesInvitation - * @property {() => void} notifyEcon + * @property {() => void} updateMetrics */ /** diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 24edbdd0eb4..3d951d079ca 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -272,7 +272,7 @@ const machineBehavior = { } // TODO add aggregate debt tracking at the vaultFactory level #4482 // totalDebt = AmountMath.add(totalDebt, toMint); - facets.machine.notifyEcon(); + facets.machine.updateMetrics(); }; /** @@ -309,7 +309,7 @@ const machineBehavior = { const { install, terms } = getLiquidationConfig(directorParamManager); await vm.setupLiquidator(install, terms); watchGovernance(directorParamManager, vm, install, terms); - facets.machine.notifyEcon(); + facets.machine.updateMetrics(); return vm; }, getCollaterals, @@ -326,7 +326,7 @@ const machineBehavior = { /** @param {MethodContext} context */ getContractGovernor: ({ state }) => state.zcf.getTerms().electionManager, /** @param {MethodContext} context */ - notifyEcon: ({ state }) => { + updateMetrics: ({ state }) => { /** @type {MetricsNotification} */ const metrics = harden({ collaterals: Array.from(state.collateralTypes.keys()), @@ -391,10 +391,8 @@ const publicBehavior = { /** * @param {MethodContext} context */ - getPublicNotifiers: ({ state }) => { - const { metricsNotifier } = state; - return { metrics: metricsNotifier }; - }, + getMetrics: ({ state }) => state.metricsNotifier, + /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ makeLoanInvitation: makeVaultInvitation, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index bbaee2c95f1..a7795a69bef 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -496,7 +496,7 @@ const collateralBehavior = { /** @param {MethodContext} context */ getAssetNotifier: ({ state }) => state.assetNotifier, /** @param {MethodContext} context */ - getPublicNotifiers: ({ state }) => ({ metrics: state.metricsNotifier }), + getMetrics: ({ state }) => state.metricsNotifier, /** @param {MethodContext} context */ getCompoundedInterest: ({ state }) => state.compoundedInterest, }; diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 8c24f35d8a7..2774f030fe9 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -2355,7 +2355,7 @@ test('director notifiers', async t => { const { lender, vaultFactory } = services.vaultFactory; - const { econ } = await E(lender).getPublicNotifiers(); + const econ = await E(lender).getMetrics(); let state = await E(econ).getUpdateSince(); t.deepEqual(state.value, { @@ -2396,7 +2396,7 @@ test('manager notifiers', async t => { const { aethVaultManager, lender } = services.vaultFactory; const cm = await E(aethVaultManager).getPublicFacet(); - const { econ } = await E(cm).getPublicNotifiers(); + const econ = await E(cm).getMetrics(); let state = await E(econ).getUpdateSince(); t.deepEqual(state.value, { numVaults: 0, From 30a8eaf22be99bbeeebb88eeb1c0ee03a9277425 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 14:25:21 -0700 Subject: [PATCH 34/39] use subscriptions --- .../src/vaultFactory/vaultDirector.js | 18 ++++---- .../src/vaultFactory/vaultManager.js | 45 +++++++++++-------- .../test/vaultFactory/test-vaultFactory.js | 17 ++++--- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultDirector.js b/packages/run-protocol/src/vaultFactory/vaultDirector.js index 3d951d079ca..c806946163f 100644 --- a/packages/run-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/run-protocol/src/vaultFactory/vaultDirector.js @@ -18,7 +18,7 @@ import { Far } from '@endo/marshal'; import { AmountMath } from '@agoric/ertp'; import { assertKeywordName } from '@agoric/zoe/src/cleanProposal.js'; import { defineKindMulti } from '@agoric/vat-data'; -import { makeNotifierKit, observeIteration } from '@agoric/notifier'; +import { makeSubscriptionKit, observeIteration } from '@agoric/notifier'; import { makeVaultManager } from './vaultManager.js'; import { makeMakeCollectFeesInvitation } from '../collectFees.js'; import { @@ -42,12 +42,12 @@ const { details: X } = assert; * collateralTypes: Store, * electionManager: Instance, * directorParamManager: import('@agoric/governance/src/contractGovernance/typedParamManager').TypedParamManager, + * metricsPublication: IterationObserver + * metricsSubscription: Subscription * mintSeat: ZCFSeat, * penaltyPoolSeat: ZCFSeat, * rewardPoolSeat: ZCFSeat, * vaultParamManagers: Store, - * metricsNotifier: Notifier - * metricsUpdater: IterationObserver * zcf: import('./vaultFactory.js').VaultFactoryZCF, * }>} ImmutableState * @@ -78,15 +78,15 @@ const initState = (zcf, directorParamManager, debtMint) => { const vaultParamManagers = makeScalarMap('brand'); - const { notifier: metricsNotifier, updater: metricsUpdater } = - makeNotifierKit(); + const { publication: metricsPublication, subscription: metricsSubscription } = + makeSubscriptionKit(); return { collateralTypes, debtMint, directorParamManager, - metricsNotifier, - metricsUpdater, + metricsSubscription, + metricsPublication, mintSeat, penaltyPoolSeat, rewardPoolSeat, @@ -333,7 +333,7 @@ const machineBehavior = { penaltyPoolAllocation: state.penaltyPoolSeat.getCurrentAllocation(), rewardPoolAllocation: state.rewardPoolSeat.getCurrentAllocation(), }); - state.metricsUpdater.updateState(metrics); + state.metricsPublication.updateState(metrics); }, // XXX accessors for tests @@ -391,7 +391,7 @@ const publicBehavior = { /** * @param {MethodContext} context */ - getMetrics: ({ state }) => state.metricsNotifier, + getMetrics: ({ state }) => state.metricsSubscription, /** @deprecated use getCollateralManager and then makeVaultInvitation instead */ makeLoanInvitation: makeVaultInvitation, diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index a7795a69bef..d27221b927d 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -14,7 +14,11 @@ import { makeRatio, floorDivideBy, } from '@agoric/zoe/src/contractSupport/index.js'; -import { makeNotifierKit, observeNotifier } from '@agoric/notifier'; +import { + makeNotifierKit, + makeSubscriptionKit, + observeNotifier, +} from '@agoric/notifier'; import { AmountMath } from '@agoric/ertp'; import { defineKindMulti, pickFacet } from '@agoric/vat-data'; @@ -60,6 +64,8 @@ const trace = makeTracer('VM', false); * debtBrand: Brand<'nat'>, * debtMint: ZCFMint<'nat'>, * factoryPowers: import('./vaultDirector.js').FactoryPowersFacet, + * metricsPublication: IterationObserver, + * metricsSubscription: Subscription, * penaltyPoolSeat: ZCFSeat, * periodNotifier: ERef>, * poolIncrementSeat: ZCFSeat, @@ -74,8 +80,6 @@ const trace = makeTracer('VM', false); * assetNotifier: Notifier, * assetUpdater: IterationObserver, * compoundedInterest: Ratio, - * metricsNotifier: Notifier, - * metricsUpdater: IterationObserver, * latestInterestUpdate: bigint, * liquidator?: Liquidator * liquidatorInstance?: Instance @@ -128,12 +132,28 @@ const initState = ( factoryPowers.getGovernedParams().getChargingPeriod(), ); + const debtBrand = debtMint.getIssuerRecord().brand; + const totalCollateral = AmountMath.makeEmpty(collateralBrand, 'nat'); + const totalDebt = AmountMath.makeEmpty(debtBrand, 'nat'); + + const { publication: metricsPublication, subscription: metricsSubscription } = + makeSubscriptionKit(); + metricsPublication.updateState( + harden({ + numVaults: 0, + totalCollateral, + totalDebt, + }), + ); + /** @type {ImmutableState} */ const fixed = { collateralBrand, - debtBrand: debtMint.getIssuerRecord().brand, + debtBrand, debtMint, factoryPowers, + metricsSubscription, + metricsPublication, penaltyPoolSeat, periodNotifier, poolIncrementSeat: zcf.makeEmptySeatKit().zcfSeat, @@ -145,8 +165,6 @@ const initState = ( zcf, }; - const totalCollateral = AmountMath.makeEmpty(fixed.collateralBrand, 'nat'); - const totalDebt = AmountMath.makeEmpty(fixed.debtBrand, 'nat'); const compoundedInterest = makeRatio(100n, fixed.debtBrand); // starts at 1.0, no interest // timestamp of most recent update to interest const latestInterestUpdate = startTimeStamp; @@ -159,23 +177,12 @@ const initState = ( }), ); - const { updater: metricsUpdater, notifier: metricsNotifier } = - makeNotifierKit( - harden({ - numVaults: 0, - totalCollateral, - totalDebt, - }), - ); - /** @type {MutableState & ImmutableState} */ const state = { ...fixed, assetNotifier, assetUpdater, debtBrand: fixed.debtBrand, - metricsNotifier, - metricsUpdater, vaultCounter: 0, liquidator: undefined, liquidatorInstance: undefined, @@ -270,7 +277,7 @@ const helperBehavior = { totalCollateral: state.totalCollateral, totalDebt: state.totalDebt, }); - state.metricsUpdater.updateState(payload); + state.metricsPublication.updateState(payload); }, /** @@ -496,7 +503,7 @@ const collateralBehavior = { /** @param {MethodContext} context */ getAssetNotifier: ({ state }) => state.assetNotifier, /** @param {MethodContext} context */ - getMetrics: ({ state }) => state.metricsNotifier, + getMetrics: ({ state }) => state.metricsSubscription, /** @param {MethodContext} context */ getCompoundedInterest: ({ state }) => state.compoundedInterest, }; diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 2774f030fe9..9247fd5daed 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -40,6 +40,7 @@ import { installGovernance, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; +import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; // #region Support @@ -2355,9 +2356,11 @@ test('director notifiers', async t => { const { lender, vaultFactory } = services.vaultFactory; - const econ = await E(lender).getMetrics(); + /** @type {Subscription} */ + const metricsSub = await E(lender).getMetrics(); + const metrics = makeNotifierFromAsyncIterable(metricsSub); - let state = await E(econ).getUpdateSince(); + let state = await E(metrics).getUpdateSince(); t.deepEqual(state.value, { collaterals: [aethBrand], penaltyPoolAllocation: {}, @@ -2371,7 +2374,7 @@ test('director notifiers', async t => { 'Chit', defaultParamValues(chit.brand), ); - state = await E(econ).getUpdateSince(state.updateCount); + state = await E(metrics).getUpdateSince(state.updateCount); t.deepEqual(state.value, { collaterals: [aethBrand, chit.brand], penaltyPoolAllocation: {}, @@ -2396,8 +2399,10 @@ test('manager notifiers', async t => { const { aethVaultManager, lender } = services.vaultFactory; const cm = await E(aethVaultManager).getPublicFacet(); - const econ = await E(cm).getMetrics(); - let state = await E(econ).getUpdateSince(); + /** @type {Subscription} */ + const metricsSub = await E(cm).getMetrics(); + const metrics = makeNotifierFromAsyncIterable(metricsSub); + let state = await E(metrics).getUpdateSince(); t.deepEqual(state.value, { numVaults: 0, totalCollateral: AmountMath.makeEmpty(aethKit.brand), @@ -2421,7 +2426,7 @@ test('manager notifiers', async t => { await E(vaultSeat).getOfferResult(); - state = await E(econ).getUpdateSince(state.updateCount); + state = await E(metrics).getUpdateSince(state.updateCount); t.deepEqual(state.value, { numVaults: 1, totalCollateral: collateralAmount, From 9dd27d91cce5d493807f8c3136cedd7ca36a71e8 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 14:33:30 -0700 Subject: [PATCH 35/39] revert rename getNotifier (no ambiguity anymore) --- packages/run-protocol/src/vaultFactory/vaultManager.js | 2 +- packages/run-protocol/test/vaultFactory/test-liquidator.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index d27221b927d..fc9974b7c52 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -501,7 +501,7 @@ const collateralBehavior = { makeVaultInvitation: ({ state: { zcf }, facets: { self } }) => zcf.makeInvitation(self.makeVaultKit, 'MakeVault'), /** @param {MethodContext} context */ - getAssetNotifier: ({ state }) => state.assetNotifier, + getNotifier: ({ state }) => state.assetNotifier, /** @param {MethodContext} context */ getMetrics: ({ state }) => state.metricsSubscription, /** @param {MethodContext} context */ diff --git a/packages/run-protocol/test/vaultFactory/test-liquidator.js b/packages/run-protocol/test/vaultFactory/test-liquidator.js index f92933a2a75..b52a7b65a1a 100644 --- a/packages/run-protocol/test/vaultFactory/test-liquidator.js +++ b/packages/run-protocol/test/vaultFactory/test-liquidator.js @@ -344,7 +344,7 @@ const makeDriver = async (t, initialPrice, priceBase) => { } = services; const managerNotifier = await E( E(lender).getCollateralManager(aethBrand), - ).getAssetNotifier(); + ).getNotifier(); let managerNotification = await E(managerNotifier).getUpdateSince(); /** @type {UserSeat} */ From 905e07c9d6b55b6f45ed61752768bb865e81b254 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 15:09:07 -0700 Subject: [PATCH 36/39] =?UTF-8?q?fix=20lint=20my=20editor=20didn't=20show?= =?UTF-8?q?=20=F0=9F=A4=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/run-protocol/test/vaultFactory/test-vaultFactory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 9247fd5daed..1cbb7ccd09d 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -7,6 +7,7 @@ import { E } from '@endo/eventual-send'; import { deeplyFulfilled } from '@endo/marshal'; import { makeIssuerKit, AssetKind, AmountMath } from '@agoric/ertp'; +import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; import buildManualTimer from '@agoric/zoe/tools/manualTimer.js'; import { makeRatio, @@ -40,7 +41,6 @@ import { installGovernance, } from '../supports.js'; import { unsafeMakeBundleCache } from '../bundleTool.js'; -import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; // #region Support From d1b23440f7a9184ea3f3873b70f68f5c508cbea1 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 15:15:52 -0700 Subject: [PATCH 37/39] fixup! getMetrics --- packages/run-protocol/src/vaultFactory/vaultManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index fc9974b7c52..b51384e78d3 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -270,7 +270,7 @@ const helperBehavior = { }, /** @param {MethodContext} context */ - metricsNotify: ({ state }) => { + updateMetrics: ({ state }) => { /** @type {MetricsNotification} */ const payload = harden({ numVaults: state.prioritizedVaults.getCount(), @@ -554,7 +554,7 @@ const selfBehavior = { vaultKit.vault.getCollateralAmount(), ); seat.exit(); - helper.metricsNotify(); + helper.updateMetrics(); return vaultKit; } catch (err) { // remove it from prioritizedVaults From 41fa373c0f7660122cbce86b5f607c8b526a5009 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 May 2022 15:16:12 -0700 Subject: [PATCH 38/39] update metrics after each liquidation --- .../run-protocol/src/vaultFactory/liquidation.js | 3 +-- .../run-protocol/src/vaultFactory/vaultManager.js | 5 +++++ .../test/vaultFactory/test-vaultFactory.js | 12 ++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/run-protocol/src/vaultFactory/liquidation.js b/packages/run-protocol/src/vaultFactory/liquidation.js index 5e74f839b2c..c4ea0e65e1d 100644 --- a/packages/run-protocol/src/vaultFactory/liquidation.js +++ b/packages/run-protocol/src/vaultFactory/liquidation.js @@ -69,7 +69,7 @@ const liquidate = async ( 'Collateral', collateralBrand, ); - trace(`liq prep`, collateralToSell, debtBeforePenalty, debt); + trace(`liq prep`, { collateralToSell, debtBeforePenalty, debt }); const { deposited, userSeatPromise: liqSeat } = await offerTo( zcf, @@ -83,7 +83,6 @@ const liquidate = async ( vaultZcfSeat, harden({ debt }), ); - trace(` offeredTo`, collateralToSell, debt); // await deposited, but we don't need the value. await Promise.all([deposited, E(liqSeat).getOfferResult()]); diff --git a/packages/run-protocol/src/vaultFactory/vaultManager.js b/packages/run-protocol/src/vaultFactory/vaultManager.js index b51384e78d3..cffbda9f671 100644 --- a/packages/run-protocol/src/vaultFactory/vaultManager.js +++ b/packages/run-protocol/src/vaultFactory/vaultManager.js @@ -336,6 +336,9 @@ const helperBehavior = { trace('update quote', highestDebtRatio); }, + /** + * @param {MethodContext} context + */ processLiquidations: async ({ state, facets }) => { const { prioritizedVaults, priceAuthority } = state; const govParams = state.factoryPowers.getGovernedParams(); @@ -410,6 +413,7 @@ const helperBehavior = { .then(() => { prioritizedVaults.removeVault(key); trace('liquidated'); + facets.helper.updateMetrics(); }) .catch(e => { // XXX should notify interested parties @@ -467,6 +471,7 @@ const managerBehavior = { * @param {ZCFSeat} seat */ burnAndRecord: ({ state }, toBurn, seat) => { + trace('burnAndRecord', { toBurn, totalDebt: state.totalDebt }); const { burnDebt } = state.factoryPowers; burnDebt(toBurn, seat); state.totalDebt = AmountMath.subtract(state.totalDebt, toBurn); diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index 1cbb7ccd09d..b42f96c4bf2 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -2409,8 +2409,8 @@ test('manager notifiers', async t => { totalDebt: AmountMath.makeEmpty(t.context.runKit.brand), }); - // Create a loan for 470 RUN with 1100 aeth collateral - const collateralAmount = AmountMath.make(aethKit.brand, 1100n); + // Create a loan for 470 RUN with 210_000 aeth collateral + const collateralAmount = AmountMath.make(aethKit.brand, 210_000n); const loanAmount = AmountMath.make(runKit.brand, 470n); /** @type {UserSeat} */ const vaultSeat = await E(services.zoe).offer( @@ -2432,4 +2432,12 @@ test('manager notifiers', async t => { totalCollateral: collateralAmount, totalDebt: AmountMath.make(runKit.brand, 494n), // 470 plus fee }); + + await E(aethVaultManager).liquidateAll(); + state = await E(metrics).getUpdateSince(state.updateCount); + t.deepEqual(state.value, { + numVaults: 0, + totalCollateral: collateralAmount, + totalDebt: AmountMath.make(runKit.brand, 48n), // FIXME none should be left + }); }); From fc545891acc376909582b4f1230e58444af1d591 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 May 2022 07:38:28 -0700 Subject: [PATCH 39/39] fix test for manager notifiers --- .../test/vaultFactory/test-vaultFactory.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js index e9709d0d0a7..9848692e79c 100644 --- a/packages/run-protocol/test/vaultFactory/test-vaultFactory.js +++ b/packages/run-protocol/test/vaultFactory/test-vaultFactory.js @@ -2397,14 +2397,18 @@ test('director notifiers', async t => { }); test('manager notifiers', async t => { + const LOAN = 450n; + const DEBT = 473n; // with penalty + const AMPLE = 100_000n; + const { aethKit, runKit } = t.context; const services = await setupServices( t, - [500n, 15n], + [10n], AmountMath.make(aethKit.brand, 900n), undefined, undefined, - 500n, + AMPLE, ); const { aethVaultManager, lender } = services.vaultFactory; @@ -2419,9 +2423,9 @@ test('manager notifiers', async t => { totalDebt: AmountMath.makeEmpty(t.context.runKit.brand), }); - // Create a loan for 470 RUN with 210_000 aeth collateral - const collateralAmount = AmountMath.make(aethKit.brand, 210_000n); - const loanAmount = AmountMath.make(runKit.brand, 470n); + // Create a loan with ample collateral + const collateralAmount = AmountMath.make(aethKit.brand, AMPLE); + const loanAmount = AmountMath.make(runKit.brand, LOAN); /** @type {UserSeat} */ const vaultSeat = await E(services.zoe).offer( await E(lender).makeVaultInvitation(), @@ -2440,7 +2444,7 @@ test('manager notifiers', async t => { t.deepEqual(state.value, { numVaults: 1, totalCollateral: collateralAmount, - totalDebt: AmountMath.make(runKit.brand, 494n), // 470 plus fee + totalDebt: AmountMath.make(runKit.brand, DEBT), }); await E(aethVaultManager).liquidateAll(); @@ -2448,6 +2452,6 @@ test('manager notifiers', async t => { t.deepEqual(state.value, { numVaults: 0, totalCollateral: collateralAmount, - totalDebt: AmountMath.make(runKit.brand, 48n), // FIXME none should be left + totalDebt: AmountMath.make(runKit.brand, 0n), }); });