@reserve-protocol/dtf-rebalance-lib 1.2.0 → 1.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.
@@ -58,12 +58,12 @@ export declare const getTargetBasket: (_initialWeights: WeightRange[], _prices:
58
58
  *
59
59
  * @param rebalance The result of calling folio.getRebalance(), today
60
60
  * @param _supply {share} The totalSupply() of the basket, today
61
- * @param _initialFolio D18{tok/share} Initial balances per share, e.g result of folio.toAssets(1e18, 0) at time rebalance was first proposed
61
+ * @param _initialAssets {tok} Initial asset balances in the Folio, e.g result of folio.totalAssets() at time rebalance was first proposed
62
62
  * @param _targetBasket D18{1} Result of calling `getTargetBasket()`
63
- * @param _folio D18{tok/share} Current ratio of token per share, e.g result of folio.toAssets(1e18, 0), today
63
+ * @param _assets {tok} Current asset balances in the Folio, e.g result of folio.totalAssets(), today
64
64
  * @param _decimals Decimals of each token
65
65
  * @param _prices {USD/wholeTok} USD prices for each *whole* token, today
66
66
  * @param _priceError {1} Price error to use for each token during auction pricing; should be smaller than price error during startRebalance
67
67
  * @param _finalStageAt {1} The % rebalanced from the initial Folio to determine when is the final stage of the rebalance
68
68
  */
69
- export declare const getOpenAuction: (rebalance: Rebalance, _supply: bigint, _initialFolio: bigint[] | undefined, _targetBasket: bigint[] | undefined, _folio: bigint[], _decimals: bigint[], _prices: number[], _priceError: number[], _finalStageAt: number, debug?: boolean) => [OpenAuctionArgs, AuctionMetrics];
69
+ export declare const getOpenAuction: (rebalance: Rebalance, _supply: bigint, _initialAssets: bigint[] | undefined, _targetBasket: bigint[] | undefined, _assets: bigint[], _decimals: bigint[], _prices: number[], _priceError: number[], _finalStageAt: number, debug?: boolean) => [OpenAuctionArgs, AuctionMetrics];
@@ -53,24 +53,24 @@ exports.getTargetBasket = getTargetBasket;
53
53
  *
54
54
  * @param rebalance The result of calling folio.getRebalance(), today
55
55
  * @param _supply {share} The totalSupply() of the basket, today
56
- * @param _initialFolio D18{tok/share} Initial balances per share, e.g result of folio.toAssets(1e18, 0) at time rebalance was first proposed
56
+ * @param _initialAssets {tok} Initial asset balances in the Folio, e.g result of folio.totalAssets() at time rebalance was first proposed
57
57
  * @param _targetBasket D18{1} Result of calling `getTargetBasket()`
58
- * @param _folio D18{tok/share} Current ratio of token per share, e.g result of folio.toAssets(1e18, 0), today
58
+ * @param _assets {tok} Current asset balances in the Folio, e.g result of folio.totalAssets(), today
59
59
  * @param _decimals Decimals of each token
60
60
  * @param _prices {USD/wholeTok} USD prices for each *whole* token, today
61
61
  * @param _priceError {1} Price error to use for each token during auction pricing; should be smaller than price error during startRebalance
62
62
  * @param _finalStageAt {1} The % rebalanced from the initial Folio to determine when is the final stage of the rebalance
63
63
  */
64
- const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket = [], _folio, _decimals, _prices, _priceError, _finalStageAt, debug) => {
64
+ const getOpenAuction = (rebalance, _supply, _initialAssets = [], _targetBasket = [], _assets, _decimals, _prices, _priceError, _finalStageAt, debug) => {
65
65
  if (debug === undefined) {
66
66
  debug = true;
67
67
  }
68
68
  if (debug) {
69
- console.log("getOpenAuction", rebalance, _supply, _initialFolio, _targetBasket, _folio, _decimals, _prices, _priceError, _finalStageAt);
69
+ console.log("getOpenAuction", rebalance, _supply, _initialAssets, _targetBasket, _assets, _decimals, _prices, _priceError, _finalStageAt);
70
70
  }
71
71
  if (rebalance.tokens.length != _targetBasket.length ||
72
- _targetBasket.length != _folio.length ||
73
- _folio.length != _decimals.length ||
72
+ _targetBasket.length != _assets.length ||
73
+ _assets.length != _decimals.length ||
74
74
  _decimals.length != _prices.length ||
75
75
  _prices.length != _priceError.length) {
76
76
  throw new Error("length mismatch");
@@ -94,10 +94,10 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
94
94
  const priceError = _priceError.map((a) => new utils_1.Decimal(a.toString()));
95
95
  // {tok/wholeTok}
96
96
  const decimalScale = _decimals.map((a) => new utils_1.Decimal(`1e${a}`));
97
- // {wholeTok/wholeShare} = D18{tok/share} * {share/wholeShare} / {tok/wholeTok} / D18
98
- const initialFolio = _initialFolio.map((c, i) => new utils_1.Decimal(c.toString()).div(decimalScale[i]));
99
- // {wholeTok/wholeShare} = D18{tok/share} * {share/wholeShare} / {tok/wholeTok} / D18
100
- const folio = _folio.map((c, i) => new utils_1.Decimal(c.toString()).div(decimalScale[i]));
97
+ // {wholeTok} = {tok} / {tok/wholeTok}
98
+ const initialAssets = _initialAssets.map((bal, i) => new utils_1.Decimal(bal.toString()).div(decimalScale[i]));
99
+ // {wholeTok} = {tok} / {tok/wholeTok}
100
+ const assets = _assets.map((bal, i) => new utils_1.Decimal(bal.toString()).div(decimalScale[i]));
101
101
  // {wholeTok/wholeBU} = D27{tok/BU} * {BU/wholeBU} / {tok/wholeTok} / D27
102
102
  let weightRanges = rebalance.weights.map((range, i) => {
103
103
  return {
@@ -108,33 +108,36 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
108
108
  });
109
109
  const finalStageAt = new utils_1.Decimal(_finalStageAt.toString());
110
110
  // ================================================================
111
- // calculate ideal spot limit, the actual BU<->share ratio
112
- // {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
113
- const shareValue = folio
111
+ // calculate ideal spot limit, the actual basket<->share ratio
112
+ // {USD}
113
+ const folioValue = assets
114
114
  .map((f, i) => {
115
115
  if (!rebalance.inRebalance[i]) {
116
116
  return numbers_1.ZERO;
117
117
  }
118
+ // {USD} = {wholeTok} * {USD/wholeTok}
118
119
  return f.mul(prices[i]);
119
120
  })
120
121
  .reduce((a, b) => a.add(b));
121
- // {USD/wholeBU} = {wholeTok/wholeBU} * {USD/wholeTok}
122
- const buValue = weightRanges
122
+ // {USD}
123
+ const basketValue = weightRanges
123
124
  .map((weightRange, i) => {
124
125
  if (!rebalance.inRebalance[i]) {
125
126
  return numbers_1.ZERO;
126
127
  }
127
- return weightRange.spot.mul(prices[i]);
128
+ // {USD} = {wholeTok/wholeBU} * {USD/wholeTok} * {wholeBU}
129
+ // assume basket and share are the same
130
+ return weightRange.spot.mul(prices[i]).mul(supply);
128
131
  })
129
132
  .reduce((a, b) => a.add(b));
130
- const buPriceChange = buValue.sub(shareValue).div(shareValue);
131
- console.log(` 🧺 ${buPriceChange.mul(100).toFixed(2)}% basket price difference`);
133
+ const basketPriceChange = basketValue.sub(folioValue).div(folioValue);
134
+ console.log(` 🧺 ${basketPriceChange.mul(100).toFixed(2)}% basket price difference`);
132
135
  if (debug) {
133
- console.log("shareValue", shareValue.toString());
134
- console.log("buValue", buValue.toString());
136
+ console.log("folioValue", folioValue.toString());
137
+ console.log("basketValue", basketValue.toString());
135
138
  }
136
- if (buValue.div(shareValue).gt(10) || shareValue.div(buValue).gt(10)) {
137
- throw new Error("buValue and shareValue are too different, something probably went wrong");
139
+ if (basketValue.div(folioValue).gt(10) || folioValue.div(basketValue).gt(10)) {
140
+ throw new Error("basketValue and folioValue are too different, something probably went wrong");
138
141
  }
139
142
  // ================================================================
140
143
  // calculate portionBeingEjected
@@ -144,50 +147,50 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
144
147
  ejectionIndices.push(i);
145
148
  }
146
149
  }
147
- // {1} = {wholeTok/wholeShare} * {USD/wholeTok} / {USD/wholeShare}
150
+ // {1}
148
151
  const portionBeingEjected = ejectionIndices
149
- .map((i) => {
150
- return folio[i].mul(prices[i]);
151
- })
152
+ // {USD} = {wholeTok} * {USD/wholeTok}
153
+ .map((i) => assets[i].mul(prices[i]))
152
154
  .reduce((a, b) => a.add(b), numbers_1.ZERO)
153
- .div(shareValue);
155
+ .div(folioValue);
154
156
  // ================================================================
155
157
  // calculate progressions
156
- // {wholeBU/wholeShare} = {USD/wholeShare} / {USD/wholeBU}
157
- const spotLimit = shareValue.div(buValue);
158
+ // {1} = {USD} / {USD}
159
+ const idealSpotLimit = folioValue.div(basketValue);
158
160
  // {wholeBU/wholeShare} = D18{BU/share} / D18
159
161
  const prevSpotLimit = new utils_1.Decimal(rebalance.limits.spot.toString()).div(numbers_1.D18d);
160
- const maxSpotLimit = spotLimit.gt(prevSpotLimit) ? spotLimit : prevSpotLimit;
161
- // {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
162
- const expectedBalances = weightRanges.map((weightRange) => weightRange.spot.mul(maxSpotLimit));
162
+ const maxSpotLimit = idealSpotLimit.gt(prevSpotLimit) ? idealSpotLimit : prevSpotLimit;
163
+ // known: units a little weird here, combining {1} and {wholeBU/wholeShare}
164
+ // {wholeTok} = {wholeTok/wholeBU} * {wholeBU/wholeShare} * {wholeShare}
165
+ const expectedBalances = weightRanges.map((weightRange) => weightRange.spot.mul(maxSpotLimit).mul(supply));
163
166
  // absolute scale
164
- // {1} = {USD/wholeShare} / {USD/wholeShare}
165
- let progression = folio
167
+ // {1}
168
+ let progression = assets
166
169
  .map((actualBalance, i) => {
167
170
  if (!rebalance.inRebalance[i]) {
168
171
  return numbers_1.ZERO;
169
172
  }
170
- // {wholeTok/wholeShare}
173
+ // {wholeTok}
171
174
  const balanceInBasket = expectedBalances[i].gt(actualBalance) ? actualBalance : expectedBalances[i];
172
- // {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
175
+ // {USD} = {wholeTok} * {USD/wholeTok}
173
176
  return balanceInBasket.mul(prices[i]);
174
177
  })
175
178
  .reduce((a, b) => a.add(b))
176
- .div(shareValue);
179
+ .div(folioValue);
177
180
  // absolute scale
178
- // {1} = {USD/wholeShare} / {USD/wholeShare}
179
- const initialProgression = initialFolio
181
+ // {1}
182
+ const initialProgression = initialAssets
180
183
  .map((initialBalance, i) => {
181
184
  if (!rebalance.inRebalance[i]) {
182
185
  return numbers_1.ZERO;
183
186
  }
184
- // {wholeTok/wholeShare}
187
+ // {wholeTok}
185
188
  const balanceInBasket = expectedBalances[i].gt(initialBalance) ? initialBalance : expectedBalances[i];
186
- // {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
189
+ // {USD} = {wholeTok} * {USD/wholeTok}
187
190
  return balanceInBasket.mul(prices[i]);
188
191
  })
189
192
  .reduce((a, b) => a.add(b))
190
- .div(shareValue);
193
+ .div(folioValue);
191
194
  if (progression < initialProgression) {
192
195
  if (debug) {
193
196
  console.log("progression < initialProgression", progression.toString(), initialProgression.toString());
@@ -246,11 +249,12 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
246
249
  const delta = numbers_1.ONE.sub(rebalanceTarget);
247
250
  // ================================================================
248
251
  // get new limits, constrained by extremes
249
- // D18{BU/share} = {wholeBU/wholeShare} * D18 * {1}
252
+ // D18{BU/share}
250
253
  const newLimits = {
251
- low: (0, numbers_1.bn)(spotLimit.sub(spotLimit.mul(delta)).mul(numbers_1.D18d)),
252
- spot: (0, numbers_1.bn)(spotLimit.mul(numbers_1.D18d)),
253
- high: (0, numbers_1.bn)(spotLimit.add(spotLimit.mul(delta)).mul(numbers_1.D18d)),
254
+ // D18{BU/share} = {wholeBU/wholeShare} * {1} * D18
255
+ low: (0, numbers_1.bn)(idealSpotLimit.sub(idealSpotLimit.mul(delta)).mul(numbers_1.D18d)),
256
+ spot: (0, numbers_1.bn)(idealSpotLimit.mul(numbers_1.D18d)),
257
+ high: (0, numbers_1.bn)(idealSpotLimit.add(idealSpotLimit.mul(delta)).mul(numbers_1.D18d)),
254
258
  };
255
259
  // hold some surpluses aside if ejecting
256
260
  if (round == AuctionRound.EJECT) {
@@ -282,18 +286,20 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
282
286
  }
283
287
  // ================================================================
284
288
  // get new weights, constrained by extremes
285
- // {wholeBU/wholeShare} = D18{BU/share} / D18
289
+ // {wholeBU/wholeShare}
286
290
  const actualLimits = {
291
+ // {wholeBU/wholeShare} = D18{BU/share} / D18
287
292
  low: new utils_1.Decimal(newLimits.low.toString()).div(numbers_1.D18d),
288
293
  spot: new utils_1.Decimal(newLimits.spot.toString()).div(numbers_1.D18d),
289
294
  high: new utils_1.Decimal(newLimits.high.toString()).div(numbers_1.D18d),
290
295
  };
291
296
  // D27{tok/BU}
292
297
  const newWeights = rebalance.weights.map((weightRange, i) => {
293
- // {wholeTok/wholeBU} = {USD/wholeShare} * {1} / {wholeBU/wholeShare} / {USD/wholeTok}
294
- const idealWeight = shareValue.mul(targetBasket[i]).div(actualLimits.spot).div(prices[i]);
295
- // D27{tok/BU} = {wholeTok/wholeBU} * D27 * {tok/wholeTok} / {BU/wholeBU}
298
+ // {wholeTok/wholeBU} = {USD} / {wholeShare} * {1} / {wholeBU/wholeShare} / {USD/wholeTok}
299
+ const idealWeight = folioValue.div(supply).mul(targetBasket[i]).div(actualLimits.spot).div(prices[i]);
300
+ // D27{tok/BU}
296
301
  const newWeightsD27 = {
302
+ // D27{tok/BU} = {wholeTok/wholeBU} * D27 * {tok/wholeTok} / {BU/wholeBU}
297
303
  low: (0, numbers_1.bn)(idealWeight
298
304
  .mul(numbers_1.ONE.sub(delta).div(actualLimits.low.div(actualLimits.spot))) // add remaining delta into weight
299
305
  .mul(numbers_1.D9d)
@@ -343,8 +349,9 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
343
349
  if (rebalance.priceControl == types_1.PriceControl.NONE) {
344
350
  return initialPrice;
345
351
  }
346
- // D27{nanoUSD/tok} = {USD/wholeTok} * {nanoUSD/USD} / {tok/wholeTok} * D27
352
+ // D27{nanoUSD/tok}
347
353
  const pricesD27 = {
354
+ // D27{nanoUSD/tok} = {USD/wholeTok} * {nanoUSD/USD} / {tok/wholeTok} * D27
348
355
  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)),
349
356
  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)),
350
357
  };
@@ -397,21 +404,21 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
397
404
  auctionTokens.push(token);
398
405
  auctionWeights.push(newWeights[i]);
399
406
  auctionPrices.push(newPrices[i]);
400
- // {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
401
- const buyUpTo = weightRanges[i].low.mul(actualLimits.low);
402
- const sellDownTo = weightRanges[i].high.mul(actualLimits.high);
403
- if (folio[i].lt(buyUpTo)) {
404
- // {USD} = {wholeTok/wholeShare} * {USD/wholeTok} * {wholeShare}
405
- const tokenDeficitValue = buyUpTo.sub(folio[i]).mul(prices[i]).mul(supply);
407
+ // {wholeTok} = {wholeTok/wholeBU} * {wholeBU/wholeShare} * {wholeShare}
408
+ const buyUpTo = weightRanges[i].low.mul(actualLimits.low).mul(supply);
409
+ const sellDownTo = weightRanges[i].high.mul(actualLimits.high).mul(supply);
410
+ if (assets[i].lt(buyUpTo)) {
411
+ // {USD} = {wholeTok} * {USD/wholeTok}
412
+ const tokenDeficitValue = buyUpTo.sub(assets[i]).mul(prices[i]);
406
413
  // $1 minimum
407
414
  if (tokenDeficitValue.gte(numbers_1.ONE)) {
408
415
  deficitTokens.push(token);
409
416
  deficitTokenSizes.push(tokenDeficitValue.toNumber());
410
417
  }
411
418
  }
412
- else if (folio[i].gt(sellDownTo)) {
413
- // {USD} = {wholeTok/wholeShare} * {USD/wholeTok} * {wholeShare}
414
- const tokenSurplusValue = folio[i].sub(sellDownTo).mul(prices[i]).mul(supply);
419
+ else if (assets[i].gt(sellDownTo)) {
420
+ // {USD} = {wholeTok} * {USD/wholeTok}
421
+ const tokenSurplusValue = assets[i].sub(sellDownTo).mul(prices[i]);
415
422
  // $1 minimum
416
423
  if (tokenSurplusValue.gte(numbers_1.ONE)) {
417
424
  surplusTokens.push(token);
@@ -11,7 +11,7 @@ export interface StartRebalanceArgsPartial {
11
11
  *
12
12
  * @param _supply {share}
13
13
  * @param tokens Addresses of tokens in the basket
14
- * @param _folio D18{tok/share} Folio of the basket
14
+ * @param _assets {tok} Folio asset assets
15
15
  * @param decimals Decimals of each token
16
16
  * @param _targetBasket D18{1} Ideal basket
17
17
  * @param _prices {USD/wholeTok} USD prices for each *whole* token
@@ -20,4 +20,4 @@ export interface StartRebalanceArgsPartial {
20
20
  * @param weightControl TRACKING=false, NATIVE=true
21
21
  * @param deferWeights Whether to use the full range for weights, only possible for NATIVE DTFs
22
22
  */
23
- export declare const getStartRebalance: (_supply: bigint, tokens: string[], _folio: bigint[], decimals: bigint[], _targetBasket: bigint[], _prices: number[], _priceError: number[], weightControl: boolean, deferWeights: boolean, debug?: boolean) => StartRebalanceArgsPartial;
23
+ export declare const getStartRebalance: (_supply: bigint, tokens: string[], _assets: bigint[], decimals: bigint[], _targetBasket: bigint[], _prices: number[], _priceError: number[], weightControl: boolean, deferWeights: boolean, debug?: boolean) => StartRebalanceArgsPartial;
@@ -10,7 +10,7 @@ const numbers_1 = require("./numbers");
10
10
  *
11
11
  * @param _supply {share}
12
12
  * @param tokens Addresses of tokens in the basket
13
- * @param _folio D18{tok/share} Folio of the basket
13
+ * @param _assets {tok} Folio asset assets
14
14
  * @param decimals Decimals of each token
15
15
  * @param _targetBasket D18{1} Ideal basket
16
16
  * @param _prices {USD/wholeTok} USD prices for each *whole* token
@@ -19,15 +19,17 @@ const numbers_1 = require("./numbers");
19
19
  * @param weightControl TRACKING=false, NATIVE=true
20
20
  * @param deferWeights Whether to use the full range for weights, only possible for NATIVE DTFs
21
21
  */
22
- const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _prices, _priceError, weightControl, deferWeights, debug) => {
22
+ const getStartRebalance = (_supply, tokens, _assets, decimals, _targetBasket, _prices, _priceError, weightControl, deferWeights, debug) => {
23
23
  if (debug) {
24
- console.log("getStartRebalance", _supply, tokens, _folio, decimals, _targetBasket, _prices, _priceError, weightControl, deferWeights);
24
+ console.log("getStartRebalance", _supply, tokens, _assets, decimals, _targetBasket, _prices, _priceError, weightControl, deferWeights);
25
25
  }
26
26
  if (deferWeights && !weightControl) {
27
27
  throw new Error("deferWeights is not supported for tracking DTFs");
28
28
  }
29
- // {wholeTok/wholeShare} = D18{tok/share} * {share/wholeShare} / {tok/wholeTok} / D18
30
- const folio = _folio.map((c, i) => new utils_1.Decimal(c.toString()).div(new utils_1.Decimal(`1e${decimals[i]}`)));
29
+ // {wholeShare} = {share} / {share/wholeShare}
30
+ const supply = new utils_1.Decimal(_supply.toString()).div(numbers_1.D18d);
31
+ // {wholeTok} = {tok} * {share/wholeShare} / {tok/wholeTok} / D18
32
+ const assets = _assets.map((c, i) => new utils_1.Decimal(c.toString()).div(new utils_1.Decimal(`1e${decimals[i]}`)));
31
33
  // convert price number inputs to bigints
32
34
  // {USD/wholeTok}
33
35
  const prices = _prices.map((a) => new utils_1.Decimal(a.toString()));
@@ -48,12 +50,12 @@ const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _pr
48
50
  throw new Error("price error >= 1");
49
51
  }
50
52
  // === newWeights ===
51
- // {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
52
- const dtfPrice = folio
53
+ // {USD} = {wholeTok} * {USD/wholeTok}
54
+ const dtfValue = assets
53
55
  .map((f, i) => f.mul(prices[i]))
54
56
  .reduce((a, b) => a.add(b));
55
- // {wholeTok/wholeShare} = {1} * {USD/wholeShare} / {USD/wholeTok}
56
- const spotWeight = targetBasket[i].mul(dtfPrice).div(prices[i]);
57
+ // {wholeTok/wholeShare} = {1} * {USD} / {USD/wholeTok} / {wholeShare}
58
+ const spotWeight = targetBasket[i].mul(dtfValue).div(prices[i]).div(supply);
57
59
  // D27{tok/share}{wholeShare/wholeTok} = D27 * {tok/wholeTok} / {share/wholeShare}
58
60
  const limitMultiplier = numbers_1.D27d.mul(new utils_1.Decimal(`1e${decimals[i]}`)).div(numbers_1.D18d);
59
61
  if (debug) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reserve-protocol/dtf-rebalance-lib",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Rebalancing library for DTFs in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",