@agoric/inter-protocol 0.13.2-dev-55d06de.0 → 0.13.2-dev-097dca8.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-amm-meta.js +128 -128
- package/bundles/bundle-amm.js +1 -1
- package/bundles/bundle-econCommitteeCharter-meta.js +74 -74
- package/bundles/bundle-econCommitteeCharter.js +1 -1
- package/bundles/bundle-feeDistributor-meta.js +54 -54
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-interchainPool-meta.js +104 -104
- package/bundles/bundle-interchainPool.js +1 -1
- package/bundles/bundle-liquidateIncrementally-meta.js +68 -68
- package/bundles/bundle-liquidateIncrementally.js +1 -1
- package/bundles/bundle-liquidateMinimum-meta.js +68 -68
- package/bundles/bundle-liquidateMinimum.js +1 -1
- package/bundles/bundle-priceAggregatorChainlink-meta.js +73 -73
- package/bundles/bundle-priceAggregatorChainlink.js +1 -1
- package/bundles/bundle-psm-meta.js +107 -107
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-meta.js +105 -105
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-meta.js +80 -80
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-stakeFactory-meta.js +114 -114
- package/bundles/bundle-stakeFactory.js +1 -1
- package/bundles/bundle-vaultFactory-meta.js +132 -132
- package/bundles/bundle-vaultFactory.js +1 -1
- package/package.json +14 -14
- package/src/contractSupport.js +7 -0
- package/src/vaultFactory/vault.js +48 -83
- package/src/vaultFactory/vaultDirector.js +427 -528
- package/src/vaultFactory/vaultFactory.js +7 -3
- package/src/vaultFactory/vaultHolder.js +3 -3
- package/src/vaultFactory/vaultKit.js +9 -5
- package/src/vaultFactory/vaultManager.js +132 -256
|
@@ -23,17 +23,17 @@ import {
|
|
|
23
23
|
} from '@agoric/ertp';
|
|
24
24
|
import { makeTracer } from '@agoric/internal';
|
|
25
25
|
import {
|
|
26
|
+
makeStoredNotifier,
|
|
26
27
|
makeStoredSubscriber,
|
|
27
28
|
observeNotifier,
|
|
28
|
-
SubscriberShape,
|
|
29
29
|
prepareDurablePublishKit,
|
|
30
|
-
|
|
30
|
+
SubscriberShape,
|
|
31
31
|
} from '@agoric/notifier';
|
|
32
32
|
import {
|
|
33
33
|
M,
|
|
34
|
-
makeScalarBigMapStore,
|
|
35
|
-
makeScalarBigSetStore,
|
|
36
34
|
prepareExoClassKit,
|
|
35
|
+
provideDurableMapStore,
|
|
36
|
+
provideDurableSetStore,
|
|
37
37
|
} from '@agoric/vat-data';
|
|
38
38
|
import {
|
|
39
39
|
assertProposalShape,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
48
48
|
import { InstallationShape, SeatShape } from '@agoric/zoe/src/typeGuards.js';
|
|
49
49
|
import { E } from '@endo/eventual-send';
|
|
50
|
-
import { checkDebtLimit,
|
|
50
|
+
import { checkDebtLimit, provideEmptySeat } from '../contractSupport.js';
|
|
51
51
|
import { chargeInterest } from '../interest.js';
|
|
52
52
|
import { liquidate, makeQuote, updateQuote } from './liquidation.js';
|
|
53
53
|
import { makePrioritizedVaults } from './prioritizedVaults.js';
|
|
@@ -98,17 +98,6 @@ const trace = makeTracer('VM', false);
|
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
100
|
* @typedef {Readonly<{
|
|
101
|
-
* assetSubscriber: Subscriber<AssetState>,
|
|
102
|
-
* assetPublisher: Publisher<AssetState>,
|
|
103
|
-
* collateralBrand: Brand<'nat'>,
|
|
104
|
-
* debtBrand: Brand<'nat'>,
|
|
105
|
-
* debtMint: ZCFMint<'nat'>,
|
|
106
|
-
* metricsPublisher: Publisher<MetricsNotification>,
|
|
107
|
-
* metricsSubscriber: Subscriber<MetricsNotification>,
|
|
108
|
-
* poolIncrementSeat: ZCFSeat,
|
|
109
|
-
* retainedCollateralSeat: ZCFSeat,
|
|
110
|
-
* unsettledVaults: MapStore<string, Vault>,
|
|
111
|
-
* liquidatingVaults: SetStore<Vault>,
|
|
112
101
|
* }>} ImmutableState
|
|
113
102
|
*/
|
|
114
103
|
|
|
@@ -129,31 +118,6 @@ const trace = makeTracer('VM', false);
|
|
|
129
118
|
* }} MutableState
|
|
130
119
|
*/
|
|
131
120
|
|
|
132
|
-
/**
|
|
133
|
-
* Ephemera are the elements of state that cannot (or need not) be durable.
|
|
134
|
-
* When there's a single instance it can be held in a closure, but there are
|
|
135
|
-
* many vault manaager objects. So we hold their ephemera keyed by the durable
|
|
136
|
-
* vault manager.
|
|
137
|
-
*
|
|
138
|
-
* XXX However since we don't have the vault manager object during
|
|
139
|
-
* initState when we hold values that need to go into ephemera, we key for now
|
|
140
|
-
* using a proxy for the manager object, collateralBrand.
|
|
141
|
-
*
|
|
142
|
-
* @type {(collateralBrand: Brand) => Partial<{
|
|
143
|
-
* liquidationQueueing: boolean,
|
|
144
|
-
* outstandingQuote: Promise<MutableQuote>?,
|
|
145
|
-
* periodNotifier: ERef<Notifier<Timestamp>>,
|
|
146
|
-
* prioritizedVaults: ReturnType<typeof makePrioritizedVaults>,
|
|
147
|
-
* storedAssetSubscriber: StoredSubscriber<AssetState>,
|
|
148
|
-
* storedMetricsSubscriber: StoredSubscriber<MetricsNotification>,
|
|
149
|
-
* storedQuotesNotifier: import('@agoric/notifier').StoredNotifier<PriceQuote>,
|
|
150
|
-
* }>} */
|
|
151
|
-
const provideEphemera = makeEphemeraProvider(() => ({
|
|
152
|
-
liquidationQueueing: false,
|
|
153
|
-
}));
|
|
154
|
-
|
|
155
|
-
// TODO move params of initState here because it's a singleton
|
|
156
|
-
// and remove from State what doesn't need to be stored between upgrades
|
|
157
121
|
/**
|
|
158
122
|
*
|
|
159
123
|
* @param {import('@agoric/ertp').Baggage} baggage
|
|
@@ -177,115 +141,89 @@ export const prepareVaultManagerKit = (
|
|
|
177
141
|
storageNode,
|
|
178
142
|
marshaller,
|
|
179
143
|
) => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
'Vault Manager metrics',
|
|
144
|
+
assert(
|
|
145
|
+
storageNode && marshaller,
|
|
146
|
+
'VaultManager missing storageNode or marshaller',
|
|
184
147
|
);
|
|
185
|
-
|
|
148
|
+
|
|
149
|
+
const { priceAuthority, timerService } = zcf.getTerms();
|
|
150
|
+
|
|
151
|
+
const makeVault = prepareVault(baggage, marshaller, zcf);
|
|
152
|
+
const makeVaultManagerPublishKit = prepareDurablePublishKit(
|
|
186
153
|
baggage,
|
|
187
|
-
'Vault Manager
|
|
154
|
+
'Vault Manager publish kit',
|
|
155
|
+
);
|
|
156
|
+
const periodNotifier = E(timerService).makeNotifier(
|
|
157
|
+
0n,
|
|
158
|
+
factoryPowers.getGovernedParams().getChargingPeriod(),
|
|
188
159
|
);
|
|
189
160
|
|
|
190
|
-
const {
|
|
161
|
+
const { publisher: metricsPublisher, subscriber: metricsSubscriber } =
|
|
162
|
+
makeVaultManagerPublishKit();
|
|
191
163
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
'VaultManager missing storageNode or marshaller',
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
const periodNotifier = E(timerService).makeNotifier(
|
|
199
|
-
0n,
|
|
200
|
-
factoryPowers.getGovernedParams().getChargingPeriod(),
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
const debtBrand = debtMint.getIssuerRecord().brand;
|
|
204
|
-
const zeroCollateral = AmountMath.makeEmpty(collateralBrand, 'nat');
|
|
205
|
-
const zeroDebt = AmountMath.makeEmpty(debtBrand, 'nat');
|
|
206
|
-
|
|
207
|
-
const { publisher: metricsPublisher, subscriber: metricsSubscriber } =
|
|
208
|
-
makeVaultManagerMetricsPublishKit();
|
|
209
|
-
|
|
210
|
-
/** @type {PublishKit<AssetState>} */
|
|
211
|
-
const { publisher: assetPublisher, subscriber: assetSubscriber } =
|
|
212
|
-
makeVaultManagerAssetsPublishKit();
|
|
213
|
-
|
|
214
|
-
/** @type {MapStore<string, Vault>} */
|
|
215
|
-
const unsettledVaults = makeScalarBigMapStore('orderedVaultStore', {
|
|
216
|
-
durable: true,
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* If things are going well, the set will contain at most one Vault. Otherwise
|
|
221
|
-
* failures remain and are available to be repaired via contract upgrade.
|
|
222
|
-
*
|
|
223
|
-
* @type {SetStore<Vault>}
|
|
224
|
-
*/
|
|
225
|
-
const liquidatingVaults = makeScalarBigSetStore('liquidatingVaults', {
|
|
226
|
-
durable: true,
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
/** @type {ImmutableState} */
|
|
230
|
-
const fixed = {
|
|
231
|
-
collateralBrand,
|
|
232
|
-
debtBrand,
|
|
233
|
-
debtMint,
|
|
234
|
-
poolIncrementSeat: zcf.makeEmptySeatKit().zcfSeat,
|
|
235
|
-
retainedCollateralSeat: zcf.makeEmptySeatKit().zcfSeat,
|
|
236
|
-
unsettledVaults,
|
|
237
|
-
liquidatingVaults,
|
|
238
|
-
assetSubscriber,
|
|
239
|
-
assetPublisher,
|
|
240
|
-
metricsPublisher,
|
|
241
|
-
metricsSubscriber,
|
|
242
|
-
};
|
|
164
|
+
/** @type {PublishKit<AssetState>} */
|
|
165
|
+
const { publisher: assetPublisher, subscriber: assetSubscriber } =
|
|
166
|
+
makeVaultManagerPublishKit();
|
|
243
167
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const latestInterestUpdate = startTimeStamp;
|
|
168
|
+
/** @type {MapStore<string, Vault>} */
|
|
169
|
+
const unsettledVaults = provideDurableMapStore(baggage, 'orderedVaultStore');
|
|
247
170
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
171
|
+
const debtBrand = debtMint.getIssuerRecord().brand;
|
|
172
|
+
const zeroCollateral = AmountMath.makeEmpty(collateralBrand, 'nat');
|
|
173
|
+
const zeroDebt = AmountMath.makeEmpty(debtBrand, 'nat');
|
|
174
|
+
|
|
175
|
+
const storedMetricsSubscriber = makeStoredSubscriber(
|
|
176
|
+
metricsSubscriber,
|
|
177
|
+
E(storageNode).makeChildNode('metrics'),
|
|
178
|
+
marshaller,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const storedAssetSubscriber = makeStoredSubscriber(
|
|
182
|
+
assetSubscriber,
|
|
183
|
+
storageNode,
|
|
184
|
+
marshaller,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const storedQuotesNotifier = makeStoredNotifier(
|
|
188
|
+
E(priceAuthority).makeQuoteNotifier(collateralUnit, debtBrand),
|
|
189
|
+
E(storageNode).makeChildNode('quotes'),
|
|
190
|
+
marshaller,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const prioritizedVaults = makePrioritizedVaults(unsettledVaults);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* If things are going well, the set will contain at most one Vault. Otherwise
|
|
197
|
+
* failures remain and are available to be repaired via contract upgrade.
|
|
198
|
+
*
|
|
199
|
+
* @type {SetStore<Vault>}
|
|
200
|
+
*/
|
|
201
|
+
const liquidatingVaults = provideDurableSetStore(
|
|
202
|
+
baggage,
|
|
203
|
+
'liquidatingVaults',
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const poolIncrementSeat = provideEmptySeat(zcf, baggage, 'pool increment');
|
|
207
|
+
const retainedCollateralSeat = provideEmptySeat(
|
|
208
|
+
zcf,
|
|
209
|
+
baggage,
|
|
210
|
+
'retained collateral',
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// ephemeral state
|
|
214
|
+
/** @type {boolean} */
|
|
215
|
+
let liquidationQueueing = false;
|
|
216
|
+
/** @type {Promise<MutableQuote>?} */
|
|
217
|
+
let outstandingQuote = null;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* This class is a singleton kind so initState will be called only once per prepare.
|
|
221
|
+
*/
|
|
222
|
+
const initState = () => {
|
|
223
|
+
/** @type {MutableState} */
|
|
224
|
+
return {
|
|
225
|
+
compoundedInterest: makeRatio(100n, debtBrand), // starts at 1.0, no interest
|
|
226
|
+
latestInterestUpdate: startTimeStamp,
|
|
289
227
|
liquidator: undefined,
|
|
290
228
|
liquidatorInstance: undefined,
|
|
291
229
|
numLiquidationsCompleted: 0,
|
|
@@ -297,8 +235,6 @@ export const prepareVaultManagerKit = (
|
|
|
297
235
|
totalShortfallReceived: zeroDebt,
|
|
298
236
|
vaultCounter: 0,
|
|
299
237
|
};
|
|
300
|
-
|
|
301
|
-
return state;
|
|
302
238
|
};
|
|
303
239
|
|
|
304
240
|
// TODO find a way to not have to indent a level deeper than defineDurableExoClassKit does
|
|
@@ -359,24 +295,12 @@ export const prepareVaultManagerKit = (
|
|
|
359
295
|
);
|
|
360
296
|
},
|
|
361
297
|
getSubscriber() {
|
|
362
|
-
const { storedAssetSubscriber } = provideEphemera(
|
|
363
|
-
this.state.collateralBrand,
|
|
364
|
-
);
|
|
365
|
-
assert(storedAssetSubscriber);
|
|
366
298
|
return storedAssetSubscriber;
|
|
367
299
|
},
|
|
368
300
|
getMetrics() {
|
|
369
|
-
const { storedMetricsSubscriber } = provideEphemera(
|
|
370
|
-
this.state.collateralBrand,
|
|
371
|
-
);
|
|
372
|
-
assert(storedMetricsSubscriber);
|
|
373
301
|
return storedMetricsSubscriber;
|
|
374
302
|
},
|
|
375
303
|
getQuotes() {
|
|
376
|
-
const { storedQuotesNotifier } = provideEphemera(
|
|
377
|
-
this.state.collateralBrand,
|
|
378
|
-
);
|
|
379
|
-
assert(storedQuotesNotifier);
|
|
380
304
|
return storedQuotesNotifier;
|
|
381
305
|
},
|
|
382
306
|
getCompoundedInterest() {
|
|
@@ -388,11 +312,10 @@ export const prepareVaultManagerKit = (
|
|
|
388
312
|
helper: {
|
|
389
313
|
/**
|
|
390
314
|
* @param {Timestamp} updateTime
|
|
391
|
-
* @param {ZCFSeat} poolIncrementSeat
|
|
392
315
|
*/
|
|
393
|
-
async chargeAllVaults(updateTime
|
|
316
|
+
async chargeAllVaults(updateTime) {
|
|
394
317
|
const { state, facets } = this;
|
|
395
|
-
trace('chargeAllVaults',
|
|
318
|
+
trace('chargeAllVaults', collateralBrand, {
|
|
396
319
|
updateTime,
|
|
397
320
|
});
|
|
398
321
|
|
|
@@ -404,7 +327,7 @@ export const prepareVaultManagerKit = (
|
|
|
404
327
|
|
|
405
328
|
const changes = chargeInterest(
|
|
406
329
|
{
|
|
407
|
-
mint:
|
|
330
|
+
mint: debtMint,
|
|
408
331
|
mintAndReallocateWithFee: factoryPowers.mintAndReallocate,
|
|
409
332
|
poolIncrementSeat,
|
|
410
333
|
seatAllocationKeyword: 'Minted',
|
|
@@ -431,7 +354,7 @@ export const prepareVaultManagerKit = (
|
|
|
431
354
|
state.totalDebt = changes.totalDebt;
|
|
432
355
|
|
|
433
356
|
facets.helper.assetNotify();
|
|
434
|
-
trace('chargeAllVaults complete',
|
|
357
|
+
trace('chargeAllVaults complete', collateralBrand);
|
|
435
358
|
// price to check against has changed
|
|
436
359
|
return facets.helper.reschedulePriceCheck();
|
|
437
360
|
},
|
|
@@ -453,21 +376,19 @@ export const prepareVaultManagerKit = (
|
|
|
453
376
|
// that doesn't seem to be cost-effective.
|
|
454
377
|
liquidatorInstance: state.liquidatorInstance,
|
|
455
378
|
});
|
|
456
|
-
|
|
379
|
+
assetPublisher.publish(payload);
|
|
457
380
|
},
|
|
458
381
|
|
|
459
382
|
updateMetrics() {
|
|
460
383
|
const { state } = this;
|
|
461
|
-
const { prioritizedVaults } = provideEphemera(state.collateralBrand);
|
|
462
|
-
assert(prioritizedVaults);
|
|
463
384
|
|
|
464
385
|
const retainedCollateral =
|
|
465
|
-
|
|
466
|
-
AmountMath.makeEmpty(
|
|
386
|
+
retainedCollateralSeat.getCurrentAllocation()?.Collateral ??
|
|
387
|
+
AmountMath.makeEmpty(collateralBrand, 'nat');
|
|
467
388
|
/** @type {MetricsNotification} */
|
|
468
389
|
const payload = harden({
|
|
469
390
|
numActiveVaults: prioritizedVaults.getCount(),
|
|
470
|
-
numLiquidatingVaults:
|
|
391
|
+
numLiquidatingVaults: liquidatingVaults.getSize(),
|
|
471
392
|
totalCollateral: state.totalCollateral,
|
|
472
393
|
totalDebt: state.totalDebt,
|
|
473
394
|
retainedCollateral,
|
|
@@ -478,7 +399,7 @@ export const prepareVaultManagerKit = (
|
|
|
478
399
|
totalProceedsReceived: state.totalProceedsReceived,
|
|
479
400
|
totalShortfallReceived: state.totalShortfallReceived,
|
|
480
401
|
});
|
|
481
|
-
|
|
402
|
+
metricsPublisher.publish(payload);
|
|
482
403
|
},
|
|
483
404
|
|
|
484
405
|
/**
|
|
@@ -497,26 +418,24 @@ export const prepareVaultManagerKit = (
|
|
|
497
418
|
* @returns {Promise<void>}
|
|
498
419
|
*/
|
|
499
420
|
async reschedulePriceCheck(highestRatio) {
|
|
500
|
-
const {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
);
|
|
504
|
-
assert(prioritizedVaults);
|
|
505
|
-
trace('reschedulePriceCheck', state.collateralBrand, ephemera);
|
|
421
|
+
const { facets } = this;
|
|
422
|
+
trace('reschedulePriceCheck', collateralBrand, {
|
|
423
|
+
liquidationQueueing,
|
|
424
|
+
});
|
|
506
425
|
// INTERLOCK: the first time through, start the activity to wait for
|
|
507
426
|
// and process liquidations over time.
|
|
508
|
-
if (!
|
|
509
|
-
|
|
427
|
+
if (!liquidationQueueing) {
|
|
428
|
+
liquidationQueueing = true;
|
|
510
429
|
// eslint-disable-next-line consistent-return
|
|
511
430
|
return facets.helper
|
|
512
431
|
.processLiquidations()
|
|
513
432
|
.catch(e => console.error('Liquidator failed', e))
|
|
514
433
|
.finally(() => {
|
|
515
|
-
|
|
434
|
+
liquidationQueueing = false;
|
|
516
435
|
});
|
|
517
436
|
}
|
|
518
437
|
|
|
519
|
-
if (!
|
|
438
|
+
if (!outstandingQuote) {
|
|
520
439
|
// the new threshold will be picked up by the next quote request
|
|
521
440
|
return;
|
|
522
441
|
}
|
|
@@ -535,23 +454,15 @@ export const prepareVaultManagerKit = (
|
|
|
535
454
|
const govParams = factoryPowers.getGovernedParams();
|
|
536
455
|
const liquidationMargin = govParams.getLiquidationMargin();
|
|
537
456
|
// Safe to call extraneously (lightweight and idempotent)
|
|
538
|
-
updateQuote(
|
|
539
|
-
|
|
540
|
-
highestDebtRatio,
|
|
541
|
-
liquidationMargin,
|
|
542
|
-
);
|
|
543
|
-
trace('update quote', state.collateralBrand, highestDebtRatio);
|
|
457
|
+
updateQuote(outstandingQuote, highestDebtRatio, liquidationMargin);
|
|
458
|
+
trace('update quote', collateralBrand, highestDebtRatio);
|
|
544
459
|
},
|
|
545
460
|
|
|
546
461
|
async processLiquidations() {
|
|
547
|
-
const {
|
|
548
|
-
const { prioritizedVaults, ...ephemera } = provideEphemera(
|
|
549
|
-
state.collateralBrand,
|
|
550
|
-
);
|
|
462
|
+
const { facets } = this;
|
|
551
463
|
const govParams = factoryPowers.getGovernedParams();
|
|
552
464
|
|
|
553
465
|
async function* eventualLiquidations() {
|
|
554
|
-
assert(prioritizedVaults);
|
|
555
466
|
while (true) {
|
|
556
467
|
const highestDebtRatio = prioritizedVaults.highestRatio();
|
|
557
468
|
if (!highestDebtRatio) {
|
|
@@ -562,22 +473,18 @@ export const prepareVaultManagerKit = (
|
|
|
562
473
|
// ask to be alerted when the price level falls enough that the vault
|
|
563
474
|
// with the highest debt to collateral ratio will no longer be valued at the
|
|
564
475
|
// liquidationMargin above its debt.
|
|
565
|
-
|
|
476
|
+
outstandingQuote = makeQuote(
|
|
566
477
|
priceAuthority,
|
|
567
478
|
highestDebtRatio,
|
|
568
479
|
liquidationMargin,
|
|
569
480
|
);
|
|
570
|
-
trace(
|
|
571
|
-
'posted quote request',
|
|
572
|
-
state.collateralBrand,
|
|
573
|
-
highestDebtRatio,
|
|
574
|
-
);
|
|
481
|
+
trace('posted quote request', collateralBrand, highestDebtRatio);
|
|
575
482
|
|
|
576
483
|
// The rest of this method will not happen until after a quote is received.
|
|
577
484
|
// This may not happen until much later, when the market changes.
|
|
578
485
|
// eslint-disable-next-line no-await-in-loop, @jessie.js/no-nested-await -- loop/nesting to yield each unconditionally
|
|
579
|
-
const quote = await E(
|
|
580
|
-
|
|
486
|
+
const quote = await E(outstandingQuote).getPromise();
|
|
487
|
+
outstandingQuote = null;
|
|
581
488
|
// When we receive a quote, we check whether the vault with the highest
|
|
582
489
|
// ratio of debt to collateral is below the liquidationMargin, and if so,
|
|
583
490
|
// we liquidate it. We use ceilDivide to round up because ratios above
|
|
@@ -586,12 +493,7 @@ export const prepareVaultManagerKit = (
|
|
|
586
493
|
ceilDivideBy(getAmountOut(quote), liquidationMargin),
|
|
587
494
|
getAmountIn(quote),
|
|
588
495
|
);
|
|
589
|
-
trace(
|
|
590
|
-
'quote',
|
|
591
|
-
state.collateralBrand,
|
|
592
|
-
quote,
|
|
593
|
-
quoteRatioPlusMargin,
|
|
594
|
-
);
|
|
496
|
+
trace('quote', collateralBrand, quote, quoteRatioPlusMargin);
|
|
595
497
|
|
|
596
498
|
// Liquidate the head of the queue
|
|
597
499
|
const [next] =
|
|
@@ -603,7 +505,7 @@ export const prepareVaultManagerKit = (
|
|
|
603
505
|
}
|
|
604
506
|
for await (const next of eventualLiquidations()) {
|
|
605
507
|
await facets.helper.liquidateAndRemove(next);
|
|
606
|
-
trace('price check liq',
|
|
508
|
+
trace('price check liq', collateralBrand, next && next[0]);
|
|
607
509
|
}
|
|
608
510
|
},
|
|
609
511
|
|
|
@@ -612,24 +514,22 @@ export const prepareVaultManagerKit = (
|
|
|
612
514
|
*/
|
|
613
515
|
liquidateAndRemove([key, vault]) {
|
|
614
516
|
const { state, facets } = this;
|
|
615
|
-
const { prioritizedVaults } = provideEphemera(state.collateralBrand);
|
|
616
|
-
assert(factoryPowers && prioritizedVaults && zcf);
|
|
617
517
|
const vaultSeat = vault.getVaultSeat();
|
|
618
|
-
trace('liquidating',
|
|
518
|
+
trace('liquidating', collateralBrand, vaultSeat.getProposal());
|
|
619
519
|
|
|
620
520
|
const collateralPre = vault.getCollateralAmount();
|
|
621
521
|
|
|
622
522
|
// Start liquidation (vaultState: LIQUIDATING)
|
|
623
523
|
const liquidator = state.liquidator;
|
|
624
524
|
assert(liquidator);
|
|
625
|
-
|
|
525
|
+
liquidatingVaults.add(vault);
|
|
626
526
|
prioritizedVaults.removeVault(key);
|
|
627
527
|
|
|
628
528
|
return liquidate(
|
|
629
529
|
zcf,
|
|
630
530
|
vault,
|
|
631
531
|
liquidator,
|
|
632
|
-
|
|
532
|
+
collateralBrand,
|
|
633
533
|
factoryPowers.getGovernedParams().getLiquidationPenalty(),
|
|
634
534
|
)
|
|
635
535
|
.then(accounting => {
|
|
@@ -650,7 +550,7 @@ export const prepareVaultManagerKit = (
|
|
|
650
550
|
// it. We could hold it until it crosses some threshold, then sell it
|
|
651
551
|
// to the AMM, or we could transfer it to the reserve. At least it's
|
|
652
552
|
// visible in the accounting.
|
|
653
|
-
atomicTransfer(zcf, vaultSeat,
|
|
553
|
+
atomicTransfer(zcf, vaultSeat, retainedCollateralSeat, {
|
|
654
554
|
Collateral: collateralPost,
|
|
655
555
|
});
|
|
656
556
|
}
|
|
@@ -679,8 +579,8 @@ export const prepareVaultManagerKit = (
|
|
|
679
579
|
state.totalShortfallReceived,
|
|
680
580
|
accounting.shortfall,
|
|
681
581
|
);
|
|
682
|
-
|
|
683
|
-
trace('liquidated',
|
|
582
|
+
liquidatingVaults.delete(vault);
|
|
583
|
+
trace('liquidated', collateralBrand);
|
|
684
584
|
state.numLiquidationsCompleted += 1;
|
|
685
585
|
facets.helper.updateMetrics();
|
|
686
586
|
|
|
@@ -712,8 +612,6 @@ export const prepareVaultManagerKit = (
|
|
|
712
612
|
*/
|
|
713
613
|
async maxDebtFor(collateralAmount) {
|
|
714
614
|
trace('maxDebtFor', collateralAmount);
|
|
715
|
-
const { state } = this;
|
|
716
|
-
const { debtBrand } = state;
|
|
717
615
|
assert(factoryPowers && priceAuthority);
|
|
718
616
|
const quoteAmount = await E(priceAuthority).quoteGiven(
|
|
719
617
|
collateralAmount,
|
|
@@ -754,7 +652,7 @@ export const prepareVaultManagerKit = (
|
|
|
754
652
|
*/
|
|
755
653
|
burnAndRecord(toBurn, seat) {
|
|
756
654
|
const { state } = this;
|
|
757
|
-
trace('burnAndRecord',
|
|
655
|
+
trace('burnAndRecord', collateralBrand, {
|
|
758
656
|
toBurn,
|
|
759
657
|
totalDebt: state.totalDebt,
|
|
760
658
|
});
|
|
@@ -763,17 +661,13 @@ export const prepareVaultManagerKit = (
|
|
|
763
661
|
state.totalDebt = AmountMath.subtract(state.totalDebt, toBurn);
|
|
764
662
|
},
|
|
765
663
|
getAssetSubscriber() {
|
|
766
|
-
const { storedAssetSubscriber } = provideEphemera(
|
|
767
|
-
this.state.collateralBrand,
|
|
768
|
-
);
|
|
769
|
-
assert(storedAssetSubscriber);
|
|
770
664
|
return storedAssetSubscriber;
|
|
771
665
|
},
|
|
772
666
|
getCollateralBrand() {
|
|
773
|
-
return
|
|
667
|
+
return collateralBrand;
|
|
774
668
|
},
|
|
775
669
|
getDebtBrand() {
|
|
776
|
-
return
|
|
670
|
+
return debtBrand;
|
|
777
671
|
},
|
|
778
672
|
/**
|
|
779
673
|
* coefficient on existing debt to calculate new debt
|
|
@@ -798,8 +692,6 @@ export const prepareVaultManagerKit = (
|
|
|
798
692
|
vault,
|
|
799
693
|
) {
|
|
800
694
|
const { state, facets } = this;
|
|
801
|
-
const { prioritizedVaults } = provideEphemera(state.collateralBrand);
|
|
802
|
-
assert(prioritizedVaults);
|
|
803
695
|
|
|
804
696
|
// the manager holds only vaults that can accrue interest or be liquidated;
|
|
805
697
|
// i.e. vaults that have debt. The one exception is at the outset when
|
|
@@ -863,11 +755,8 @@ export const prepareVaultManagerKit = (
|
|
|
863
755
|
*/
|
|
864
756
|
async liquidateAll() {
|
|
865
757
|
const {
|
|
866
|
-
state,
|
|
867
758
|
facets: { helper },
|
|
868
759
|
} = this;
|
|
869
|
-
const { prioritizedVaults } = provideEphemera(state.collateralBrand);
|
|
870
|
-
assert(prioritizedVaults);
|
|
871
760
|
const toLiquidate = Array.from(prioritizedVaults.entries()).map(
|
|
872
761
|
entry => helper.liquidateAndRemove(entry),
|
|
873
762
|
);
|
|
@@ -883,9 +772,7 @@ export const prepareVaultManagerKit = (
|
|
|
883
772
|
state,
|
|
884
773
|
facets: { manager },
|
|
885
774
|
} = this;
|
|
886
|
-
const { prioritizedVaults } = provideEphemera(state.collateralBrand);
|
|
887
775
|
assert(marshaller, 'makeVaultKit missing marshaller');
|
|
888
|
-
assert(prioritizedVaults, 'makeVaultKit missing prioritizedVaults');
|
|
889
776
|
assert(storageNode, 'makeVaultKit missing storageNode');
|
|
890
777
|
assert(zcf, 'makeVaultKit missing zcf');
|
|
891
778
|
assertProposalShape(seat, {
|
|
@@ -898,17 +785,12 @@ export const prepareVaultManagerKit = (
|
|
|
898
785
|
state.vaultCounter += 1;
|
|
899
786
|
const vaultId = String(state.vaultCounter);
|
|
900
787
|
|
|
901
|
-
|
|
788
|
+
// must be a presence to be stored in vault state
|
|
789
|
+
const vaultStorageNode = await E(
|
|
902
790
|
E(storageNode).makeChildNode(`vaults`),
|
|
903
791
|
).makeChildNode(`vault${vaultId}`);
|
|
904
792
|
|
|
905
|
-
const { self: vault } = makeVault(
|
|
906
|
-
zcf,
|
|
907
|
-
manager,
|
|
908
|
-
vaultId,
|
|
909
|
-
vaultStorageNode,
|
|
910
|
-
marshaller,
|
|
911
|
-
);
|
|
793
|
+
const { self: vault } = makeVault(manager, vaultId, vaultStorageNode);
|
|
912
794
|
trace('makevaultKit made vault', vault);
|
|
913
795
|
|
|
914
796
|
try {
|
|
@@ -927,7 +809,7 @@ export const prepareVaultManagerKit = (
|
|
|
927
809
|
// remove it from the store if it got in
|
|
928
810
|
/** @type {NormalizedDebt} */
|
|
929
811
|
// @ts-expect-error cast
|
|
930
|
-
const normalizedDebt = AmountMath.makeEmpty(
|
|
812
|
+
const normalizedDebt = AmountMath.makeEmpty(debtBrand);
|
|
931
813
|
const collateralPre = seat.getCurrentAllocation().Collateral;
|
|
932
814
|
try {
|
|
933
815
|
prioritizedVaults.removeVaultByAttributes(
|
|
@@ -958,12 +840,11 @@ export const prepareVaultManagerKit = (
|
|
|
958
840
|
*/
|
|
959
841
|
async setupLiquidator(liquidationInstall, liquidationTerms) {
|
|
960
842
|
const { state, facets } = this;
|
|
961
|
-
const { debtBrand } = state;
|
|
962
843
|
const { ammPublicFacet, reservePublicFacet } = zcf.getTerms();
|
|
963
844
|
const zoe = zcf.getZoeService();
|
|
964
845
|
const collateralIssuer = zcf.getIssuerForBrand(collateralBrand);
|
|
965
846
|
const debtIssuer = zcf.getIssuerForBrand(debtBrand);
|
|
966
|
-
trace('setup liquidator',
|
|
847
|
+
trace('setup liquidator', collateralBrand, {
|
|
967
848
|
debtBrand,
|
|
968
849
|
debtIssuer,
|
|
969
850
|
collateralBrand,
|
|
@@ -981,7 +862,7 @@ export const prepareVaultManagerKit = (
|
|
|
981
862
|
timerService,
|
|
982
863
|
}),
|
|
983
864
|
);
|
|
984
|
-
trace('setup liquidator complete',
|
|
865
|
+
trace('setup liquidator complete', collateralBrand, {
|
|
985
866
|
instance,
|
|
986
867
|
old: state.liquidatorInstance,
|
|
987
868
|
equal: state.liquidatorInstance === instance,
|
|
@@ -992,9 +873,6 @@ export const prepareVaultManagerKit = (
|
|
|
992
873
|
},
|
|
993
874
|
|
|
994
875
|
async getCollateralQuote() {
|
|
995
|
-
const { state } = this;
|
|
996
|
-
|
|
997
|
-
const { debtBrand } = state;
|
|
998
876
|
// get a quote for one unit of the collateral
|
|
999
877
|
return E(priceAuthority).quoteGiven(collateralUnit, debtBrand);
|
|
1000
878
|
},
|
|
@@ -1005,26 +883,24 @@ export const prepareVaultManagerKit = (
|
|
|
1005
883
|
},
|
|
1006
884
|
},
|
|
1007
885
|
{
|
|
1008
|
-
|
|
1009
|
-
finish: context => {
|
|
1010
|
-
const {
|
|
1011
|
-
state,
|
|
1012
|
-
facets: { helper },
|
|
1013
|
-
} = context;
|
|
1014
|
-
const { periodNotifier, prioritizedVaults } = provideEphemera(
|
|
1015
|
-
state.collateralBrand,
|
|
1016
|
-
);
|
|
1017
|
-
assert(periodNotifier && prioritizedVaults && zcf);
|
|
1018
|
-
|
|
886
|
+
finish: ({ state, facets: { helper } }) => {
|
|
1019
887
|
prioritizedVaults.onHigherHighest(() => helper.reschedulePriceCheck());
|
|
1020
888
|
|
|
889
|
+
assetPublisher.publish(
|
|
890
|
+
harden({
|
|
891
|
+
compoundedInterest: state.compoundedInterest,
|
|
892
|
+
interestRate: factoryPowers.getGovernedParams().getInterestRate(),
|
|
893
|
+
latestInterestUpdate: state.latestInterestUpdate,
|
|
894
|
+
}),
|
|
895
|
+
);
|
|
896
|
+
|
|
1021
897
|
// push initial state of metrics
|
|
1022
898
|
helper.updateMetrics();
|
|
1023
899
|
|
|
1024
900
|
void observeNotifier(periodNotifier, {
|
|
1025
901
|
updateState: updateTime =>
|
|
1026
902
|
helper
|
|
1027
|
-
.chargeAllVaults(updateTime
|
|
903
|
+
.chargeAllVaults(updateTime)
|
|
1028
904
|
.catch(e =>
|
|
1029
905
|
console.error('🚨 vaultManager failed to charge interest', e),
|
|
1030
906
|
),
|