@agoric/inter-protocol 0.16.2-other-dev-8f8782b.0 → 0.16.2-other-dev-fbe72e7.0.fbe72e7

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.
Files changed (166) hide show
  1. package/README.md +6 -6
  2. package/package.json +46 -39
  3. package/scripts/build-bundles.js +5 -21
  4. package/src/auction/auctionBook.d.ts +147 -0
  5. package/src/auction/auctionBook.d.ts.map +1 -0
  6. package/src/auction/auctionBook.js +182 -151
  7. package/src/auction/auctionMath.d.ts +17 -0
  8. package/src/auction/auctionMath.d.ts.map +1 -0
  9. package/src/auction/auctionMath.js +81 -0
  10. package/src/auction/auctioneer.d.ts +70 -0
  11. package/src/auction/auctioneer.d.ts.map +1 -0
  12. package/src/auction/auctioneer.js +72 -59
  13. package/src/auction/offerBook.d.ts +46 -0
  14. package/src/auction/offerBook.d.ts.map +1 -0
  15. package/src/auction/offerBook.js +17 -12
  16. package/src/auction/params.d.ts +145 -0
  17. package/src/auction/params.d.ts.map +1 -0
  18. package/src/auction/params.js +11 -9
  19. package/src/auction/scheduleMath.d.ts +5 -0
  20. package/src/auction/scheduleMath.d.ts.map +1 -0
  21. package/src/auction/scheduleMath.js +18 -16
  22. package/src/auction/scheduler.d.ts +50 -0
  23. package/src/auction/scheduler.d.ts.map +1 -0
  24. package/src/auction/scheduler.js +53 -47
  25. package/src/auction/sortedOffers.d.ts +8 -0
  26. package/src/auction/sortedOffers.d.ts.map +1 -0
  27. package/src/auction/sortedOffers.js +10 -9
  28. package/src/auction/util.d.ts +31 -0
  29. package/src/auction/util.d.ts.map +1 -0
  30. package/src/auction/util.js +12 -6
  31. package/src/clientSupport.d.ts +168 -0
  32. package/src/clientSupport.d.ts.map +1 -0
  33. package/src/clientSupport.js +161 -98
  34. package/src/collectFees.d.ts +2 -0
  35. package/src/collectFees.d.ts.map +1 -0
  36. package/src/contractSupport.d.ts +28 -0
  37. package/src/contractSupport.d.ts.map +1 -0
  38. package/src/contractSupport.js +19 -13
  39. package/src/econCommitteeCharter.d.ts +43 -0
  40. package/src/econCommitteeCharter.d.ts.map +1 -0
  41. package/src/econCommitteeCharter.js +25 -20
  42. package/src/feeDistributor.d.ts +224 -0
  43. package/src/feeDistributor.d.ts.map +1 -0
  44. package/src/feeDistributor.js +41 -33
  45. package/src/index.d.ts +2 -0
  46. package/src/index.d.ts.map +1 -0
  47. package/src/index.js +1 -0
  48. package/src/interest-math.d.ts +4 -0
  49. package/src/interest-math.d.ts.map +1 -0
  50. package/src/interest-math.js +5 -1
  51. package/src/interest.d.ts +30 -0
  52. package/src/interest.d.ts.map +1 -0
  53. package/src/interest.js +25 -23
  54. package/src/price/README.md +14 -1
  55. package/src/price/fluxAggregatorContract.d.ts +71 -0
  56. package/src/price/fluxAggregatorContract.d.ts.map +1 -0
  57. package/src/price/fluxAggregatorContract.js +64 -55
  58. package/src/price/fluxAggregatorKit.d.ts +104 -0
  59. package/src/price/fluxAggregatorKit.d.ts.map +1 -0
  60. package/src/price/fluxAggregatorKit.js +55 -42
  61. package/src/price/priceOracleKit.d.ts +39 -0
  62. package/src/price/priceOracleKit.d.ts.map +1 -0
  63. package/src/price/priceOracleKit.js +17 -15
  64. package/src/price/roundsManager.d.ts +204 -0
  65. package/src/price/roundsManager.d.ts.map +1 -0
  66. package/src/price/roundsManager.js +132 -85
  67. package/src/proposals/README.md +2 -3
  68. package/src/proposals/add-auction.js +285 -0
  69. package/src/proposals/addAssetToVault.js +192 -40
  70. package/src/proposals/committee-proposal.js +25 -31
  71. package/src/proposals/core-proposal.js +9 -11
  72. package/src/proposals/deploy-price-feeds.js +341 -0
  73. package/src/proposals/econ-behaviors.js +84 -49
  74. package/src/proposals/price-feed-proposal.js +109 -51
  75. package/src/proposals/replace-fee-distributor.js +198 -0
  76. package/src/proposals/replace-scaledPriceAuthorities.js +124 -0
  77. package/src/proposals/replaceElectorate.js +610 -0
  78. package/src/proposals/startEconCommittee.js +2 -2
  79. package/src/proposals/startPSM.js +44 -29
  80. package/src/proposals/upgrade-scaledPriceAuthorities.js +78 -0
  81. package/src/proposals/upgrade-vaults.js +207 -0
  82. package/src/proposals/utils.d.ts +21 -0
  83. package/src/proposals/utils.d.ts.map +1 -0
  84. package/src/proposals/utils.js +66 -9
  85. package/src/proposals/withdraw-reserve-proposal.js +63 -0
  86. package/src/provisionPool.d.ts +69 -0
  87. package/src/provisionPool.d.ts.map +1 -0
  88. package/src/provisionPool.js +138 -0
  89. package/src/provisionPoolKit.d.ts +129 -0
  90. package/src/provisionPoolKit.d.ts.map +1 -0
  91. package/src/provisionPoolKit.js +608 -0
  92. package/src/psm/psm.d.ts +133 -0
  93. package/src/psm/psm.d.ts.map +1 -0
  94. package/src/psm/psm.js +85 -79
  95. package/src/psm/types-ambient.d.ts +2 -0
  96. package/src/psm/types-ambient.d.ts.map +1 -0
  97. package/src/psm/types-ambient.js +3 -0
  98. package/src/reserve/assetReserve.d.ts +58 -0
  99. package/src/reserve/assetReserve.d.ts.map +1 -0
  100. package/src/reserve/assetReserve.js +42 -34
  101. package/src/reserve/assetReserveKit.d.ts +103 -0
  102. package/src/reserve/assetReserveKit.d.ts.map +1 -0
  103. package/src/reserve/assetReserveKit.js +134 -32
  104. package/src/reserve/params.d.ts +16 -0
  105. package/src/reserve/params.d.ts.map +1 -0
  106. package/src/reserve/params.js +8 -2
  107. package/src/tokens.d.ts +3 -0
  108. package/src/tokens.d.ts.map +1 -0
  109. package/src/tokens.js +5 -0
  110. package/src/vaultFactory/burn.d.ts +2 -0
  111. package/src/vaultFactory/burn.d.ts.map +1 -0
  112. package/src/vaultFactory/burn.js +1 -1
  113. package/src/vaultFactory/liquidation.d.ts +25 -0
  114. package/src/vaultFactory/liquidation.d.ts.map +1 -0
  115. package/src/vaultFactory/liquidation.js +37 -24
  116. package/src/vaultFactory/math.d.ts +11 -0
  117. package/src/vaultFactory/math.d.ts.map +1 -0
  118. package/src/vaultFactory/math.js +11 -10
  119. package/src/vaultFactory/orderedVaultStore.d.ts +94 -0
  120. package/src/vaultFactory/orderedVaultStore.d.ts.map +1 -0
  121. package/src/vaultFactory/orderedVaultStore.js +9 -10
  122. package/src/vaultFactory/params.d.ts +143 -0
  123. package/src/vaultFactory/params.d.ts.map +1 -0
  124. package/src/vaultFactory/params.js +56 -25
  125. package/src/vaultFactory/prioritizedVaults.d.ts +280 -0
  126. package/src/vaultFactory/prioritizedVaults.d.ts.map +1 -0
  127. package/src/vaultFactory/prioritizedVaults.js +7 -4
  128. package/src/vaultFactory/proceeds.d.ts +35 -0
  129. package/src/vaultFactory/proceeds.d.ts.map +1 -0
  130. package/src/vaultFactory/proceeds.js +26 -18
  131. package/src/vaultFactory/storeUtils.d.ts +25 -0
  132. package/src/vaultFactory/storeUtils.d.ts.map +1 -0
  133. package/src/vaultFactory/storeUtils.js +10 -12
  134. package/src/vaultFactory/types-ambient.d.ts +137 -0
  135. package/src/vaultFactory/types-ambient.d.ts.map +1 -0
  136. package/src/vaultFactory/{types.js → types-ambient.js} +47 -44
  137. package/src/vaultFactory/vault.d.ts +344 -0
  138. package/src/vaultFactory/vault.d.ts.map +1 -0
  139. package/src/vaultFactory/vault.js +107 -100
  140. package/src/vaultFactory/vaultDirector.d.ts +347 -0
  141. package/src/vaultFactory/vaultDirector.d.ts.map +1 -0
  142. package/src/vaultFactory/vaultDirector.js +94 -64
  143. package/src/vaultFactory/vaultFactory.d.ts +250 -0
  144. package/src/vaultFactory/vaultFactory.d.ts.map +1 -0
  145. package/src/vaultFactory/vaultFactory.js +56 -33
  146. package/src/vaultFactory/vaultHolder.d.ts +170 -0
  147. package/src/vaultFactory/vaultHolder.d.ts.map +1 -0
  148. package/src/vaultFactory/vaultHolder.js +14 -15
  149. package/src/vaultFactory/vaultKit.d.ts +33 -0
  150. package/src/vaultFactory/vaultKit.d.ts.map +1 -0
  151. package/src/vaultFactory/vaultKit.js +9 -4
  152. package/src/vaultFactory/vaultManager.d.ts +676 -0
  153. package/src/vaultFactory/vaultManager.d.ts.map +1 -0
  154. package/src/vaultFactory/vaultManager.js +286 -167
  155. package/CHANGELOG.md +0 -1041
  156. package/exported.js +0 -2
  157. package/scripts/add-collateral-core.js +0 -112
  158. package/scripts/deploy-contracts.js +0 -100
  159. package/scripts/init-core.js +0 -198
  160. package/scripts/invite-committee-core.js +0 -42
  161. package/scripts/manual-price-feed.js +0 -117
  162. package/scripts/price-feed-core.js +0 -104
  163. package/scripts/start-local-chain.sh +0 -84
  164. package/src/psm/types.js +0 -3
  165. package/src/typeGuards.js +0 -13
  166. package/src/vaultFactory/type-imports.js +0 -4
@@ -1,22 +1,25 @@
1
- /* eslint-disable consistent-return */
2
1
  /**
3
2
  * @file Vault Manager object manages vault-based debts for a collateral type.
4
3
  *
5
- * The responsibilities include:
6
- * - opening a new vault backed by the collateral
7
- * - publishing metrics on the vault economy for that collateral
8
- * - charging interest on all active vaults
9
- * - liquidating active vaults that have exceeded the debt ratio
4
+ * The responsibilities include:
10
5
  *
11
- * Once a vault is settled (liquidated or closed) it can still be used, traded,
12
- * etc. but is no longer the concern of the manager. It can't be liquidated,
13
- * have interest charged, or be counted in the metrics.
6
+ * - opening a new vault backed by the collateral
7
+ * - publishing metrics on the vault economy for that collateral
8
+ * - charging interest on all active vaults
9
+ * - liquidating active vaults that have exceeded the debt ratio
14
10
  *
15
- * Undercollateralized vaults can have their assets sent to the auctioneer to be
16
- * liquidated. If the auction is unsuccessful, the liquidation may be reverted.
11
+ * Once a vault is settled (liquidated or closed) it can still be used, traded,
12
+ * etc. but is no longer the concern of the manager. It can't be liquidated,
13
+ * have interest charged, or be counted in the metrics.
14
+ *
15
+ * Undercollateralized vaults can have their assets sent to the auctioneer to be
16
+ * liquidated. If the auction is unsuccessful, the liquidation may be
17
+ * reverted.
17
18
  */
18
- import '@agoric/zoe/exported.js';
19
+ /// <reference types="@agoric/zoe/exported" />
19
20
 
21
+ import { X, Fail, q, makeError } from '@endo/errors';
22
+ import { E } from '@endo/eventual-send';
20
23
  import {
21
24
  AmountMath,
22
25
  AmountShape,
@@ -36,7 +39,6 @@ import {
36
39
  } from '@agoric/vat-data';
37
40
  import { TransferPartShape } from '@agoric/zoe/src/contractSupport/atomicTransfer.js';
38
41
  import {
39
- atomicRearrange,
40
42
  ceilMultiplyBy,
41
43
  floorDivideBy,
42
44
  getAmountIn,
@@ -49,8 +51,7 @@ import {
49
51
  TopicsRecordShape,
50
52
  } from '@agoric/zoe/src/contractSupport/index.js';
51
53
  import { PriceQuoteShape, SeatShape } from '@agoric/zoe/src/typeGuards.js';
52
- import { E } from '@endo/eventual-send';
53
- import { AuctionPFShape } from '../auction/auctioneer.js';
54
+ import { multiplyBy } from '@agoric/ertp/src/ratio.js';
54
55
  import {
55
56
  checkDebtLimit,
56
57
  makeNatAmountShape,
@@ -62,117 +63,165 @@ import { calculateMinimumCollateralization, minimumPrice } from './math.js';
62
63
  import { makePrioritizedVaults } from './prioritizedVaults.js';
63
64
  import { Phase, prepareVault } from './vault.js';
64
65
  import { calculateDistributionPlan } from './proceeds.js';
66
+ import { AuctionPFShape } from '../auction/auctioneer.js';
65
67
 
66
- const { details: X, Fail, quote: q } = assert;
68
+ /**
69
+ * @import {MapStore, SetStore} from '@agoric/store';
70
+ * @import {EReturn} from '@endo/far';
71
+ * @import {ZCFMint} from '@agoric/zoe';
72
+ * @import {PriceQuote} from '@agoric/zoe/tools/types.js';
73
+ */
67
74
 
68
75
  const trace = makeTracer('VM');
69
76
 
70
- /** @typedef {import('./storeUtils.js').NormalizedDebt} NormalizedDebt */
71
- /** @typedef {import('@agoric/time/src/types').RelativeTime} RelativeTime */
77
+ /**
78
+ * Watch a notifier that isn't expected to fail or finish unless the vat hosting
79
+ * the notifier is upgraded. This watcher supports that by providing a
80
+ * straightforward way to get a replacement if the notifier breaks.
81
+ *
82
+ * @template T notifier topic
83
+ * @template {any[]} [A=unknown[]] arbitrary arguments
84
+ * @param {ERef<LatestTopic<T>>} notifierP
85
+ * @param {import('@agoric/swingset-liveslots').PromiseWatcher<T, A>} watcher
86
+ * @param {A} args
87
+ */
88
+ export const watchQuoteNotifier = async (notifierP, watcher, ...args) => {
89
+ await undefined;
90
+
91
+ let updateCount;
92
+ for (;;) {
93
+ let value;
94
+ try {
95
+ ({ value, updateCount } = await E(notifierP).getUpdateSince(updateCount));
96
+ watcher.onFulfilled && watcher.onFulfilled(value, ...args);
97
+ } catch (e) {
98
+ watcher.onRejected && watcher.onRejected(e, ...args);
99
+ break;
100
+ }
101
+ if (updateCount === undefined) {
102
+ watcher.onRejected &&
103
+ watcher.onRejected(Error('stream finished'), ...args);
104
+ break;
105
+ }
106
+ }
107
+ };
108
+
109
+ /** @import {NormalizedDebt} from './storeUtils.js' */
110
+ /** @import {RelativeTime} from '@agoric/time' */
72
111
 
73
112
  // Metrics naming scheme: nouns are present values; past-participles are accumulative.
74
113
  /**
75
114
  * @typedef {object} MetricsNotification
76
- *
77
- * @property {Ratio | null} lockedQuote priceQuote that will be used for liquidation.
78
- * Non-null from priceLock time until liquidation has taken place.
79
- * @property {number} numActiveVaults present count of vaults
80
- * @property {number} numLiquidatingVaults present count of liquidating vaults
81
- * @property {Amount<'nat'>} totalCollateral present sum of collateral across all vaults
82
- * @property {Amount<'nat'>} totalDebt present sum of debt across all vaults
83
- * @property {Amount<'nat'>} retainedCollateral collateral held as a result of not returning excess refunds
84
- * to owners of vaults liquidated with shortfalls
85
- * @property {Amount<'nat'>} liquidatingCollateral present sum of collateral in vaults sent for liquidation
86
- * @property {Amount<'nat'>} liquidatingDebt present sum of debt in vaults sent for liquidation
87
- *
88
- * @property {Amount<'nat'>} totalCollateralSold running sum of collateral sold in liquidation
89
- * @property {Amount<'nat'>} totalOverageReceived running sum of overages, central received greater than debt
90
- * @property {Amount<'nat'>} totalProceedsReceived running sum of minted received from liquidation
91
- * @property {Amount<'nat'>} totalShortfallReceived running sum of shortfalls, minted received less than debt
92
- * @property {number} numLiquidationsCompleted running count of liquidated vaults
93
- * @property {number} numLiquidationsAborted running count of vault liquidations that were reverted.
115
+ * @property {Ratio | null} lockedQuote priceQuote that will be used for
116
+ * liquidation. Non-null from priceLock time until liquidation has taken
117
+ * place.
118
+ * @property {number} numActiveVaults present count of vaults
119
+ * @property {number} numLiquidatingVaults present count of liquidating vaults
120
+ * @property {Amount<'nat'>} totalCollateral present sum of collateral across
121
+ * all vaults
122
+ * @property {Amount<'nat'>} totalDebt present sum of debt across all vaults
123
+ * @property {Amount<'nat'>} retainedCollateral collateral held as a result of
124
+ * not returning excess refunds to owners of vaults liquidated with
125
+ * shortfalls
126
+ * @property {Amount<'nat'>} liquidatingCollateral present sum of collateral in
127
+ * vaults sent for liquidation
128
+ * @property {Amount<'nat'>} liquidatingDebt present sum of debt in vaults sent
129
+ * for liquidation
130
+ * @property {Amount<'nat'>} totalCollateralSold running sum of collateral sold
131
+ * in liquidation
132
+ * @property {Amount<'nat'>} totalOverageReceived running sum of overages,
133
+ * central received greater than debt
134
+ * @property {Amount<'nat'>} totalProceedsReceived running sum of minted
135
+ * received from liquidation
136
+ * @property {Amount<'nat'>} totalShortfallReceived running sum of shortfalls,
137
+ * minted received less than debt
138
+ * @property {number} numLiquidationsCompleted running count of liquidated
139
+ * vaults
140
+ * @property {number} numLiquidationsAborted running count of vault liquidations
141
+ * that were reverted.
94
142
  */
95
143
 
96
144
  /**
97
145
  * @typedef {{
98
- * compoundedInterest: Ratio,
99
- * interestRate: Ratio,
100
- * latestInterestUpdate: Timestamp,
146
+ * compoundedInterest: Ratio;
147
+ * interestRate: Ratio;
148
+ * latestInterestUpdate: Timestamp;
101
149
  * }} AssetState
102
150
  *
151
+ *
103
152
  * @typedef {{
104
- * getChargingPeriod: () => RelativeTime,
105
- * getRecordingPeriod: () => RelativeTime,
106
- * getDebtLimit: () => Amount<'nat'>,
107
- * getInterestRate: () => Ratio,
108
- * getLiquidationPadding: () => Ratio,
109
- * getLiquidationMargin: () => Ratio,
110
- * getLiquidationPenalty: () => Ratio,
111
- * getMintFee: () => Ratio,
112
- * getMinInitialDebt: () => Amount<'nat'>,
153
+ * getChargingPeriod: () => RelativeTime;
154
+ * getRecordingPeriod: () => RelativeTime;
155
+ * getDebtLimit: () => Amount<'nat'>;
156
+ * getInterestRate: () => Ratio;
157
+ * getLiquidationPadding: () => Ratio;
158
+ * getLiquidationMargin: () => Ratio;
159
+ * getLiquidationPenalty: () => Ratio;
160
+ * getMintFee: () => Ratio;
161
+ * getMinInitialDebt: () => Amount<'nat'>;
113
162
  * }} GovernedParamGetters
114
163
  */
115
164
 
116
165
  /**
117
166
  * @typedef {Readonly<{
118
- * debtMint: ZCFMint<'nat'>,
119
- * collateralBrand: Brand<'nat'>,
120
- * collateralUnit: Amount<'nat'>,
121
- * descriptionScope: string,
122
- * startTimeStamp: Timestamp,
123
- * storageNode: StorageNode,
167
+ * debtMint: ZCFMint<'nat'>;
168
+ * collateralBrand: Brand<'nat'>;
169
+ * collateralUnit: Amount<'nat'>;
170
+ * descriptionScope: string;
171
+ * startTimeStamp: Timestamp;
172
+ * storageNode: StorageNode;
124
173
  * }>} HeldParams
125
174
  */
126
175
 
127
176
  /**
128
177
  * @typedef {{
129
- * assetTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<AssetState>,
130
- * debtBrand: Brand<'nat'>,
131
- * liquidatingVaults: SetStore<Vault>,
132
- * metricsTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<MetricsNotification>,
133
- * poolIncrementSeat: ZCFSeat,
134
- * retainedCollateralSeat: ZCFSeat,
135
- * unsettledVaults: MapStore<string, Vault>,
178
+ * assetTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<AssetState>;
179
+ * debtBrand: Brand<'nat'>;
180
+ * liquidatingVaults: SetStore<Vault>;
181
+ * metricsTopicKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<MetricsNotification>;
182
+ * poolIncrementSeat: ZCFSeat;
183
+ * retainedCollateralSeat: ZCFSeat;
184
+ * unsettledVaults: MapStore<string, Vault>;
136
185
  * }} ImmutableState
137
186
  */
138
187
 
139
188
  /**
140
189
  * @typedef {{
141
- * compoundedInterest: Ratio,
142
- * latestInterestUpdate: Timestamp,
143
- * numLiquidationsCompleted: number,
144
- * numLiquidationsAborted: number,
145
- * totalCollateral: Amount<'nat'>,
146
- * totalCollateralSold: Amount<'nat'>,
147
- * totalDebt: Amount<'nat'>,
148
- * liquidatingCollateral: Amount<'nat'>,
149
- * liquidatingDebt: Amount<'nat'>,
150
- * totalOverageReceived: Amount<'nat'>,
151
- * totalProceedsReceived: Amount<'nat'>,
152
- * totalShortfallReceived: Amount<'nat'>,
153
- * vaultCounter: number,
154
- * lockedQuote: PriceQuote | undefined,
190
+ * compoundedInterest: Ratio;
191
+ * latestInterestUpdate: Timestamp;
192
+ * numLiquidationsCompleted: number;
193
+ * numLiquidationsAborted: number;
194
+ * totalCollateral: Amount<'nat'>;
195
+ * totalCollateralSold: Amount<'nat'>;
196
+ * totalDebt: Amount<'nat'>;
197
+ * liquidatingCollateral: Amount<'nat'>;
198
+ * liquidatingDebt: Amount<'nat'>;
199
+ * totalOverageReceived: Amount<'nat'>;
200
+ * totalProceedsReceived: Amount<'nat'>;
201
+ * totalShortfallReceived: Amount<'nat'>;
202
+ * vaultCounter: number;
203
+ * lockedQuote: PriceQuote | undefined;
155
204
  * }} MutableState
156
205
  */
157
206
 
158
207
  /**
159
208
  * @type {(brand: Brand) => {
160
- * prioritizedVaults: ReturnType<typeof makePrioritizedVaults>,
161
- * storedQuotesNotifier: import('@agoric/notifier').StoredNotifier<PriceQuote>,
162
- * storedCollateralQuote: PriceQuote,
209
+ * prioritizedVaults: ReturnType<typeof makePrioritizedVaults>;
210
+ * storedQuotesNotifier: import('@agoric/notifier').StoredNotifier<PriceQuote>;
211
+ * storedCollateralQuote: PriceQuote | null;
163
212
  * }}
164
213
  */
165
214
  // any b/c will be filled after start()
166
215
  const collateralEphemera = makeEphemeraProvider(() => /** @type {any} */ ({}));
167
216
 
168
217
  /**
169
- * @param {import('@agoric/ertp').Baggage} baggage
218
+ * @param {import('@agoric/swingset-liveslots').Baggage} baggage
170
219
  * @param {{
171
- * zcf: import('./vaultFactory.js').VaultFactoryZCF,
172
- * marshaller: ERef<Marshaller>,
173
- * makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit,
174
- * makeERecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeERecorderKit,
175
- * factoryPowers: import('./vaultDirector.js').FactoryPowersFacet,
220
+ * zcf: import('./vaultFactory.js').VaultFactoryZCF;
221
+ * marshaller: ERef<Marshaller>;
222
+ * makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit;
223
+ * makeERecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeERecorderKit;
224
+ * factoryPowers: import('./vaultDirector.js').FactoryPowersFacet;
176
225
  * }} powers
177
226
  */
178
227
  export const prepareVaultManagerKit = (
@@ -180,6 +229,7 @@ export const prepareVaultManagerKit = (
180
229
  { zcf, marshaller, makeRecorderKit, factoryPowers },
181
230
  ) => {
182
231
  const { priceAuthority, timerService, reservePublicFacet } = zcf.getTerms();
232
+ const watchedBrands = new Set();
183
233
 
184
234
  const makeVault = prepareVault(baggage, makeRecorderKit, zcf);
185
235
 
@@ -203,8 +253,9 @@ export const prepareVaultManagerKit = (
203
253
  poolIncrementSeat: zcf.makeEmptySeatKit().zcfSeat,
204
254
 
205
255
  /**
206
- * Vaults that have been sent for liquidation. When we get proceeds (or lack
207
- * thereof) back from the liquidator, we will allocate them among the vaults.
256
+ * Vaults that have been sent for liquidation. When we get proceeds (or
257
+ * lack thereof) back from the liquidator, we will allocate them among the
258
+ * vaults.
208
259
  *
209
260
  * @type {SetStore<Vault>}
210
261
  */
@@ -292,7 +343,7 @@ export const prepareVaultManagerKit = (
292
343
  getCollateralQuote: M.call().returns(PriceQuoteShape),
293
344
  getPublicFacet: M.call().returns(M.remotable('publicFacet')),
294
345
  lockOraclePrices: M.call().returns(PriceQuoteShape),
295
- liquidateVaults: M.call(AuctionPFShape).returns(M.promise()),
346
+ liquidateVaults: M.call(M.eref(AuctionPFShape)).returns(M.promise()),
296
347
  }),
297
348
  },
298
349
  initState,
@@ -339,19 +390,11 @@ export const prepareVaultManagerKit = (
339
390
 
340
391
  // Some of these could go in closures but are kept on a facet anticipating future durability options.
341
392
  helper: {
342
- /**
343
- * Start non-durable processes (or restart if needed after vat restart)
344
- */
393
+ /** Start non-durable processes (or restart if needed after vat restart) */
345
394
  start() {
346
395
  const { state, facets } = this;
347
396
  trace(state.collateralBrand, 'helper.start()', state.vaultCounter);
348
- const {
349
- collateralBrand,
350
- collateralUnit,
351
- debtBrand,
352
- storageNode,
353
- unsettledVaults,
354
- } = state;
397
+ const { collateralBrand, unsettledVaults } = state;
355
398
 
356
399
  const ephemera = collateralEphemera(collateralBrand);
357
400
  ephemera.prioritizedVaults = makePrioritizedVaults(unsettledVaults);
@@ -374,44 +417,81 @@ export const prepareVaultManagerKit = (
374
417
  ),
375
418
  fail: reason => {
376
419
  zcf.shutdownWithFailure(
377
- assert.error(X`Unable to continue without a timer: ${reason}`),
420
+ makeError(X`Unable to continue without a timer: ${reason}`),
378
421
  );
379
422
  },
380
423
  finish: done => {
381
424
  zcf.shutdownWithFailure(
382
- assert.error(X`Unable to continue without a timer: ${done}`),
425
+ makeError(X`Unable to continue without a timer: ${done}`),
383
426
  );
384
427
  },
385
428
  });
386
429
 
387
- trace('helper.start() making quoteNotifier from', priceAuthority);
388
- const quoteNotifier = E(priceAuthority).makeQuoteNotifier(
430
+ void facets.helper.ensureQuoteNotifierWatched();
431
+
432
+ trace('helper.start() done');
433
+ },
434
+ ensureQuoteNotifierWatched() {
435
+ const { state } = this;
436
+
437
+ const { collateralBrand, collateralUnit, debtBrand, storageNode } =
438
+ state;
439
+ if (watchedBrands.has(collateralBrand)) {
440
+ return;
441
+ }
442
+ watchedBrands.add(collateralBrand);
443
+
444
+ const ephemera = collateralEphemera(collateralBrand);
445
+
446
+ const quoteNotifierP = E(priceAuthority).makeQuoteNotifier(
389
447
  collateralUnit,
390
448
  debtBrand,
391
449
  );
392
- ephemera.storedQuotesNotifier = makeStoredNotifier(
393
- quoteNotifier,
394
- E(storageNode).makeChildNode('quotes'),
395
- marshaller,
396
- );
397
- trace('helper.start() awaiting observe storedQuotesNotifier');
398
- // NB: upon restart, there may not be a price for a while. If manager
399
- // operations are permitted, ones the depend on price information will
400
- // throw. See https://github.com/Agoric/agoric-sdk/issues/4317
401
- void observeNotifier(quoteNotifier, {
402
- updateState(value) {
403
- trace('vaultManager got new collateral quote', value);
404
- ephemera.storedCollateralQuote = value;
450
+
451
+ void E.when(
452
+ quoteNotifierP,
453
+ quoteNotifier => {
454
+ // @ts-expect-error XXX quotes
455
+ ephemera.storedQuotesNotifier = makeStoredNotifier(
456
+ // @ts-expect-error XXX quotes
457
+ quoteNotifier,
458
+ E(storageNode).makeChildNode('quotes'),
459
+ marshaller,
460
+ );
461
+ trace(
462
+ 'helper.start() awaiting observe storedQuotesNotifier',
463
+ collateralBrand,
464
+ );
465
+ // NB: upon restart, there may not be a price for a while. If manager
466
+ // operations are permitted, ones that depend on price information
467
+ // will throw. See https://github.com/Agoric/agoric-sdk/issues/4317
468
+ const quoteWatcher = harden({
469
+ onFulfilled(value) {
470
+ trace('watcher updated price', value);
471
+ ephemera.storedCollateralQuote = value;
472
+ },
473
+ onRejected() {
474
+ // NOTE: drastic action, if the quoteNotifier fails, we don't know
475
+ // the value of the asset, nor do we know how long we'll be in
476
+ // ignorance. Best choice is to disable actions that require
477
+ // prices and restart when we have a new price. If we restart the
478
+ // notifier immediately, we'll trigger an infinite loop, so try
479
+ // to restart each time we get a request.
480
+
481
+ ephemera.storedCollateralQuote = null;
482
+ watchedBrands.delete(collateralBrand);
483
+ },
484
+ });
485
+ void watchQuoteNotifier(quoteNotifier, quoteWatcher);
405
486
  },
406
- fail(reason) {
407
- console.error('quoteNotifier failed to iterate', reason);
487
+ e => {
488
+ trace('makeQuoteNotifier failed, resetting', e);
489
+ ephemera.storedCollateralQuote = null;
490
+ watchedBrands.delete(collateralBrand);
408
491
  },
409
- });
410
- trace('helper.start() done');
492
+ );
411
493
  },
412
- /**
413
- * @param {Timestamp} updateTime
414
- */
494
+ /** @param {Timestamp} updateTime */
415
495
  async chargeAllVaults(updateTime) {
416
496
  const { state, facets } = this;
417
497
  const { collateralBrand, debtMint, poolIncrementSeat } = state;
@@ -515,7 +595,6 @@ export const prepareVaultManagerKit = (
515
595
  state.liquidatingDebt = AmountMath.add(state.liquidatingDebt, debt);
516
596
  },
517
597
  /**
518
- *
519
598
  * @param {Amount<'nat'>} debt
520
599
  * @param {Amount<'nat'>} collateral
521
600
  * @param {Amount<'nat'>} overage
@@ -598,14 +677,18 @@ export const prepareVaultManagerKit = (
598
677
  },
599
678
 
600
679
  /**
601
- * This is designed to tolerate an incomplete plan, in case calculateDistributionPlan encounters
602
- * an error during its calculation. We don't have a way to induce such errors in CI so we've
603
- * done so manually in dev and verified this function recovers as expected.
680
+ * This is designed to tolerate an incomplete plan, in case
681
+ * calculateDistributionPlan encounters an error during its calculation.
682
+ * We don't have a way to induce such errors in CI so we've done so
683
+ * manually in dev and verified this function recovers as expected.
604
684
  *
605
685
  * @param {AmountKeywordRecord} proceeds
606
686
  * @param {Amount<'nat'>} totalDebt
607
687
  * @param {Pick<PriceQuote, 'quoteAmount'>} oraclePriceAtStart
608
- * @param {MapStore<Vault, { collateralAmount: Amount<'nat'>, debtAmount: Amount<'nat'>}>} vaultData
688
+ * @param {MapStore<
689
+ * Vault,
690
+ * { collateralAmount: Amount<'nat'>; debtAmount: Amount<'nat'> }
691
+ * >} vaultData
609
692
  * @param {Amount<'nat'>} totalCollateral
610
693
  */
611
694
  planProceedsDistribution(
@@ -661,13 +744,14 @@ export const prepareVaultManagerKit = (
661
744
  },
662
745
 
663
746
  /**
664
- * This is designed to tolerate an incomplete plan, in case calculateDistributionPlan encounters
665
- * an error during its calculation. We don't have a way to induce such errors in CI so we've
666
- * done so manually in dev and verified this function recovers as expected.
747
+ * This is designed to tolerate an incomplete plan, in case
748
+ * calculateDistributionPlan encounters an error during its calculation.
749
+ * We don't have a way to induce such errors in CI so we've done so
750
+ * manually in dev and verified this function recovers as expected.
667
751
  *
668
752
  * @param {object} obj
669
753
  * @param {import('./proceeds.js').DistributionPlan} obj.plan
670
- * @param {Array<Vault>} obj.vaultsInPlan
754
+ * @param {Vault[]} obj.vaultsInPlan
671
755
  * @param {ZCFSeat} obj.liqSeat
672
756
  * @param {Amount<'nat'>} obj.totalCollateral
673
757
  * @param {Amount<'nat'>} obj.totalDebt
@@ -687,13 +771,13 @@ export const prepareVaultManagerKit = (
687
771
  if (plan.transfersToVault.length > 0) {
688
772
  const transfers = plan.transfersToVault.map(
689
773
  ([vaultIndex, amounts]) =>
690
- /** @type {import('@agoric/zoe/src/contractSupport/atomicTransfer.js').TransferPart} */ ([
774
+ /** @type {TransferPart} */ ([
691
775
  liqSeat,
692
776
  vaultsInPlan[vaultIndex].getVaultSeat(),
693
777
  amounts,
694
778
  ]),
695
779
  );
696
- atomicRearrange(zcf, harden(transfers));
780
+ zcf.atomicRearrange(harden(transfers));
697
781
  }
698
782
 
699
783
  const { prioritizedVaults } = collateralEphemera(
@@ -773,10 +857,15 @@ export const prepareVaultManagerKit = (
773
857
  * @param {Amount<'nat'>} collateralAmount
774
858
  */
775
859
  maxDebtFor(collateralAmount) {
776
- const { collateralBrand } = this.state;
860
+ const { state, facets } = this;
861
+ const { collateralBrand } = state;
777
862
  const { storedCollateralQuote } = collateralEphemera(collateralBrand);
778
- if (!storedCollateralQuote)
779
- throw Fail`maxDebtFor called before a collateral quote was available`;
863
+ if (!storedCollateralQuote) {
864
+ facets.helper.ensureQuoteNotifierWatched();
865
+
866
+ // it might take an arbitrary amount of time to get a new quote
867
+ throw Fail`maxDebtFor called before a collateral quote was available for ${collateralBrand}`;
868
+ }
780
869
  // use the lower price to prevent vault adjustments that put them imminently underwater
781
870
  const collateralPrice = minimumPrice(
782
871
  storedCollateralQuote,
@@ -840,9 +929,7 @@ export const prepareVaultManagerKit = (
840
929
  const { descriptionScope } = this.state;
841
930
  return `${descriptionScope}: ${base}`;
842
931
  },
843
- /**
844
- * coefficient on existing debt to calculate new debt
845
- */
932
+ /** coefficient on existing debt to calculate new debt */
846
933
  getCompoundedInterest() {
847
934
  return this.state.compoundedInterest;
848
935
  },
@@ -852,7 +939,8 @@ export const prepareVaultManagerKit = (
852
939
  * @param {NormalizedDebt} oldDebtNormalized
853
940
  * @param {Amount<'nat'>} oldCollateral
854
941
  * @param {VaultId} vaultId
855
- * @param {import('./vault.js').VaultPhase} vaultPhase at the end of whatever change updated balances
942
+ * @param {import('./vault.js').VaultPhase} vaultPhase at the end of
943
+ * whatever change updated balances
856
944
  * @param {Vault} vault
857
945
  * @returns {void}
858
946
  */
@@ -926,8 +1014,9 @@ export const prepareVaultManagerKit = (
926
1014
  );
927
1015
  state.totalDebt = AmountMath.subtract(
928
1016
  AmountMath.add(state.totalDebt, vault.getCurrentDebt()),
929
- oldDebtNormalized,
1017
+ multiplyBy(oldDebtNormalized, state.compoundedInterest),
930
1018
  );
1019
+
931
1020
  void facets.helper.writeMetrics();
932
1021
  },
933
1022
  },
@@ -937,9 +1026,7 @@ export const prepareVaultManagerKit = (
937
1026
  return factoryPowers.getGovernedParams(collateralBrand);
938
1027
  },
939
1028
 
940
- /**
941
- * @param {ZCFSeat} seat
942
- */
1029
+ /** @param {ZCFSeat} seat */
943
1030
  async makeVaultKit(seat) {
944
1031
  const {
945
1032
  state,
@@ -963,7 +1050,6 @@ export const prepareVaultManagerKit = (
963
1050
 
964
1051
  try {
965
1052
  // TODO `await` is allowed until the above ordering is fixed
966
- // eslint-disable-next-line @jessie.js/no-nested-await
967
1053
  const vaultKit = await vault.initVaultKit(seat, vaultStorageNode);
968
1054
  // initVaultKit calls back to handleBalanceChange() which will add the
969
1055
  // vault to prioritizedVaults
@@ -1017,11 +1103,17 @@ export const prepareVaultManagerKit = (
1017
1103
  },
1018
1104
 
1019
1105
  getCollateralQuote() {
1106
+ const { state, facets } = this;
1020
1107
  const { storedCollateralQuote } = collateralEphemera(
1021
- this.state.collateralBrand,
1108
+ state.collateralBrand,
1022
1109
  );
1023
- if (!storedCollateralQuote)
1110
+ if (!storedCollateralQuote) {
1111
+ facets.helper.ensureQuoteNotifierWatched();
1112
+
1113
+ // it might take an arbitrary amount of time to get a new quote
1024
1114
  throw Fail`getCollateralQuote called before a collateral quote was available`;
1115
+ }
1116
+
1025
1117
  return storedCollateralQuote;
1026
1118
  },
1027
1119
 
@@ -1034,21 +1126,24 @@ export const prepareVaultManagerKit = (
1034
1126
  const { storedCollateralQuote } = collateralEphemera(
1035
1127
  state.collateralBrand,
1036
1128
  );
1037
- if (!storedCollateralQuote)
1038
- throw Fail`lockOraclePrices called before a collateral quote was available`;
1129
+ if (!storedCollateralQuote) {
1130
+ facets.helper.ensureQuoteNotifierWatched();
1131
+
1132
+ // it might take an arbitrary amount of time to get a new quote
1133
+ throw Fail`lockOraclePrices called before a collateral quote was available for ${state.collateralBrand}`;
1134
+ }
1135
+
1039
1136
  trace(
1040
- `lockPrice`,
1137
+ `lockOraclePrices`,
1041
1138
  getAmountIn(storedCollateralQuote),
1042
1139
  getAmountOut(storedCollateralQuote),
1043
1140
  );
1044
1141
 
1045
1142
  state.lockedQuote = storedCollateralQuote;
1046
- facets.helper.writeMetrics();
1143
+ void facets.helper.writeMetrics();
1047
1144
  return storedCollateralQuote;
1048
1145
  },
1049
- /**
1050
- * @param {AuctioneerPublicFacet} auctionPF
1051
- */
1146
+ /** @param {ERef<AuctioneerPublicFacet>} auctionPF */
1052
1147
  async liquidateVaults(auctionPF) {
1053
1148
  const { state, facets } = this;
1054
1149
  const { self, helper } = facets;
@@ -1061,11 +1156,28 @@ export const prepareVaultManagerKit = (
1061
1156
  } = state;
1062
1157
  trace(collateralBrand, 'considering liquidation');
1063
1158
 
1159
+ if (!lockedQuote) {
1160
+ // By design, the first cycle of auction may call this before a quote is locked
1161
+ // because the schedule is global at the vaultDirector level, and if a manager
1162
+ // starts after the price lock time there's nothing to be done.
1163
+ // NB: this message should not log repeatedly.
1164
+ console.error(
1165
+ 'Skipping liquidation because no quote is locked yet (may happen with new manager)',
1166
+ );
1167
+ return;
1168
+ }
1169
+
1170
+ const { storedCollateralQuote: collateralQuoteBefore } =
1171
+ collateralEphemera(this.state.collateralBrand);
1172
+ if (!collateralQuoteBefore) {
1173
+ console.error(
1174
+ 'Skipping liquidation because collateralQuote is missing',
1175
+ );
1176
+ return;
1177
+ }
1178
+
1064
1179
  const { prioritizedVaults } = collateralEphemera(collateralBrand);
1065
- assert(factoryPowers && prioritizedVaults && zcf);
1066
- lockedQuote ||
1067
- Fail`Must have locked a quote before liquidating vaults.`;
1068
- assert(lockedQuote); // redundant with previous line
1180
+ prioritizedVaults || Fail`prioritizedVaults missing from ephemera`;
1069
1181
 
1070
1182
  const liqMargin = self.getGovernedParams().getLiquidationMargin();
1071
1183
 
@@ -1087,6 +1199,7 @@ export const prepareVaultManagerKit = (
1087
1199
  state.lockedQuote = undefined;
1088
1200
 
1089
1201
  if (vaultData.getSize() === 0) {
1202
+ void helper.writeMetrics();
1090
1203
  return;
1091
1204
  }
1092
1205
  trace(
@@ -1126,7 +1239,10 @@ export const prepareVaultManagerKit = (
1126
1239
  const { plan, vaultsInPlan } = helper.planProceedsDistribution(
1127
1240
  proceeds,
1128
1241
  totalDebt,
1129
- storedCollateralQuote,
1242
+ // If a quote was available at the start of liquidation, but is no
1243
+ // longer, using the earlier price is better than failing to
1244
+ // distribute proceeds
1245
+ storedCollateralQuote || collateralQuoteBefore,
1130
1246
  vaultData,
1131
1247
  totalCollateral,
1132
1248
  );
@@ -1150,7 +1266,7 @@ export const prepareVaultManagerKit = (
1150
1266
  liquidatingVaults.delete(vault);
1151
1267
  }
1152
1268
 
1153
- await facets.helper.writeMetrics();
1269
+ void helper.writeMetrics();
1154
1270
  },
1155
1271
  },
1156
1272
  },
@@ -1174,7 +1290,12 @@ export const prepareVaultManagerKit = (
1174
1290
  },
1175
1291
  );
1176
1292
 
1177
- /** @param {Omit<Parameters<typeof makeVaultManagerKitInternal>[0], 'metricsStorageNode'>} externalParams */
1293
+ /**
1294
+ * @param {Omit<
1295
+ * Parameters<typeof makeVaultManagerKitInternal>[0],
1296
+ * 'metricsStorageNode'
1297
+ * >} externalParams
1298
+ */
1178
1299
  const makeVaultManagerKit = async externalParams => {
1179
1300
  const metricsStorageNode = await E(
1180
1301
  externalParams.storageNode,
@@ -1187,15 +1308,13 @@ export const prepareVaultManagerKit = (
1187
1308
  return makeVaultManagerKit;
1188
1309
  };
1189
1310
 
1311
+ /** @typedef {EReturn<EReturn<typeof prepareVaultManagerKit>>} VaultManagerKit */
1190
1312
  /**
1191
- * @typedef {Awaited<ReturnType<ReturnType<typeof prepareVaultManagerKit>>>} VaultManagerKit
1192
- */
1193
- /**
1194
- * @typedef {VaultManagerKit['self']} VaultManager
1195
- * Each VaultManager manages a single collateral type.
1313
+ * @typedef {VaultManagerKit['self']} VaultManager Each VaultManager manages a
1314
+ * single collateral type.
1196
1315
  *
1197
- * It manages some number of outstanding debt positions, each called a Vault,
1198
- * for which the collateral is provided in exchange for borrowed Minted.
1316
+ * It manages some number of outstanding debt positions, each called a Vault,
1317
+ * for which the collateral is provided in exchange for borrowed Minted.
1199
1318
  */
1200
1319
  /** @typedef {VaultManagerKit['collateral']} CollateralManager */
1201
1320