@agoric/inter-protocol 0.13.3 → 0.13.4-dev-800c2bb.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +26 -20
  2. package/bundles/bundle-auctioneer-js-meta.json +722 -0
  3. package/bundles/bundle-auctioneer.js +1 -0
  4. package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
  5. package/bundles/bundle-econCommitteeCharter.js +1 -0
  6. package/bundles/bundle-feeDistributor-js-meta.json +458 -0
  7. package/bundles/bundle-feeDistributor.js +1 -1
  8. package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
  9. package/bundles/bundle-fluxAggregatorKit.js +1 -0
  10. package/bundles/bundle-psm-js-meta.json +666 -0
  11. package/bundles/bundle-psm.js +1 -1
  12. package/bundles/bundle-reserve-js-meta.json +662 -0
  13. package/bundles/bundle-reserve.js +1 -1
  14. package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
  15. package/bundles/bundle-scaledPriceAuthority.js +1 -1
  16. package/bundles/bundle-vaultFactory-js-meta.json +786 -0
  17. package/bundles/bundle-vaultFactory.js +1 -1
  18. package/exported.js +0 -2
  19. package/package.json +34 -31
  20. package/scripts/add-collateral-core.js +14 -4
  21. package/scripts/build-bundles.js +9 -2
  22. package/scripts/deploy-contracts.js +1 -4
  23. package/scripts/init-core.js +20 -38
  24. package/scripts/invite-committee-core.js +1 -1
  25. package/scripts/manual-price-feed.js +2 -2
  26. package/scripts/price-feed-core.js +7 -6
  27. package/scripts/start-local-chain.sh +84 -0
  28. package/src/auction/auctionBook.js +755 -0
  29. package/src/auction/auctioneer.js +720 -0
  30. package/src/auction/offerBook.js +221 -0
  31. package/src/auction/params.js +174 -0
  32. package/src/auction/scheduleMath.js +167 -0
  33. package/src/auction/scheduler.js +370 -0
  34. package/src/auction/sortedOffers.js +136 -0
  35. package/src/auction/util.js +55 -0
  36. package/src/clientSupport.js +324 -0
  37. package/src/collectFees.js +8 -14
  38. package/src/contractSupport.js +24 -68
  39. package/src/econCommitteeCharter.js +161 -77
  40. package/src/feeDistributor.js +60 -20
  41. package/src/index.js +2 -0
  42. package/src/interest-math.js +1 -4
  43. package/src/interest.js +20 -13
  44. package/src/price/README.md +57 -0
  45. package/src/price/fluxAggregatorContract.js +190 -0
  46. package/src/price/fluxAggregatorKit.js +375 -0
  47. package/src/price/priceOracleKit.js +127 -0
  48. package/src/price/roundsManager.js +726 -0
  49. package/src/proposals/addAssetToVault.js +89 -94
  50. package/src/proposals/committee-proposal.js +141 -40
  51. package/src/proposals/core-proposal.js +100 -167
  52. package/src/proposals/econ-behaviors.js +320 -564
  53. package/src/proposals/price-feed-proposal.js +175 -78
  54. package/src/proposals/startEconCommittee.js +25 -12
  55. package/src/proposals/startPSM.js +231 -211
  56. package/src/proposals/utils.js +31 -17
  57. package/src/psm/README.md +71 -0
  58. package/src/psm/psm.js +272 -160
  59. package/src/psm/types.js +2 -0
  60. package/src/reserve/assetReserve.js +56 -413
  61. package/src/reserve/assetReserveKit.js +303 -0
  62. package/src/reserve/doc.md +1 -3
  63. package/src/reserve/params.js +2 -5
  64. package/src/typeGuards.js +13 -0
  65. package/src/vaultFactory/Liquidation.md +100 -0
  66. package/src/vaultFactory/burn.js +2 -1
  67. package/src/vaultFactory/liquidation.js +270 -108
  68. package/src/vaultFactory/math.js +95 -0
  69. package/src/vaultFactory/orderedVaultStore.js +0 -1
  70. package/src/vaultFactory/params.js +133 -112
  71. package/src/vaultFactory/prioritizedVaults.js +36 -79
  72. package/src/vaultFactory/storeUtils.js +67 -9
  73. package/src/vaultFactory/type-imports.js +2 -0
  74. package/src/vaultFactory/types.js +22 -26
  75. package/src/vaultFactory/vault.js +772 -709
  76. package/src/vaultFactory/vaultDirector.js +480 -483
  77. package/src/vaultFactory/vaultFactory.js +99 -60
  78. package/src/vaultFactory/vaultHolder.js +121 -95
  79. package/src/vaultFactory/vaultKit.js +39 -31
  80. package/src/vaultFactory/vaultManager.js +1249 -868
  81. package/bundles/bundle-amm-meta.js +0 -618
  82. package/bundles/bundle-amm.js +0 -1
  83. package/bundles/bundle-feeDistributor-meta.js +0 -346
  84. package/bundles/bundle-interchainPool-meta.js +0 -534
  85. package/bundles/bundle-interchainPool.js +0 -1
  86. package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
  87. package/bundles/bundle-liquidateIncrementally.js +0 -1
  88. package/bundles/bundle-liquidateMinimum-meta.js +0 -442
  89. package/bundles/bundle-liquidateMinimum.js +0 -1
  90. package/bundles/bundle-psm-meta.js +0 -538
  91. package/bundles/bundle-psmCharter-meta.js +0 -418
  92. package/bundles/bundle-psmCharter.js +0 -1
  93. package/bundles/bundle-reserve-meta.js +0 -542
  94. package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
  95. package/bundles/bundle-stakeFactory-meta.js +0 -574
  96. package/bundles/bundle-stakeFactory.js +0 -1
  97. package/bundles/bundle-vaultFactory-meta.js +0 -598
  98. package/scripts/add-initial-liquidity.js +0 -180
  99. package/src/collect.js +0 -13
  100. package/src/interchainPool.js +0 -135
  101. package/src/makeTracer.js +0 -36
  102. package/src/my-lien.js +0 -85
  103. package/src/proposals/demoIssuers.js +0 -685
  104. package/src/proposals/sim-behaviors.js +0 -40
  105. package/src/psm/psmCharter.js +0 -139
  106. package/src/stakeFactory/README.md +0 -62
  107. package/src/stakeFactory/attestation.js +0 -267
  108. package/src/stakeFactory/attestationTool.js +0 -66
  109. package/src/stakeFactory/constants.js +0 -16
  110. package/src/stakeFactory/params.js +0 -31
  111. package/src/stakeFactory/stakeFactory.js +0 -236
  112. package/src/stakeFactory/stakeFactoryKit.js +0 -455
  113. package/src/stakeFactory/stakeFactoryManager.js +0 -296
  114. package/src/stakeFactory/types.js +0 -42
  115. package/src/vaultFactory/liquidateIncrementally.js +0 -350
  116. package/src/vaultFactory/liquidateMinimum.js +0 -100
  117. package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
  118. package/src/vpool-xyk-amm/addLiquidity.js +0 -222
  119. package/src/vpool-xyk-amm/addPool.js +0 -197
  120. package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
  121. package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
  122. package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
  123. package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
  124. package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
  125. package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
  126. package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
  127. package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
  128. package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
  129. package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
  130. package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
  131. package/src/vpool-xyk-amm/doublePool.js +0 -194
  132. package/src/vpool-xyk-amm/estimate.js +0 -155
  133. package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
  134. package/src/vpool-xyk-amm/params.js +0 -61
  135. package/src/vpool-xyk-amm/pool.js +0 -396
  136. package/src/vpool-xyk-amm/priceAuthority.js +0 -94
  137. package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
  138. package/src/vpool-xyk-amm/singlePool.js +0 -73
  139. package/src/vpool-xyk-amm/swap.js +0 -69
  140. package/src/vpool-xyk-amm/types.js +0 -154
@@ -1,144 +1,306 @@
1
- // @ts-check
2
1
  // @jessie-check
3
2
 
4
- import { E } from '@endo/eventual-send';
5
3
  import { AmountMath } from '@agoric/ertp';
6
- import {
7
- ceilMultiplyBy,
8
- makeRatio,
9
- offerTo,
10
- } from '@agoric/zoe/src/contractSupport/index.js';
11
- import { makeTracer } from '../makeTracer.js';
4
+ import { makeTracer } from '@agoric/internal';
5
+ import { observeIteration, subscribeEach } from '@agoric/notifier';
6
+ import { makeScalarMapStore } from '@agoric/store';
7
+ import { TimeMath } from '@agoric/time';
8
+ import { atomicRearrange } from '@agoric/zoe/src/contractSupport/index.js';
9
+ import { E } from '@endo/eventual-send';
10
+
11
+ import { AUCTION_START_DELAY, PRICE_LOCK_PERIOD } from '../auction/params.js';
12
+ import { makeCancelTokenMaker } from '../auction/util.js';
13
+
14
+ const trace = makeTracer('LIQ');
12
15
 
13
- const trace = makeTracer('LIQ', false);
16
+ /** @typedef {import('@agoric/time/src/types').TimerService} TimerService */
17
+ /** @typedef {import('@agoric/time/src/types').TimerWaker} TimerWaker */
18
+ /** @typedef {import('@agoric/time/src/types').CancelToken} CancelToken */
19
+ /** @typedef {import('@agoric/time/src/types').RelativeTimeRecord} RelativeTimeRecord */
20
+
21
+ const makeCancelToken = makeCancelTokenMaker('liq');
14
22
 
15
23
  /**
16
- * Threshold to alert when the price level falls enough that the vault
17
- * with the highest debt to collateral ratio will no longer be valued at the
18
- * liquidationMargin above its debt.
24
+ * This will normally be set. If the schedule goes sideways, we'll unschedule
25
+ * all events and unset it. When auction params are changed, we'll restart the schedule
19
26
  *
20
- * @param {Ratio} highestDebtRatio
21
- * @param {Ratio} liquidationMargin
27
+ * @type {object | undefined}
22
28
  */
23
- const liquidationThreshold = (highestDebtRatio, liquidationMargin) =>
24
- ceilMultiplyBy(
25
- highestDebtRatio.numerator, // debt
26
- liquidationMargin,
29
+ let cancelToken = makeCancelToken();
30
+
31
+ const waitForRepair = () => {
32
+ // the params observer will setWakeup to resume.
33
+ console.warn(
34
+ '🛠️ No wake for reschedule. Repair by resetting auction params.',
27
35
  );
36
+ };
37
+
38
+ // Generally, canceling wakups has to be followed by setting up new ones but
39
+ // not in the case of pausing wakeups. We do that in the event of invalid
40
+ // schedule params. When they are repaired by governance, the wakers resume.
41
+ /** @param {ERef<TimerService>} timer */
42
+ const cancelWakeups = timer => {
43
+ if (cancelToken) {
44
+ void E(timer).cancel(cancelToken);
45
+ }
46
+ cancelToken = undefined;
47
+ };
28
48
 
29
49
  /**
30
- * @param {ERef<PriceAuthority>} priceAuthority
31
- * @param {Ratio} highestDebtRatio
32
- * @param {Ratio} liquidationMargin
50
+ * Schedule wakeups for the *next* auction round.
51
+ *
52
+ * In practice, there are these cases to handle (with N as "live" and N+1 is "next"):
53
+ *
54
+ * | when (now within the range) | what |
55
+ * | -------------------------------- | --------------------------------------- |
56
+ * | [start N, nominalStart N+1] | good: schedule normally the three wakers|
57
+ * | (nominalStart N+1, endTime N+1] | recover: skip round N+1 and schedule N+2|
58
+ * | (endTime N+1, ∞) | give up: wait for repair by governance |
59
+ *
60
+ * @param {object} opts
61
+ * @param {ERef<TimerService>} opts.timer
62
+ * @param {TimerWaker} opts.priceLockWaker
63
+ * @param {TimerWaker} opts.liquidationWaker
64
+ * @param {TimerWaker} opts.reschedulerWaker
65
+ * @param {import('../auction/scheduler.js').Schedule} opts.nextAuctionSchedule
66
+ * @param {import('@agoric/time/src/types').TimestampRecord} opts.now
67
+ * @param {ParamStateRecord} opts.params
68
+ * @returns {void}
33
69
  */
34
- const makeQuote = (priceAuthority, highestDebtRatio, liquidationMargin) => {
35
- return E(priceAuthority).mutableQuoteWhenLT(
36
- highestDebtRatio.denominator, // collateral
37
- liquidationThreshold(highestDebtRatio, liquidationMargin),
70
+ const setWakeups = ({
71
+ nextAuctionSchedule,
72
+ now,
73
+ timer,
74
+ reschedulerWaker,
75
+ liquidationWaker,
76
+ priceLockWaker,
77
+ params,
78
+ }) => {
79
+ const { startTime, endTime } = nextAuctionSchedule;
80
+
81
+ /** @type {RelativeTimeRecord} */
82
+ // @ts-expect-error Casting
83
+ // eslint-disable-next-line no-restricted-syntax -- https://github.com/Agoric/eslint-config-jessie/issues/33
84
+ const priceLockPeriod = params[PRICE_LOCK_PERIOD].value;
85
+ /** @type {RelativeTimeRecord} */
86
+ // @ts-expect-error Casting
87
+ // eslint-disable-next-line no-restricted-syntax -- https://github.com/Agoric/eslint-config-jessie/issues/33
88
+ const auctionStartDelay = params[AUCTION_START_DELAY].value;
89
+
90
+ // nominal is the declared start time, but the actual auctioning begins after auctionStartDelay
91
+ const nominalStart = TimeMath.subtractAbsRel(startTime, auctionStartDelay);
92
+
93
+ // Is there a problem (case 2 or 3)?
94
+ // setWakeupsForNextAuction is supposed to be called just after an auction
95
+ // started. If we're late but there's still time for the nominal start, then
96
+ // we'll proceed. Reschedule for the next round if that's still in the future.
97
+ // Otherwise, wait for governance params to change.
98
+ if (TimeMath.compareAbs(now, nominalStart) > 0) {
99
+ // nominalStart is past, so cancel timers and plan to recover
100
+ cancelWakeups(timer);
101
+
102
+ if (TimeMath.compareAbs(now, endTime) < 0) {
103
+ // We're currently scheduling the N+1 (where N is live), but we need to skip it.
104
+ // So wake up for the N+2 round's startTime
105
+ const afterNextStartTime = TimeMath.addAbsRel(endTime, 1n);
106
+ trace(
107
+ 'CASE 2: endTime is in the future or now so reschedule waking to startTime of the following round',
108
+ afterNextStartTime,
109
+ );
110
+ void E(timer).setWakeup(afterNextStartTime, reschedulerWaker);
111
+ } else {
112
+ trace('CASE 3: endTime is past; wait for repair');
113
+ waitForRepair();
114
+ }
115
+
116
+ return;
117
+ }
118
+ trace('CASE 1: nominalStart is now or in the future');
119
+
120
+ cancelToken = cancelToken || makeCancelToken();
121
+ const priceLockWakeTime = TimeMath.subtractAbsRel(
122
+ nominalStart,
123
+ priceLockPeriod,
38
124
  );
125
+ const a = t => TimeMath.absValue(t);
126
+ trace('scheduling ', a(priceLockWakeTime), a(nominalStart), a(startTime));
127
+ void E(timer).setWakeup(priceLockWakeTime, priceLockWaker, cancelToken);
128
+ void E(timer).setWakeup(nominalStart, liquidationWaker, cancelToken);
129
+ // Call setWakeupsForNextAuction again one tick after nominalStart
130
+ const afterStart = TimeMath.addAbsRel(startTime, 1n);
131
+ void E(timer).setWakeup(afterStart, reschedulerWaker, cancelToken);
39
132
  };
40
133
 
41
134
  /**
135
+ * Schedule wakeups for the *next* auction round.
136
+ *
137
+ * Called by vaultDirector's resetWakeupsForNextAuction at start() and every
138
+ * time there's a "reschedule" wakeup.
42
139
  *
43
- * @param {PromiseLike<MutableQuote>} quote
44
- * @param {Ratio} highestDebtRatio
45
- * @param {Ratio} liquidationMargin
140
+ * @param {ERef<import('../auction/auctioneer.js').AuctioneerPublicFacet>} auctioneerPublicFacet
141
+ * @param {ERef<TimerService>} timer
142
+ * @param {TimerWaker} priceLockWaker
143
+ * @param {TimerWaker} liquidationWaker
144
+ * @param {TimerWaker} reschedulerWaker
145
+ * @returns {Promise<void>}
46
146
  */
47
- const updateQuote = (quote, highestDebtRatio, liquidationMargin) => {
48
- E(quote).updateLevel(
49
- highestDebtRatio.denominator, // collateral
50
- liquidationThreshold(highestDebtRatio, liquidationMargin),
51
- );
147
+ const setWakeupsForNextAuction = async (
148
+ auctioneerPublicFacet,
149
+ timer,
150
+ priceLockWaker,
151
+ liquidationWaker,
152
+ reschedulerWaker,
153
+ ) => {
154
+ const [{ nextAuctionSchedule }, params, now] = await Promise.all([
155
+ E(auctioneerPublicFacet).getSchedules(),
156
+ E(auctioneerPublicFacet).getGovernedParams(),
157
+ E(timer).getCurrentTimestamp(),
158
+ ]);
159
+
160
+ trace('SCHEDULE', now.absValue, nextAuctionSchedule);
161
+ if (!nextAuctionSchedule) {
162
+ // There should always be a nextAuctionSchedule. If there isn't, give up for now.
163
+ cancelWakeups(timer);
164
+ waitForRepair();
165
+ return;
166
+ }
167
+
168
+ setWakeups({
169
+ nextAuctionSchedule,
170
+ now,
171
+ timer,
172
+ reschedulerWaker,
173
+ liquidationWaker,
174
+ priceLockWaker,
175
+ params,
176
+ });
52
177
  };
53
178
 
54
179
  /**
55
- * Liquidates a Vault, using the strategy to parameterize the particular
56
- * contract being used. The strategy provides a KeywordMapping and proposal
57
- * suitable for `offerTo()`, and an invitation.
58
- *
59
- * Once collateral has been sold using the contract, we burn the amount
60
- * necessary to cover the debt and return the remainder.
180
+ * @param {Amount<'nat'>} debt
181
+ * @param {Amount<'nat'>} minted
182
+ * @returns {{ overage: Amount<'nat'>, shortfall: Amount<'nat'>, toBurn: Amount<'nat'>}}
183
+ */
184
+ const liquidationResults = (debt, minted) => {
185
+ if (AmountMath.isEmpty(minted)) {
186
+ return {
187
+ overage: minted,
188
+ toBurn: minted,
189
+ shortfall: debt,
190
+ };
191
+ }
192
+
193
+ const [overage, shortfall] = AmountMath.isGTE(debt, minted)
194
+ ? [AmountMath.makeEmptyFromAmount(debt), AmountMath.subtract(debt, minted)]
195
+ : [AmountMath.subtract(minted, debt), AmountMath.makeEmptyFromAmount(debt)];
196
+
197
+ const toBurn = AmountMath.min(minted, debt);
198
+ // debt is fully accounted for, with toBurn and shortfall
199
+ assert(AmountMath.isEqual(debt, AmountMath.add(toBurn, shortfall)));
200
+
201
+ return {
202
+ overage,
203
+ toBurn,
204
+ shortfall,
205
+ };
206
+ };
207
+
208
+ /**
209
+ * Watch governed params for change
61
210
  *
211
+ * @param {ERef<import('../auction/auctioneer.js').AuctioneerPublicFacet>} auctioneerPublicFacet
212
+ * @param {ERef<TimerService>} timer
213
+ * @param {TimerWaker} reschedulerWaker
214
+ * @returns {void}
215
+ */
216
+ export const watchForGovernanceChange = (
217
+ auctioneerPublicFacet,
218
+ timer,
219
+ reschedulerWaker,
220
+ ) => {
221
+ void E.when(E(timer).getCurrentTimestamp(), now =>
222
+ // make one observer that will usually ignore the update.
223
+ observeIteration(
224
+ subscribeEach(E(auctioneerPublicFacet).getSubscription()),
225
+ harden({
226
+ async updateState(_newState) {
227
+ if (!cancelToken) {
228
+ cancelToken = makeCancelToken();
229
+ void E(timer).setWakeup(
230
+ // bump one tick to prevent an infinite loop
231
+ TimeMath.addAbsRel(now, 1n),
232
+ reschedulerWaker,
233
+ cancelToken,
234
+ );
235
+ }
236
+ },
237
+ }),
238
+ ),
239
+ );
240
+ };
241
+
242
+ /**
62
243
  * @param {ZCF} zcf
63
- * @param {Vault} vault
64
- * @param {Liquidator} liquidator
65
- * @param {Brand} collateralBrand
66
- * @param {Ratio} penaltyRate
244
+ * @param {object} collateralizationDetails
245
+ * @param {PriceQuote} collateralizationDetails.quote
246
+ * @param {Ratio} collateralizationDetails.interest
247
+ * @param {Ratio} collateralizationDetails.margin
248
+ * @param {ReturnType<typeof import('./prioritizedVaults.js').makePrioritizedVaults>} prioritizedVaults
249
+ * @param {SetStore<Vault>} liquidatingVaults
250
+ * @param {Brand<'nat'>} debtBrand
251
+ * @param {Brand<'nat'>} collateralBrand
252
+ * @returns {{
253
+ * vaultData: MapStore<Vault, { collateralAmount: Amount<'nat'>, debtAmount: Amount<'nat'>}>,
254
+ * totalDebt: Amount<'nat'>,
255
+ * totalCollateral: Amount<'nat'>,
256
+ * liqSeat: ZCFSeat}}
67
257
  */
68
- const liquidate = async (
258
+ const getLiquidatableVaults = (
69
259
  zcf,
70
- vault,
71
- liquidator,
260
+ collateralizationDetails,
261
+ prioritizedVaults,
262
+ liquidatingVaults,
263
+ debtBrand,
72
264
  collateralBrand,
73
- penaltyRate,
74
265
  ) => {
75
- trace('liquidate start', vault);
76
- vault.liquidating();
266
+ const vaultsToLiquidate = prioritizedVaults.removeVaultsBelow(
267
+ collateralizationDetails,
268
+ );
269
+ /** @type {MapStore<Vault, { collateralAmount: Amount<'nat'>, debtAmount: Amount<'nat'>}>} */
270
+ const vaultData = makeScalarMapStore();
77
271
 
78
- const debt = vault.getCurrentDebt();
272
+ const { zcfSeat: liqSeat } = zcf.makeEmptySeatKit();
273
+ let totalDebt = AmountMath.makeEmpty(debtBrand);
274
+ let totalCollateral = AmountMath.makeEmpty(collateralBrand);
275
+ /** @type {import('@agoric/zoe/src/contractSupport/atomicTransfer.js').TransferPart[]} */
276
+ const transfers = [];
79
277
 
80
- const vaultZcfSeat = vault.getVaultSeat();
278
+ for (const vault of vaultsToLiquidate.values()) {
279
+ vault.liquidating();
280
+ liquidatingVaults.add(vault);
81
281
 
82
- const collateralToSell = vaultZcfSeat.getAmountAllocated(
83
- 'Collateral',
84
- collateralBrand,
85
- );
86
- trace(`liq prep`, { collateralToSell, debt, liquidator });
87
-
88
- const { deposited, userSeatPromise: liqSeat } = await offerTo(
89
- zcf,
90
- E(liquidator).makeLiquidateInvitation(),
91
- harden({ Collateral: 'In', Minted: 'Out' }),
92
- harden({
93
- give: { In: collateralToSell },
94
- want: { Out: AmountMath.makeEmpty(debt.brand) },
95
- }),
96
- vaultZcfSeat,
97
- vaultZcfSeat,
98
- harden({ debt, penaltyRate }),
99
- );
100
- trace(` offeredTo`, { collateralToSell, debt });
282
+ const collateralAmount = vault.getCollateralAmount();
283
+ totalCollateral = AmountMath.add(totalCollateral, collateralAmount);
101
284
 
102
- // await deposited and offer result, but ignore the latter
103
- const [proceeds] = await Promise.all([
104
- deposited,
105
- E(liqSeat).getOfferResult(),
106
- ]);
107
- // NB: all the proceeds from AMM sale are on the vault seat instead of a staging seat
108
-
109
- const [overage, shortfall] = AmountMath.isGTE(debt, proceeds.Minted)
110
- ? [
111
- AmountMath.makeEmptyFromAmount(debt),
112
- AmountMath.subtract(debt, proceeds.Minted),
113
- ]
114
- : [
115
- AmountMath.subtract(proceeds.Minted, debt),
116
- AmountMath.makeEmptyFromAmount(debt),
117
- ];
118
-
119
- const toBurn = AmountMath.min(proceeds.Minted, debt);
120
- // debt is fully accounted for, with toBurn and shortfall
121
- assert(AmountMath.isEqual(debt, AmountMath.add(toBurn, shortfall)));
285
+ const debtAmount = vault.getCurrentDebt();
286
+ totalDebt = AmountMath.add(totalDebt, debtAmount);
287
+ transfers.push([
288
+ vault.getVaultSeat(),
289
+ liqSeat,
290
+ { Collateral: collateralAmount },
291
+ ]);
292
+ vaultData.init(vault, { collateralAmount, debtAmount });
293
+ }
122
294
 
123
- // Manager accounting changes determined. Update the vault state.
124
- vault.liquidated();
125
- // remaining funds are left on the vault for the user to close and claim
295
+ if (transfers.length > 0) {
296
+ atomicRearrange(zcf, harden(transfers));
297
+ }
126
298
 
127
- // for manager's accounting
128
- return { proceeds: proceeds.Minted, overage, toBurn, shortfall };
299
+ return { vaultData, totalDebt, totalCollateral, liqSeat };
129
300
  };
130
301
 
131
- const liquidationDetailTerms = debtBrand =>
132
- harden({
133
- MaxImpactBP: 50n,
134
- OracleTolerance: makeRatio(30n, debtBrand),
135
- AMMMaxSlippage: makeRatio(30n, debtBrand),
136
- });
137
- /** @typedef {ReturnType<typeof liquidationDetailTerms>} LiquidationTerms */
138
-
139
- harden(liquidate);
140
- harden(liquidationDetailTerms);
141
- harden(makeQuote);
142
- harden(updateQuote);
302
+ harden(setWakeupsForNextAuction);
303
+ harden(liquidationResults);
304
+ harden(getLiquidatableVaults);
143
305
 
144
- export { liquidate, liquidationDetailTerms, makeQuote, updateQuote };
306
+ export { setWakeupsForNextAuction, liquidationResults, getLiquidatableVaults };
@@ -0,0 +1,95 @@
1
+ // @jessie-check
2
+
3
+ /**
4
+ * @file calculations specific to the Vault Factory contract
5
+ * See also ../interest-math.js
6
+ */
7
+
8
+ import { AmountMath } from '@agoric/ertp';
9
+ import { getAmountOut } from '@agoric/zoe/src/contractSupport/priceQuote.js';
10
+ import {
11
+ addRatios,
12
+ ceilMultiplyBy,
13
+ floorDivideBy,
14
+ ratioGTE,
15
+ } from '@agoric/zoe/src/contractSupport/ratio.js';
16
+ import { priceFrom } from '../auction/util.js';
17
+ import { addSubtract } from '../contractSupport.js';
18
+
19
+ /**
20
+ * Calculate the minimum collateralization given the liquidation margin and the "padding"
21
+ * from that liquidation threshold.
22
+ *
23
+ * @param {Ratio} liquidationMargin
24
+ * @param {Ratio} liquidationPadding
25
+ * @returns {Ratio}
26
+ */
27
+ export const calculateMinimumCollateralization = (
28
+ liquidationMargin,
29
+ liquidationPadding,
30
+ ) => addRatios(liquidationMargin, liquidationPadding);
31
+
32
+ /**
33
+ * Calculate the lesser price of the given quotes.
34
+ *
35
+ * @param {PriceQuote} quoteA
36
+ * @param {PriceQuote} [quoteB]
37
+ * @returns {Ratio}
38
+ */
39
+ export const minimumPrice = (quoteA, quoteB) => {
40
+ const priceA = priceFrom(quoteA);
41
+ if (quoteB === undefined) {
42
+ return priceA;
43
+ }
44
+ const priceB = priceFrom(quoteB);
45
+ if (ratioGTE(priceA, priceB)) {
46
+ return priceB;
47
+ } else {
48
+ return priceA;
49
+ }
50
+ };
51
+ harden(minimumPrice);
52
+
53
+ /**
54
+ * Calculate the maximum debt allowed based on the price quote and the lesser of
55
+ * the `liquidationMargin` or the `liquidationPadding`.
56
+ *
57
+ * @param {PriceQuote} quoteAmount
58
+ * @param {Ratio} liquidationMargin
59
+ * @param {Ratio} liquidationPadding
60
+ * @returns {Amount<'nat'>}
61
+ */
62
+ export const maxDebtForVault = (
63
+ quoteAmount,
64
+ liquidationMargin,
65
+ liquidationPadding,
66
+ ) => {
67
+ const debtByQuote = getAmountOut(quoteAmount);
68
+ const minimumCollateralization = calculateMinimumCollateralization(
69
+ liquidationMargin,
70
+ liquidationPadding,
71
+ );
72
+ // floorDivide because we want the debt ceiling lower
73
+ return floorDivideBy(debtByQuote, minimumCollateralization);
74
+ };
75
+
76
+ /**
77
+ * Calculate the fee, the amount to mint and the resulting debt.
78
+ * The give and the want together reflect a delta, where typically
79
+ * one is zero because they come from the gave/want of an offer
80
+ * proposal. If the `want` is zero, the `fee` will also be zero,
81
+ * so the simple math works.
82
+ *
83
+ * @param {Amount<'nat'>} currentDebt
84
+ * @param {Amount<'nat'>} give excess of currentDebt is returned in 'surplus'
85
+ * @param {Amount<'nat'>} want
86
+ * @param {Ratio} debtFee
87
+ */
88
+ export const calculateDebtCosts = (currentDebt, give, want, debtFee) => {
89
+ const maxGive = AmountMath.min(currentDebt, give);
90
+ const surplus = AmountMath.subtract(give, maxGive);
91
+ const fee = ceilMultiplyBy(want, debtFee);
92
+ const toMint = AmountMath.add(want, fee);
93
+ const newDebt = addSubtract(currentDebt, toMint, maxGive);
94
+ return { newDebt, toMint, fee, surplus };
95
+ };
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
  import { fromVaultKey, toVaultKey } from './storeUtils.js';
3
2
 
4
3
  /**