@agoric/inter-protocol 0.13.4-pismo-dev-0d5327f.0 → 0.14.1-dev-bf4b59f.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 +287 -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,221 @@
1
+ // book of offers to buy liquidating vaults with prices in terms of
2
+ // discount/markup from the current oracle price.
3
+
4
+ import { AmountMath } from '@agoric/ertp';
5
+ import { M, mustMatch } from '@agoric/store';
6
+ import { makeScalarBigMapStore, prepareExoClass } from '@agoric/vat-data';
7
+
8
+ import {
9
+ toBidScalingComparator,
10
+ toPartialOfferKey,
11
+ toPriceOfferKey,
12
+ toScaledRateOfferKey,
13
+ } from './sortedOffers.js';
14
+
15
+ /** @typedef {import('@agoric/vat-data').Baggage} Baggage */
16
+
17
+ // multiple offers might be provided at the same time (since the time
18
+ // granularity is limited to blocks), so we increment a sequenceNumber with each
19
+ // offer for uniqueness.
20
+ let latestSequenceNumber = 0n;
21
+ const nextSequenceNumber = () => {
22
+ latestSequenceNumber += 1n;
23
+ return latestSequenceNumber;
24
+ };
25
+
26
+ /**
27
+ * @typedef {{
28
+ * seat: ZCFSeat,
29
+ * wanted: Amount<'nat'>,
30
+ * seqNum: NatValue,
31
+ * received: Amount<'nat'>,
32
+ * } & {exitAfterBuy: boolean} & ({ bidScaling: Pattern, price: undefined } | { bidScaling: undefined, price: Ratio})
33
+ * } BidderRecord
34
+ */
35
+
36
+ const ScaledBidBookStateShape = harden({
37
+ bidScalingPattern: M.any(),
38
+ collateralBrand: M.any(),
39
+ records: M.any(),
40
+ });
41
+
42
+ /**
43
+ * Prices in this book are expressed as percentage of the full oracle price
44
+ * snapshot taken when the auction started. .4 is 60% off. 1.1 is 10% above par.
45
+ *
46
+ * @param {Baggage} baggage
47
+ */
48
+ export const prepareScaledBidBook = baggage =>
49
+ prepareExoClass(
50
+ baggage,
51
+ 'scaledBidBook',
52
+ undefined,
53
+ /**
54
+ *
55
+ * @param {Pattern} bidScalingPattern
56
+ * @param {Brand} collateralBrand
57
+ */
58
+ (bidScalingPattern, collateralBrand) => ({
59
+ bidScalingPattern,
60
+ collateralBrand,
61
+ /** @type {MapStore<string, BidderRecord>} */
62
+ records: makeScalarBigMapStore('scaledBidRecords', { durable: true }),
63
+ }),
64
+ {
65
+ /**
66
+ * @param {ZCFSeat} seat
67
+ * @param {Ratio} bidScaling
68
+ * @param {Amount<'nat'>} wanted
69
+ * @param {boolean} exitAfterBuy
70
+ */
71
+ add(seat, bidScaling, wanted, exitAfterBuy) {
72
+ const { bidScalingPattern, collateralBrand, records } = this.state;
73
+ mustMatch(bidScaling, bidScalingPattern);
74
+
75
+ const seqNum = nextSequenceNumber();
76
+ const key = toScaledRateOfferKey(bidScaling, seqNum);
77
+ const empty = AmountMath.makeEmpty(collateralBrand);
78
+ /** @type {BidderRecord} */
79
+ const bidderRecord = {
80
+ bidScaling,
81
+ price: undefined,
82
+ received: empty,
83
+ seat,
84
+ seqNum,
85
+ wanted,
86
+ exitAfterBuy,
87
+ };
88
+ records.init(key, harden(bidderRecord));
89
+ return key;
90
+ },
91
+ /** @param {Ratio} bidScaling */
92
+ offersAbove(bidScaling) {
93
+ const { records } = this.state;
94
+ return [...records.entries(M.gte(toBidScalingComparator(bidScaling)))];
95
+ },
96
+ hasOrders() {
97
+ const { records } = this.state;
98
+ return records.getSize() > 0;
99
+ },
100
+ delete(key) {
101
+ const { records } = this.state;
102
+ records.delete(key);
103
+ },
104
+ updateReceived(key, sold) {
105
+ const { records } = this.state;
106
+ const oldRec = records.get(key);
107
+ records.set(
108
+ key,
109
+ harden({
110
+ ...oldRec,
111
+ received: AmountMath.add(oldRec.received, sold),
112
+ }),
113
+ );
114
+ },
115
+ exitAllSeats() {
116
+ const { records } = this.state;
117
+ for (const [key, { seat }] of records.entries()) {
118
+ if (!seat.hasExited()) {
119
+ seat.exit();
120
+ records.delete(key);
121
+ }
122
+ }
123
+ },
124
+ },
125
+ {
126
+ stateShape: ScaledBidBookStateShape,
127
+ },
128
+ );
129
+
130
+ const PriceBookStateShape = harden({
131
+ priceRatioPattern: M.any(),
132
+ collateralBrand: M.any(),
133
+ records: M.any(),
134
+ });
135
+
136
+ /**
137
+ * Prices in this book are actual prices expressed in terms of bid amount
138
+ * and collateral amount.
139
+ *
140
+ * @param {Baggage} baggage
141
+ */
142
+ export const preparePriceBook = baggage =>
143
+ prepareExoClass(
144
+ baggage,
145
+ 'priceBook',
146
+ undefined,
147
+ /**
148
+ *
149
+ * @param {Pattern} priceRatioPattern
150
+ * @param {Brand} collateralBrand
151
+ */
152
+ (priceRatioPattern, collateralBrand) => ({
153
+ priceRatioPattern,
154
+ collateralBrand,
155
+ /** @type {MapStore<string, BidderRecord>} */
156
+ records: makeScalarBigMapStore('scaledBidRecords', { durable: true }),
157
+ }),
158
+ {
159
+ /**
160
+ * @param {ZCFSeat} seat
161
+ * @param {Ratio} price
162
+ * @param {Amount<'nat'>} wanted
163
+ * @param {boolean} exitAfterBuy
164
+ */
165
+ add(seat, price, wanted, exitAfterBuy) {
166
+ const { priceRatioPattern, collateralBrand, records } = this.state;
167
+ mustMatch(price, priceRatioPattern);
168
+
169
+ const seqNum = nextSequenceNumber();
170
+ const key = toPriceOfferKey(price, seqNum);
171
+ const empty = AmountMath.makeEmpty(collateralBrand);
172
+ /** @type {BidderRecord} */
173
+ const bidderRecord = {
174
+ bidScaling: undefined,
175
+ price,
176
+ received: empty,
177
+ seat,
178
+ seqNum,
179
+ wanted,
180
+ exitAfterBuy,
181
+ };
182
+ records.init(key, harden(bidderRecord));
183
+ return key;
184
+ },
185
+ offersAbove(price) {
186
+ const { records } = this.state;
187
+ return [...records.entries(M.gte(toPartialOfferKey(price)))];
188
+ },
189
+ hasOrders() {
190
+ const { records } = this.state;
191
+ return records.getSize() > 0;
192
+ },
193
+ delete(key) {
194
+ const { records } = this.state;
195
+ records.delete(key);
196
+ },
197
+ updateReceived(key, sold) {
198
+ const { records } = this.state;
199
+ const oldRec = records.get(key);
200
+ records.set(
201
+ key,
202
+ harden({
203
+ ...oldRec,
204
+ received: AmountMath.add(oldRec.received, sold),
205
+ }),
206
+ );
207
+ },
208
+ exitAllSeats() {
209
+ const { records } = this.state;
210
+ for (const [key, { seat }] of records.entries()) {
211
+ if (!seat.hasExited()) {
212
+ seat.exit();
213
+ records.delete(key);
214
+ }
215
+ }
216
+ },
217
+ },
218
+ {
219
+ stateShape: PriceBookStateShape,
220
+ },
221
+ );
@@ -0,0 +1,174 @@
1
+ import {
2
+ CONTRACT_ELECTORATE,
3
+ makeParamManager,
4
+ ParamTypes,
5
+ } from '@agoric/governance';
6
+ import { TimeMath, RelativeTimeRecordShape } from '@agoric/time';
7
+ import { M } from '@agoric/store';
8
+
9
+ /** @typedef {import('@agoric/governance/src/contractGovernance/typedParamManager.js').AsyncSpecTuple} AsyncSpecTuple */
10
+ /** @typedef {import('@agoric/governance/src/contractGovernance/typedParamManager.js').SyncSpecTuple} SyncSpecTuple */
11
+
12
+ // TODO duplicated with zoe/src/TypeGuards.js
13
+ export const InvitationShape = M.remotable('Invitation');
14
+
15
+ /**
16
+ * In seconds, how often to start an auction. The auction will start at
17
+ * AUCTION_START_DELAY seconds after a multiple of START_FREQUENCY, with the
18
+ * price at STARTING_RATE_BP. Every CLOCK_STEP, the price will be reduced by
19
+ * DISCOUNT_STEP_BP, as long as the rate is at or above LOWEST_RATE_BP, or until
20
+ * START_FREQUENCY has elapsed.
21
+ */
22
+ export const START_FREQUENCY = 'StartFrequency';
23
+ /** in seconds, how often to reduce the price */
24
+ export const CLOCK_STEP = 'ClockStep';
25
+ /** discount or markup for starting price in basis points. 9999 = 1bp discount */
26
+ export const STARTING_RATE_BP = 'StartingRate';
27
+ /** A limit below which the price will not be discounted. */
28
+ export const LOWEST_RATE_BP = 'LowestRate';
29
+ /** amount to reduce prices each time step in bp, as % of the start price */
30
+ export const DISCOUNT_STEP_BP = 'DiscountStep';
31
+ /**
32
+ * VaultManagers liquidate vaults at a frequency configured by START_FREQUENCY.
33
+ * Auctions start this long after the hour to give vaults time to finish.
34
+ */
35
+ export const AUCTION_START_DELAY = 'AuctionStartDelay';
36
+
37
+ // /////// used by VaultDirector /////////////////////
38
+ // time before each auction that the prices are locked.
39
+ export const PRICE_LOCK_PERIOD = 'PriceLockPeriod';
40
+
41
+ export const auctioneerParamPattern = M.splitRecord({
42
+ [CONTRACT_ELECTORATE]: InvitationShape,
43
+ [START_FREQUENCY]: RelativeTimeRecordShape,
44
+ [CLOCK_STEP]: RelativeTimeRecordShape,
45
+ [STARTING_RATE_BP]: M.nat(),
46
+ [LOWEST_RATE_BP]: M.nat(),
47
+ [DISCOUNT_STEP_BP]: M.nat(),
48
+ [AUCTION_START_DELAY]: RelativeTimeRecordShape,
49
+ [PRICE_LOCK_PERIOD]: RelativeTimeRecordShape,
50
+ });
51
+
52
+ export const auctioneerParamTypes = harden({
53
+ [CONTRACT_ELECTORATE]: ParamTypes.INVITATION,
54
+ [START_FREQUENCY]: ParamTypes.RELATIVE_TIME,
55
+ [CLOCK_STEP]: ParamTypes.RELATIVE_TIME,
56
+ [STARTING_RATE_BP]: ParamTypes.NAT,
57
+ [LOWEST_RATE_BP]: ParamTypes.NAT,
58
+ [DISCOUNT_STEP_BP]: ParamTypes.NAT,
59
+ [AUCTION_START_DELAY]: ParamTypes.RELATIVE_TIME,
60
+ [PRICE_LOCK_PERIOD]: ParamTypes.RELATIVE_TIME,
61
+ });
62
+
63
+ /**
64
+ * @typedef {object} AuctionParams
65
+ * @property {Amount<'set'>} ElectorateInvitationAmount
66
+ * @property {RelativeTime} StartFrequency
67
+ * @property {RelativeTime} ClockStep
68
+ * @property {bigint} StartingRate
69
+ * @property {bigint} LowestRate
70
+ * @property {bigint} DiscountStep
71
+ * @property {RelativeTime} AuctionStartDelay
72
+ * @property {RelativeTime} PriceLockPeriod
73
+ * @property {import('@agoric/time/src/types').TimerBrand} TimerBrand
74
+ */
75
+
76
+ /**
77
+ * @param {AuctionParams} initial
78
+ */
79
+ export const makeAuctioneerParams = ({
80
+ ElectorateInvitationAmount,
81
+ StartFrequency,
82
+ ClockStep,
83
+ LowestRate,
84
+ StartingRate,
85
+ DiscountStep,
86
+ AuctionStartDelay,
87
+ PriceLockPeriod,
88
+ TimerBrand,
89
+ }) => {
90
+ return harden({
91
+ [CONTRACT_ELECTORATE]: {
92
+ type: ParamTypes.INVITATION,
93
+ value: ElectorateInvitationAmount,
94
+ },
95
+ [START_FREQUENCY]: {
96
+ type: ParamTypes.RELATIVE_TIME,
97
+ value: TimeMath.coerceRelativeTimeRecord(StartFrequency, TimerBrand),
98
+ },
99
+ [CLOCK_STEP]: {
100
+ type: ParamTypes.RELATIVE_TIME,
101
+ value: TimeMath.coerceRelativeTimeRecord(ClockStep, TimerBrand),
102
+ },
103
+ [AUCTION_START_DELAY]: {
104
+ type: ParamTypes.RELATIVE_TIME,
105
+ value: TimeMath.coerceRelativeTimeRecord(AuctionStartDelay, TimerBrand),
106
+ },
107
+ [PRICE_LOCK_PERIOD]: {
108
+ type: ParamTypes.RELATIVE_TIME,
109
+ value: TimeMath.coerceRelativeTimeRecord(PriceLockPeriod, TimerBrand),
110
+ },
111
+ [STARTING_RATE_BP]: { type: ParamTypes.NAT, value: StartingRate },
112
+ [LOWEST_RATE_BP]: { type: ParamTypes.NAT, value: LowestRate },
113
+ [DISCOUNT_STEP_BP]: { type: ParamTypes.NAT, value: DiscountStep },
114
+ });
115
+ };
116
+ harden(makeAuctioneerParams);
117
+
118
+ /**
119
+ * @param {import('@agoric/notifier').StoredPublisherKit<GovernanceSubscriptionState>} publisherKit
120
+ * @param {ZCF} zcf
121
+ * @param {AuctionParams} initial
122
+ */
123
+ export const makeAuctioneerParamManager = (publisherKit, zcf, initial) => {
124
+ return makeParamManager(
125
+ publisherKit,
126
+ {
127
+ [CONTRACT_ELECTORATE]: [
128
+ ParamTypes.INVITATION,
129
+ initial[CONTRACT_ELECTORATE],
130
+ ],
131
+ [START_FREQUENCY]: [ParamTypes.RELATIVE_TIME, initial[START_FREQUENCY]],
132
+ [CLOCK_STEP]: [ParamTypes.RELATIVE_TIME, initial[CLOCK_STEP]],
133
+ [STARTING_RATE_BP]: [ParamTypes.NAT, initial[STARTING_RATE_BP]],
134
+ [LOWEST_RATE_BP]: [ParamTypes.NAT, initial[LOWEST_RATE_BP]],
135
+ [DISCOUNT_STEP_BP]: [ParamTypes.NAT, initial[DISCOUNT_STEP_BP]],
136
+ [AUCTION_START_DELAY]: [
137
+ ParamTypes.RELATIVE_TIME,
138
+ initial[AUCTION_START_DELAY],
139
+ ],
140
+ [PRICE_LOCK_PERIOD]: [
141
+ ParamTypes.RELATIVE_TIME,
142
+ initial[PRICE_LOCK_PERIOD],
143
+ ],
144
+ },
145
+ zcf,
146
+ );
147
+ };
148
+ harden(makeAuctioneerParamManager);
149
+
150
+ /**
151
+ * @param {{storageNode: ERef<StorageNode>, marshaller: ERef<Marshaller>}} caps
152
+ * @param {ERef<Timer>} timer
153
+ * @param {ERef<PriceAuthority>} priceAuthority
154
+ * @param {ERef<AssetReservePublicFacet>} reservePublicFacet
155
+ * @param {AuctionParams} params
156
+ */
157
+ export const makeGovernedTerms = (
158
+ { storageNode: _storageNode, marshaller: _marshaller },
159
+ timer,
160
+ priceAuthority,
161
+ reservePublicFacet,
162
+ params,
163
+ ) => {
164
+ // XXX use storageNode and Marshaller
165
+ return harden({
166
+ priceAuthority,
167
+ reservePublicFacet,
168
+ timerService: timer,
169
+ governedParams: makeAuctioneerParams(params),
170
+ });
171
+ };
172
+ harden(makeGovernedTerms);
173
+
174
+ /** @typedef {ReturnType<typeof makeAuctioneerParamManager>} AuctionParamManager */
@@ -0,0 +1,167 @@
1
+ // @jessie-check
2
+
3
+ import { TimeMath } from '@agoric/time';
4
+ import { natSafeMath } from '@agoric/zoe/src/contractSupport/index.js';
5
+ import { assertAllDefined, makeTracer } from '@agoric/internal';
6
+
7
+ const { subtract, multiply, floorDivide } = natSafeMath;
8
+ const { Fail } = assert;
9
+
10
+ const trace = makeTracer('SMath', true);
11
+
12
+ const subtract1 = relTime =>
13
+ TimeMath.subtractRelRel(
14
+ relTime,
15
+ TimeMath.coerceRelativeTimeRecord(1n, relTime.timerBrand),
16
+ );
17
+
18
+ /**
19
+ * The length of the auction has to be inferred from the governed params.
20
+ *
21
+ * 1. The auction starts by offering collateral at a `StartingRate` (e.g., 105%)
22
+ * of the market price at auction start, and continues until it reaches
23
+ * (or would exceed on its next step) LowestRate (e.g., 65%)
24
+ * 2. The offer price changes every `ClockStep` seconds
25
+ * 3. The offer price changes by `DiscountStep` amount (e.g., 5%) each step So
26
+ * it must run however many `ClockSteps` are required to get from
27
+ * `StartingRate` to `LowestRate` changing by `DiscountStep` each time.
28
+ *
29
+ * Therefore, the duration is `(StartingRate - LowestRate) / DiscountStep * ClockStep`.
30
+ *
31
+ * Note that this is what's *scheduled*. More than one auction can be running
32
+ * simultaneously, and some conditions can cause some of the auctions to stop
33
+ * selling early (e.g. reaching their target debt to raise or selling all of
34
+ * their collateral).
35
+ *
36
+ * @param {Awaited<import('./params.js').AuctionParamManager>} params
37
+ * @param {Timestamp} baseTime
38
+ * @returns {import('./scheduler.js').Schedule}
39
+ */
40
+ export const computeRoundTiming = (params, baseTime) => {
41
+ const freq = params.getStartFrequency();
42
+ const clockStep = params.getClockStep();
43
+ const startingRate = params.getStartingRate();
44
+ const discountStep = params.getDiscountStep();
45
+ const lockPeriod = params.getPriceLockPeriod();
46
+ const lowestRate = params.getLowestRate();
47
+ const startDelay = params.getAuctionStartDelay();
48
+
49
+ TimeMath.compareRel(freq, startDelay) > 0 ||
50
+ Fail`startFrequency must exceed startDelay, ${freq}, ${startDelay}`;
51
+ TimeMath.compareRel(freq, lockPeriod) > 0 ||
52
+ Fail`startFrequency must exceed lock period, ${freq}, ${lockPeriod}`;
53
+ TimeMath.compareRel(freq, clockStep) >= 0 ||
54
+ Fail`clockStep ${TimeMath.relValue(
55
+ clockStep,
56
+ )} must be shorter than startFrequency ${TimeMath.relValue(
57
+ freq,
58
+ )} to allow at least one step down`;
59
+
60
+ startingRate > lowestRate ||
61
+ Fail`startingRate ${startingRate} must be more than lowest: ${lowestRate}`;
62
+
63
+ const rateChange = subtract(startingRate, lowestRate);
64
+ const requestedSteps = floorDivide(rateChange, discountStep);
65
+ requestedSteps > 0n ||
66
+ Fail`discountStep ${discountStep} too large for requested rates`;
67
+
68
+ // How many steps fit in a full auction? We want the biggest integer for which
69
+ // steps * discountStep <= startingRate - lowestRate, and
70
+ // steps * clockStep < freq
71
+ const maxRateSteps = floorDivide(startingRate - lowestRate, discountStep);
72
+ const maxTimeSteps = TimeMath.divideRelRel(subtract1(freq), clockStep);
73
+ const steps = maxRateSteps < maxTimeSteps ? maxRateSteps : maxTimeSteps;
74
+
75
+ const duration = TimeMath.multiplyRelNat(clockStep, steps);
76
+ steps > 0n ||
77
+ Fail`clockStep ${clockStep} too long for auction duration ${duration}`;
78
+ const endRate = subtract(startingRate, multiply(steps, discountStep));
79
+
80
+ // Use a duration that exactly matches the last step completing (no remainder)
81
+ const actualDuration = TimeMath.multiplyRelNat(clockStep, steps);
82
+ // computed start is `startDelay + baseTime + freq - (baseTime mod freq)`.
83
+ // That is, if there are hourly starts, we add an hour to the time, and
84
+ // subtract baseTime mod freq. Then we add the delay.
85
+ /** @type {import('@agoric/time/src/types').TimestampRecord} */
86
+ const startTime = TimeMath.addAbsRel(
87
+ TimeMath.addAbsRel(
88
+ baseTime,
89
+ TimeMath.subtractRelRel(freq, TimeMath.modAbsRel(baseTime, freq)),
90
+ ),
91
+ startDelay,
92
+ );
93
+ const endTime = TimeMath.addAbsRel(startTime, actualDuration);
94
+ const lockTime = TimeMath.subtractAbsRel(startTime, lockPeriod);
95
+
96
+ /** @type {import('./scheduler.js').Schedule} */
97
+ const next = {
98
+ startTime,
99
+ endTime,
100
+ steps,
101
+ endRate,
102
+ startDelay,
103
+ clockStep,
104
+ lockTime,
105
+ };
106
+ return harden(next);
107
+ };
108
+ harden(computeRoundTiming);
109
+
110
+ /**
111
+ * Calculate when the next descending step will start. If we're between
112
+ * auctions (i.e. liveSchedule is undefined), or the last step of the current
113
+ * auction has started, then it'll be nextSchedule.startTime. Otherwise, it's
114
+ * the start of the step following the current step.
115
+ *
116
+ * @param {import('./scheduler.js').Schedule | null} liveSchedule
117
+ * @param {import('./scheduler.js').Schedule | null} nextSchedule
118
+ * @param {Timestamp} now
119
+ * @returns {Timestamp | null}
120
+ */
121
+ export const nextDescendingStepTime = (liveSchedule, nextSchedule, now) => {
122
+ if (!liveSchedule) {
123
+ return nextSchedule?.startTime || null;
124
+ }
125
+
126
+ const { startTime, endTime, clockStep } = liveSchedule;
127
+ trace('calc', startTime, now);
128
+ if (TimeMath.compareAbs(startTime, now) > 0) {
129
+ return startTime;
130
+ }
131
+
132
+ const elapsed = TimeMath.subtractAbsAbs(now, startTime);
133
+ const sinceLastStep = TimeMath.modRelRel(elapsed, clockStep);
134
+ const lastStepStart = TimeMath.subtractAbsRel(now, sinceLastStep);
135
+ const expectedNext = TimeMath.addAbsRel(lastStepStart, clockStep);
136
+
137
+ if (TimeMath.compareAbs(expectedNext, endTime) > 0) {
138
+ return nextSchedule?.startTime || null;
139
+ }
140
+
141
+ return expectedNext;
142
+ };
143
+ harden(nextDescendingStepTime);
144
+
145
+ /**
146
+ *
147
+ * @param {Timestamp} time
148
+ * @param {import('./scheduler.js').Schedule} schedule
149
+ * @returns {'before' | 'during' | 'endExactly' | 'after'}
150
+ */
151
+ export const timeVsSchedule = (time, schedule) => {
152
+ const { startTime, endTime } = schedule;
153
+ assertAllDefined({ startTime, endTime });
154
+
155
+ if (TimeMath.compareAbs(time, schedule.startTime) < 0) {
156
+ return 'before';
157
+ }
158
+ if (TimeMath.compareAbs(time, schedule.endTime) < 0) {
159
+ return 'during';
160
+ }
161
+ if (TimeMath.compareAbs(time, schedule.endTime) === 0) {
162
+ return 'endExactly';
163
+ }
164
+
165
+ return 'after';
166
+ };
167
+ harden(timeVsSchedule);