@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,25 +1,25 @@
1
- import '@agoric/governance/exported.js';
2
- import '@agoric/zoe/exported.js';
3
- import '@agoric/zoe/src/contracts/exported.js';
1
+ /// <reference types="@agoric/internal/exported" />
2
+ /// <reference types="@agoric/governance/exported" />
3
+ /// <reference types="@agoric/zoe/exported" />
4
4
 
5
- import { AmountMath } from '@agoric/ertp';
5
+ import { Fail } from '@endo/errors';
6
+ import { E } from '@endo/captp';
7
+ import { AmountMath, RatioShape } from '@agoric/ertp';
6
8
  import { mustMatch } from '@agoric/store';
7
9
  import { M, prepareExoClassKit } from '@agoric/vat-data';
8
10
 
9
11
  import { assertAllDefined, makeTracer } from '@agoric/internal';
10
12
  import {
11
- atomicRearrange,
12
13
  ceilMultiplyBy,
13
- floorDivideBy,
14
14
  makeRatioFromAmounts,
15
15
  makeRecorderTopic,
16
16
  multiplyRatios,
17
17
  ratioGTE,
18
18
  } from '@agoric/zoe/src/contractSupport/index.js';
19
- import { E } from '@endo/captp';
20
19
  import { observeNotifier } from '@agoric/notifier';
21
20
 
22
21
  import { makeNatAmountShape } from '../contractSupport.js';
22
+ import { amountsToSettle } from './auctionMath.js';
23
23
  import { preparePriceBook, prepareScaledBidBook } from './offerBook.js';
24
24
  import {
25
25
  isScaledBidPriceHigher,
@@ -27,41 +27,51 @@ import {
27
27
  priceFrom,
28
28
  } from './util.js';
29
29
 
30
- const { Fail } = assert;
30
+ /**
31
+ * @import {EReturn} from '@endo/far';
32
+ * @import {Baggage} from '@agoric/vat-data';
33
+ * @import {PriceAuthority} from '@agoric/zoe/tools/types.js';
34
+ * @import {TypedPattern} from '@agoric/internal';
35
+ */
36
+
31
37
  const { makeEmpty } = AmountMath;
32
38
 
33
- const DEFAULT_DECIMALS = 9;
39
+ const QUOTE_SCALE = 10n ** 9n;
34
40
 
35
41
  /**
36
42
  * @file The book represents the collateral-specific state of an ongoing
37
- * auction. It holds the book, the capturedPrice, and the collateralSeat that has
38
- * the allocation of assets for sale.
43
+ * auction. It holds the book, the capturedPrice, and the collateralSeat that
44
+ * has the allocation of assets for sale.
45
+ *
46
+ * The book contains orders for the collateral. It holds two kinds of orders:
39
47
  *
40
- * The book contains orders for the collateral. It holds two kinds of
41
- * orders:
42
48
  * - Prices express the bidding offer in terms of a Bid amount
43
- * - ScaledBids express the offer in terms of a discount (or markup) from the
44
- * most recent oracle price.
49
+ * - ScaledBids express the offer in terms of a discount (or markup) from the most
50
+ * recent oracle price.
45
51
  *
46
- * Offers can be added in three ways. 1) When the auction is not active, prices
47
- * are automatically added to the appropriate collection. When the auction is
48
- * active, 2) if a new offer is at or above the current price, it will be
49
- * settled immediately; 2) If the offer is below the current price, it will be
50
- * added in the appropriate place and settled when the price reaches that level.
52
+ * Offers can be added in three ways. 1) When the auction is not active, prices
53
+ * are automatically added to the appropriate collection. When the auction is
54
+ * active, 2) if a new offer is at or above the current price, it will be
55
+ * settled immediately; 2) If the offer is below the current price, it will be
56
+ * added in the appropriate place and settled when the price reaches that
57
+ * level.
51
58
  */
52
59
 
53
60
  const trace = makeTracer('AucBook', true);
54
61
 
55
62
  /**
56
63
  * @typedef {{
57
- * maxBuy: Amount<'nat'>
64
+ * maxBuy: Amount<'nat'>;
58
65
  * } & {
59
- * exitAfterBuy?: boolean,
60
- * } & ({
61
- * offerPrice: Ratio,
62
- * } | {
63
- * offerBidScaling: Ratio,
64
- * })} OfferSpec
66
+ * exitAfterBuy?: boolean;
67
+ * } & (
68
+ * | {
69
+ * offerPrice: Ratio;
70
+ * }
71
+ * | {
72
+ * offerBidScaling: Ratio;
73
+ * }
74
+ * )} OfferSpec
65
75
  */
66
76
  /**
67
77
  * @param {Brand<'nat'>} bidBrand
@@ -84,21 +94,21 @@ export const makeOfferSpecShape = (bidBrand, collateralBrand) => {
84
94
  );
85
95
  };
86
96
 
87
- /** @typedef {import('@agoric/vat-data').Baggage} Baggage */
88
-
89
97
  /**
90
98
  * @typedef {object} BookDataNotification
91
- *
92
- * @property {Ratio | null} startPrice identifies the priceAuthority and price
93
- * @property {Ratio | null} currentPriceLevel the price at the current auction tier
94
- * @property {Amount<'nat'> | null} startProceedsGoal The proceeds the sellers were targeting to raise
95
- * @property {Amount<'nat'> | null} remainingProceedsGoal The remainder of
96
- * the proceeds the sellers were targeting to raise
97
- * @property {Amount<'nat'> | undefined} proceedsRaised The proceeds raised so far in the auction
98
- * @property {Amount<'nat'>} startCollateral How much collateral was
99
- * available for sale at the start. (If more is deposited later, it'll be
100
- * added in.)
101
- * @property {Amount<'nat'> | null} collateralAvailable The amount of collateral remaining
99
+ * @property {Ratio | null} startPrice identifies the priceAuthority and price
100
+ * @property {Ratio | null} currentPriceLevel the price at the current auction
101
+ * tier
102
+ * @property {Amount<'nat'> | null} startProceedsGoal The proceeds the sellers
103
+ * were targeting to raise
104
+ * @property {Amount<'nat'> | null} remainingProceedsGoal The remainder of the
105
+ * proceeds the sellers were targeting to raise
106
+ * @property {Amount<'nat'> | undefined} proceedsRaised The proceeds raised so
107
+ * far in the auction
108
+ * @property {Amount<'nat'>} startCollateral How much collateral was available
109
+ * for sale at the start. (If more is deposited later, it'll be added in.)
110
+ * @property {Amount<'nat'> | null} collateralAvailable The amount of collateral
111
+ * remaining
102
112
  */
103
113
 
104
114
  /**
@@ -109,6 +119,8 @@ export const makeOfferSpecShape = (bidBrand, collateralBrand) => {
109
119
  export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
110
120
  const makeScaledBidBook = prepareScaledBidBook(baggage);
111
121
  const makePriceBook = preparePriceBook(baggage);
122
+ // Brands that have or are making active quoteNotifier Observers
123
+ const observedBrands = new Set();
112
124
 
113
125
  const AuctionBookStateShape = harden({
114
126
  collateralBrand: M.any(),
@@ -118,7 +130,7 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
118
130
  bidHoldingSeat: M.any(),
119
131
  bidAmountShape: M.any(),
120
132
  priceAuthority: M.any(),
121
- updatingOracleQuote: M.any(),
133
+ updatingOracleQuote: M.or(RatioShape, M.null()),
122
134
  bookDataKit: M.any(),
123
135
  priceBook: M.any(),
124
136
  scaledBidBook: M.any(),
@@ -141,11 +153,6 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
141
153
  */
142
154
  (bidBrand, collateralBrand, pAuthority, node) => {
143
155
  assertAllDefined({ bidBrand, collateralBrand, pAuthority });
144
- const zeroBid = makeEmpty(bidBrand);
145
- const zeroRatio = makeRatioFromAmounts(
146
- zeroBid,
147
- AmountMath.make(collateralBrand, 1n),
148
- );
149
156
 
150
157
  // these don't have to be durable, since we're currently assuming that upgrade
151
158
  // from a quiescent state is sufficient. When the auction is quiescent, there
@@ -168,9 +175,7 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
168
175
 
169
176
  const bookDataKit = makeRecorderKit(
170
177
  node,
171
- /** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<BookDataNotification>} */ (
172
- M.any()
173
- ),
178
+ /** @type {TypedPattern<BookDataNotification>} */ (M.any()),
174
179
  );
175
180
 
176
181
  return {
@@ -182,7 +187,7 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
182
187
  bidAmountShape,
183
188
 
184
189
  priceAuthority: pAuthority,
185
- updatingOracleQuote: zeroRatio,
190
+ updatingOracleQuote: /** @type {Ratio | null} */ (null),
186
191
 
187
192
  bookDataKit,
188
193
 
@@ -231,8 +236,8 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
231
236
  {
232
237
  helper: {
233
238
  /**
234
- * remove the key from the appropriate book, indicated by whether the price
235
- * is defined.
239
+ * remove the key from the appropriate book, indicated by whether the
240
+ * price is defined.
236
241
  *
237
242
  * @param {string} key
238
243
  * @param {Ratio | undefined} price
@@ -247,8 +252,8 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
247
252
  },
248
253
 
249
254
  /**
250
- * Update the entry in the appropriate book, indicated by whether the price
251
- * is defined.
255
+ * Update the entry in the appropriate book, indicated by whether the
256
+ * price is defined.
252
257
  *
253
258
  * @param {string} key
254
259
  * @param {Amount} collateralSold
@@ -264,7 +269,8 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
264
269
  },
265
270
 
266
271
  /**
267
- * Settle with seat. The caller is responsible for updating the book, if any.
272
+ * Settle with seat. The caller is responsible for updating the book, if
273
+ * any.
268
274
  *
269
275
  * @param {ZCFSeat} seat
270
276
  * @param {Amount<'nat'>} collateralWanted
@@ -278,46 +284,36 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
278
284
  return makeEmpty(collateralBrand);
279
285
  }
280
286
 
281
- /** @type {Amount<'nat'>} */
282
- const initialCollateralTarget = AmountMath.min(
283
- collateralWanted,
284
- collateralAvailable,
285
- );
286
-
287
287
  const { curAuctionPrice, bidHoldingSeat, remainingProceedsGoal } =
288
288
  this.state;
289
289
  curAuctionPrice !== null ||
290
290
  Fail`auctionPrice must be set before each round`;
291
291
  assert(curAuctionPrice);
292
292
 
293
- const proceedsNeeded = ceilMultiplyBy(
294
- initialCollateralTarget,
295
- curAuctionPrice,
296
- );
297
- if (AmountMath.isEmpty(proceedsNeeded)) {
293
+ const { proceedsExpected, proceedsTarget, collateralTarget } =
294
+ amountsToSettle(
295
+ {
296
+ bidAlloc,
297
+ collateralWanted,
298
+ collateralAvailable,
299
+ curAuctionPrice,
300
+ remainingProceedsGoal,
301
+ },
302
+ trace,
303
+ );
304
+
305
+ if (proceedsExpected === null) {
298
306
  seat.fail(Error('price fell to zero'));
299
307
  return makeEmpty(collateralBrand);
300
308
  }
301
309
 
302
- const minProceedsTarget = AmountMath.min(proceedsNeeded, bidAlloc);
303
- const proceedsLimit = remainingProceedsGoal
304
- ? AmountMath.min(remainingProceedsGoal, minProceedsTarget)
305
- : minProceedsTarget;
306
- const isRaiseLimited =
307
- remainingProceedsGoal ||
308
- !AmountMath.isGTE(proceedsLimit, proceedsNeeded);
309
-
310
- const [proceedsTarget, collateralTarget] = isRaiseLimited
311
- ? [proceedsLimit, floorDivideBy(proceedsLimit, curAuctionPrice)]
312
- : [minProceedsTarget, initialCollateralTarget];
313
-
310
+ // check that the requested amount could be satisfied
314
311
  const { Collateral } = seat.getProposal().want;
315
312
  if (Collateral && AmountMath.isGTE(Collateral, collateralTarget)) {
316
313
  seat.exit('unable to satisfy want');
317
314
  }
318
315
 
319
- atomicRearrange(
320
- zcf,
316
+ zcf.atomicRearrange(
321
317
  harden([
322
318
  [collateralSeat, seat, { Collateral: collateralTarget }],
323
319
  [seat, bidHoldingSeat, { Bid: proceedsTarget }],
@@ -331,7 +327,7 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
331
327
  );
332
328
  }
333
329
 
334
- trace('settle', {
330
+ trace('settled', {
335
331
  collateralTarget,
336
332
  proceedsTarget,
337
333
  remainingProceedsGoal: this.state.remainingProceedsGoal,
@@ -341,15 +337,16 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
341
337
  },
342
338
 
343
339
  /**
344
- * Accept an offer expressed as a price. If the auction is active, attempt to
345
- * buy collateral. If any of the offer remains add it to the book.
340
+ * Accept an offer expressed as a price. If the auction is active,
341
+ * attempt to buy collateral. If any of the offer remains add it to the
342
+ * book.
346
343
  *
347
- * @param {ZCFSeat} seat
348
- * @param {Ratio} price
349
- * @param {Amount<'nat'>} maxBuy
350
- * @param {object} opts
351
- * @param {boolean} opts.trySettle
352
- * @param {boolean} [opts.exitAfterBuy]
344
+ * @param {ZCFSeat} seat
345
+ * @param {Ratio} price
346
+ * @param {Amount<'nat'>} maxBuy
347
+ * @param {object} opts
348
+ * @param {boolean} opts.trySettle
349
+ * @param {boolean} [opts.exitAfterBuy]
353
350
  */
354
351
  acceptPriceOffer(
355
352
  seat,
@@ -388,16 +385,16 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
388
385
  },
389
386
 
390
387
  /**
391
- * Accept an offer expressed as a discount (or markup). If the auction is
392
- * active, attempt to buy collateral. If any of the offer remains add it to
393
- * the book.
388
+ * Accept an offer expressed as a discount (or markup). If the auction
389
+ * is active, attempt to buy collateral. If any of the offer remains add
390
+ * it to the book.
394
391
  *
395
- * @param {ZCFSeat} seat
396
- * @param {Ratio} bidScaling
397
- * @param {Amount<'nat'>} maxBuy
398
- * @param {object} opts
399
- * @param {boolean} opts.trySettle
400
- * @param {boolean} [opts.exitAfterBuy]
392
+ * @param {ZCFSeat} seat
393
+ * @param {Ratio} bidScaling
394
+ * @param {Amount<'nat'>} maxBuy
395
+ * @param {object} opts
396
+ * @param {boolean} opts.trySettle
397
+ * @param {boolean} [opts.exitAfterBuy]
401
398
  */
402
399
  acceptScaledBidOffer(
403
400
  seat,
@@ -460,16 +457,72 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
460
457
  });
461
458
  return state.bookDataKit.recorder.write(bookData);
462
459
  },
460
+ // Ensure that there is an observer monitoring the quoteNotifier. We
461
+ // assume that all failure modes for quoteNotifier eventually lead to
462
+ // fail or finish.
463
+ ensureQuoteNotifierObserved() {
464
+ const { state, facets } = this;
465
+ const { collateralBrand, bidBrand, priceAuthority } = state;
466
+
467
+ if (observedBrands.has(collateralBrand)) {
468
+ return;
469
+ }
470
+ observedBrands.add(collateralBrand);
471
+ trace('observing');
472
+
473
+ const quoteNotifierP = E(priceAuthority).makeQuoteNotifier(
474
+ AmountMath.make(collateralBrand, QUOTE_SCALE),
475
+ bidBrand,
476
+ );
477
+
478
+ void E.when(
479
+ quoteNotifierP,
480
+ quoteNotifier =>
481
+ observeNotifier(quoteNotifier, {
482
+ updateState: quote => {
483
+ trace(
484
+ `BOOK notifier ${priceFrom(quote).numerator.value}/${
485
+ priceFrom(quote).denominator.value
486
+ }`,
487
+ );
488
+ state.updatingOracleQuote = priceFrom(quote);
489
+ },
490
+ fail: reason => {
491
+ trace(
492
+ `Failure from quoteNotifier (${reason}) setting to null`,
493
+ );
494
+ // lack of quote will trigger restart
495
+ state.updatingOracleQuote = null;
496
+ observedBrands.delete(collateralBrand);
497
+ },
498
+ finish: done => {
499
+ trace(
500
+ `quoteNotifier invoked finish(${done}). setting quote to null`,
501
+ );
502
+ // lack of quote will trigger restart
503
+ state.updatingOracleQuote = null;
504
+ observedBrands.delete(collateralBrand);
505
+ },
506
+ }),
507
+ e => {
508
+ trace('makeQuoteNotifier failed, resetting', e);
509
+ state.updatingOracleQuote = null;
510
+ observedBrands.delete(collateralBrand);
511
+ },
512
+ );
513
+
514
+ void facets.helper.publishBookData();
515
+ },
463
516
  },
464
517
  self: {
465
518
  /**
466
519
  * @param {Amount<'nat'>} assetAmount
467
520
  * @param {ZCFSeat} sourceSeat
468
521
  * @param {Amount<'nat'>} [proceedsGoal] an amount that the depositor
469
- * would like to raise. The auction is requested to not sell more
470
- * collateral than required to raise that much. The auctioneer might
471
- * sell more if there is more than one supplier of collateral, and
472
- * they request inconsistent limits.
522
+ * would like to raise. The auction is requested to not sell more
523
+ * collateral than required to raise that much. The auctioneer might
524
+ * sell more if there is more than one supplier of collateral, and
525
+ * they request inconsistent limits.
473
526
  */
474
527
  addAssets(assetAmount, sourceSeat, proceedsGoal) {
475
528
  const { state, facets } = this;
@@ -531,8 +584,7 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
531
584
  state.startProceedsGoal = nextProceedsGoal;
532
585
  }
533
586
 
534
- atomicRearrange(
535
- zcf,
587
+ zcf.atomicRearrange(
536
588
  harden([[sourceSeat, collateralSeat, { Collateral: assetAmount }]]),
537
589
  );
538
590
 
@@ -547,9 +599,12 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
547
599
 
548
600
  trace(this.state.collateralBrand, 'settleAtNewRate', reduction);
549
601
  const { capturedPriceForRound, priceBook, scaledBidBook } = state;
550
- capturedPriceForRound !== null ||
551
- Fail`price must be captured before auction starts`;
552
- assert(capturedPriceForRound);
602
+ if (!capturedPriceForRound) {
603
+ console.error(
604
+ `⚠️No price for ${this.state.collateralBrand}, skipping auction.`,
605
+ );
606
+ return;
607
+ }
553
608
 
554
609
  state.curAuctionPrice = multiplyRatios(
555
610
  reduction,
@@ -561,20 +616,14 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
561
616
  const pricedOffers = priceBook.offersAbove(curAuctionPrice);
562
617
  const scaledBidOffers = scaledBidBook.offersAbove(reduction);
563
618
 
564
- const compareValues = (v1, v2) => {
565
- if (v1 < v2) {
566
- return -1;
567
- } else if (v1 === v2) {
568
- return 0;
569
- } else {
570
- return 1;
571
- }
572
- };
573
- trace(`settling`, pricedOffers.length, scaledBidOffers.length);
574
619
  // requested price or BidScaling gives no priority beyond specifying which
575
620
  // round the order will be serviced in.
576
621
  const prioritizedOffers = [...pricedOffers, ...scaledBidOffers].sort(
577
- (a, b) => compareValues(a[1].seqNum, b[1].seqNum),
622
+ (a, b) => Number(a[1].seqNum - b[1].seqNum),
623
+ );
624
+
625
+ trace(
626
+ `settling ${prioritizedOffers.length} offers at ${curAuctionPrice} (priced ${pricedOffers.length}, scaled ${scaledBidOffers.length}) `,
578
627
  );
579
628
 
580
629
  const { remainingProceedsGoal } = state;
@@ -619,6 +668,13 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
619
668
  const { facets, state } = this;
620
669
 
621
670
  trace(`capturing oracle price `, state.updatingOracleQuote);
671
+ if (!state.updatingOracleQuote) {
672
+ // if the price feed has died (or hasn't been started for this
673
+ // incarnation), (re)start it.
674
+ facets.helper.ensureQuoteNotifierObserved();
675
+ return;
676
+ }
677
+
622
678
  state.capturedPriceForRound = state.updatingOracleQuote;
623
679
  void facets.helper.publishBookData();
624
680
  },
@@ -718,46 +774,21 @@ export const prepareAuctionBook = (baggage, zcf, makeRecorderKit) => {
718
774
  finish: ({ state, facets }) => {
719
775
  const { collateralBrand, bidBrand, priceAuthority } = state;
720
776
  assertAllDefined({ collateralBrand, bidBrand, priceAuthority });
721
- void E.when(
722
- E(collateralBrand).getDisplayInfo(),
723
- ({ decimalPlaces = DEFAULT_DECIMALS }) => {
724
- // TODO(#6946) use this to keep a current price that can be published in state.
725
- const quoteNotifier = E(priceAuthority).makeQuoteNotifier(
726
- AmountMath.make(collateralBrand, 10n ** BigInt(decimalPlaces)),
727
- bidBrand,
728
- );
729
- void observeNotifier(quoteNotifier, {
730
- updateState: quote => {
731
- trace(
732
- `BOOK notifier ${priceFrom(quote).numerator.value}/${
733
- priceFrom(quote).denominator.value
734
- }`,
735
- );
736
- state.updatingOracleQuote = priceFrom(quote);
737
- },
738
- fail: reason => {
739
- throw Error(
740
- `auction observer of ${collateralBrand} failed: ${reason}`,
741
- );
742
- },
743
- finish: done => {
744
- throw Error(
745
- `auction observer for ${collateralBrand} died: ${done}`,
746
- );
747
- },
748
- });
749
- },
750
- );
751
- void facets.helper.publishBookData();
777
+
778
+ facets.helper.ensureQuoteNotifierObserved();
752
779
  },
753
780
  stateShape: AuctionBookStateShape,
754
781
  },
755
782
  );
756
783
 
757
- /** @type {(...args: Parameters<typeof makeAuctionBookKit>) => ReturnType<typeof makeAuctionBookKit>['self']} */
784
+ /**
785
+ * @type {(
786
+ * ...args: Parameters<typeof makeAuctionBookKit>
787
+ * ) => ReturnType<typeof makeAuctionBookKit>['self']}
788
+ */
758
789
  const makeAuctionBook = (...args) => makeAuctionBookKit(...args).self;
759
790
  return makeAuctionBook;
760
791
  };
761
792
  harden(prepareAuctionBook);
762
793
 
763
- /** @typedef {ReturnType<ReturnType<typeof prepareAuctionBook>>} AuctionBook */
794
+ /** @typedef {EReturn<EReturn<typeof prepareAuctionBook>>} AuctionBook */
@@ -0,0 +1,17 @@
1
+ export function amountsToSettle({ bidAlloc, collateralWanted, collateralAvailable, curAuctionPrice, remainingProceedsGoal, }: {
2
+ bidAlloc: Amount<"nat">;
3
+ collateralWanted: Amount<"nat">;
4
+ collateralAvailable: Amount<"nat">;
5
+ curAuctionPrice: Ratio;
6
+ remainingProceedsGoal: Amount<"nat"> | null;
7
+ }, log?: (...msgs: any[]) => void): {
8
+ proceedsExpected: null;
9
+ proceedsTarget?: undefined;
10
+ collateralTarget?: undefined;
11
+ } | {
12
+ proceedsExpected: import("@agoric/ertp").NatAmount;
13
+ proceedsTarget: import("@agoric/ertp").NatAmount;
14
+ collateralTarget: import("@agoric/ertp").NatAmount;
15
+ };
16
+ import type { Amount } from '@agoric/ertp/src/types.js';
17
+ //# sourceMappingURL=auctionMath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auctionMath.d.ts","sourceRoot":"","sources":["auctionMath.js"],"names":[],"mappings":"AAoBO,8HARJ;IAAyB,QAAQ,EAAzB,OAAO,KAAK,CAAC;IACI,gBAAgB,EAAjC,OAAO,KAAK,CAAC;IACI,mBAAmB,EAApC,OAAO,KAAK,CAAC;IACJ,eAAe,EAAxB,KAAK;IACmB,qBAAqB,EAA7C,OAAO,KAAK,CAAC,GAAG,IAAI;CAE5B,QAAQ,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;;;;;;;;EA6DlC;4BAxEwB,2BAA2B"}
@@ -0,0 +1,81 @@
1
+ import { AmountMath } from '@agoric/ertp';
2
+ import {
3
+ ceilMultiplyBy,
4
+ floorDivideBy,
5
+ } from '@agoric/zoe/src/contractSupport/index.js';
6
+
7
+ /**
8
+ * @import {Amount} from '@agoric/ertp/src/types.js';
9
+ */
10
+
11
+ /**
12
+ * @param {object} p
13
+ * @param {Amount<'nat'>} p.bidAlloc current allocation of the bidding seat
14
+ * @param {Amount<'nat'>} p.collateralWanted want of the offer
15
+ * @param {Amount<'nat'>} p.collateralAvailable available to auction
16
+ * @param {Ratio} p.curAuctionPrice current auction price
17
+ * @param {Amount<'nat'> | null} p.remainingProceedsGoal amount still needing
18
+ * liquidating over multiple rounds; null indicates no limit
19
+ * @param {(...msgs: any[]) => void} [log]
20
+ */
21
+ export const amountsToSettle = (
22
+ {
23
+ bidAlloc,
24
+ collateralWanted,
25
+ collateralAvailable,
26
+ curAuctionPrice,
27
+ remainingProceedsGoal,
28
+ },
29
+ log = () => {},
30
+ ) => {
31
+ log('amountsToSettle', {
32
+ bidAlloc,
33
+ collateralWanted,
34
+ collateralAvailable,
35
+ curAuctionPrice,
36
+ remainingProceedsGoal,
37
+ });
38
+ const initialCollateralTarget = AmountMath.min(
39
+ collateralWanted,
40
+ collateralAvailable,
41
+ );
42
+
43
+ const proceedsExpected = ceilMultiplyBy(
44
+ initialCollateralTarget,
45
+ curAuctionPrice,
46
+ );
47
+ if (AmountMath.isEmpty(proceedsExpected)) {
48
+ return { proceedsExpected: null };
49
+ }
50
+
51
+ const targetByProceeds = proceedsLimit =>
52
+ AmountMath.min(
53
+ collateralAvailable,
54
+ floorDivideBy(proceedsLimit, curAuctionPrice),
55
+ );
56
+
57
+ const [proceedsTarget, collateralTarget] = (() => {
58
+ // proceeds cannot exceed what is needed or being offered
59
+ const proceedsBidded = AmountMath.min(proceedsExpected, bidAlloc);
60
+ if (remainingProceedsGoal) {
61
+ const goalProceeds = AmountMath.min(
62
+ remainingProceedsGoal,
63
+ proceedsBidded,
64
+ );
65
+ return [goalProceeds, targetByProceeds(goalProceeds)];
66
+ } else if (AmountMath.isGTE(proceedsBidded, proceedsExpected)) {
67
+ // initial collateral suffices
68
+ return [proceedsBidded, initialCollateralTarget];
69
+ } else {
70
+ return [proceedsBidded, targetByProceeds(proceedsBidded)];
71
+ }
72
+ })();
73
+
74
+ assert(
75
+ AmountMath.isGTE(collateralAvailable, collateralTarget),
76
+ 'target cannot exceed available',
77
+ );
78
+
79
+ return { proceedsExpected, proceedsTarget, collateralTarget };
80
+ };
81
+ harden(amountsToSettle);