@agoric/inter-protocol 0.13.3-pismo-dev-50dc068.0 → 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 (141) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +26 -20
  3. package/bundles/bundle-auctioneer-js-meta.json +722 -0
  4. package/bundles/bundle-auctioneer.js +1 -0
  5. package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
  6. package/bundles/bundle-econCommitteeCharter.js +1 -0
  7. package/bundles/bundle-feeDistributor-js-meta.json +458 -0
  8. package/bundles/bundle-feeDistributor.js +1 -1
  9. package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
  10. package/bundles/bundle-fluxAggregatorKit.js +1 -0
  11. package/bundles/bundle-psm-js-meta.json +666 -0
  12. package/bundles/bundle-psm.js +1 -1
  13. package/bundles/bundle-reserve-js-meta.json +662 -0
  14. package/bundles/bundle-reserve.js +1 -1
  15. package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
  16. package/bundles/bundle-scaledPriceAuthority.js +1 -1
  17. package/bundles/bundle-vaultFactory-js-meta.json +786 -0
  18. package/bundles/bundle-vaultFactory.js +1 -1
  19. package/exported.js +0 -2
  20. package/package.json +34 -31
  21. package/scripts/add-collateral-core.js +14 -4
  22. package/scripts/build-bundles.js +9 -2
  23. package/scripts/deploy-contracts.js +1 -4
  24. package/scripts/init-core.js +20 -38
  25. package/scripts/invite-committee-core.js +1 -1
  26. package/scripts/manual-price-feed.js +2 -2
  27. package/scripts/price-feed-core.js +7 -6
  28. package/scripts/start-local-chain.sh +84 -0
  29. package/src/auction/auctionBook.js +755 -0
  30. package/src/auction/auctioneer.js +720 -0
  31. package/src/auction/offerBook.js +221 -0
  32. package/src/auction/params.js +174 -0
  33. package/src/auction/scheduleMath.js +167 -0
  34. package/src/auction/scheduler.js +370 -0
  35. package/src/auction/sortedOffers.js +136 -0
  36. package/src/auction/util.js +55 -0
  37. package/src/clientSupport.js +324 -0
  38. package/src/collectFees.js +8 -14
  39. package/src/contractSupport.js +24 -68
  40. package/src/econCommitteeCharter.js +161 -77
  41. package/src/feeDistributor.js +60 -20
  42. package/src/index.js +2 -0
  43. package/src/interest-math.js +1 -4
  44. package/src/interest.js +20 -13
  45. package/src/price/README.md +57 -0
  46. package/src/price/fluxAggregatorContract.js +190 -0
  47. package/src/price/fluxAggregatorKit.js +375 -0
  48. package/src/price/priceOracleKit.js +127 -0
  49. package/src/price/roundsManager.js +726 -0
  50. package/src/proposals/addAssetToVault.js +89 -94
  51. package/src/proposals/committee-proposal.js +141 -40
  52. package/src/proposals/core-proposal.js +100 -167
  53. package/src/proposals/econ-behaviors.js +320 -564
  54. package/src/proposals/price-feed-proposal.js +175 -78
  55. package/src/proposals/startEconCommittee.js +25 -12
  56. package/src/proposals/startPSM.js +231 -211
  57. package/src/proposals/utils.js +31 -17
  58. package/src/psm/README.md +71 -0
  59. package/src/psm/psm.js +272 -160
  60. package/src/psm/types.js +2 -0
  61. package/src/reserve/assetReserve.js +56 -413
  62. package/src/reserve/assetReserveKit.js +303 -0
  63. package/src/reserve/doc.md +1 -3
  64. package/src/reserve/params.js +2 -5
  65. package/src/typeGuards.js +13 -0
  66. package/src/vaultFactory/Liquidation.md +100 -0
  67. package/src/vaultFactory/burn.js +2 -1
  68. package/src/vaultFactory/liquidation.js +270 -108
  69. package/src/vaultFactory/math.js +95 -0
  70. package/src/vaultFactory/orderedVaultStore.js +0 -1
  71. package/src/vaultFactory/params.js +133 -112
  72. package/src/vaultFactory/prioritizedVaults.js +36 -79
  73. package/src/vaultFactory/storeUtils.js +67 -9
  74. package/src/vaultFactory/type-imports.js +2 -0
  75. package/src/vaultFactory/types.js +22 -26
  76. package/src/vaultFactory/vault.js +772 -709
  77. package/src/vaultFactory/vaultDirector.js +480 -483
  78. package/src/vaultFactory/vaultFactory.js +99 -60
  79. package/src/vaultFactory/vaultHolder.js +121 -95
  80. package/src/vaultFactory/vaultKit.js +39 -31
  81. package/src/vaultFactory/vaultManager.js +1249 -868
  82. package/bundles/bundle-amm-meta.js +0 -618
  83. package/bundles/bundle-amm.js +0 -1
  84. package/bundles/bundle-feeDistributor-meta.js +0 -346
  85. package/bundles/bundle-interchainPool-meta.js +0 -534
  86. package/bundles/bundle-interchainPool.js +0 -1
  87. package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
  88. package/bundles/bundle-liquidateIncrementally.js +0 -1
  89. package/bundles/bundle-liquidateMinimum-meta.js +0 -442
  90. package/bundles/bundle-liquidateMinimum.js +0 -1
  91. package/bundles/bundle-psm-meta.js +0 -538
  92. package/bundles/bundle-psmCharter-meta.js +0 -418
  93. package/bundles/bundle-psmCharter.js +0 -1
  94. package/bundles/bundle-reserve-meta.js +0 -542
  95. package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
  96. package/bundles/bundle-stakeFactory-meta.js +0 -574
  97. package/bundles/bundle-stakeFactory.js +0 -1
  98. package/bundles/bundle-vaultFactory-meta.js +0 -598
  99. package/scripts/add-initial-liquidity.js +0 -180
  100. package/src/collect.js +0 -13
  101. package/src/interchainPool.js +0 -135
  102. package/src/makeTracer.js +0 -36
  103. package/src/my-lien.js +0 -85
  104. package/src/proposals/demoIssuers.js +0 -685
  105. package/src/proposals/sim-behaviors.js +0 -40
  106. package/src/psm/psmCharter.js +0 -139
  107. package/src/stakeFactory/README.md +0 -62
  108. package/src/stakeFactory/attestation.js +0 -267
  109. package/src/stakeFactory/attestationTool.js +0 -66
  110. package/src/stakeFactory/constants.js +0 -16
  111. package/src/stakeFactory/params.js +0 -31
  112. package/src/stakeFactory/stakeFactory.js +0 -236
  113. package/src/stakeFactory/stakeFactoryKit.js +0 -455
  114. package/src/stakeFactory/stakeFactoryManager.js +0 -296
  115. package/src/stakeFactory/types.js +0 -42
  116. package/src/vaultFactory/liquidateIncrementally.js +0 -350
  117. package/src/vaultFactory/liquidateMinimum.js +0 -100
  118. package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
  119. package/src/vpool-xyk-amm/addLiquidity.js +0 -222
  120. package/src/vpool-xyk-amm/addPool.js +0 -197
  121. package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
  122. package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
  123. package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
  124. package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
  125. package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
  126. package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
  127. package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
  128. package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
  129. package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
  130. package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
  131. package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
  132. package/src/vpool-xyk-amm/doublePool.js +0 -194
  133. package/src/vpool-xyk-amm/estimate.js +0 -155
  134. package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
  135. package/src/vpool-xyk-amm/params.js +0 -61
  136. package/src/vpool-xyk-amm/pool.js +0 -396
  137. package/src/vpool-xyk-amm/priceAuthority.js +0 -94
  138. package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
  139. package/src/vpool-xyk-amm/singlePool.js +0 -73
  140. package/src/vpool-xyk-amm/swap.js +0 -69
  141. package/src/vpool-xyk-amm/types.js +0 -154
@@ -0,0 +1,370 @@
1
+ import { E } from '@endo/eventual-send';
2
+ import { TimeMath } from '@agoric/time';
3
+ import { Far } from '@endo/marshal';
4
+ import { makeTracer } from '@agoric/internal';
5
+ import { observeIteration, subscribeEach } from '@agoric/notifier';
6
+
7
+ import { AuctionState, makeCancelTokenMaker } from './util.js';
8
+ import {
9
+ computeRoundTiming,
10
+ nextDescendingStepTime,
11
+ timeVsSchedule,
12
+ } from './scheduleMath.js';
13
+
14
+ const { details: X, Fail, quote: q } = assert;
15
+
16
+ const trace = makeTracer('SCHED', true);
17
+
18
+ // If the startAuction wakeup is no more than 5 minutes late, go ahead with it.
19
+ const MAX_LATE_TICK = 300n;
20
+
21
+ /**
22
+ * @file The scheduler is presumed to be quiescent between auction rounds. Each
23
+ * Auction round consists of a sequence of steps with decreasing prices. There
24
+ * should always be a next schedule, but between rounds, liveSchedule is null.
25
+ *
26
+ * The lock period that the liquidators use might start before the previous
27
+ * round has finished, so we need to schedule the next round each time an
28
+ * auction starts. This means if the scheduling parameters change, it'll be a
29
+ * full cycle before we switch. Otherwise, the vaults wouldn't know when to
30
+ * start their lock period. If the lock period for the next auction hasn't
31
+ * started when each aucion ends, we recalculate it, in case the parameters have
32
+ * changed.
33
+ *
34
+ * If the clock skips forward (because of a chain halt, for instance), the
35
+ * scheduler will try to cleanly and quickly finish any round already in
36
+ * progress. It would take additional work on the manual timer to test this
37
+ * thoroughly.
38
+ */
39
+
40
+ const makeCancelToken = makeCancelTokenMaker('scheduler');
41
+
42
+ /**
43
+ * @typedef {object} AuctionDriver
44
+ * @property {() => void} reducePriceAndTrade
45
+ * @property {() => void} finalize
46
+ * @property {() => void} startRound
47
+ * @property {() => void} capturePrices
48
+ */
49
+
50
+ /**
51
+ * @typedef {object} ScheduleNotification
52
+ *
53
+ * @property {Timestamp | null} activeStartTime start time of current
54
+ * auction if auction is active
55
+ * @property {Timestamp | null} nextStartTime start time of next auction
56
+ * @property {Timestamp | null} nextDescendingStepTime when the next descending step
57
+ * will take place
58
+ */
59
+
60
+ const safelyComputeRoundTiming = (params, baseTime) => {
61
+ try {
62
+ return computeRoundTiming(params, baseTime);
63
+ } catch (e) {
64
+ console.error('🚨 No Next Auction', e);
65
+ return null;
66
+ }
67
+ };
68
+
69
+ const nominalStartTime = nextSchedule =>
70
+ TimeMath.subtractAbsRel(nextSchedule.startTime, nextSchedule.startDelay);
71
+
72
+ /**
73
+ * @param {AuctionDriver} auctionDriver
74
+ * @param {import('@agoric/time/src/types').TimerService} timer
75
+ * @param {Awaited<import('./params.js').AuctionParamManager>} params
76
+ * @param {import('@agoric/time/src/types').TimerBrand} timerBrand
77
+ * @param {import('@agoric/zoe/src/contractSupport/recorder.js').Recorder<ScheduleNotification>} scheduleRecorder
78
+ * @param {StoredSubscription<GovernanceSubscriptionState>} paramUpdateSubscription
79
+ */
80
+ export const makeScheduler = async (
81
+ auctionDriver,
82
+ timer,
83
+ params,
84
+ timerBrand,
85
+ scheduleRecorder,
86
+ paramUpdateSubscription,
87
+ ) => {
88
+ /**
89
+ * live version is defined when an auction is active.
90
+ *
91
+ * @type {Schedule | null}
92
+ */
93
+ let liveSchedule = null;
94
+
95
+ /** @returns {Promise<{ now: Timestamp, nextSchedule: Schedule | null }>} */
96
+ const initializeNextSchedule = async () => {
97
+ return E.when(
98
+ // XXX manualTimer returns a bigint, not a timeRecord.
99
+ E(timer).getCurrentTimestamp(),
100
+ now => {
101
+ const nextSchedule = safelyComputeRoundTiming(
102
+ params,
103
+ TimeMath.coerceTimestampRecord(now, timerBrand),
104
+ );
105
+ return { now, nextSchedule };
106
+ },
107
+ );
108
+ };
109
+ let { now, nextSchedule } = await initializeNextSchedule();
110
+ const setTimeMonotonically = time => {
111
+ TimeMath.compareAbs(time, now) >= 0 || Fail`Time only moves forward`;
112
+ now = time;
113
+ };
114
+
115
+ const stepCancelToken = makeCancelToken();
116
+
117
+ /** @type {typeof AuctionState[keyof typeof AuctionState]} */
118
+ let auctionState = AuctionState.WAITING;
119
+
120
+ /**
121
+ * Publish the schedule. To be called after clockTick() (which processes a
122
+ * descending step) or when the next round is scheduled.
123
+ */
124
+ const publishSchedule = () => {
125
+ const sched = harden({
126
+ activeStartTime: liveSchedule?.startTime || null,
127
+ nextStartTime: nextSchedule?.startTime || null,
128
+ nextDescendingStepTime: nextDescendingStepTime(
129
+ liveSchedule,
130
+ nextSchedule,
131
+ now,
132
+ ),
133
+ });
134
+ return scheduleRecorder.write(sched);
135
+ };
136
+
137
+ /**
138
+ * @param {Schedule | null} schedule
139
+ * @returns {void}
140
+ */
141
+ const clockTick = schedule => {
142
+ trace('clockTick', schedule?.startTime, now);
143
+ if (!schedule) {
144
+ return;
145
+ }
146
+
147
+ /** @type {() => void} */
148
+ const finishAuctionRound = () => {
149
+ auctionState = AuctionState.WAITING;
150
+ auctionDriver.finalize();
151
+
152
+ if (nextSchedule) {
153
+ // only recalculate the next schedule at this point if the lock time has
154
+ // not been reached.
155
+ const nextLock = nextSchedule.lockTime;
156
+ if (nextLock && TimeMath.compareAbs(now, nextLock) < 0) {
157
+ const afterNow = TimeMath.addAbsRel(
158
+ now,
159
+ TimeMath.coerceRelativeTimeRecord(1n, timerBrand),
160
+ );
161
+ nextSchedule = safelyComputeRoundTiming(params, afterNow);
162
+ }
163
+ } else {
164
+ console.error(
165
+ '🛠️ finishAuctionRound without scheduling the next; repair with new auctioneer params',
166
+ );
167
+ }
168
+
169
+ liveSchedule = null;
170
+
171
+ // Async because a remote call. In rare event of failure, wakeup is robust.
172
+ void E(timer).cancel(stepCancelToken);
173
+ };
174
+
175
+ const advanceRound = () => {
176
+ if (auctionState === AuctionState.ACTIVE) {
177
+ auctionDriver.reducePriceAndTrade();
178
+ } else {
179
+ auctionState = AuctionState.ACTIVE;
180
+ try {
181
+ auctionDriver.startRound();
182
+ // This has been observed to fail because prices hadn't been locked.
183
+ // This may be an issue about timing during chain start-up.
184
+ } catch (err) {
185
+ console.error(
186
+ 'Unable to start auction cleanly. skipping this auction round.',
187
+ err,
188
+ );
189
+ }
190
+ }
191
+ };
192
+
193
+ switch (timeVsSchedule(now, schedule)) {
194
+ case 'before':
195
+ break;
196
+ case 'during':
197
+ advanceRound();
198
+ break;
199
+ case 'endExactly':
200
+ // do both the "during" and "after" behaviors
201
+ advanceRound();
202
+ finishAuctionRound();
203
+ break;
204
+ case 'after':
205
+ finishAuctionRound();
206
+ break;
207
+ default:
208
+ Fail`invalid case`;
209
+ }
210
+
211
+ void publishSchedule();
212
+ };
213
+
214
+ // set wakeups for the steps of this round
215
+ const scheduleDescendingSteps = () => {
216
+ if (!liveSchedule) {
217
+ console.error('🚨 scheduleDescendingSteps called with no liveSchedule');
218
+ return;
219
+ }
220
+
221
+ const { startTime } = liveSchedule;
222
+ trace('START ', startTime);
223
+
224
+ const delayFromNow =
225
+ TimeMath.compareAbs(startTime, now) > 0
226
+ ? TimeMath.subtractAbsAbs(startTime, now)
227
+ : TimeMath.subtractAbsAbs(startTime, startTime);
228
+
229
+ trace('scheduleDescendingSteps repeating', now, delayFromNow, startTime);
230
+
231
+ void E(timer).repeatAfter(
232
+ delayFromNow,
233
+ liveSchedule.clockStep,
234
+ Far('PriceStepWaker', {
235
+ wake(time) {
236
+ setTimeMonotonically(time);
237
+ trace('wake step', now);
238
+ void clockTick(liveSchedule);
239
+ },
240
+ }),
241
+ stepCancelToken,
242
+ );
243
+ };
244
+
245
+ // schedule a wakeup for the next round
246
+ const scheduleNextRound = start => {
247
+ trace(`nextRound`, start);
248
+ void E(timer).setWakeup(
249
+ start,
250
+ Far('SchedulerWaker', {
251
+ wake(time) {
252
+ setTimeMonotonically(time);
253
+ auctionDriver.capturePrices();
254
+ // eslint-disable-next-line no-use-before-define
255
+ return startAuction();
256
+ },
257
+ }),
258
+ );
259
+ void publishSchedule();
260
+ };
261
+
262
+ const relativeTime = t => TimeMath.coerceRelativeTimeRecord(t, timerBrand);
263
+
264
+ const startAuction = async () => {
265
+ !liveSchedule || Fail`can't start an auction round while one is active`;
266
+
267
+ if (!nextSchedule) {
268
+ console.error(
269
+ assert.error(X`tried to start auction when none is scheduled`),
270
+ );
271
+ return;
272
+ }
273
+
274
+ // The clock tick may have arrived too late to trigger the next scheduled
275
+ // round, for example because of a chain halt. When this happens the oracle
276
+ // quote may out of date and so must be ignored. Recover by returning
277
+ // deposits and scheduling the next round. If it's only a little late,
278
+ // continue with auction, just starting late.
279
+ const nominalStart = nominalStartTime(nextSchedule);
280
+ if (TimeMath.compareAbs(now, nominalStart) > 0) {
281
+ const late = TimeMath.subtractAbsAbs(now, nominalStart);
282
+ const maxLate = relativeTime(MAX_LATE_TICK);
283
+
284
+ if (TimeMath.compareRel(late, maxLate) > 0) {
285
+ console.warn(
286
+ `Auction time jumped to ${q(now)} before next scheduled start ${q(
287
+ nextSchedule.startTime,
288
+ )}. Skipping that round.`,
289
+ );
290
+ nextSchedule = safelyComputeRoundTiming(params, now);
291
+ } else {
292
+ console.warn(`Auction started late by ${q(late)}. Starting ${q(now)}`);
293
+ }
294
+ }
295
+
296
+ if (!nextSchedule) {
297
+ // nothing new to schedule
298
+ return;
299
+ }
300
+ // activate the nextSchedule as the live one
301
+ // (read here and in function calls below)
302
+ liveSchedule = nextSchedule;
303
+ scheduleDescendingSteps();
304
+ nextSchedule = safelyComputeRoundTiming(
305
+ params,
306
+ TimeMath.addAbsRel(liveSchedule.endTime, relativeTime(1n)),
307
+ );
308
+
309
+ if (nextSchedule) {
310
+ scheduleNextRound(nominalStartTime(nextSchedule));
311
+ } else {
312
+ console.warn(
313
+ 'no nextSchedule so cannot schedule next round or price capture',
314
+ );
315
+ }
316
+ };
317
+
318
+ // initial setting: firstStart is startDelay before next's startTime
319
+ const startSchedulingFromScratch = () => {
320
+ trace('startSchedulingFromScratch');
321
+ if (nextSchedule) {
322
+ scheduleNextRound(nominalStartTime(nextSchedule));
323
+ }
324
+ };
325
+ startSchedulingFromScratch();
326
+
327
+ // when auction parameters change, schedule a next auction if one isn't
328
+ // already scheduled.
329
+ // NB: what is already scheduled (live or next) is unaffected by param changes
330
+ void observeIteration(
331
+ subscribeEach(paramUpdateSubscription),
332
+ harden({
333
+ // NB: may be fired with the initial params as well
334
+ async updateState(_newState) {
335
+ trace('received param update', _newState);
336
+ if (!nextSchedule) {
337
+ trace('repairing nextSchedule and restarting');
338
+ ({ nextSchedule } = await initializeNextSchedule());
339
+ startSchedulingFromScratch();
340
+ }
341
+ },
342
+ }),
343
+ );
344
+
345
+ return Far('scheduler', {
346
+ getSchedule: () =>
347
+ harden({
348
+ liveAuctionSchedule: liveSchedule,
349
+ nextAuctionSchedule: nextSchedule,
350
+ }),
351
+ getAuctionState: () => auctionState,
352
+ });
353
+ };
354
+
355
+ /**
356
+ * @typedef {object} Schedule
357
+ * @property {import('@agoric/time/src/types').TimestampRecord} startTime
358
+ * @property {import('@agoric/time/src/types').TimestampRecord} endTime
359
+ * @property {NatValue} steps
360
+ * @property {NatValue} endRate
361
+ * @property {RelativeTime} startDelay
362
+ * @property {RelativeTime} clockStep
363
+ * @property {Timestamp} [lockTime]
364
+ */
365
+
366
+ /**
367
+ * @typedef {object} FullSchedule
368
+ * @property {Schedule | null} nextAuctionSchedule
369
+ * @property {Schedule | null} liveAuctionSchedule
370
+ */
@@ -0,0 +1,136 @@
1
+ // @jessie-check
2
+
3
+ import {
4
+ makeRatio,
5
+ ratioToNumber,
6
+ } from '@agoric/zoe/src/contractSupport/index.js';
7
+ import { M, mustMatch } from '@agoric/store';
8
+ import { RatioShape } from '@agoric/ertp';
9
+
10
+ import { decodeData, encodeData } from '../vaultFactory/storeUtils.js';
11
+
12
+ const { Fail } = assert;
13
+
14
+ /**
15
+ * @file we use a floating point representation of the price or rate as the
16
+ * first part of the key in the store. The second part is the sequence number of
17
+ * the bid, but it doesn't matter for sorting. When we retrieve multiple bids,
18
+ * it's only by bid value, so we don't care how the sequence numbers sort.
19
+ *
20
+ * We take advantage of the fact that encodeData takes a passable and turns it
21
+ * into a sort key. Arrays of passable data sort like composite keys.
22
+ */
23
+
24
+ /**
25
+ * Return a sort key that will compare based only on price. Price is the prefix
26
+ * of the complete sort key, which is sufficient to find offers below a cutoff.
27
+ *
28
+ * @param {Ratio} offerPrice
29
+ */
30
+ export const toPartialOfferKey = offerPrice => {
31
+ assert(offerPrice);
32
+ const mostSignificantPart = ratioToNumber(offerPrice);
33
+ return encodeData(harden([mostSignificantPart, 0n]));
34
+ };
35
+
36
+ /**
37
+ * Return a sort key that distinguishes by Price and sequence number
38
+ *
39
+ * @param {Ratio} offerPrice IST/collateral
40
+ * @param {bigint} sequenceNumber
41
+ * @returns {string} lexically sortable string in which highest price is first,
42
+ * ties will be broken by sequenceNumber of offer
43
+ */
44
+ export const toPriceOfferKey = (offerPrice, sequenceNumber) => {
45
+ mustMatch(offerPrice, RatioShape);
46
+ offerPrice.numerator.brand !== offerPrice.denominator.brand ||
47
+ Fail`offer prices must have different numerator and denominator`;
48
+ mustMatch(sequenceNumber, M.nat());
49
+
50
+ const mostSignificantPart = ratioToNumber(offerPrice);
51
+ return encodeData(harden([mostSignificantPart, sequenceNumber]));
52
+ };
53
+
54
+ /**
55
+ * @param {number} floatPrice
56
+ * @param {Brand<'nat'>} numBrand
57
+ * @param {Brand<'nat'>} denomBrand
58
+ * @param {number} useDecimals
59
+ * @returns {Ratio}
60
+ */
61
+ const priceRatioFromFloat = (floatPrice, numBrand, denomBrand, useDecimals) => {
62
+ const denominatorValue = 10 ** useDecimals;
63
+ return makeRatio(
64
+ BigInt(Math.round(floatPrice * denominatorValue)),
65
+ numBrand,
66
+ BigInt(denominatorValue),
67
+ denomBrand,
68
+ );
69
+ };
70
+
71
+ const bidScalingRatioFromKey = (bidScaleFloat, numBrand, useDecimals) => {
72
+ const denominatorValue = 10 ** useDecimals;
73
+ return makeRatio(
74
+ BigInt(Math.round(bidScaleFloat * denominatorValue)),
75
+ numBrand,
76
+ BigInt(denominatorValue),
77
+ );
78
+ };
79
+
80
+ /**
81
+ * fromPriceOfferKey is only used for diagnostics.
82
+ *
83
+ * @param {string} key
84
+ * @param {Brand<'nat'>} numBrand
85
+ * @param {Brand<'nat'>} denomBrand
86
+ * @param {number} useDecimals
87
+ * @returns {[normalizedPrice: Ratio, sequenceNumber: bigint]}
88
+ */
89
+ export const fromPriceOfferKey = (key, numBrand, denomBrand, useDecimals) => {
90
+ const [pricePart, sequenceNumberPart] = decodeData(key);
91
+ return [
92
+ priceRatioFromFloat(pricePart, numBrand, denomBrand, useDecimals),
93
+ sequenceNumberPart,
94
+ ];
95
+ };
96
+
97
+ /** @type {(rate: Ratio) => string} */
98
+ export const toBidScalingComparator = rate => {
99
+ assert(rate);
100
+ const mostSignificantPart = ratioToNumber(rate);
101
+ return encodeData(harden([mostSignificantPart, 0n]));
102
+ };
103
+
104
+ /**
105
+ * Sorts offers expressed as percentage of the current oracle price.
106
+ *
107
+ * @param {Ratio} rate discount/markup rate expressed as a ratio IST/IST
108
+ * @param {bigint} sequenceNumber
109
+ * @returns {string} lexically sortable string in which highest price is first,
110
+ * ties will be broken by sequenceNumber of offer
111
+ */
112
+ export const toScaledRateOfferKey = (rate, sequenceNumber) => {
113
+ mustMatch(rate, RatioShape);
114
+ rate.numerator.brand === rate.denominator.brand ||
115
+ Fail`bid scaling rate must have the same numerator and denominator`;
116
+ mustMatch(sequenceNumber, M.nat());
117
+
118
+ const mostSignificantPart = ratioToNumber(rate);
119
+ return encodeData(harden([mostSignificantPart, sequenceNumber]));
120
+ };
121
+
122
+ /**
123
+ * fromScaledRateOfferKey is only used for diagnostics.
124
+ *
125
+ * @param {string} key
126
+ * @param {Brand} brand
127
+ * @param {number} useDecimals
128
+ * @returns {[normalizedPrice: Ratio, sequenceNumber: bigint]}
129
+ */
130
+ export const fromScaledRateOfferKey = (key, brand, useDecimals) => {
131
+ const [bidScalingPart, sequenceNumberPart] = decodeData(key);
132
+ return [
133
+ bidScalingRatioFromKey(bidScalingPart, brand, useDecimals),
134
+ sequenceNumberPart,
135
+ ];
136
+ };
@@ -0,0 +1,55 @@
1
+ // @jessie-check
2
+
3
+ import {
4
+ makeRatioFromAmounts,
5
+ multiplyRatios,
6
+ ratioGTE,
7
+ } from '@agoric/zoe/src/contractSupport/index.js';
8
+ import { Far } from '@endo/marshal';
9
+
10
+ /**
11
+ * Constants for Auction State.
12
+ *
13
+ * @type {{ ACTIVE: 'active', WAITING: 'waiting' }}
14
+ */
15
+ export const AuctionState = {
16
+ ACTIVE: 'active',
17
+ WAITING: 'waiting',
18
+ };
19
+
20
+ /**
21
+ * @param {{ brand: Brand, value: Pattern }} numeratorAmountShape
22
+ * @param {{ brand: Brand, value: Pattern }} denominatorAmountShape
23
+ */
24
+ export const makeBrandedRatioPattern = (
25
+ numeratorAmountShape,
26
+ denominatorAmountShape,
27
+ ) => {
28
+ return harden({
29
+ numerator: numeratorAmountShape,
30
+ denominator: denominatorAmountShape,
31
+ });
32
+ };
33
+
34
+ /**
35
+ * @param {Ratio} bidScaling
36
+ * @param {Ratio} currentPrice
37
+ * @param {Ratio} oraclePrice
38
+ * @returns {boolean} TRUE iff the discount(/markup) applied to the price is
39
+ * higher than the quote.
40
+ */
41
+ export const isScaledBidPriceHigher = (bidScaling, currentPrice, oraclePrice) =>
42
+ ratioGTE(multiplyRatios(oraclePrice, bidScaling), currentPrice);
43
+
44
+ /** @type {(quote: PriceQuote) => Ratio} */
45
+ export const priceFrom = quote =>
46
+ makeRatioFromAmounts(
47
+ quote.quoteAmount.value[0].amountOut,
48
+ quote.quoteAmount.value[0].amountIn,
49
+ );
50
+
51
+ export const makeCancelTokenMaker = name => {
52
+ let tokenCount = 1;
53
+
54
+ return () => Far(`cancelToken-${name}-${(tokenCount += 1)}`, {});
55
+ };