@agoric/inter-protocol 0.17.0 → 0.17.1-upgrade-23-dev-bd79330.0.bd79330

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 (148) hide show
  1. package/package.json +23 -27
  2. package/source-spec-registry.js +67 -0
  3. package/src/auction/util.d.ts +3 -1
  4. package/src/auction/util.d.ts.map +1 -1
  5. package/src/auction/util.js +1 -2
  6. package/src/clientSupport.d.ts +29 -73
  7. package/src/clientSupport.d.ts.map +1 -1
  8. package/src/clientSupport.js +25 -129
  9. package/src/collectFees.d.ts +4 -0
  10. package/src/collectFees.d.ts.map +1 -1
  11. package/src/collectFees.js +5 -2
  12. package/src/contractSupport.d.ts +10 -2
  13. package/src/contractSupport.d.ts.map +1 -1
  14. package/src/contractSupport.js +8 -3
  15. package/src/econCommitteeCharter.d.ts +19 -8
  16. package/src/econCommitteeCharter.d.ts.map +1 -1
  17. package/src/econCommitteeCharter.js +12 -12
  18. package/src/feeDistributor.d.ts +56 -52
  19. package/src/feeDistributor.d.ts.map +1 -1
  20. package/src/feeDistributor.js +5 -3
  21. package/src/index.js +0 -3
  22. package/src/interest-math.d.ts +1 -0
  23. package/src/interest-math.d.ts.map +1 -1
  24. package/src/interest-math.js +1 -2
  25. package/src/interest.d.ts +13 -1
  26. package/src/interest.d.ts.map +1 -1
  27. package/src/interest.js +6 -3
  28. package/src/price/fluxAggregatorContract.d.ts +38 -14
  29. package/src/price/fluxAggregatorContract.d.ts.map +1 -1
  30. package/src/price/fluxAggregatorContract.js +26 -12
  31. package/src/price/fluxAggregatorKit.d.ts +18 -8
  32. package/src/price/fluxAggregatorKit.d.ts.map +1 -1
  33. package/src/price/fluxAggregatorKit.js +22 -8
  34. package/src/price/priceOracleKit.d.ts +3 -1
  35. package/src/price/priceOracleKit.d.ts.map +1 -1
  36. package/src/price/priceOracleKit.js +3 -1
  37. package/src/price/roundsManager.d.ts +15 -8
  38. package/src/price/roundsManager.d.ts.map +1 -1
  39. package/src/price/roundsManager.js +9 -2
  40. package/src/proposals/addAssetToVault.js +17 -105
  41. package/src/proposals/committee-proposal.js +14 -14
  42. package/src/proposals/core-proposal.js +12 -37
  43. package/src/proposals/deploy-price-feeds.js +12 -5
  44. package/src/proposals/econ-behaviors.js +23 -154
  45. package/src/proposals/price-feed-proposal.js +14 -4
  46. package/src/proposals/replace-fee-distributor.js +8 -4
  47. package/src/proposals/replace-scaledPriceAuthorities.js +8 -2
  48. package/src/proposals/replaceElectorate.js +7 -1
  49. package/src/proposals/startEconCommittee.js +5 -1
  50. package/src/proposals/startPSM.js +15 -6
  51. package/src/proposals/upgrade-scaledPriceAuthorities.js +5 -0
  52. package/src/proposals/utils.d.ts +10 -4
  53. package/src/proposals/utils.d.ts.map +1 -1
  54. package/src/proposals/utils.js +16 -8
  55. package/src/proposals/withdraw-reserve-proposal.js +6 -1
  56. package/src/provisionPool.d.ts +36 -18
  57. package/src/provisionPool.d.ts.map +1 -1
  58. package/src/provisionPool.js +19 -12
  59. package/src/provisionPoolKit.d.ts +29 -77
  60. package/src/provisionPoolKit.d.ts.map +1 -1
  61. package/src/provisionPoolKit.js +33 -23
  62. package/src/psm/psm.d.ts +36 -24
  63. package/src/psm/psm.d.ts.map +1 -1
  64. package/src/psm/psm.js +19 -15
  65. package/src/reserve/assetReserve.d.ts +16 -6
  66. package/src/reserve/assetReserve.d.ts.map +1 -1
  67. package/src/reserve/assetReserve.js +17 -9
  68. package/src/reserve/assetReserveKit.d.ts +13 -10
  69. package/src/reserve/assetReserveKit.d.ts.map +1 -1
  70. package/src/reserve/assetReserveKit.js +7 -5
  71. package/src/reserve/params.d.ts +1 -1
  72. package/src/reserve/params.d.ts.map +1 -1
  73. package/src/reserve/params.js +1 -3
  74. package/src/vaultFactory/burn.d.ts +4 -1
  75. package/src/vaultFactory/burn.d.ts.map +1 -1
  76. package/src/vaultFactory/burn.js +5 -4
  77. package/src/vaultFactory/math.d.ts +2 -0
  78. package/src/vaultFactory/math.d.ts.map +1 -1
  79. package/src/vaultFactory/math.js +5 -3
  80. package/src/vaultFactory/orderedVaultStore.d.ts +36 -36
  81. package/src/vaultFactory/params.d.ts +37 -10
  82. package/src/vaultFactory/params.d.ts.map +1 -1
  83. package/src/vaultFactory/params.js +34 -13
  84. package/src/vaultFactory/prioritizedVaults.d.ts +98 -95
  85. package/src/vaultFactory/prioritizedVaults.d.ts.map +1 -1
  86. package/src/vaultFactory/prioritizedVaults.js +3 -2
  87. package/src/vaultFactory/storeUtils.d.ts +8 -3
  88. package/src/vaultFactory/storeUtils.d.ts.map +1 -1
  89. package/src/vaultFactory/storeUtils.js +8 -4
  90. package/src/vaultFactory/{types-ambient.d.ts → types.d.ts} +40 -40
  91. package/src/vaultFactory/types.d.ts.map +1 -0
  92. package/src/vaultFactory/{types-ambient.js → types.js} +26 -25
  93. package/src/vaultFactory/vault.d.ts +51 -35
  94. package/src/vaultFactory/vault.d.ts.map +1 -1
  95. package/src/vaultFactory/vault.js +29 -17
  96. package/src/vaultFactory/vaultDirector.d.ts +102 -112
  97. package/src/vaultFactory/vaultDirector.d.ts.map +1 -1
  98. package/src/vaultFactory/vaultDirector.js +40 -82
  99. package/src/vaultFactory/vaultFactory.d.ts +47 -95
  100. package/src/vaultFactory/vaultFactory.d.ts.map +1 -1
  101. package/src/vaultFactory/vaultFactory.js +27 -27
  102. package/src/vaultFactory/vaultHolder.d.ts +62 -55
  103. package/src/vaultFactory/vaultHolder.d.ts.map +1 -1
  104. package/src/vaultFactory/vaultHolder.js +10 -4
  105. package/src/vaultFactory/vaultKit.d.ts +15 -10
  106. package/src/vaultFactory/vaultKit.d.ts.map +1 -1
  107. package/src/vaultFactory/vaultKit.js +8 -7
  108. package/src/vaultFactory/vaultManager.d.ts +112 -262
  109. package/src/vaultFactory/vaultManager.d.ts.map +1 -1
  110. package/src/vaultFactory/vaultManager.js +42 -319
  111. package/NEWS.md +0 -0
  112. package/scripts/build-bundles.js +0 -22
  113. package/src/auction/auctionBook.d.ts +0 -147
  114. package/src/auction/auctionBook.d.ts.map +0 -1
  115. package/src/auction/auctionBook.js +0 -794
  116. package/src/auction/auctionMath.d.ts +0 -17
  117. package/src/auction/auctionMath.d.ts.map +0 -1
  118. package/src/auction/auctionMath.js +0 -81
  119. package/src/auction/auctioneer.d.ts +0 -70
  120. package/src/auction/auctioneer.d.ts.map +0 -1
  121. package/src/auction/auctioneer.js +0 -733
  122. package/src/auction/offerBook.d.ts +0 -46
  123. package/src/auction/offerBook.d.ts.map +0 -1
  124. package/src/auction/offerBook.js +0 -226
  125. package/src/auction/params.d.ts +0 -145
  126. package/src/auction/params.d.ts.map +0 -1
  127. package/src/auction/params.js +0 -176
  128. package/src/auction/scheduleMath.d.ts +0 -5
  129. package/src/auction/scheduleMath.d.ts.map +0 -1
  130. package/src/auction/scheduleMath.js +0 -169
  131. package/src/auction/scheduler.d.ts +0 -50
  132. package/src/auction/scheduler.d.ts.map +0 -1
  133. package/src/auction/scheduler.js +0 -376
  134. package/src/auction/sortedOffers.d.ts +0 -8
  135. package/src/auction/sortedOffers.d.ts.map +0 -1
  136. package/src/auction/sortedOffers.js +0 -137
  137. package/src/proposals/add-auction.js +0 -285
  138. package/src/proposals/upgrade-vaults.js +0 -207
  139. package/src/psm/types-ambient.d.ts +0 -2
  140. package/src/psm/types-ambient.d.ts.map +0 -1
  141. package/src/psm/types-ambient.js +0 -3
  142. package/src/vaultFactory/liquidation.d.ts +0 -25
  143. package/src/vaultFactory/liquidation.d.ts.map +0 -1
  144. package/src/vaultFactory/liquidation.js +0 -309
  145. package/src/vaultFactory/proceeds.d.ts +0 -35
  146. package/src/vaultFactory/proceeds.d.ts.map +0 -1
  147. package/src/vaultFactory/proceeds.js +0 -282
  148. package/src/vaultFactory/types-ambient.d.ts.map +0 -1
@@ -1,733 +0,0 @@
1
- /// <reference types="@agoric/governance/exported" />
2
- /// <reference types="@agoric/zoe/exported" />
3
-
4
- import { Fail, q } from '@endo/errors';
5
- import { E } from '@endo/eventual-send';
6
- import { Far } from '@endo/marshal';
7
- import { AmountMath, AmountShape, BrandShape } from '@agoric/ertp';
8
- import { handleParamGovernance } from '@agoric/governance';
9
- import { makeTracer } from '@agoric/internal';
10
- import { prepareDurablePublishKit } from '@agoric/notifier';
11
- import { mustMatch } from '@agoric/store';
12
- import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js';
13
- import { M, provideDurableMapStore } from '@agoric/vat-data';
14
- import {
15
- ceilDivideBy,
16
- ceilMultiplyBy,
17
- defineERecorderKit,
18
- defineRecorderKit,
19
- floorDivideBy,
20
- floorMultiplyBy,
21
- makeRatio,
22
- makeRatioFromAmounts,
23
- makeRecorderTopic,
24
- natSafeMath,
25
- prepareRecorder,
26
- provideEmptySeat,
27
- offerTo,
28
- } from '@agoric/zoe/src/contractSupport/index.js';
29
- import { FullProposalShape } from '@agoric/zoe/src/typeGuards.js';
30
-
31
- import { makeNatAmountShape } from '../contractSupport.js';
32
- import { makeOfferSpecShape, prepareAuctionBook } from './auctionBook.js';
33
- import { auctioneerParamTypes } from './params.js';
34
- import { makeScheduler } from './scheduler.js';
35
- import { AuctionState } from './util.js';
36
-
37
- /**
38
- * @import {TypedPattern} from '@agoric/internal';
39
- * @import {MapStore} from '@agoric/store';
40
- * @import {Baggage} from '@agoric/vat-data';
41
- * @import {ContractOf} from '@agoric/zoe/src/zoeService/utils.js';
42
- * @import {PriceAuthority, PriceDescription, PriceQuote, PriceQuoteValue, PriceQuery,} from '@agoric/zoe/tools/types.js';
43
- */
44
-
45
- const BASIS_POINTS = 10_000n;
46
-
47
- const { add, multiply } = natSafeMath;
48
-
49
- const trace = makeTracer('Auction', true);
50
-
51
- /**
52
- * @file In this file, 'Bid' is the name of the ERTP issuer used to purchase
53
- * collateral from various issuers. It's too confusing to also use Bid as a
54
- * verb or a description of amounts offered, so we've tried to find
55
- * alternatives in all those cases.
56
- */
57
-
58
- const MINIMUM_BID_GIVE = 1n;
59
-
60
- /**
61
- * @param {NatValue} rate
62
- * @param {Brand<'nat'>} bidBrand
63
- * @param {Brand<'nat'>} collateralBrand
64
- */
65
- const makeBPRatio = (rate, bidBrand, collateralBrand = bidBrand) =>
66
- makeRatioFromAmounts(
67
- AmountMath.make(bidBrand, rate),
68
- AmountMath.make(collateralBrand, BASIS_POINTS),
69
- );
70
-
71
- /**
72
- * The auction sold some amount of collateral, and raised a certain amount of
73
- * Bid. The excess collateral was returned as `unsoldCollateral`. The Bid amount
74
- * collected from the auction participants is `proceeds`.
75
- *
76
- * Return a set of transfers for atomicRearrange() that distribute
77
- * `unsoldCollateral` and `proceeds` proportionally to each seat's deposited
78
- * amount. Any uneven split should be allocated to the reserve.
79
- *
80
- * @param {Amount} unsoldCollateral
81
- * @param {Amount} proceeds
82
- * @param {{ seat: ZCFSeat; amount: Amount<'nat'>; goal: Amount<'nat'> }[]} deposits
83
- * @param {ZCFSeat} collateralSeat
84
- * @param {ZCFSeat} bidHoldingSeat seat with the Bid allocation to be
85
- * distributed
86
- * @param {string} collateralKeyword The Reserve will hold multiple collaterals,
87
- * so they need distinct keywords
88
- * @param {ZCFSeat} reserveSeat
89
- * @param {Brand} brand
90
- */
91
- const distributeProportionalShares = (
92
- unsoldCollateral,
93
- proceeds,
94
- deposits,
95
- collateralSeat,
96
- bidHoldingSeat,
97
- collateralKeyword,
98
- reserveSeat,
99
- brand,
100
- ) => {
101
- const totalCollDeposited = deposits.reduce((prev, { amount }) => {
102
- return AmountMath.add(prev, amount);
103
- }, AmountMath.makeEmpty(brand));
104
-
105
- const collShare = makeRatioFromAmounts(unsoldCollateral, totalCollDeposited);
106
- const currShare = makeRatioFromAmounts(proceeds, totalCollDeposited);
107
- /** @type {TransferPart[]} */
108
- const transfers = [];
109
- let proceedsLeft = proceeds;
110
- let collateralLeft = unsoldCollateral;
111
-
112
- // each depositor gets a share that equals their amount deposited
113
- // divided by the total deposited multiplied by the Bid and
114
- // collateral being distributed.
115
- for (const { seat, amount } of deposits.values()) {
116
- const currPortion = floorMultiplyBy(amount, currShare);
117
- proceedsLeft = AmountMath.subtract(proceedsLeft, currPortion);
118
- const collPortion = floorMultiplyBy(amount, collShare);
119
- collateralLeft = AmountMath.subtract(collateralLeft, collPortion);
120
- transfers.push([bidHoldingSeat, seat, { Bid: currPortion }]);
121
- transfers.push([collateralSeat, seat, { Collateral: collPortion }]);
122
- }
123
-
124
- transfers.push([bidHoldingSeat, reserveSeat, { Bid: proceedsLeft }]);
125
-
126
- if (!AmountMath.isEmpty(collateralLeft)) {
127
- transfers.push([
128
- collateralSeat,
129
- reserveSeat,
130
- { Collateral: collateralLeft },
131
- { [collateralKeyword]: collateralLeft },
132
- ]);
133
- }
134
-
135
- return transfers;
136
- };
137
-
138
- /**
139
- * The auction sold some amount of collateral, and raised a certain amount of
140
- * Bid. The excess collateral was returned as `unsoldCollateral`. The Bid amount
141
- * collected from the auction participants is `proceeds`.
142
- *
143
- * Return a set of transfers for atomicRearrange() that distribute
144
- * `unsoldCollateral` and `proceeds` proportionally to each seat's deposited
145
- * amount. Any uneven split should be allocated to the reserve.
146
- *
147
- * This function is exported for testability, and is not expected to be used
148
- * outside the contract below.
149
- *
150
- * Some or all of the depositors may have specified a goal amount.
151
- *
152
- * - A if none did, return collateral and Bid prorated to deposits.
153
- * - B if proceeds < proceedsGoal everyone gets prorated amounts of both.
154
- * - C if proceeds matches proceedsGoal, everyone gets the Bid they asked for,
155
- * plus enough collateral to reach the same proportional payout. If any
156
- * depositor's goal amount exceeded their share of the total, we'll fall back
157
- * to the first approach.
158
- * - D if proceeds > proceedsGoal && all depositors specified a limit, all
159
- * depositors get their goal first, then we distribute the remainder
160
- * (collateral and Bid) to get the same proportional payout.
161
- * - E if proceeds > proceedsGoal && some depositors didn't specify a limit,
162
- * depositors who did will get their goal first, then we distribute the
163
- * remainder (collateral and Bid) to get the same proportional payout. If any
164
- * depositor's goal amount exceeded their share of the total, we'll fall back
165
- * as above. Think of it this way: those who specified a limit want as much
166
- * collateral back as possible, consistent with raising a certain amount of
167
- * Bid. Those who didn't specify a limit are trying to sell collateral, and
168
- * would prefer to have as much as possible converted to Bid.
169
- *
170
- * @param {Amount<'nat'>} unsoldCollateral
171
- * @param {Amount<'nat'>} proceeds
172
- * @param {{ seat: ZCFSeat; amount: Amount<'nat'>; goal: Amount<'nat'> }[]} deposits
173
- * @param {ZCFSeat} collateralSeat
174
- * @param {ZCFSeat} bidHoldingSeat seat with the Bid allocation to be
175
- * distributed
176
- * @param {string} collateralKeyword The Reserve will hold multiple collaterals,
177
- * so they need distinct keywords
178
- * @param {ZCFSeat} reserveSeat
179
- * @param {Brand} brand
180
- */
181
- export const distributeProportionalSharesWithLimits = (
182
- unsoldCollateral,
183
- proceeds,
184
- deposits,
185
- collateralSeat,
186
- bidHoldingSeat,
187
- collateralKeyword,
188
- reserveSeat,
189
- brand,
190
- ) => {
191
- trace('distributeProportionally with limits');
192
- // unmatched is the sum of the deposits by those who didn't specify a goal
193
- const [collDeposited, proceedsGoal, unmatchedDeposits] = deposits.reduce(
194
- (prev, { amount, goal }) => {
195
- const nextDeposit = AmountMath.add(prev[0], amount);
196
- const [proceedsSum, unmatchedSum] = goal
197
- ? [AmountMath.add(goal, prev[1]), prev[2]]
198
- : [prev[1], AmountMath.add(prev[2], amount)];
199
- return [nextDeposit, proceedsSum, unmatchedSum];
200
- },
201
- [
202
- AmountMath.makeEmpty(brand),
203
- AmountMath.makeEmptyFromAmount(proceeds),
204
- AmountMath.makeEmpty(brand),
205
- ],
206
- );
207
-
208
- const distributeProportionally = () =>
209
- distributeProportionalShares(
210
- unsoldCollateral,
211
- proceeds,
212
- deposits,
213
- collateralSeat,
214
- bidHoldingSeat,
215
- collateralKeyword,
216
- reserveSeat,
217
- brand,
218
- );
219
-
220
- // cases A and B
221
- if (
222
- AmountMath.isEmpty(proceedsGoal) ||
223
- !AmountMath.isGTE(proceeds, proceedsGoal)
224
- ) {
225
- return distributeProportionally();
226
- }
227
-
228
- // Calculate multiplier for collateral that gives total value each depositor
229
- // should get.
230
- //
231
- // The average price of collateral is proceeds / CollateralSold.
232
- // The value of Collateral is Price * unsoldCollateral.
233
- // The overall total value to be distributed is
234
- // Proceeds + collateralValue.
235
- // Each depositor should get bid and collateral that sum to the overall
236
- // total value multiplied by the ratio of that depositor's collateral
237
- // deposited to all the collateral deposited.
238
- //
239
- // To improve the resolution of the result, we only divide once, so we
240
- // multiply each depositor's collateral remaining by this expression.
241
- //
242
- // collSold * proceeds + proceeds * unsoldCollateral
243
- // -----------------------------------------------------------
244
- // collSold * totalCollDeposit
245
- //
246
- // If you do the dimension analysis, we'll multiply collateral by a ratio
247
- // representing Bid/collateral.
248
-
249
- // average value of collateral is collateralSold / proceeds
250
- const collateralSold = AmountMath.subtract(collDeposited, unsoldCollateral);
251
- const numeratorValue = add(
252
- multiply(collateralSold.value, proceeds.value),
253
- multiply(unsoldCollateral.value, proceeds.value),
254
- );
255
- const denominatorValue = multiply(collateralSold.value, collDeposited.value);
256
- const totalValueRatio = makeRatioFromAmounts(
257
- AmountMath.make(proceeds.brand, numeratorValue),
258
- AmountMath.make(brand, denominatorValue),
259
- );
260
-
261
- const avgPrice = makeRatioFromAmounts(proceeds, collateralSold);
262
-
263
- // Allocate the proceedsGoal amount to depositors who specified it. Add
264
- // collateral to reach their share. Then see what's left, and allocate it
265
- // among the remaining depositors. Escape to distributeProportionalShares if
266
- // anything doesn't work.
267
- /** @type {TransferPart[]} */
268
- const transfers = [];
269
- let proceedsLeft = proceeds;
270
- let collateralLeft = unsoldCollateral;
271
-
272
- // case C
273
- if (AmountMath.isEqual(proceedsGoal, proceeds)) {
274
- // each depositor gets a share that equals their amount deposited
275
- // multiplied by totalValueRatio computed above.
276
-
277
- for (const { seat, amount, goal } of deposits.values()) {
278
- const depositorValue = floorMultiplyBy(amount, totalValueRatio);
279
- if (goal === null || AmountMath.isGTE(depositorValue, goal)) {
280
- let valueNeeded = depositorValue;
281
- if (goal !== null && !AmountMath.isEmpty(goal)) {
282
- proceedsLeft = AmountMath.subtract(proceedsLeft, goal);
283
- transfers.push([bidHoldingSeat, seat, { Bid: goal }]);
284
- valueNeeded = AmountMath.subtract(depositorValue, goal);
285
- }
286
-
287
- const collateralToAdd = floorDivideBy(valueNeeded, avgPrice);
288
- collateralLeft = AmountMath.subtract(collateralLeft, collateralToAdd);
289
- transfers.push([collateralSeat, seat, { Collateral: collateralToAdd }]);
290
- } else {
291
- // This depositor asked for more than their share.
292
- // ignore `transfers` and distribute everything proportionally.
293
- return distributeProportionally();
294
- }
295
- }
296
- } else {
297
- // Cases D & E. Proceeds > proceedsGoal, so those who specified a limit
298
- // receive at least their target.
299
-
300
- const collateralValue = floorMultiplyBy(unsoldCollateral, avgPrice);
301
- const totalDistributableValue = AmountMath.add(proceeds, collateralValue);
302
- // The share for those who specified a limit is proportional to their
303
- // collateral. ceiling because it's a lower limit on the restrictive branch
304
- const limitedShare = ceilMultiplyBy(
305
- AmountMath.subtract(collDeposited, unmatchedDeposits),
306
- makeRatioFromAmounts(totalDistributableValue, collDeposited),
307
- );
308
-
309
- // if proceedsGoal + value of unsoldCollateral >= limitedShare then those
310
- // who specified a limit can get all the excess over their limit in
311
- // collateral. Others share whatever is left.
312
- // If proceedsGoal + unsoldCollateral < limitedShare then those who
313
- // specified share all the collateral, and everyone gets Bid to cover
314
- // the remainder of their share.
315
- const limitedGetMaxCollateral = AmountMath.isGTE(
316
- AmountMath.add(proceedsGoal, collateralValue),
317
- limitedShare,
318
- );
319
-
320
- const calcNotLimitedCollateralShare = () => {
321
- if (limitedGetMaxCollateral) {
322
- // those who limited will get limitedShare - proceedsGoal in collateral
323
- const ltdCollatValue = AmountMath.subtract(limitedShare, proceedsGoal);
324
- const ltdCollatShare = ceilDivideBy(ltdCollatValue, avgPrice);
325
- // the unlimited will get the remainder of the collateral
326
- return AmountMath.subtract(unsoldCollateral, ltdCollatShare);
327
- } else {
328
- return AmountMath.makeEmpty(brand);
329
- }
330
- };
331
- const notLimitedCollateralShare = calcNotLimitedCollateralShare();
332
-
333
- for (const { seat, amount, goal } of deposits.values()) {
334
- const depositorValue = floorMultiplyBy(amount, totalValueRatio);
335
-
336
- const addRemainderInBid = collateralAdded => {
337
- const collateralVal = ceilMultiplyBy(collateralAdded, avgPrice);
338
- /** @type {Amount<'nat'>} XXX for package depth type resolution */
339
- const valueNeeded = AmountMath.subtract(depositorValue, collateralVal);
340
-
341
- proceedsLeft = AmountMath.subtract(proceedsLeft, valueNeeded);
342
- transfers.push([bidHoldingSeat, seat, { Bid: valueNeeded }]);
343
- };
344
-
345
- if (goal === null || AmountMath.isEmpty(goal)) {
346
- const collateralShare = floorMultiplyBy(
347
- notLimitedCollateralShare,
348
- makeRatioFromAmounts(amount, unmatchedDeposits),
349
- );
350
- collateralLeft = AmountMath.subtract(collateralLeft, collateralShare);
351
- addRemainderInBid(collateralShare);
352
- transfers.push([collateralSeat, seat, { Collateral: collateralShare }]);
353
- } else if (limitedGetMaxCollateral) {
354
- proceedsLeft = AmountMath.subtract(proceedsLeft, goal);
355
- transfers.push([bidHoldingSeat, seat, { Bid: goal }]);
356
-
357
- const valueNeeded = AmountMath.subtract(depositorValue, goal);
358
- const collateralToAdd = floorDivideBy(valueNeeded, avgPrice);
359
- collateralLeft = AmountMath.subtract(collateralLeft, collateralToAdd);
360
- transfers.push([collateralSeat, seat, { Collateral: collateralToAdd }]);
361
- } else {
362
- // There's not enough collateral to completely cover the gap above
363
- // the proceedsGoal amount, so each depositor gets a proportional share
364
- // of unsoldCollateral plus enough Bid to reach their share.
365
- const collateralShare = floorMultiplyBy(
366
- unsoldCollateral,
367
- makeRatioFromAmounts(amount, collDeposited),
368
- );
369
- collateralLeft = AmountMath.subtract(collateralLeft, collateralShare);
370
- addRemainderInBid(collateralShare);
371
- transfers.push([collateralSeat, seat, { Collateral: collateralShare }]);
372
- }
373
- }
374
- }
375
-
376
- transfers.push([bidHoldingSeat, reserveSeat, { Bid: proceedsLeft }]);
377
-
378
- if (!AmountMath.isEmpty(collateralLeft)) {
379
- transfers.push([
380
- collateralSeat,
381
- reserveSeat,
382
- { Collateral: collateralLeft },
383
- { [collateralKeyword]: collateralLeft },
384
- ]);
385
- }
386
- return transfers;
387
- };
388
-
389
- /**
390
- * @param {ZCF<
391
- * GovernanceTerms<typeof auctioneerParamTypes> & {
392
- * timerService: import('@agoric/time').TimerService;
393
- * reservePublicFacet: AssetReservePublicFacet;
394
- * priceAuthority: PriceAuthority;
395
- * }
396
- * >} zcf
397
- * @param {{
398
- * initialPoserInvitation: Invitation;
399
- * storageNode: StorageNode;
400
- * marshaller: Marshaller;
401
- * }} privateArgs
402
- * @param {Baggage} baggage
403
- */
404
- export const start = async (zcf, privateArgs, baggage) => {
405
- const { brands, timerService: timer, priceAuthority } = zcf.getTerms();
406
- timer || Fail`Timer must be in Auctioneer terms`;
407
- const timerBrand = await E(timer).getTimerBrand();
408
-
409
- const bidAmountShape = { brand: brands.Bid, value: M.nat() };
410
-
411
- /** @type {MapStore<Brand, import('./auctionBook.js').AuctionBook>} */
412
- const books = provideDurableMapStore(baggage, 'auctionBooks');
413
- /**
414
- * @type {MapStore<
415
- * Brand,
416
- * { seat: ZCFSeat; amount: Amount<'nat'>; goal: Amount<'nat'> }[]
417
- * >}
418
- */
419
- const deposits = provideDurableMapStore(baggage, 'deposits');
420
- /** @type {MapStore<Brand, Keyword>} */
421
- const brandToKeyword = provideDurableMapStore(baggage, 'brandToKeyword');
422
-
423
- const reserveSeat = provideEmptySeat(zcf, baggage, 'collateral');
424
-
425
- let bookCounter = 0;
426
-
427
- const makeDurablePublishKit = prepareDurablePublishKit(
428
- baggage,
429
- 'Auction publish kit',
430
- );
431
- const makeRecorder = prepareRecorder(baggage, privateArgs.marshaller);
432
-
433
- const makeRecorderKit = defineRecorderKit({
434
- makeRecorder,
435
- makeDurablePublishKit,
436
- });
437
-
438
- const makeAuctionBook = prepareAuctionBook(baggage, zcf, makeRecorderKit);
439
-
440
- const makeERecorderKit = defineERecorderKit({
441
- makeRecorder,
442
- makeDurablePublishKit,
443
- });
444
- const scheduleKit = makeERecorderKit(
445
- E(privateArgs.storageNode).makeChildNode('schedule'),
446
- /**
447
- * @type {TypedPattern<import('./scheduler.js').ScheduleNotification>}
448
- */ (M.any()),
449
- );
450
-
451
- /**
452
- * @param {ZCFSeat} seat
453
- * @param {Amount<'nat'>} amount
454
- * @param {Amount<'nat'> | null} goal
455
- */
456
- const addDeposit = (seat, amount, goal = null) => {
457
- appendToStoredArray(deposits, amount.brand, harden({ seat, amount, goal }));
458
- };
459
-
460
- const sendToReserve = keyword => {
461
- const { reservePublicFacet } = zcf.getTerms();
462
-
463
- const amount = reserveSeat.getCurrentAllocation()[keyword];
464
- if (!amount || AmountMath.isEmpty(amount)) {
465
- return;
466
- }
467
-
468
- const invitation = E(reservePublicFacet).makeAddCollateralInvitation();
469
- // don't wait for a response
470
- void E.when(invitation, invite => {
471
- const proposal = { give: { Collateral: amount } };
472
- void offerTo(
473
- zcf,
474
- invite,
475
- { [keyword]: 'Collateral' },
476
- proposal,
477
- reserveSeat,
478
- );
479
- });
480
- };
481
-
482
- // Called "discount" rate even though it can be above or below 100%.
483
- /** @type {NatValue} */
484
- let currentDiscountRateBP;
485
-
486
- const distributeProceeds = () => {
487
- for (const brand of deposits.keys()) {
488
- const book = books.get(brand);
489
- const { collateralSeat, bidHoldingSeat } = book.getSeats();
490
-
491
- const depositsForBrand = deposits.get(brand);
492
- if (depositsForBrand.length === 1) {
493
- // send it all to the one
494
- const liqSeat = depositsForBrand[0].seat;
495
-
496
- zcf.atomicRearrange(
497
- harden([
498
- [collateralSeat, liqSeat, collateralSeat.getCurrentAllocation()],
499
- [bidHoldingSeat, liqSeat, bidHoldingSeat.getCurrentAllocation()],
500
- ]),
501
- );
502
- liqSeat.exit();
503
- deposits.set(brand, []);
504
- } else if (depositsForBrand.length > 1) {
505
- const collProceeds = collateralSeat.getCurrentAllocation().Collateral;
506
- const currProceeds =
507
- bidHoldingSeat.getCurrentAllocation().Bid ||
508
- AmountMath.makeEmpty(brands.Bid);
509
- const transfers = distributeProportionalSharesWithLimits(
510
- collProceeds,
511
- currProceeds,
512
- depositsForBrand,
513
- collateralSeat,
514
- bidHoldingSeat,
515
- brandToKeyword.get(brand),
516
- reserveSeat,
517
- brand,
518
- );
519
- zcf.atomicRearrange(harden(transfers));
520
-
521
- for (const { seat } of depositsForBrand) {
522
- seat.exit();
523
- }
524
-
525
- sendToReserve(brandToKeyword.get(brand));
526
- deposits.set(brand, []);
527
- }
528
- }
529
- };
530
-
531
- const { augmentPublicFacet, makeFarGovernorFacet, params } =
532
- await handleParamGovernance(
533
- zcf,
534
- privateArgs.initialPoserInvitation,
535
- auctioneerParamTypes,
536
- privateArgs.storageNode,
537
- privateArgs.marshaller,
538
- );
539
-
540
- const tradeEveryBook = () => {
541
- const offerScalingRatio = makeRatio(
542
- currentDiscountRateBP,
543
- brands.Bid,
544
- BASIS_POINTS,
545
- );
546
-
547
- for (const book of books.values()) {
548
- book.settleAtNewRate(offerScalingRatio);
549
- }
550
- };
551
-
552
- const driver = Far('Auctioneer', {
553
- reducePriceAndTrade: () => {
554
- trace('reducePriceAndTrade');
555
-
556
- natSafeMath.isGTE(currentDiscountRateBP, params.getDiscountStep()) ||
557
- Fail`rates must fall ${currentDiscountRateBP}`;
558
-
559
- currentDiscountRateBP = natSafeMath.subtract(
560
- currentDiscountRateBP,
561
- params.getDiscountStep(),
562
- );
563
-
564
- tradeEveryBook();
565
- },
566
- finalize: () => {
567
- trace('finalize');
568
-
569
- for (const book of books.values()) {
570
- book.endAuction();
571
- }
572
- distributeProceeds();
573
- },
574
- startRound() {
575
- trace('startRound');
576
-
577
- currentDiscountRateBP = params.getStartingRate();
578
- for (const book of books.values()) {
579
- book.setStartingRate(makeBPRatio(currentDiscountRateBP, brands.Bid));
580
- }
581
-
582
- tradeEveryBook();
583
- },
584
- capturePrices() {
585
- for (const book of books.values()) {
586
- book.captureOraclePriceForRound();
587
- }
588
- },
589
- });
590
-
591
- const isActive = () => scheduler.getAuctionState() === AuctionState.ACTIVE;
592
-
593
- /**
594
- * @param {ZCFSeat} zcfSeat
595
- * @param {{ goal: Amount<'nat'> }} offerArgs
596
- */
597
- const depositOfferHandler = (zcfSeat, offerArgs) => {
598
- const goalMatcher = M.or(undefined, { goal: bidAmountShape });
599
- mustMatch(offerArgs, harden(goalMatcher));
600
- const { Collateral: collateralAmount } = zcfSeat.getCurrentAllocation();
601
- const book = books.get(collateralAmount.brand);
602
- trace(`deposited ${q(collateralAmount)} goal: ${q(offerArgs?.goal)}`);
603
-
604
- book.addAssets(collateralAmount, zcfSeat, offerArgs?.goal);
605
- addDeposit(zcfSeat, collateralAmount, offerArgs?.goal);
606
- return 'deposited';
607
- };
608
-
609
- const makeDepositInvitation = () =>
610
- zcf.makeInvitation(
611
- depositOfferHandler,
612
- 'deposit Collateral',
613
- undefined,
614
- M.splitRecord({ give: { Collateral: AmountShape } }),
615
- );
616
-
617
- const biddingProposalShape = M.splitRecord(
618
- {
619
- give: {
620
- Bid: makeNatAmountShape(brands.Bid, MINIMUM_BID_GIVE),
621
- },
622
- },
623
- {
624
- maxBuy: M.or({ Collateral: AmountShape }, {}),
625
- exit: FullProposalShape.exit,
626
- },
627
- );
628
-
629
- const publicFacet = augmentPublicFacet(
630
- harden({
631
- /** @param {Brand<'nat'>} collateralBrand */
632
- makeBidInvitation(collateralBrand) {
633
- mustMatch(collateralBrand, BrandShape);
634
- books.has(collateralBrand) ||
635
- Fail`No book for brand ${collateralBrand}`;
636
- const offerSpecShape = makeOfferSpecShape(brands.Bid, collateralBrand);
637
- /**
638
- * @param {ZCFSeat} zcfSeat
639
- * @param {import('./auctionBook.js').OfferSpec} offerSpec
640
- */
641
- const newBidHandler = (zcfSeat, offerSpec) => {
642
- // xxx consider having Zoe guard the offerArgs with a provided shape
643
- mustMatch(offerSpec, offerSpecShape);
644
- const auctionBook = books.get(collateralBrand);
645
- auctionBook.addOffer(offerSpec, zcfSeat, isActive());
646
- return 'Your bid has been accepted';
647
- };
648
-
649
- return zcf.makeInvitation(
650
- newBidHandler,
651
- 'new bidding offer',
652
- {},
653
- biddingProposalShape,
654
- );
655
- },
656
- getSchedules() {
657
- return scheduler.getSchedule();
658
- },
659
- getScheduleUpdates() {
660
- return scheduleKit.subscriber;
661
- },
662
- getBookDataUpdates(brand) {
663
- return books.get(brand).getDataUpdates();
664
- },
665
- getPublicTopics(brand) {
666
- if (brand) {
667
- return books.get(brand).getPublicTopics();
668
- }
669
-
670
- return {
671
- schedule: makeRecorderTopic('Auction schedule', scheduleKit),
672
- };
673
- },
674
- makeDepositInvitation,
675
- ...params,
676
- }),
677
- );
678
-
679
- const scheduler = await E.when(scheduleKit.recorderP, scheduleRecorder =>
680
- makeScheduler(
681
- driver,
682
- timer,
683
- // @ts-expect-error types are correct. How to convince TS?
684
- params,
685
- timerBrand,
686
- scheduleRecorder,
687
- publicFacet.getSubscription(),
688
- ),
689
- );
690
-
691
- const creatorFacet = makeFarGovernorFacet(
692
- Far('Auctioneer creatorFacet', {
693
- /**
694
- * @param {Issuer<'nat'>} issuer
695
- * @param {Keyword} kwd
696
- */
697
- async addBrand(issuer, kwd) {
698
- zcf.assertUniqueKeyword(kwd);
699
- !baggage.has(kwd) ||
700
- Fail`cannot add brand with keyword ${kwd}. it's in use`;
701
- const { brand } = await zcf.saveIssuer(issuer, kwd);
702
-
703
- const bookId = `book${bookCounter}`;
704
- bookCounter += 1;
705
- const bNode = await E(privateArgs.storageNode).makeChildNode(bookId);
706
-
707
- const newBook = await makeAuctionBook(
708
- brands.Bid,
709
- brand,
710
- priceAuthority,
711
- bNode,
712
- );
713
-
714
- // These three store.init() calls succeed or fail atomically
715
- deposits.init(brand, harden([]));
716
- books.init(brand, newBook);
717
- brandToKeyword.init(brand, kwd);
718
- },
719
- /** @returns {Promise<import('./scheduler.js').FullSchedule>} */
720
- getSchedule() {
721
- return E(scheduler).getSchedule();
722
- },
723
- }),
724
- );
725
-
726
- return { publicFacet, creatorFacet };
727
- };
728
-
729
- /** @typedef {ContractOf<typeof start>} AuctioneerContract */
730
- /** @typedef {AuctioneerContract['publicFacet']} AuctioneerPublicFacet */
731
- /** @typedef {AuctioneerContract['creatorFacet']} AuctioneerCreatorFacet */
732
-
733
- export const AuctionPFShape = M.remotable('Auction Public Facet');