@reserve-protocol/dtf-rebalance-lib 0.2.17 → 0.3.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.
@@ -45,7 +45,7 @@ export interface OpenAuctionArgs {
45
45
  * @param _prices {USD/wholeTok} either CURRENT or HISTORICAL prices
46
46
  * @returns D18{1} The target basket
47
47
  */
48
- export declare const getTargetBasket: (_initialWeights: WeightRange[], _prices: number[], _decimals: bigint[]) => bigint[];
48
+ export declare const getTargetBasket: (_initialWeights: WeightRange[], _prices: number[], _decimals: bigint[], debug?: boolean) => bigint[];
49
49
  /**
50
50
  * Get the values needed to call `folio.openAuction()` as the AUCTION_LAUNCHER
51
51
  *
@@ -22,8 +22,13 @@ var AuctionRound;
22
22
  * @param _prices {USD/wholeTok} either CURRENT or HISTORICAL prices
23
23
  * @returns D18{1} The target basket
24
24
  */
25
- const getTargetBasket = (_initialWeights, _prices, _decimals) => {
26
- console.log("getTargetBasket", _initialWeights, _prices, _decimals);
25
+ const getTargetBasket = (_initialWeights, _prices, _decimals, debug) => {
26
+ if (debug === undefined) {
27
+ debug = true;
28
+ }
29
+ if (debug) {
30
+ console.log("getTargetBasket", _initialWeights, _prices, _decimals);
31
+ }
27
32
  if (_initialWeights.length != _prices.length) {
28
33
  throw new Error("length mismatch");
29
34
  }
@@ -79,7 +84,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
79
84
  // {1} = D18{1} / D18
80
85
  const targetBasket = _targetBasket.map((a) => new utils_1.Decimal(a.toString()).div(numbers_1.D18d));
81
86
  // {USD/wholeTok}
82
- const prices = _prices.map((a) => new utils_1.Decimal(a));
87
+ const prices = _prices.map((a) => new utils_1.Decimal(a.toString()));
83
88
  for (let i = 0; i < prices.length; i++) {
84
89
  if (prices[i].lte(numbers_1.ZERO)) {
85
90
  throw new Error(`missing price for token ${rebalance.tokens[i]}`);
@@ -148,10 +153,14 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
148
153
  .div(shareValue);
149
154
  // ================================================================
150
155
  // calculate progressions
156
+ // {wholeBU/wholeShare} = {USD/wholeShare} / {USD/wholeBU}
157
+ const spotLimit = shareValue.div(buValue);
151
158
  // {wholeBU/wholeShare} = D18{BU/share} / D18
152
159
  const prevSpotLimit = new utils_1.Decimal(rebalance.limits.spot.toString()).div(numbers_1.D18d);
160
+ const maxSpotLimit = spotLimit.gt(prevSpotLimit) ? spotLimit : prevSpotLimit;
153
161
  // {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
154
- const expectedBalances = weightRanges.map((weightRange) => weightRange.spot.mul(prevSpotLimit));
162
+ const expectedBalances = weightRanges.map((weightRange) => weightRange.spot.mul(maxSpotLimit));
163
+ // absolute scale
155
164
  // {1} = {USD/wholeShare} / {USD/wholeShare}
156
165
  let progression = folio
157
166
  .map((actualBalance, i) => {
@@ -165,6 +174,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
165
174
  })
166
175
  .reduce((a, b) => a.add(b))
167
176
  .div(shareValue);
177
+ // absolute scale
168
178
  // {1} = {USD/wholeShare} / {USD/wholeShare}
169
179
  const initialProgression = initialFolio
170
180
  .map((initialBalance, i) => {
@@ -188,7 +198,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
188
198
  let relativeProgression = initialProgression.eq(numbers_1.ONE)
189
199
  ? numbers_1.ONE
190
200
  : progression.sub(initialProgression).div(numbers_1.ONE.sub(initialProgression));
191
- let rebalanceTarget = numbers_1.ONE;
201
+ let rebalanceTarget = numbers_1.ONE; // absolute scale
192
202
  let round = AuctionRound.FINAL;
193
203
  if (debug) {
194
204
  console.log("initialProgression", initialProgression.toString());
@@ -209,6 +219,8 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
209
219
  }
210
220
  }
211
221
  // EJECT
222
+ // TODO maybe increase threshold to nonzero value, taking into account price
223
+ // currently will get stuck trying to eject tiny dust over and over
212
224
  if (portionBeingEjected.gt(0)) {
213
225
  round = AuctionRound.EJECT;
214
226
  // if the ejections are everything that's left, keep the finalStageAt targeting from above
@@ -236,8 +248,6 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
236
248
  const delta = numbers_1.ONE.sub(rebalanceTarget);
237
249
  // ================================================================
238
250
  // get new limits, constrained by extremes
239
- // {wholeBU/wholeShare} = {USD/wholeShare} / {USD/wholeBU}
240
- const spotLimit = shareValue.div(buValue);
241
251
  // D18{BU/share} = {wholeBU/wholeShare} * D18 * {1}
242
252
  const newLimits = {
243
253
  low: (0, numbers_1.bn)(spotLimit.sub(spotLimit.mul(delta)).mul(numbers_1.D18d)),
@@ -287,7 +297,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
287
297
  // D27{tok/BU} = {wholeTok/wholeBU} * D27 * {tok/wholeTok} / {BU/wholeBU}
288
298
  const newWeightsD27 = {
289
299
  low: (0, numbers_1.bn)(idealWeight
290
- .mul(rebalanceTarget.div(actualLimits.low.div(actualLimits.spot))) // add remaining delta into weight
300
+ .mul(numbers_1.ONE.sub(delta).div(actualLimits.low.div(actualLimits.spot))) // add remaining delta into weight
291
301
  .mul(numbers_1.D9d)
292
302
  .mul(decimalScale[i])),
293
303
  spot: (0, numbers_1.bn)(idealWeight.mul(numbers_1.D9d).mul(decimalScale[i])),
@@ -325,20 +335,20 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
325
335
  }
326
336
  // ================================================================
327
337
  // get new prices, constrained by extremes
328
- // D27{USD/tok}
338
+ // D27{nanoUSD/tok}
329
339
  const newPrices = rebalance.initialPrices.map((initialPrice, i) => {
330
- // revert if price out of bounds
331
- const spotPrice = (0, numbers_1.bn)(prices[i].div(decimalScale[i]).mul(numbers_1.D27d));
340
+ // {nanoUSD/tok} = {USD/wholeTok} * {nanoUSD/USD} / {tok/wholeTok} * D27
341
+ const spotPrice = (0, numbers_1.bn)(prices[i].mul(numbers_1.D9d).div(decimalScale[i]).mul(numbers_1.D27d));
332
342
  if (spotPrice < initialPrice.low || spotPrice > initialPrice.high) {
333
343
  throw new Error(`spot price ${spotPrice.toString()} out of bounds relative to initial range [${initialPrice.low.toString()}, ${initialPrice.high.toString()}]! auction launcher MUST closeRebalance to prevent loss!`);
334
344
  }
335
345
  if (rebalance.priceControl == types_1.PriceControl.NONE) {
336
346
  return initialPrice;
337
347
  }
338
- // D27{USD/tok} = {USD/wholeTok} * D27 / {tok/wholeTok}
348
+ // D27{nanoUSD/tok} = {USD/wholeTok} * {nanoUSD/USD} / {tok/wholeTok} * D27
339
349
  const pricesD27 = {
340
- low: (0, numbers_1.bn)(prices[i].mul(numbers_1.ONE.sub(priceError[i])).div(decimalScale[i]).mul(numbers_1.D27d)),
341
- high: (0, numbers_1.bn)(prices[i].div(numbers_1.ONE.sub(priceError[i])).div(decimalScale[i]).mul(numbers_1.D27d)),
350
+ low: (0, numbers_1.bn)(prices[i].mul(numbers_1.ONE.sub(priceError[i])).mul(numbers_1.D9d).div(decimalScale[i]).mul(numbers_1.D27d)),
351
+ high: (0, numbers_1.bn)(prices[i].div(numbers_1.ONE.sub(priceError[i])).mul(numbers_1.D9d).div(decimalScale[i]).mul(numbers_1.D27d)),
342
352
  };
343
353
  // low
344
354
  if (pricesD27.low < initialPrice.low) {
@@ -420,7 +430,8 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
420
430
  const returnWeights = [];
421
431
  const returnPrices = [];
422
432
  for (let i = 0; i < rebalance.tokens.length; i++) {
423
- if (rebalance.inRebalance[i]) {
433
+ if (rebalance.inRebalance[i] &&
434
+ (surplusTokens.includes(rebalance.tokens[i]) || deficitTokens.includes(rebalance.tokens[i]))) {
424
435
  returnTokens.push(rebalance.tokens[i]);
425
436
  returnWeights.push(newWeights[i]);
426
437
  returnPrices.push(newPrices[i]);
@@ -84,14 +84,11 @@ const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _pr
84
84
  // === newPrices ===
85
85
  // D27{wholeTok/tok} = D27 / {tok/wholeTok}
86
86
  const priceMultiplier = numbers_1.D27d.div(new utils_1.Decimal(`1e${decimals[i]}`));
87
- // {USD/wholeTok} = {USD/wholeTok} * {1}
88
- const lowPrice = prices[i].mul(numbers_1.ONE.sub(priceError[i]));
89
- // {USD/wholeTok} = {USD/wholeTok} / {1}
90
- const highPrice = prices[i].div(numbers_1.ONE.sub(priceError[i]));
91
- // D27{USD/tok} = {USD/wholeTok} * D27{wholeTok/tok}
92
87
  newPrices.push({
93
- low: (0, numbers_1.bn)(lowPrice.mul(priceMultiplier)),
94
- high: (0, numbers_1.bn)(highPrice.mul(priceMultiplier)),
88
+ // D27{nanoUSD/tok} = {USD/wholeTok} * {1} * D27{wholeTok/tok} * {nanoUSD/USD}
89
+ low: (0, numbers_1.bn)(prices[i].mul(numbers_1.ONE.sub(priceError[i])).mul(priceMultiplier).mul(numbers_1.D9d)),
90
+ // D27{nanoUSD/tok} = {USD/wholeTok} / {1} * D27{wholeTok/tok} * {nanoUSD/USD}
91
+ high: (0, numbers_1.bn)(prices[i].div(numbers_1.ONE.sub(priceError[i])).mul(priceMultiplier).mul(numbers_1.D9d)),
95
92
  });
96
93
  }
97
94
  // update low/high for tracking DTFs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reserve-protocol/dtf-rebalance-lib",
3
- "version": "0.2.17",
3
+ "version": "0.3.0",
4
4
  "description": "Rebalancing library for DTFs in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",