@agoric/inter-protocol 0.13.2-dev-2354e8d.0 → 0.13.2-dev-f243a2c.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/bundle-auctioneer-js-meta.json +117 -117
- package/bundles/bundle-auctioneer.js +1 -1
- package/bundles/bundle-econCommitteeCharter-js-meta.json +71 -71
- package/bundles/bundle-feeDistributor-js-meta.json +57 -57
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +113 -113
- package/bundles/bundle-fluxAggregatorKit.js +1 -1
- package/bundles/bundle-psm-js-meta.json +110 -110
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-js-meta.json +106 -106
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +77 -77
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-stakeFactory-js-meta.json +114 -114
- package/bundles/bundle-stakeFactory.js +1 -1
- package/bundles/bundle-vaultFactory-js-meta.json +143 -143
- package/bundles/bundle-vaultFactory.js +1 -1
- package/package.json +17 -17
- package/src/proposals/econ-behaviors.js +3 -1
- package/src/vaultFactory/params.js +56 -1
- package/src/vaultFactory/types.js +0 -1
- package/src/vaultFactory/vaultDirector.js +206 -185
- package/src/vaultFactory/vaultFactory.js +20 -11
- package/src/vaultFactory/vaultManager.js +289 -157
|
@@ -26,12 +26,14 @@ import {
|
|
|
26
26
|
} from '@agoric/ertp';
|
|
27
27
|
import { makeTracer } from '@agoric/internal';
|
|
28
28
|
import { makeStoredNotifier, observeNotifier } from '@agoric/notifier';
|
|
29
|
+
import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js';
|
|
29
30
|
import {
|
|
30
31
|
M,
|
|
32
|
+
makeScalarBigMapStore,
|
|
33
|
+
makeScalarBigSetStore,
|
|
31
34
|
makeScalarMapStore,
|
|
32
35
|
prepareExoClassKit,
|
|
33
|
-
|
|
34
|
-
provideDurableSetStore,
|
|
36
|
+
provide,
|
|
35
37
|
} from '@agoric/vat-data';
|
|
36
38
|
import { TransferPartShape } from '@agoric/zoe/src/contractSupport/atomicTransfer.js';
|
|
37
39
|
import {
|
|
@@ -41,12 +43,12 @@ import {
|
|
|
41
43
|
floorMultiplyBy,
|
|
42
44
|
getAmountIn,
|
|
43
45
|
getAmountOut,
|
|
46
|
+
makeEphemeraProvider,
|
|
44
47
|
makeRatio,
|
|
45
48
|
makeRatioFromAmounts,
|
|
46
49
|
makeRecorderTopic,
|
|
47
50
|
multiplyRatios,
|
|
48
51
|
offerTo,
|
|
49
|
-
provideEmptySeat,
|
|
50
52
|
SubscriberShape,
|
|
51
53
|
TopicsRecordShape,
|
|
52
54
|
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
@@ -108,6 +110,29 @@ const trace = makeTracer('VM', false);
|
|
|
108
110
|
* }} GovernedParamGetters
|
|
109
111
|
*/
|
|
110
112
|
|
|
113
|
+
/**
|
|
114
|
+
* @typedef {Readonly<{
|
|
115
|
+
* debtMint: ZCFMint<'nat'>,
|
|
116
|
+
* collateralBrand: Brand<'nat'>,
|
|
117
|
+
* collateralUnit: Amount<'nat'>,
|
|
118
|
+
* descriptionScope: string,
|
|
119
|
+
* startTimeStamp: Timestamp,
|
|
120
|
+
* storageNode: StorageNode,
|
|
121
|
+
* }>} HeldParams
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @typedef {{
|
|
126
|
+
* assetTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<AssetState>,
|
|
127
|
+
* debtBrand: Brand<'nat'>,
|
|
128
|
+
* liquidatingVaults: SetStore<Vault>,
|
|
129
|
+
* metricsTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<MetricsNotification>,
|
|
130
|
+
* poolIncrementSeat: ZCFSeat,
|
|
131
|
+
* retainedCollateralSeat: ZCFSeat,
|
|
132
|
+
* unsettledVaults: MapStore<string, Vault>,
|
|
133
|
+
* }} ImmutableState
|
|
134
|
+
*/
|
|
135
|
+
|
|
111
136
|
/**
|
|
112
137
|
* @typedef {{
|
|
113
138
|
* compoundedInterest: Ratio,
|
|
@@ -131,127 +156,81 @@ const trace = makeTracer('VM', false);
|
|
|
131
156
|
const quoteAsRatio = quoteAmount =>
|
|
132
157
|
makeRatioFromAmounts(quoteAmount.amountIn, quoteAmount.amountOut);
|
|
133
158
|
|
|
159
|
+
/**
|
|
160
|
+
* @type {(brand: Brand) => {
|
|
161
|
+
* prioritizedVaults: ReturnType<typeof makePrioritizedVaults>,
|
|
162
|
+
* storedQuotesNotifier: import('@agoric/notifier').StoredNotifier<PriceQuote>,
|
|
163
|
+
* storedCollateralQuote: PriceQuote,
|
|
164
|
+
* }}
|
|
165
|
+
*/
|
|
166
|
+
// any b/c will be filled after start()
|
|
167
|
+
const collateralEphemera = makeEphemeraProvider(() => /** @type {any} */ ({}));
|
|
168
|
+
|
|
134
169
|
/**
|
|
135
170
|
* @param {import('@agoric/ertp').Baggage} baggage
|
|
136
|
-
* @param {
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* @
|
|
141
|
-
* debtMint: ZCFMint<'nat'>,
|
|
142
|
-
* collateralBrand: Brand<'nat'>,
|
|
143
|
-
* collateralUnit: Amount<'nat'>,
|
|
171
|
+
* @param {{
|
|
172
|
+
* zcf: import('./vaultFactory.js').VaultFactoryZCF,
|
|
173
|
+
* marshaller: ERef<Marshaller>,
|
|
174
|
+
* makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit,
|
|
175
|
+
* makeERecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeERecorderKit,
|
|
144
176
|
* factoryPowers: import('./vaultDirector.js').FactoryPowersFacet,
|
|
145
|
-
*
|
|
146
|
-
* startTimeStamp: Timestamp,
|
|
147
|
-
* storageNode: StorageNode,
|
|
148
|
-
* }>} unique per singleton
|
|
177
|
+
* }} powers
|
|
149
178
|
*/
|
|
150
179
|
export const prepareVaultManagerKit = (
|
|
151
180
|
baggage,
|
|
152
|
-
zcf,
|
|
153
|
-
marshaller,
|
|
154
|
-
makeRecorderKit,
|
|
155
|
-
makeERecorderKit,
|
|
156
|
-
{
|
|
157
|
-
debtMint,
|
|
158
|
-
collateralBrand,
|
|
159
|
-
collateralUnit,
|
|
160
|
-
descriptionScope,
|
|
161
|
-
factoryPowers,
|
|
162
|
-
startTimeStamp,
|
|
163
|
-
storageNode,
|
|
164
|
-
},
|
|
181
|
+
{ zcf, marshaller, makeRecorderKit, factoryPowers },
|
|
165
182
|
) => {
|
|
166
|
-
assert(
|
|
167
|
-
storageNode && marshaller,
|
|
168
|
-
'VaultManager missing storageNode or marshaller',
|
|
169
|
-
);
|
|
170
|
-
|
|
171
183
|
const { priceAuthority, timerService, reservePublicFacet } = zcf.getTerms();
|
|
172
184
|
|
|
173
185
|
const makeVault = prepareVault(baggage, makeRecorderKit, zcf);
|
|
174
186
|
|
|
175
|
-
const periodNotifier = E(timerService).makeNotifier(
|
|
176
|
-
0n,
|
|
177
|
-
factoryPowers.getGovernedParams().getChargingPeriod(),
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
const assetKit = makeRecorderKit(
|
|
181
|
-
storageNode,
|
|
182
|
-
/** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<AssetState>} */ (
|
|
183
|
-
M.any()
|
|
184
|
-
),
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
/** @type {MapStore<string, Vault>} */
|
|
188
|
-
const unsettledVaults = provideDurableMapStore(baggage, 'orderedVaultStore');
|
|
189
|
-
|
|
190
|
-
const debtBrand = debtMint.getIssuerRecord().brand;
|
|
191
|
-
const zeroCollateral = AmountMath.makeEmpty(collateralBrand, 'nat');
|
|
192
|
-
const zeroDebt = AmountMath.makeEmpty(debtBrand, 'nat');
|
|
193
|
-
|
|
194
|
-
const metricsTopicKit = makeERecorderKit(
|
|
195
|
-
E(storageNode).makeChildNode('metrics'),
|
|
196
|
-
/** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<MetricsNotification>} */ (
|
|
197
|
-
M.any()
|
|
198
|
-
),
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
const quoteNotifier = E(priceAuthority).makeQuoteNotifier(
|
|
202
|
-
collateralUnit,
|
|
203
|
-
debtBrand,
|
|
204
|
-
);
|
|
205
|
-
const storedQuotesNotifier = makeStoredNotifier(
|
|
206
|
-
quoteNotifier,
|
|
207
|
-
E(storageNode).makeChildNode('quotes'),
|
|
208
|
-
marshaller,
|
|
209
|
-
);
|
|
210
|
-
/** @type {PriceQuote?} */
|
|
211
|
-
let storedCollateralQuote = null;
|
|
212
|
-
void observeNotifier(quoteNotifier, {
|
|
213
|
-
updateState(value) {
|
|
214
|
-
storedCollateralQuote = value;
|
|
215
|
-
},
|
|
216
|
-
fail(reason) {
|
|
217
|
-
console.error('quoteNotifier failed to iterate', reason);
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const prioritizedVaults = makePrioritizedVaults(unsettledVaults);
|
|
222
|
-
|
|
223
187
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* @type {SetStore<Vault>}
|
|
188
|
+
* @param {HeldParams & { metricsStorageNode: StorageNode }} params
|
|
189
|
+
* @returns {HeldParams & ImmutableState & MutableState}
|
|
228
190
|
*/
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
191
|
+
const initState = params => {
|
|
192
|
+
const {
|
|
193
|
+
debtMint,
|
|
194
|
+
collateralBrand,
|
|
195
|
+
metricsStorageNode,
|
|
196
|
+
startTimeStamp,
|
|
197
|
+
storageNode,
|
|
198
|
+
} = params;
|
|
199
|
+
const debtBrand = debtMint.getIssuerRecord().brand;
|
|
200
|
+
|
|
201
|
+
/** @type {ImmutableState} */
|
|
202
|
+
const immutable = {
|
|
203
|
+
debtBrand,
|
|
204
|
+
poolIncrementSeat: zcf.makeEmptySeatKit().zcfSeat,
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Vaults that have been sent for liquidation. When we get proceeds (or lack
|
|
208
|
+
* thereof) back from the liquidator, we will allocate them among the vaults.
|
|
209
|
+
*
|
|
210
|
+
* @type {SetStore<Vault>}
|
|
211
|
+
*/
|
|
212
|
+
liquidatingVaults: makeScalarBigSetStore('liquidatingVaults', {
|
|
213
|
+
durable: true,
|
|
214
|
+
}),
|
|
233
215
|
|
|
234
|
-
|
|
216
|
+
assetTopicKit: makeRecorderKit(storageNode),
|
|
235
217
|
|
|
236
|
-
|
|
237
|
-
const retainedCollateralSeat = provideEmptySeat(
|
|
238
|
-
zcf,
|
|
239
|
-
baggage,
|
|
240
|
-
'retained collateral',
|
|
241
|
-
);
|
|
218
|
+
metricsTopicKit: makeRecorderKit(metricsStorageNode),
|
|
242
219
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
metrics: makeRecorderTopic('Vault Factory metrics', metricsTopicKit),
|
|
246
|
-
});
|
|
220
|
+
// TODO(#7074) not used while liquidation is disabled. Reinstate with #7074
|
|
221
|
+
retainedCollateralSeat: zcf.makeEmptySeatKit().zcfSeat,
|
|
247
222
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
223
|
+
unsettledVaults: makeScalarBigMapStore('orderedVaultStore', {
|
|
224
|
+
durable: true,
|
|
225
|
+
}),
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const zeroCollateral = AmountMath.makeEmpty(collateralBrand, 'nat');
|
|
229
|
+
const zeroDebt = AmountMath.makeEmpty(debtBrand, 'nat');
|
|
230
|
+
|
|
231
|
+
return harden({
|
|
232
|
+
...params,
|
|
233
|
+
...immutable,
|
|
255
234
|
compoundedInterest: makeRatio(100n, debtBrand), // starts at 1.0, no interest
|
|
256
235
|
latestInterestUpdate: startTimeStamp,
|
|
257
236
|
numLiquidationsCompleted: 0,
|
|
@@ -266,11 +245,10 @@ export const prepareVaultManagerKit = (
|
|
|
266
245
|
totalShortfallReceived: zeroDebt,
|
|
267
246
|
vaultCounter: 0,
|
|
268
247
|
lockedQuote: undefined,
|
|
269
|
-
};
|
|
248
|
+
});
|
|
270
249
|
};
|
|
271
250
|
|
|
272
|
-
|
|
273
|
-
return prepareExoClassKit(
|
|
251
|
+
const makeVaultManagerKitInternal = prepareExoClassKit(
|
|
274
252
|
baggage,
|
|
275
253
|
'VaultManagerKit',
|
|
276
254
|
{
|
|
@@ -325,6 +303,7 @@ export const prepareVaultManagerKit = (
|
|
|
325
303
|
collateral: {
|
|
326
304
|
makeVaultInvitation() {
|
|
327
305
|
const { facets } = this;
|
|
306
|
+
const { collateralBrand, debtBrand } = this.state;
|
|
328
307
|
return zcf.makeInvitation(
|
|
329
308
|
seat => this.facets.self.makeVaultKit(seat),
|
|
330
309
|
facets.manager.scopeDescription('MakeVault'),
|
|
@@ -341,36 +320,108 @@ export const prepareVaultManagerKit = (
|
|
|
341
320
|
},
|
|
342
321
|
/** @deprecated use getPublicTopics */
|
|
343
322
|
getSubscriber() {
|
|
344
|
-
return
|
|
323
|
+
return this.state.assetTopicKit.subscriber;
|
|
345
324
|
},
|
|
346
325
|
/** @deprecated use getPublicTopics */
|
|
347
326
|
getMetrics() {
|
|
348
|
-
return
|
|
327
|
+
return this.state.metricsTopicKit.subscriber;
|
|
349
328
|
},
|
|
350
329
|
getQuotes() {
|
|
351
|
-
|
|
330
|
+
const ephemera = collateralEphemera(this.state.collateralBrand);
|
|
331
|
+
return ephemera.storedQuotesNotifier;
|
|
352
332
|
},
|
|
353
333
|
getCompoundedInterest() {
|
|
354
334
|
return this.state.compoundedInterest;
|
|
355
335
|
},
|
|
356
336
|
getPublicTopics() {
|
|
357
|
-
|
|
337
|
+
const { assetTopicKit, metricsTopicKit } = this.state;
|
|
338
|
+
return harden({
|
|
339
|
+
asset: makeRecorderTopic(
|
|
340
|
+
'State of the assets managed',
|
|
341
|
+
assetTopicKit,
|
|
342
|
+
),
|
|
343
|
+
metrics: makeRecorderTopic(
|
|
344
|
+
'Vault Factory metrics',
|
|
345
|
+
metricsTopicKit,
|
|
346
|
+
),
|
|
347
|
+
});
|
|
358
348
|
},
|
|
359
349
|
},
|
|
360
350
|
|
|
361
351
|
// Some of these could go in closures but are kept on a facet anticipating future durability options.
|
|
362
352
|
helper: {
|
|
353
|
+
/**
|
|
354
|
+
* Start non-durable processes (or restart if needed after vat restart)
|
|
355
|
+
*/
|
|
356
|
+
start() {
|
|
357
|
+
const { state, facets } = this;
|
|
358
|
+
const {
|
|
359
|
+
collateralBrand,
|
|
360
|
+
collateralUnit,
|
|
361
|
+
debtBrand,
|
|
362
|
+
storageNode,
|
|
363
|
+
unsettledVaults,
|
|
364
|
+
} = state;
|
|
365
|
+
|
|
366
|
+
const ephemera = collateralEphemera(collateralBrand);
|
|
367
|
+
ephemera.prioritizedVaults = makePrioritizedVaults(unsettledVaults);
|
|
368
|
+
|
|
369
|
+
const periodNotifier = E(timerService).makeNotifier(
|
|
370
|
+
0n,
|
|
371
|
+
factoryPowers
|
|
372
|
+
.getGovernedParams(collateralBrand)
|
|
373
|
+
.getChargingPeriod(),
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
void observeNotifier(periodNotifier, {
|
|
377
|
+
updateState: updateTime =>
|
|
378
|
+
facets.helper
|
|
379
|
+
.chargeAllVaults(updateTime)
|
|
380
|
+
.catch(e =>
|
|
381
|
+
console.error('🚨 vaultManager failed to charge interest', e),
|
|
382
|
+
),
|
|
383
|
+
fail: reason => {
|
|
384
|
+
zcf.shutdownWithFailure(
|
|
385
|
+
assert.error(X`Unable to continue without a timer: ${reason}`),
|
|
386
|
+
);
|
|
387
|
+
},
|
|
388
|
+
finish: done => {
|
|
389
|
+
zcf.shutdownWithFailure(
|
|
390
|
+
assert.error(X`Unable to continue without a timer: ${done}`),
|
|
391
|
+
);
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const quoteNotifier = E(priceAuthority).makeQuoteNotifier(
|
|
396
|
+
collateralUnit,
|
|
397
|
+
debtBrand,
|
|
398
|
+
);
|
|
399
|
+
ephemera.storedQuotesNotifier = makeStoredNotifier(
|
|
400
|
+
quoteNotifier,
|
|
401
|
+
E(storageNode).makeChildNode('quotes'),
|
|
402
|
+
marshaller,
|
|
403
|
+
);
|
|
404
|
+
void observeNotifier(quoteNotifier, {
|
|
405
|
+
updateState(value) {
|
|
406
|
+
ephemera.storedCollateralQuote = value;
|
|
407
|
+
},
|
|
408
|
+
fail(reason) {
|
|
409
|
+
console.error('quoteNotifier failed to iterate', reason);
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
},
|
|
363
413
|
/**
|
|
364
414
|
* @param {Timestamp} updateTime
|
|
365
415
|
*/
|
|
366
416
|
async chargeAllVaults(updateTime) {
|
|
367
417
|
const { state, facets } = this;
|
|
418
|
+
const { collateralBrand, debtMint, poolIncrementSeat } = state;
|
|
368
419
|
trace('chargeAllVaults', collateralBrand, {
|
|
369
420
|
updateTime,
|
|
370
421
|
});
|
|
371
422
|
|
|
372
423
|
const interestRate = factoryPowers
|
|
373
|
-
.getGovernedParams()
|
|
424
|
+
.getGovernedParams(collateralBrand)
|
|
374
425
|
.getInterestRate();
|
|
375
426
|
|
|
376
427
|
// Update state with the results of charging interest
|
|
@@ -385,10 +436,10 @@ export const prepareVaultManagerKit = (
|
|
|
385
436
|
{
|
|
386
437
|
interestRate,
|
|
387
438
|
chargingPeriod: factoryPowers
|
|
388
|
-
.getGovernedParams()
|
|
439
|
+
.getGovernedParams(collateralBrand)
|
|
389
440
|
.getChargingPeriod(),
|
|
390
441
|
recordingPeriod: factoryPowers
|
|
391
|
-
.getGovernedParams()
|
|
442
|
+
.getGovernedParams(collateralBrand)
|
|
392
443
|
.getRecordingPeriod(),
|
|
393
444
|
},
|
|
394
445
|
{
|
|
@@ -405,11 +456,11 @@ export const prepareVaultManagerKit = (
|
|
|
405
456
|
|
|
406
457
|
return facets.helper.assetNotify();
|
|
407
458
|
},
|
|
408
|
-
|
|
409
459
|
assetNotify() {
|
|
410
460
|
const { state } = this;
|
|
461
|
+
const { collateralBrand, assetTopicKit } = state;
|
|
411
462
|
const interestRate = factoryPowers
|
|
412
|
-
.getGovernedParams()
|
|
463
|
+
.getGovernedParams(collateralBrand)
|
|
413
464
|
.getInterestRate();
|
|
414
465
|
/** @type {AssetState} */
|
|
415
466
|
const payload = harden({
|
|
@@ -417,7 +468,7 @@ export const prepareVaultManagerKit = (
|
|
|
417
468
|
interestRate,
|
|
418
469
|
latestInterestUpdate: state.latestInterestUpdate,
|
|
419
470
|
});
|
|
420
|
-
return
|
|
471
|
+
return assetTopicKit.recorder.write(payload);
|
|
421
472
|
},
|
|
422
473
|
burnToCoverDebt(debt, proceeds, seat) {
|
|
423
474
|
const { state } = this;
|
|
@@ -526,6 +577,9 @@ export const prepareVaultManagerKit = (
|
|
|
526
577
|
},
|
|
527
578
|
updateMetrics() {
|
|
528
579
|
const { state } = this;
|
|
580
|
+
const { collateralBrand, retainedCollateralSeat, metricsTopicKit } =
|
|
581
|
+
state;
|
|
582
|
+
const { prioritizedVaults } = collateralEphemera(collateralBrand);
|
|
529
583
|
|
|
530
584
|
const retainedCollateral =
|
|
531
585
|
retainedCollateralSeat.getCurrentAllocation()?.Collateral ??
|
|
@@ -534,7 +588,7 @@ export const prepareVaultManagerKit = (
|
|
|
534
588
|
/** @type {MetricsNotification} */
|
|
535
589
|
const payload = harden({
|
|
536
590
|
numActiveVaults: prioritizedVaults.getCount(),
|
|
537
|
-
numLiquidatingVaults: liquidatingVaults.getSize(),
|
|
591
|
+
numLiquidatingVaults: state.liquidatingVaults.getSize(),
|
|
538
592
|
totalCollateral: state.totalCollateral,
|
|
539
593
|
totalDebt: state.totalDebt,
|
|
540
594
|
retainedCollateral,
|
|
@@ -549,7 +603,7 @@ export const prepareVaultManagerKit = (
|
|
|
549
603
|
totalShortfallReceived: state.totalShortfallReceived,
|
|
550
604
|
});
|
|
551
605
|
|
|
552
|
-
return E(metricsTopicKit.
|
|
606
|
+
return E(metricsTopicKit.recorder).write(payload);
|
|
553
607
|
},
|
|
554
608
|
|
|
555
609
|
distributeProceeds(
|
|
@@ -561,6 +615,7 @@ export const prepareVaultManagerKit = (
|
|
|
561
615
|
totalCollateral,
|
|
562
616
|
) {
|
|
563
617
|
const { state, facets } = this;
|
|
618
|
+
const { collateralBrand, debtBrand, liquidatingVaults } = this.state;
|
|
564
619
|
|
|
565
620
|
state.totalCollateralSold = AmountMath.add(
|
|
566
621
|
state.totalCollateralSold,
|
|
@@ -792,6 +847,7 @@ export const prepareVaultManagerKit = (
|
|
|
792
847
|
if (transfers.length > 0) {
|
|
793
848
|
atomicRearrange(zcf, harden(transfers));
|
|
794
849
|
}
|
|
850
|
+
const { prioritizedVaults } = collateralEphemera(collateralBrand);
|
|
795
851
|
for (const [vaultId, vault] of vaultsToReinstate.entries()) {
|
|
796
852
|
prioritizedVaults.addVault(vaultId, vault);
|
|
797
853
|
}
|
|
@@ -815,7 +871,8 @@ export const prepareVaultManagerKit = (
|
|
|
815
871
|
|
|
816
872
|
manager: {
|
|
817
873
|
getGovernedParams() {
|
|
818
|
-
|
|
874
|
+
const { collateralBrand } = this.state;
|
|
875
|
+
return factoryPowers.getGovernedParams(collateralBrand);
|
|
819
876
|
},
|
|
820
877
|
|
|
821
878
|
/**
|
|
@@ -825,6 +882,8 @@ export const prepareVaultManagerKit = (
|
|
|
825
882
|
* @param {Amount<'nat'>} collateralAmount
|
|
826
883
|
*/
|
|
827
884
|
maxDebtFor(collateralAmount) {
|
|
885
|
+
const { collateralBrand } = this.state;
|
|
886
|
+
const { storedCollateralQuote } = collateralEphemera(collateralBrand);
|
|
828
887
|
if (!storedCollateralQuote)
|
|
829
888
|
throw Fail`maxDebtFor called before a collateral quote was available`;
|
|
830
889
|
// use the lower price to prevent vault adjustments that put them imminently underwater
|
|
@@ -834,8 +893,12 @@ export const prepareVaultManagerKit = (
|
|
|
834
893
|
);
|
|
835
894
|
const collatlVal = ceilMultiplyBy(collateralAmount, collateralPrice);
|
|
836
895
|
const minimumCollateralization = calculateMinimumCollateralization(
|
|
837
|
-
factoryPowers
|
|
838
|
-
|
|
896
|
+
factoryPowers
|
|
897
|
+
.getGovernedParams(collateralBrand)
|
|
898
|
+
.getLiquidationMargin(),
|
|
899
|
+
factoryPowers
|
|
900
|
+
.getGovernedParams(collateralBrand)
|
|
901
|
+
.getLiquidationPadding(),
|
|
839
902
|
);
|
|
840
903
|
// floorDivide because we want the debt ceiling lower
|
|
841
904
|
return floorDivideBy(collatlVal, minimumCollateralization);
|
|
@@ -843,10 +906,10 @@ export const prepareVaultManagerKit = (
|
|
|
843
906
|
/** @type {MintAndTransfer} */
|
|
844
907
|
mintAndTransfer(mintReceiver, toMint, fee, transfers) {
|
|
845
908
|
const { state } = this;
|
|
846
|
-
const { totalDebt } = state;
|
|
909
|
+
const { collateralBrand, totalDebt } = state;
|
|
847
910
|
|
|
848
911
|
checkDebtLimit(
|
|
849
|
-
factoryPowers.getGovernedParams().getDebtLimit(),
|
|
912
|
+
factoryPowers.getGovernedParams(collateralBrand).getDebtLimit(),
|
|
850
913
|
totalDebt,
|
|
851
914
|
toMint,
|
|
852
915
|
);
|
|
@@ -859,6 +922,7 @@ export const prepareVaultManagerKit = (
|
|
|
859
922
|
*/
|
|
860
923
|
burnAndRecord(toBurn, seat) {
|
|
861
924
|
const { state } = this;
|
|
925
|
+
const { collateralBrand } = this.state;
|
|
862
926
|
|
|
863
927
|
trace('burnAndRecord', collateralBrand, {
|
|
864
928
|
toBurn,
|
|
@@ -868,12 +932,14 @@ export const prepareVaultManagerKit = (
|
|
|
868
932
|
state.totalDebt = AmountMath.subtract(state.totalDebt, toBurn);
|
|
869
933
|
},
|
|
870
934
|
getAssetSubscriber() {
|
|
871
|
-
return
|
|
935
|
+
return this.state.assetTopicKit.subscriber;
|
|
872
936
|
},
|
|
873
937
|
getCollateralBrand() {
|
|
938
|
+
const { collateralBrand } = this.state;
|
|
874
939
|
return collateralBrand;
|
|
875
940
|
},
|
|
876
941
|
getDebtBrand() {
|
|
942
|
+
const { debtBrand } = this.state;
|
|
877
943
|
return debtBrand;
|
|
878
944
|
},
|
|
879
945
|
/**
|
|
@@ -882,6 +948,7 @@ export const prepareVaultManagerKit = (
|
|
|
882
948
|
* @param {string} base
|
|
883
949
|
*/
|
|
884
950
|
scopeDescription(base) {
|
|
951
|
+
const { descriptionScope } = this.state;
|
|
885
952
|
return `${descriptionScope}: ${base}`;
|
|
886
953
|
},
|
|
887
954
|
/**
|
|
@@ -915,6 +982,18 @@ export const prepareVaultManagerKit = (
|
|
|
915
982
|
AmountMath.isEmpty(oldDebtNormalized) &&
|
|
916
983
|
vaultPhase !== Phase.ACTIVE;
|
|
917
984
|
|
|
985
|
+
trace('handleBalanceChange', {
|
|
986
|
+
oldDebtNormalized,
|
|
987
|
+
oldCollateral,
|
|
988
|
+
vaultId,
|
|
989
|
+
vaultPhase,
|
|
990
|
+
vault,
|
|
991
|
+
settled,
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
const { prioritizedVaults } = collateralEphemera(
|
|
995
|
+
state.collateralBrand,
|
|
996
|
+
);
|
|
918
997
|
if (settled) {
|
|
919
998
|
assert(
|
|
920
999
|
!prioritizedVaults.hasVaultByAttributes(
|
|
@@ -926,6 +1005,7 @@ export const prepareVaultManagerKit = (
|
|
|
926
1005
|
);
|
|
927
1006
|
} else {
|
|
928
1007
|
const isNew = AmountMath.isEmpty(oldDebtNormalized);
|
|
1008
|
+
trace({ isNew });
|
|
929
1009
|
if (!isNew) {
|
|
930
1010
|
// its position in the queue is no longer valid
|
|
931
1011
|
|
|
@@ -938,6 +1018,7 @@ export const prepareVaultManagerKit = (
|
|
|
938
1018
|
vault === vaultInStore,
|
|
939
1019
|
'handleBalanceChange for two different vaults',
|
|
940
1020
|
);
|
|
1021
|
+
trace('removed', vault, vaultId);
|
|
941
1022
|
}
|
|
942
1023
|
|
|
943
1024
|
// replace in queue, but only if it can accrue interest or be liquidated (i.e. has debt).
|
|
@@ -961,18 +1042,20 @@ export const prepareVaultManagerKit = (
|
|
|
961
1042
|
},
|
|
962
1043
|
self: {
|
|
963
1044
|
getGovernedParams() {
|
|
964
|
-
|
|
1045
|
+
const { collateralBrand } = this.state;
|
|
1046
|
+
return factoryPowers.getGovernedParams(collateralBrand);
|
|
965
1047
|
},
|
|
966
1048
|
|
|
967
1049
|
/**
|
|
968
1050
|
* @param {ZCFSeat} seat
|
|
969
1051
|
*/
|
|
970
1052
|
async makeVaultKit(seat) {
|
|
971
|
-
trace('
|
|
1053
|
+
trace('makeVaultKit');
|
|
972
1054
|
const {
|
|
973
1055
|
state,
|
|
974
1056
|
facets: { manager },
|
|
975
1057
|
} = this;
|
|
1058
|
+
const { storageNode } = this.state;
|
|
976
1059
|
assert(marshaller, 'makeVaultKit missing marshaller');
|
|
977
1060
|
assert(storageNode, 'makeVaultKit missing storageNode');
|
|
978
1061
|
assert(zcf, 'makeVaultKit missing zcf');
|
|
@@ -985,7 +1068,7 @@ export const prepareVaultManagerKit = (
|
|
|
985
1068
|
).makeChildNode(`vault${vaultId}`);
|
|
986
1069
|
|
|
987
1070
|
const { self: vault } = makeVault(manager, vaultId, vaultStorageNode);
|
|
988
|
-
trace('
|
|
1071
|
+
trace('makeVaultKit made vault', vault);
|
|
989
1072
|
|
|
990
1073
|
try {
|
|
991
1074
|
// TODO `await` is allowed until the above ordering is fixed
|
|
@@ -1011,8 +1094,11 @@ export const prepareVaultManagerKit = (
|
|
|
1011
1094
|
// remove it from the store if it got in
|
|
1012
1095
|
/** @type {NormalizedDebt} */
|
|
1013
1096
|
// @ts-expect-error cast
|
|
1014
|
-
const normalizedDebt = AmountMath.makeEmpty(debtBrand);
|
|
1097
|
+
const normalizedDebt = AmountMath.makeEmpty(state.debtBrand);
|
|
1015
1098
|
const collateralPre = seat.getCurrentAllocation().Collateral;
|
|
1099
|
+
const { prioritizedVaults } = collateralEphemera(
|
|
1100
|
+
state.collateralBrand,
|
|
1101
|
+
);
|
|
1016
1102
|
try {
|
|
1017
1103
|
prioritizedVaults.removeVaultByAttributes(
|
|
1018
1104
|
normalizedDebt,
|
|
@@ -1040,6 +1126,9 @@ export const prepareVaultManagerKit = (
|
|
|
1040
1126
|
},
|
|
1041
1127
|
|
|
1042
1128
|
getCollateralQuote() {
|
|
1129
|
+
const { storedCollateralQuote } = collateralEphemera(
|
|
1130
|
+
this.state.collateralBrand,
|
|
1131
|
+
);
|
|
1043
1132
|
if (!storedCollateralQuote)
|
|
1044
1133
|
throw Fail`getCollateralQuote called before a collateral quote was available`;
|
|
1045
1134
|
return storedCollateralQuote;
|
|
@@ -1050,9 +1139,12 @@ export const prepareVaultManagerKit = (
|
|
|
1050
1139
|
},
|
|
1051
1140
|
|
|
1052
1141
|
lockOraclePrices() {
|
|
1142
|
+
const { state } = this;
|
|
1143
|
+
const { storedCollateralQuote } = collateralEphemera(
|
|
1144
|
+
state.collateralBrand,
|
|
1145
|
+
);
|
|
1053
1146
|
if (!storedCollateralQuote)
|
|
1054
1147
|
throw Fail`lockOraclePrices called before a collateral quote was available`;
|
|
1055
|
-
const { state } = this;
|
|
1056
1148
|
trace(
|
|
1057
1149
|
`lockPrice`,
|
|
1058
1150
|
getAmountIn(storedCollateralQuote),
|
|
@@ -1068,9 +1160,16 @@ export const prepareVaultManagerKit = (
|
|
|
1068
1160
|
async liquidateVaults(auctionPF) {
|
|
1069
1161
|
const { state, facets } = this;
|
|
1070
1162
|
const { self, helper } = facets;
|
|
1071
|
-
const {
|
|
1163
|
+
const {
|
|
1164
|
+
collateralBrand,
|
|
1165
|
+
compoundedInterest,
|
|
1166
|
+
debtBrand,
|
|
1167
|
+
liquidatingVaults,
|
|
1168
|
+
lockedQuote,
|
|
1169
|
+
} = state;
|
|
1072
1170
|
trace('considering liquidation');
|
|
1073
1171
|
|
|
1172
|
+
const { prioritizedVaults } = collateralEphemera(collateralBrand);
|
|
1074
1173
|
assert(factoryPowers && prioritizedVaults && zcf);
|
|
1075
1174
|
lockedQuote ||
|
|
1076
1175
|
Fail`Must have locked a quote before liquidating vaults.`;
|
|
@@ -1122,6 +1221,10 @@ export const prepareVaultManagerKit = (
|
|
|
1122
1221
|
// and the difference between startingRate and lowestRate.
|
|
1123
1222
|
const [proceeds] = await Promise.all([deposited, userSeatPromise]);
|
|
1124
1223
|
|
|
1224
|
+
const { storedCollateralQuote } = collateralEphemera(
|
|
1225
|
+
this.state.collateralBrand,
|
|
1226
|
+
);
|
|
1227
|
+
|
|
1125
1228
|
trace(`LiqV after long wait`, proceeds);
|
|
1126
1229
|
helper.distributeProceeds(
|
|
1127
1230
|
proceeds,
|
|
@@ -1137,45 +1240,74 @@ export const prepareVaultManagerKit = (
|
|
|
1137
1240
|
|
|
1138
1241
|
{
|
|
1139
1242
|
finish: ({ state, facets: { helper } }) => {
|
|
1140
|
-
|
|
1243
|
+
helper.start();
|
|
1244
|
+
void state.assetTopicKit.recorder.write(
|
|
1141
1245
|
harden({
|
|
1142
1246
|
compoundedInterest: state.compoundedInterest,
|
|
1143
|
-
interestRate: factoryPowers
|
|
1247
|
+
interestRate: factoryPowers
|
|
1248
|
+
.getGovernedParams(state.collateralBrand)
|
|
1249
|
+
.getInterestRate(),
|
|
1144
1250
|
latestInterestUpdate: state.latestInterestUpdate,
|
|
1145
1251
|
}),
|
|
1146
1252
|
);
|
|
1147
1253
|
|
|
1148
1254
|
// push initial state of metrics
|
|
1149
1255
|
helper.updateMetrics();
|
|
1150
|
-
|
|
1151
|
-
void observeNotifier(periodNotifier, {
|
|
1152
|
-
updateState: updateTime =>
|
|
1153
|
-
helper
|
|
1154
|
-
.chargeAllVaults(updateTime)
|
|
1155
|
-
.catch(e =>
|
|
1156
|
-
console.error('🚨 vaultManager failed to charge interest', e),
|
|
1157
|
-
),
|
|
1158
|
-
fail: reason => {
|
|
1159
|
-
zcf.shutdownWithFailure(
|
|
1160
|
-
assert.error(X`Unable to continue without a timer: ${reason}`),
|
|
1161
|
-
);
|
|
1162
|
-
},
|
|
1163
|
-
finish: done => {
|
|
1164
|
-
zcf.shutdownWithFailure(
|
|
1165
|
-
assert.error(X`Unable to continue without a timer: ${done}`),
|
|
1166
|
-
);
|
|
1167
|
-
},
|
|
1168
|
-
});
|
|
1169
1256
|
},
|
|
1170
1257
|
},
|
|
1171
1258
|
);
|
|
1259
|
+
|
|
1260
|
+
/** @param {Omit<Parameters<typeof makeVaultManagerKitInternal>[0], 'metricsStorageNode'>} externalParams */
|
|
1261
|
+
const makeVaultManagerKit = async externalParams => {
|
|
1262
|
+
const metricsStorageNode = await E(
|
|
1263
|
+
externalParams.storageNode,
|
|
1264
|
+
).makeChildNode('metrics');
|
|
1265
|
+
return makeVaultManagerKitInternal({
|
|
1266
|
+
...externalParams,
|
|
1267
|
+
metricsStorageNode,
|
|
1268
|
+
});
|
|
1269
|
+
};
|
|
1270
|
+
return makeVaultManagerKit;
|
|
1172
1271
|
};
|
|
1173
1272
|
|
|
1174
1273
|
/**
|
|
1175
|
-
* @typedef {ReturnType<ReturnType<typeof prepareVaultManagerKit
|
|
1274
|
+
* @typedef {Awaited<ReturnType<ReturnType<typeof prepareVaultManagerKit>>>} VaultManagerKit
|
|
1275
|
+
*/
|
|
1276
|
+
/**
|
|
1277
|
+
* @typedef {VaultManagerKit['self']} VaultManager
|
|
1176
1278
|
* Each VaultManager manages a single collateral type.
|
|
1177
1279
|
*
|
|
1178
1280
|
* It manages some number of outstanding debt positions, each called a Vault,
|
|
1179
1281
|
* for which the collateral is provided in exchange for borrowed Minted.
|
|
1180
1282
|
*/
|
|
1181
|
-
/** @typedef {
|
|
1283
|
+
/** @typedef {VaultManagerKit['collateral']} CollateralManager */
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* Support restarting kits from baggage and mutating the array holding them
|
|
1287
|
+
*
|
|
1288
|
+
* @param {import('@agoric/vat-data').Baggage} baggage
|
|
1289
|
+
*/
|
|
1290
|
+
export const provideAndStartVaultManagerKits = baggage => {
|
|
1291
|
+
const key = 'vaultManagerKits';
|
|
1292
|
+
|
|
1293
|
+
const noKits = /** @type {VaultManagerKit[]} */ (harden([]));
|
|
1294
|
+
|
|
1295
|
+
for (const kit of provide(baggage, key, () => noKits)) {
|
|
1296
|
+
kit.helper.start();
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
return {
|
|
1300
|
+
/** @type {(kit: VaultManagerKit) => void} */
|
|
1301
|
+
add: kit => {
|
|
1302
|
+
appendToStoredArray(baggage, key, kit);
|
|
1303
|
+
},
|
|
1304
|
+
/** @type {(index: number) => VaultManagerKit} */
|
|
1305
|
+
get: index => {
|
|
1306
|
+
const kits = baggage.get(key);
|
|
1307
|
+
index < kits.length || Fail`no VaultManagerKit at index ${index}`;
|
|
1308
|
+
return kits[index];
|
|
1309
|
+
},
|
|
1310
|
+
length: () => baggage.get(key).length,
|
|
1311
|
+
};
|
|
1312
|
+
};
|
|
1313
|
+
harden(provideAndStartVaultManagerKits);
|