@agoric/inter-protocol 0.13.3 → 0.13.4-dev-d32a66a.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.
- package/README.md +26 -20
- package/bundles/bundle-auctioneer-js-meta.json +722 -0
- package/bundles/bundle-auctioneer.js +1 -0
- package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
- package/bundles/bundle-econCommitteeCharter.js +1 -0
- package/bundles/bundle-feeDistributor-js-meta.json +458 -0
- package/bundles/bundle-feeDistributor.js +1 -1
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
- package/bundles/bundle-fluxAggregatorKit.js +1 -0
- package/bundles/bundle-psm-js-meta.json +666 -0
- package/bundles/bundle-psm.js +1 -1
- package/bundles/bundle-reserve-js-meta.json +662 -0
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
- package/bundles/bundle-scaledPriceAuthority.js +1 -1
- package/bundles/bundle-vaultFactory-js-meta.json +786 -0
- package/bundles/bundle-vaultFactory.js +1 -1
- package/exported.js +0 -2
- package/package.json +34 -31
- package/scripts/add-collateral-core.js +14 -4
- package/scripts/build-bundles.js +9 -2
- package/scripts/deploy-contracts.js +1 -4
- package/scripts/init-core.js +20 -38
- package/scripts/invite-committee-core.js +1 -1
- package/scripts/manual-price-feed.js +2 -2
- package/scripts/price-feed-core.js +7 -6
- package/scripts/start-local-chain.sh +84 -0
- package/src/auction/auctionBook.js +755 -0
- package/src/auction/auctioneer.js +720 -0
- package/src/auction/offerBook.js +221 -0
- package/src/auction/params.js +174 -0
- package/src/auction/scheduleMath.js +167 -0
- package/src/auction/scheduler.js +370 -0
- package/src/auction/sortedOffers.js +136 -0
- package/src/auction/util.js +55 -0
- package/src/clientSupport.js +324 -0
- package/src/collectFees.js +8 -14
- package/src/contractSupport.js +24 -68
- package/src/econCommitteeCharter.js +161 -77
- package/src/feeDistributor.js +60 -20
- package/src/index.js +2 -0
- package/src/interest-math.js +1 -4
- package/src/interest.js +20 -13
- package/src/price/README.md +57 -0
- package/src/price/fluxAggregatorContract.js +190 -0
- package/src/price/fluxAggregatorKit.js +375 -0
- package/src/price/priceOracleKit.js +127 -0
- package/src/price/roundsManager.js +726 -0
- package/src/proposals/addAssetToVault.js +89 -94
- package/src/proposals/committee-proposal.js +141 -40
- package/src/proposals/core-proposal.js +100 -167
- package/src/proposals/econ-behaviors.js +320 -564
- package/src/proposals/price-feed-proposal.js +175 -78
- package/src/proposals/startEconCommittee.js +25 -12
- package/src/proposals/startPSM.js +231 -211
- package/src/proposals/utils.js +31 -17
- package/src/psm/README.md +71 -0
- package/src/psm/psm.js +272 -160
- package/src/psm/types.js +2 -0
- package/src/reserve/assetReserve.js +56 -413
- package/src/reserve/assetReserveKit.js +303 -0
- package/src/reserve/doc.md +1 -3
- package/src/reserve/params.js +2 -5
- package/src/typeGuards.js +13 -0
- package/src/vaultFactory/Liquidation.md +100 -0
- package/src/vaultFactory/burn.js +2 -1
- package/src/vaultFactory/liquidation.js +270 -108
- package/src/vaultFactory/math.js +95 -0
- package/src/vaultFactory/orderedVaultStore.js +0 -1
- package/src/vaultFactory/params.js +133 -112
- package/src/vaultFactory/prioritizedVaults.js +36 -79
- package/src/vaultFactory/storeUtils.js +67 -9
- package/src/vaultFactory/type-imports.js +2 -0
- package/src/vaultFactory/types.js +22 -26
- package/src/vaultFactory/vault.js +772 -709
- package/src/vaultFactory/vaultDirector.js +480 -483
- package/src/vaultFactory/vaultFactory.js +99 -60
- package/src/vaultFactory/vaultHolder.js +121 -95
- package/src/vaultFactory/vaultKit.js +39 -31
- package/src/vaultFactory/vaultManager.js +1249 -868
- package/bundles/bundle-amm-meta.js +0 -618
- package/bundles/bundle-amm.js +0 -1
- package/bundles/bundle-feeDistributor-meta.js +0 -346
- package/bundles/bundle-interchainPool-meta.js +0 -534
- package/bundles/bundle-interchainPool.js +0 -1
- package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
- package/bundles/bundle-liquidateIncrementally.js +0 -1
- package/bundles/bundle-liquidateMinimum-meta.js +0 -442
- package/bundles/bundle-liquidateMinimum.js +0 -1
- package/bundles/bundle-psm-meta.js +0 -538
- package/bundles/bundle-psmCharter-meta.js +0 -418
- package/bundles/bundle-psmCharter.js +0 -1
- package/bundles/bundle-reserve-meta.js +0 -542
- package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
- package/bundles/bundle-stakeFactory-meta.js +0 -574
- package/bundles/bundle-stakeFactory.js +0 -1
- package/bundles/bundle-vaultFactory-meta.js +0 -598
- package/scripts/add-initial-liquidity.js +0 -180
- package/src/collect.js +0 -13
- package/src/interchainPool.js +0 -135
- package/src/makeTracer.js +0 -36
- package/src/my-lien.js +0 -85
- package/src/proposals/demoIssuers.js +0 -685
- package/src/proposals/sim-behaviors.js +0 -40
- package/src/psm/psmCharter.js +0 -139
- package/src/stakeFactory/README.md +0 -62
- package/src/stakeFactory/attestation.js +0 -267
- package/src/stakeFactory/attestationTool.js +0 -66
- package/src/stakeFactory/constants.js +0 -16
- package/src/stakeFactory/params.js +0 -31
- package/src/stakeFactory/stakeFactory.js +0 -236
- package/src/stakeFactory/stakeFactoryKit.js +0 -455
- package/src/stakeFactory/stakeFactoryManager.js +0 -296
- package/src/stakeFactory/types.js +0 -42
- package/src/vaultFactory/liquidateIncrementally.js +0 -350
- package/src/vaultFactory/liquidateMinimum.js +0 -100
- package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
- package/src/vpool-xyk-amm/addLiquidity.js +0 -222
- package/src/vpool-xyk-amm/addPool.js +0 -197
- package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
- package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
- package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
- package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
- package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
- package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
- package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
- package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
- package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
- package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
- package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
- package/src/vpool-xyk-amm/doublePool.js +0 -194
- package/src/vpool-xyk-amm/estimate.js +0 -155
- package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
- package/src/vpool-xyk-amm/params.js +0 -61
- package/src/vpool-xyk-amm/pool.js +0 -396
- package/src/vpool-xyk-amm/priceAuthority.js +0 -94
- package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
- package/src/vpool-xyk-amm/singlePool.js +0 -73
- package/src/vpool-xyk-amm/swap.js +0 -69
- 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);
|