impermax-sdk 2.1.239 → 2.1.240

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.
@@ -37,7 +37,15 @@ class OffchainAccountCollateralV2 extends offchainAccountPoolToken_1.default {
37
37
  //if (await this.getLendingPool().getLendingPool().isStable()) {
38
38
  // TODO return stablePosition
39
39
  //} else {
40
- return new position_1.UniswapV2Position(await this.getLiquidity(), await this.getLendingPool().getBorrowableA().getBorrowedAmount(), await this.getLendingPool().getBorrowableB().getBorrowedAmount(), await this.getLendingPool().getLendingPool().getMarketPrice(), await this.getLendingPool().getLendingPool().getMarketPrice(), await this.getLendingPool().getSafetyMargin(), await this.getLendingPool().getLiquidationPenalty(), lockStateChange);
40
+ return new position_1.UniswapV2Position({
41
+ liquidity: await this.getLiquidity(),
42
+ debtX: await this.getLendingPool().getBorrowableA().getBorrowedAmount(),
43
+ debtY: await this.getLendingPool().getBorrowableB().getBorrowedAmount(),
44
+ marketPrice: await this.getLendingPool().getLendingPool().getMarketPrice(),
45
+ oraclePrice: await this.getLendingPool().getLendingPool().getMarketPrice(),
46
+ safetyMargin: await this.getLendingPool().getSafetyMargin(),
47
+ liquidationPenalty: await this.getLendingPool().getLiquidationPenalty(),
48
+ });
41
49
  //}
42
50
  }
43
51
  async getPositionObject() {
@@ -37,7 +37,18 @@ class OnchainAccountCollateralV2 extends onchainAccountPoolToken_1.default {
37
37
  //if (await this.getLendingPool().getLendingPool().isStable()) {
38
38
  // TODO return stablePosition
39
39
  //} else {
40
- return new position_1.UniswapV2Position(await this.getLiquidity(), await this.getLendingPool().getBorrowableA().getBorrowed(), await this.getLendingPool().getBorrowableB().getBorrowed(), await this.getLendingPool().getLendingPool().getMarketPrice(), await this.getLendingPool().getLendingPool().getTWAPPrice(), await this.getLendingPool().getSafetyMargin(), await this.getLendingPool().getLiquidationPenalty(), lockStateChange);
40
+ return new position_1.UniswapV2Position({
41
+ liquidity: await this.getLiquidity(),
42
+ debtX: await this.getLendingPool().getBorrowableA().getBorrowed(),
43
+ debtY: await this.getLendingPool().getBorrowableB().getBorrowed(),
44
+ marketPrice: await this.getLendingPool().getLendingPool().getMarketPrice(),
45
+ oraclePrice: await this.getLendingPool().getLendingPool().getTWAPPrice(),
46
+ safetyMargin: await this.getLendingPool().getSafetyMargin(),
47
+ liquidationPenalty: await this.getLendingPool().getLiquidationPenalty(),
48
+ availableToBorrowX: await this.getLendingPool().getLendingPool().getBorrowableA().getAvailableToBorrow(),
49
+ availableToBorrowY: await this.getLendingPool().getLendingPool().getBorrowableB().getAvailableToBorrow(),
50
+ lockStateChange,
51
+ });
41
52
  //}
42
53
  }
43
54
  }
@@ -1,4 +1,16 @@
1
1
  import type { Position } from "../interface";
2
+ export interface UniswapV2PositionParams {
3
+ liquidity: number;
4
+ debtX: number;
5
+ debtY: number;
6
+ marketPrice: number;
7
+ oraclePrice: number;
8
+ safetyMargin: number;
9
+ liquidationPenalty: number;
10
+ availableToBorrowX?: number;
11
+ availableToBorrowY?: number;
12
+ lockStateChange?: boolean;
13
+ }
2
14
  export declare class UniswapV2Position implements Position {
3
15
  lockStateChange: boolean;
4
16
  state: number;
@@ -15,8 +27,9 @@ export declare class UniswapV2Position implements Position {
15
27
  oraclePrice: number;
16
28
  safetyMargin: number;
17
29
  liquidationPenalty: number;
18
- constructor(_liquidity: number, // lp amount fixed by exchangeRate and k
19
- _debtX: number, _debtY: number, _marketPrice: number, _oraclePrice: number, _safetyMargin: number, _liquidationPenalty: number, _lockStateChange: boolean);
30
+ availableToBorrowX: number;
31
+ availableToBorrowY: number;
32
+ constructor(params: UniswapV2PositionParams);
20
33
  private checkLock;
21
34
  /**
22
35
  * PRIVATE SETTERS
@@ -47,18 +60,24 @@ export declare class UniswapV2Position implements Position {
47
60
  private getDebtValueGivenPrice;
48
61
  private getInitialCollateralValue;
49
62
  private getCollateralValueGivenPrice;
63
+ private getCollateralValueGivenPriceAndDeltaLeverage;
50
64
  private getInitialEquityValue;
51
65
  private getEquityValueGivenPrice;
52
66
  private getDebtValue;
53
67
  private getCollateralValue;
54
68
  private getEquityValue;
55
69
  private getLiquidityPostLiquidationValueGivenPriceAndDebt;
70
+ private getLiquidityPostLiquidationValueGivenPriceAndDeltaLeverage;
56
71
  private isLiquidatableGivenPriceAndDebt;
72
+ private isLiquidatableGivenPriceAndDeltaLeverage;
57
73
  private isLiquidatableGivenDebt;
74
+ private isLiquidatableGivenDeltaLeverage;
58
75
  private isLiquidatableGivenPrice;
59
76
  private isUnderwaterGivenPrice;
60
77
  private getLiquidationPriceInRange;
61
78
  private getMaxDeltaDebtInRange;
79
+ private getMaxDeltaLeverageInRange;
80
+ private getMinLeverageInRange;
62
81
  /**
63
82
  * PUBLIC SETTERS
64
83
  */
@@ -92,6 +111,14 @@ export declare class UniswapV2Position implements Position {
92
111
  amountX: number;
93
112
  amountY: number;
94
113
  };
114
+ getOptimalWithdraw(amountX: number, amountY: number, withdrawAtLeast?: boolean): {
115
+ amountX: number;
116
+ amountY: number;
117
+ };
118
+ getOptimalWithdrawForDeleverage(targetLeverage: number): {
119
+ amountX: number;
120
+ amountY: number;
121
+ } | null;
95
122
  getMaxLeverage(): number;
96
123
  getMinLeverage(): number;
97
124
  getMaxWithdrawable(): {
@@ -10,19 +10,20 @@ function getRealY(liquidity, price) {
10
10
  const LOWEST_PRICE = 1 / 1e18;
11
11
  const HIGHEST_PRICE = 1e18;
12
12
  class UniswapV2Position {
13
- constructor(_liquidity, // lp amount fixed by exchangeRate and k
14
- _debtX, _debtY, _marketPrice, _oraclePrice, _safetyMargin, _liquidationPenalty, _lockStateChange) {
15
- this.liquidity = _liquidity;
16
- this.debtX = _debtX;
17
- this.debtY = _debtY;
18
- this.initialLiquidity = _liquidity;
19
- this.initialDebtX = _debtX;
20
- this.initialDebtY = _debtY;
21
- this.marketPrice = _marketPrice;
22
- this.oraclePrice = _oraclePrice;
23
- this.safetyMargin = _safetyMargin;
24
- this.liquidationPenalty = _liquidationPenalty;
25
- this.lockStateChange = _lockStateChange;
13
+ constructor(params) {
14
+ this.liquidity = params.liquidity;
15
+ this.debtX = params.debtX;
16
+ this.debtY = params.debtY;
17
+ this.initialLiquidity = params.liquidity;
18
+ this.initialDebtX = params.debtX;
19
+ this.initialDebtY = params.debtY;
20
+ this.marketPrice = params.marketPrice;
21
+ this.oraclePrice = params.oraclePrice;
22
+ this.safetyMargin = params.safetyMargin;
23
+ this.liquidationPenalty = params.liquidationPenalty;
24
+ this.availableToBorrowX = params.availableToBorrowX ?? 0;
25
+ this.availableToBorrowY = params.availableToBorrowY ?? 0;
26
+ this.lockStateChange = params.lockStateChange ?? true;
26
27
  this.state = 0;
27
28
  }
28
29
  checkLock() {
@@ -126,6 +127,10 @@ class UniswapV2Position {
126
127
  getCollateralValueGivenPrice(price) {
127
128
  return this.getValueGivenPriceAndAmounts(price, this.getRealXGivenPrice(price), this.getRealYGivenPrice(price));
128
129
  }
130
+ getCollateralValueGivenPriceAndDeltaLeverage(price, deltaX, deltaY) {
131
+ const { liquidity } = this.getOptimalLiquidity(deltaX, deltaY);
132
+ return this.getValueGivenPriceAndAmounts(price, this.getRealXGivenLiquidityAndPrice(this.liquidity + liquidity, price), this.getRealYGivenLiquidityAndPrice(this.liquidity + liquidity, price));
133
+ }
129
134
  getInitialEquityValue() {
130
135
  return this.getInitialCollateralValue() - this.getInitialDebtValue();
131
136
  }
@@ -147,13 +152,26 @@ class UniswapV2Position {
147
152
  const collateralNeeded = debtValue * this.liquidationPenalty;
148
153
  return collateralValue - collateralNeeded;
149
154
  }
155
+ getLiquidityPostLiquidationValueGivenPriceAndDeltaLeverage(price, deltaX, deltaY) {
156
+ const debtValue = this.getDebtValueGivenPrice(price) + this.getValueGivenPriceAndAmounts(price, deltaX, deltaY);
157
+ const collateralValue = this.getCollateralValueGivenPriceAndDeltaLeverage(price, deltaX, deltaY);
158
+ const collateralNeeded = debtValue * this.liquidationPenalty;
159
+ return collateralValue - collateralNeeded;
160
+ }
150
161
  isLiquidatableGivenPriceAndDebt(price, debtX, debtY) {
151
162
  return this.getLiquidityPostLiquidationValueGivenPriceAndDebt(price / this.safetyMargin, debtX, debtY) < 0
152
163
  || this.getLiquidityPostLiquidationValueGivenPriceAndDebt(price * this.safetyMargin, debtX, debtY) < 0;
153
164
  }
165
+ isLiquidatableGivenPriceAndDeltaLeverage(price, deltaX, deltaY) {
166
+ return this.getLiquidityPostLiquidationValueGivenPriceAndDeltaLeverage(price / this.safetyMargin, deltaX, deltaY) < 0
167
+ || this.getLiquidityPostLiquidationValueGivenPriceAndDeltaLeverage(price * this.safetyMargin, deltaX, deltaY) < 0;
168
+ }
154
169
  isLiquidatableGivenDebt(debtX, debtY) {
155
170
  return this.isLiquidatableGivenPriceAndDebt(this.marketPrice, debtX, debtY);
156
171
  }
172
+ isLiquidatableGivenDeltaLeverage(deltaX, deltaY) {
173
+ return this.isLiquidatableGivenPriceAndDeltaLeverage(this.marketPrice, deltaX, deltaY);
174
+ }
157
175
  isLiquidatableGivenPrice(price) {
158
176
  return this.isLiquidatableGivenPriceAndDebt(price, this.debtX, this.debtY);
159
177
  }
@@ -184,6 +202,29 @@ class UniswapV2Position {
184
202
  else
185
203
  return this.getMaxDeltaDebtInRange(avgDeltaX, avgDeltaY, highDeltaX, highDeltaY);
186
204
  }
205
+ getMaxDeltaLeverageInRange(lowDeltaX, lowDeltaY, highDeltaX, highDeltaY) {
206
+ if (Number.isNaN(lowDeltaX) || Number.isNaN(lowDeltaY) || Number.isNaN(highDeltaX) || Number.isNaN(highDeltaY))
207
+ return [0, 0];
208
+ if (highDeltaX == 0 && highDeltaY == 0)
209
+ return [0, 0];
210
+ if (Math.abs(highDeltaX / lowDeltaX) < 1.001 || Math.abs(highDeltaY / lowDeltaY) < 1.001)
211
+ return [lowDeltaX, lowDeltaY];
212
+ const avgDeltaX = (lowDeltaX + highDeltaX) / 2;
213
+ const avgDeltaY = (lowDeltaY + highDeltaY) / 2;
214
+ if (this.isLiquidatableGivenDeltaLeverage(avgDeltaX, avgDeltaY))
215
+ return this.getMaxDeltaLeverageInRange(lowDeltaX, lowDeltaY, avgDeltaX, avgDeltaY);
216
+ else
217
+ return this.getMaxDeltaLeverageInRange(avgDeltaX, avgDeltaY, highDeltaX, highDeltaY);
218
+ }
219
+ getMinLeverageInRange(lowLeverage, highLeverage) {
220
+ if (highLeverage / lowLeverage < 1.001)
221
+ return highLeverage;
222
+ const avgLeverage = (lowLeverage + highLeverage) / 2;
223
+ if (this.getOptimalWithdrawForDeleverage(avgLeverage) !== null)
224
+ return this.getMinLeverageInRange(lowLeverage, avgLeverage);
225
+ else
226
+ return this.getMinLeverageInRange(avgLeverage, highLeverage);
227
+ }
187
228
  /**
188
229
  * PUBLIC SETTERS
189
230
  */
@@ -200,10 +241,20 @@ class UniswapV2Position {
200
241
  this.setRealY(Math.max(this.getInitialRealY() - amount, 0));
201
242
  }
202
243
  borrowX(amount) {
203
- this.setDebtX(this.initialDebtX + amount);
244
+ if (amount > this.availableToBorrowX) {
245
+ throw new Error("Trying to borrow more than available liquidity");
246
+ }
247
+ else {
248
+ this.setDebtX(this.initialDebtX + amount);
249
+ }
204
250
  }
205
251
  borrowY(amount) {
206
- this.setDebtY(this.initialDebtY + amount);
252
+ if (amount > this.availableToBorrowY) {
253
+ throw new Error("Trying to borrow more than available liquidity");
254
+ }
255
+ else {
256
+ this.setDebtY(this.initialDebtY + amount);
257
+ }
207
258
  }
208
259
  repayX(amount) {
209
260
  this.setDebtX(Math.max(this.initialDebtX - amount, 0));
@@ -284,6 +335,71 @@ class UniswapV2Position {
284
335
  amountY: Number.isNaN(amountY) ? 0 : amountY ?? 0,
285
336
  };
286
337
  }
338
+ getOptimalWithdraw(amountX, amountY, withdrawAtLeast = true) {
339
+ let percentageToRemove;
340
+ const percentageToRemoveX = amountX / this.getInitialDepositedX();
341
+ const percentageToRemoveY = amountY / this.getInitialDepositedY();
342
+ // Withdraw at least amountX and amountY
343
+ if (withdrawAtLeast)
344
+ percentageToRemove = Math.min(Math.max(percentageToRemoveX, percentageToRemoveY), 1);
345
+ // Withdraw at most amountX and amountY
346
+ else
347
+ percentageToRemove = Math.min(Math.min(percentageToRemoveX, percentageToRemoveY), 1);
348
+ percentageToRemove = percentageToRemove && !Number.isNaN(percentageToRemove) ? percentageToRemove : 0;
349
+ return {
350
+ amountX: this.getInitialDepositedX() * percentageToRemove,
351
+ amountY: this.getInitialDepositedY() * percentageToRemove,
352
+ };
353
+ }
354
+ getOptimalWithdrawForDeleverage(targetLeverage) {
355
+ // 1. If target leverage out of range
356
+ if (!(targetLeverage >= 1 && targetLeverage < this.getInitialLeverage())) {
357
+ return null;
358
+ }
359
+ // 2. If target leverage is achievable through a straight deleverage
360
+ const maxStraightDeleverage = this.getOptimalWithdraw(this.initialDebtX, this.initialDebtY, false);
361
+ const maxStraightDeleverageValue = this.getValueGivenAmounts(maxStraightDeleverage.amountX, maxStraightDeleverage.amountY);
362
+ const minStraightLeverage = (this.getInitialCollateralValue() - maxStraightDeleverageValue) / this.getInitialEquityValue();
363
+ if (targetLeverage >= minStraightLeverage) {
364
+ const desiredCollateralValue = targetLeverage * this.getInitialEquityValue();
365
+ const desiredValue = this.getInitialCollateralValue() - desiredCollateralValue;
366
+ const ratio = desiredValue / maxStraightDeleverageValue;
367
+ return {
368
+ amountX: maxStraightDeleverage.amountX * ratio,
369
+ amountY: maxStraightDeleverage.amountY * ratio,
370
+ };
371
+ }
372
+ // 3. Deleveraging will result in withdrawing
373
+ const debtValue = this.getInitialDebtValue() - maxStraightDeleverageValue;
374
+ const collateralValue = this.getInitialCollateralValue() - maxStraightDeleverageValue;
375
+ let repayRatio;
376
+ if (this.initialDebtX == maxStraightDeleverage.amountX) {
377
+ repayRatio = this.getValueGivenAmounts(0, this.getInitialDepositedY()) / this.getInitialCollateralValue();
378
+ }
379
+ else {
380
+ repayRatio = this.getValueGivenAmounts(this.getInitialDepositedX(), 0) / this.getInitialCollateralValue();
381
+ }
382
+ const deltaValue = (collateralValue * (targetLeverage - 1) - debtValue * targetLeverage) / (targetLeverage * (1 - repayRatio) - 1);
383
+ // Proof:
384
+ // leverage = newCollateral / (newCollateral - newDebt)
385
+ // newCollateral = collateral - delta
386
+ // newDebt = debt - delta * repayRatio;
387
+ // ((collateral - delta) - (debt - delta * repayRatio)) * leverage = (collateral - delta)
388
+ // (collateral - delta - debt + delta * repayRatio) * leverage - collateral = - delta
389
+ // collateral * leverage - delta * leverage - debt * leverage + delta * repayRatio * leverage - collateral = - delta
390
+ // collateral * leverage - debt * leverage - collateral = - delta + delta * leverage - delta * repayRatio * leverage
391
+ // collateral * (leverage-1) - debt * leverage = delta * (leverage - repayRatio * leverage - 1)
392
+ // collateral * (leverage-1) - debt * leverage = delta * (leverage * (1-repayRatio) - 1)
393
+ // (collateral * (leverage-1) - debt * leverage) / (leverage * (1-repayRatio) - 1) = delta
394
+ // 4. Return amounts if the leverage is achievable
395
+ if (deltaValue < 0 || deltaValue > collateralValue)
396
+ return null;
397
+ const percentageToRemove = (deltaValue + maxStraightDeleverageValue) / this.getInitialCollateralValue();
398
+ return {
399
+ amountX: this.getInitialDepositedX() * percentageToRemove,
400
+ amountY: this.getInitialDepositedY() * percentageToRemove,
401
+ };
402
+ }
287
403
  getMaxLeverage() {
288
404
  const currentLeverage = this.getLeverage();
289
405
  if (this.isLiquidatable())
@@ -296,31 +412,39 @@ class UniswapV2Position {
296
412
  }
297
413
  const realX = this.getRealX();
298
414
  const realY = this.getRealY();
299
- const projectedRealX = realX * highLeverage / currentLeverage;
300
- const projectedRealY = realY * highLeverage / currentLeverage;
301
- const projectedDebtX = this.debtX + projectedRealX - realX;
302
- const projectedDebtY = this.debtY + projectedRealY - realY;
303
- const normalizedDeltaDebtX = projectedDebtX * currentLeverage / highLeverage - this.debtX;
304
- const normalizedDeltaDebtY = projectedDebtY * currentLeverage / highLeverage - this.debtY;
305
- const [deltaDebtX, deltaDebtY] = this.getMaxDeltaDebtInRange(0, 0, normalizedDeltaDebtX, normalizedDeltaDebtY);
415
+ let maxDeltaX = realX * highLeverage / currentLeverage;
416
+ let maxDeltaY = realY * highLeverage / currentLeverage;
417
+ const actualAvailableToBorrowX = this.availableToBorrowX - (this.debtX - this.initialDebtX);
418
+ const actualAvailableToBorrowY = this.availableToBorrowY - (this.debtY - this.initialDebtY);
419
+ if (maxDeltaX > actualAvailableToBorrowX) {
420
+ maxDeltaY *= actualAvailableToBorrowX / maxDeltaX;
421
+ maxDeltaX = actualAvailableToBorrowX;
422
+ }
423
+ if (maxDeltaY > actualAvailableToBorrowY) {
424
+ maxDeltaX *= actualAvailableToBorrowY / maxDeltaY;
425
+ maxDeltaY = actualAvailableToBorrowY;
426
+ }
427
+ const [deltaX, deltaY] = this.getMaxDeltaLeverageInRange(0, 0, maxDeltaX, maxDeltaY);
306
428
  const collateralValue = this.getCollateralValue();
307
- const debtValue = this.getValueGivenAmounts(this.debtX + deltaDebtX, this.debtY + deltaDebtY);
308
- const equityValue = collateralValue - debtValue;
429
+ const additionalValue = this.getValueGivenAmounts(deltaX, deltaY);
309
430
  if (setLiquidityToZero)
310
431
  this.liquidity = 0;
311
- return collateralValue / equityValue;
432
+ return (collateralValue + additionalValue) / collateralValue * currentLeverage;
312
433
  }
313
434
  getMinLeverage() {
314
435
  const depositedX = this.getDepositedX();
315
436
  const depositedY = this.getDepositedY();
316
- if (depositedX >= this.debtX && depositedY >= this.debtY)
437
+ const ratioX = this.debtX === 0 ? Infinity : depositedX / this.debtX;
438
+ const ratioY = this.debtY === 0 ? Infinity : depositedY / this.debtY;
439
+ if (ratioX >= 1 && ratioY >= 1)
317
440
  return 0;
318
- // TODO binary search
319
- return 0;
441
+ return this.getMinLeverageInRange(1, this.getInitialLeverage());
320
442
  }
321
443
  getMaxWithdrawable() {
322
444
  const depositedX = this.getDepositedX();
323
445
  const depositedY = this.getDepositedY();
446
+ const additionalDepositX = this.getRealX() - this.getInitialRealX();
447
+ const additionalDepositY = this.getRealY() - this.getInitialRealY();
324
448
  let percentage = 0;
325
449
  if (!this.isLiquidatable()) {
326
450
  if (this.debtX == 0 && this.debtY == 0) {
@@ -334,8 +458,8 @@ class UniswapV2Position {
334
458
  }
335
459
  }
336
460
  return {
337
- amountX: depositedX * percentage,
338
- amountY: depositedY * percentage,
461
+ amountX: depositedX * percentage - additionalDepositX,
462
+ amountY: depositedY * percentage - additionalDepositY,
339
463
  };
340
464
  }
341
465
  getMaxBorrowableX() {
@@ -344,7 +468,7 @@ class UniswapV2Position {
344
468
  const equityValue = this.getEquityValue();
345
469
  const highDebtX = this.getAmountXGivenValue(equityValue);
346
470
  const [debtX,] = this.getMaxDeltaDebtInRange(0, 0, highDebtX, 0);
347
- return debtX + this.debtX - this.initialDebtX;
471
+ return Math.min(debtX + this.debtX - this.initialDebtX, this.availableToBorrowX);
348
472
  }
349
473
  getMaxBorrowableY() {
350
474
  if (this.isLiquidatable())
@@ -352,7 +476,7 @@ class UniswapV2Position {
352
476
  const equityValue = this.getEquityValue();
353
477
  const highDebtY = this.getAmountYGivenValue(equityValue);
354
478
  const [, debtY] = this.getMaxDeltaDebtInRange(0, 0, 0, highDebtY);
355
- return debtY + this.debtY - this.initialDebtY;
479
+ return Math.min(debtY + this.debtY - this.initialDebtY, this.availableToBorrowY);
356
480
  }
357
481
  }
358
482
  exports.UniswapV2Position = UniswapV2Position;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impermax-sdk",
3
- "version": "2.1.239",
3
+ "version": "2.1.240",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",