@curvefi/llamalend-api 2.0.8 → 2.0.10

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.
@@ -16,7 +16,8 @@ import {
16
16
  import {Llamalend} from "../../../llamalend";
17
17
  import BigNumber from "bignumber.js";
18
18
  import {_getUserCollateral} from "../../../external-api";
19
- export class LoanBaseModule {
19
+
20
+ export abstract class LoanBaseModule {
20
21
  protected market: LendMarketTemplate;
21
22
  protected llamalend: Llamalend;
22
23
 
@@ -25,18 +26,45 @@ export class LoanBaseModule {
25
26
  this.llamalend = market.getLlamalend();
26
27
  }
27
28
 
29
+ protected abstract _calcN1(_collateral: bigint, _debt: bigint, range: number): Promise<bigint>;
30
+
31
+ protected abstract _calcN1AllRanges(_collateral: bigint, _debt: bigint, maxN: number): Promise<bigint[]>;
32
+
33
+ protected abstract _maxBorrowable(collateralAmount: TAmount, range?: number): Promise<bigint>;
34
+
35
+ protected abstract _getMaxBorrowableCall(_collateral: bigint, N: number): any;
36
+
37
+ protected abstract _createLoanContractCall(_collateral: bigint, _debt: bigint, range: number, estimateGas: boolean): Promise<string | TGas>;
38
+
39
+ protected abstract _borrowMoreContractCall(_collateral: bigint, _debt: bigint, estimateGas: boolean): Promise<string | TGas>;
40
+
41
+ protected abstract _repayContractCall(params: { _debt: bigint, address: string, n: number | bigint, estimateGas: boolean, shrink?: boolean }): Promise<string | TGas>;
42
+
43
+ protected abstract _partialLiquidateContractCall(address: string, _minAmount: bigint, frac: string, estimateGas: boolean): Promise<string | TGas>;
44
+
45
+ protected abstract _repayBands(params: { debt: number | string, address: string, shrink?: boolean }): Promise<[bigint, bigint]>;
46
+
47
+ public abstract repayBands(params: { debt: number | string; address?: string; shrink?: boolean }): Promise<[number, number]>;
48
+
49
+ public abstract repayPrices(params: { debt: number | string; address?: string; shrink?: boolean }): Promise<string[]>;
50
+
51
+ public abstract createLoanHealth(collateral: number | string, debt: number | string, range: number, full?: boolean): Promise<string>;
52
+
53
+ public abstract borrowMoreHealth(collateral: number | string, debt: number | string, full?: boolean, address?: string): Promise<string>;
54
+
55
+ public abstract addCollateralHealth(collateral: number | string, full?: boolean, address?: string): Promise<string>;
56
+
57
+ public abstract removeCollateralHealth(collateral: number | string, full?: boolean, address?: string): Promise<string>;
58
+
28
59
  public _checkRange(range: number): void {
29
60
  if (range < this.market.minBands) throw Error(`range must be >= ${this.market.minBands}`);
30
61
  if (range > this.market.maxBands) throw Error(`range must be <= ${this.market.maxBands}`);
31
62
  }
32
63
 
33
- public async createLoanMaxRecv(collateral: number | string, range: number): Promise<string> {
64
+ public async createLoanMaxRecv(collateral: TAmount, range: number): Promise<string> {
34
65
  this._checkRange(range);
35
- const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
36
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
37
66
 
38
- // TODO: currentDebt is no longer passed - now we pass user address or zero address, currentDebt is calculated under the hood
39
- return formatUnits(await contract.max_borrowable(_collateral, range, 0, this.llamalend.constantOptions), this.market.borrowed_token.decimals);
67
+ return formatUnits(await this._maxBorrowable(collateral, range), this.market.borrowed_token.decimals);
40
68
  }
41
69
 
42
70
  public createLoanMaxRecvAllRanges = memoize(async (collateral: number | string): Promise<{ [index: number]: string }> => {
@@ -44,8 +72,7 @@ export class LoanBaseModule {
44
72
 
45
73
  const calls = [];
46
74
  for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
47
- // TODO: currentDebt is no longer passed - now we pass user address or zero address, currentDebt is calculated under the hood
48
- calls.push(this.llamalend.contracts[this.market.addresses.controller].multicallContract.max_borrowable(_collateral, N, 0));
75
+ calls.push(this._getMaxBorrowableCall(_collateral, N));
49
76
  }
50
77
  const _amounts = await this.llamalend.multicallProvider.all(calls) as bigint[];
51
78
 
@@ -70,21 +97,6 @@ export class LoanBaseModule {
70
97
  return this.market.maxBands;
71
98
  }
72
99
 
73
- private async _calcN1(_collateral: bigint, _debt: bigint, range: number): Promise<bigint> {
74
- this._checkRange(range);
75
- // TODO: add 4th parameter - user address in calculate_debt_n1
76
- return await this.llamalend.contracts[this.market.addresses.controller].contract.calculate_debt_n1(_collateral, _debt, range, this.llamalend.constantOptions);
77
- }
78
-
79
- private async _calcN1AllRanges(_collateral: bigint, _debt: bigint, maxN: number): Promise<bigint[]> {
80
- const calls = [];
81
- // TODO: add 4th parameter - user address in calculate_debt_n1
82
- for (let N = this.market.minBands; N <= maxN; N++) {
83
- calls.push(this.llamalend.contracts[this.market.addresses.controller].multicallContract.calculate_debt_n1(_collateral, _debt, N));
84
- }
85
- return await this.llamalend.multicallProvider.all(calls) as bigint[];
86
- }
87
-
88
100
  private async _createLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[bigint, bigint]> {
89
101
  const _n1 = await this._calcN1(parseUnits(collateral, this.market.collateral_token.decimals), parseUnits(debt, this.market.borrowed_token.decimals), range);
90
102
  const _n2 = _n1 + BigInt(range - 1);
@@ -150,17 +162,6 @@ export class LoanBaseModule {
150
162
  return pricesAllRanges;
151
163
  }
152
164
 
153
- public async createLoanHealth(collateral: number | string, debt: number | string, range: number, full = true): Promise<string> {
154
- const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
155
- const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
156
-
157
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
158
-
159
- const _health = await contract.health_calculator(this.llamalend.constants.ZERO_ADDRESS, _collateral, _debt, full, range, this.llamalend.constantOptions) as bigint;
160
-
161
- return formatUnits(_health * BigInt(100));
162
- }
163
-
164
165
  public async createLoanIsApproved(collateral: number | string): Promise<boolean> {
165
166
  return await hasAllowance.call(this.llamalend, [this.market.collateral_token.address], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
166
167
  }
@@ -179,14 +180,7 @@ export class LoanBaseModule {
179
180
 
180
181
  const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
181
182
  const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
182
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
183
- const gas = await contract.create_loan.estimateGas(_collateral, _debt, range, { ...this.llamalend.constantOptions });
184
- if (estimateGas) return smartNumber(gas);
185
-
186
- await this.llamalend.updateFeeData();
187
- const gasLimit = _mulBy1_3(DIGas(gas));
188
- // TODO: ABI has changed (see docs)
189
- return (await contract.create_loan(_collateral, _debt, range, { ...this.llamalend.options, gasLimit })).hash
183
+ return this._createLoanContractCall(_collateral, _debt, range, estimateGas);
190
184
  }
191
185
 
192
186
  public async createLoanEstimateGas(collateral: number | string, debt: number | string, range: number): Promise<TGas> {
@@ -202,13 +196,7 @@ export class LoanBaseModule {
202
196
  // ---------------- BORROW MORE ----------------
203
197
 
204
198
  public async borrowMoreMaxRecv(collateralAmount: number | string): Promise<string> {
205
- const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
206
- const _collateral = _currentCollateral + parseUnits(collateralAmount, this.market.collateral_token.decimals);
207
-
208
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
209
- const _debt: bigint = await contract.max_borrowable(_collateral, _N, _currentDebt, this.llamalend.constantOptions);
210
- // TODO: max_borrowable(deltaCollateral, _N, user) - debt is now calculated under the hood, return as is
211
- return formatUnits(_debt - _currentDebt, this.market.borrowed_token.decimals);
199
+ return formatUnits(await this._maxBorrowable(collateralAmount), this.market.borrowed_token.decimals);
212
200
  }
213
201
 
214
202
  private async _borrowMoreBands(collateral: number | string, debt: number | string): Promise<[bigint, bigint]> {
@@ -236,17 +224,6 @@ export class LoanBaseModule {
236
224
  return await this.market.prices.getPrices(_n2, _n1);
237
225
  }
238
226
 
239
- public async borrowMoreHealth(collateral: number | string, debt: number | string, full = true, address = ""): Promise<string> {
240
- address = _getAddress.call(this.llamalend, address);
241
- const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
242
- const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
243
-
244
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
245
- const _health = await contract.health_calculator(address, _collateral, _debt, full, 0, this.llamalend.constantOptions) as bigint;
246
-
247
- return formatUnits(_health * BigInt(100));
248
- }
249
-
250
227
  public async borrowMoreIsApproved(collateral: number | string): Promise<boolean> {
251
228
  return await hasAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
252
229
  }
@@ -266,13 +243,7 @@ export class LoanBaseModule {
266
243
 
267
244
  const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
268
245
  const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
269
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
270
- const gas = await contract.borrow_more.estimateGas(_collateral, _debt, { ...this.llamalend.constantOptions });
271
- if (estimateGas) return smartNumber(gas);
272
-
273
- await this.llamalend.updateFeeData();
274
- const gasLimit = _mulBy1_3(DIGas(gas));
275
- return (await contract.borrow_more(_collateral, _debt, { ...this.llamalend.options, gasLimit })).hash
246
+ return this._borrowMoreContractCall(_collateral, _debt, estimateGas);
276
247
  }
277
248
 
278
249
  public async borrowMoreEstimateGas(collateral: number | string, debt: number | string): Promise<TGas> {
@@ -323,16 +294,6 @@ export class LoanBaseModule {
323
294
  return await this.market.prices.getPrices(_n2, _n1);
324
295
  }
325
296
 
326
- public async addCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
327
- address = _getAddress.call(this.llamalend, address);
328
- const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
329
-
330
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
331
- const _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
332
-
333
- return formatUnits(_health * BigInt(100));
334
- }
335
-
336
297
  public async addCollateralIsApproved(collateral: number | string): Promise<boolean> {
337
298
  return await hasAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
338
299
  }
@@ -416,16 +377,6 @@ export class LoanBaseModule {
416
377
  return await this.market.prices.getPrices(_n2, _n1);
417
378
  }
418
379
 
419
- public async removeCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
420
- address = _getAddress.call(this.llamalend, address);
421
- const _collateral = parseUnits(collateral, this.market.collateral_token.decimals) * BigInt(-1);
422
-
423
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
424
- const _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
425
-
426
- return formatUnits(_health * BigInt(100));
427
- }
428
-
429
380
  private async _removeCollateral(collateral: number | string, estimateGas: boolean): Promise<string | TGas> {
430
381
  const { borrowed, debt: currentDebt } = await this.market.userPosition.userState();
431
382
  if (Number(currentDebt) === 0) throw Error(`Loan for ${this.llamalend.signerAddress} does not exist`);
@@ -462,32 +413,6 @@ export class LoanBaseModule {
462
413
  }
463
414
 
464
415
  // ---------------- REPAY ----------------
465
- // TODO: add shrink: bool parameter
466
- // If bool is true, _N = n2 - n1 + 1 -> _N = n2 - activeBand
467
- private async _repayBands(debt: number | string, address: string): Promise<[bigint, bigint]> {
468
- const { _collateral: _currentCollateral, _borrowed, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt(address);
469
- if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
470
- // && shrink === false
471
- if (_borrowed > BigInt(0)) return await this.market.userPosition.userBandsBigInt(address) as [bigint, bigint];
472
- // If shrink == true, then _debt = _currentDebt - parseUnits(debt, this.market.borrowed_token.decimals) - _borrowed
473
- const _debt = _currentDebt - parseUnits(debt, this.market.borrowed_token.decimals);
474
- const _n1 = await this._calcN1(_currentCollateral, _debt, Number(_N));
475
- const _n2 = _n1 + _N - BigInt(1);
476
-
477
- return [_n2, _n1];
478
- }
479
-
480
- public async repayBands(debt: number | string, address = ""): Promise<[number, number]> {
481
- const [_n2, _n1] = await this._repayBands(debt, address);
482
-
483
- return [Number(_n2), Number(_n1)];
484
- }
485
-
486
- public async repayPrices(debt: number | string, address = ""): Promise<string[]> {
487
- const [_n2, _n1] = await this._repayBands(debt, address);
488
-
489
- return await this.market.prices.getPrices(_n2, _n1);
490
- }
491
416
 
492
417
  public async repayIsApproved(debt: number | string): Promise<boolean> {
493
418
  return await hasAllowance.call(this.llamalend, [this.market.borrowed_token.address], [debt], this.llamalend.signerAddress, this.market.addresses.controller);
@@ -501,33 +426,26 @@ export class LoanBaseModule {
501
426
  return await ensureAllowance.call(this.llamalend, [this.market.borrowed_token.address], [debt], this.market.addresses.controller);
502
427
  }
503
428
 
504
- private async _repay(debt: number | string, address: string, estimateGas: boolean): Promise<string | TGas> {
429
+ private async _repay(debt: number | string, address: string, estimateGas: boolean, shrink = false): Promise<string | TGas> {
505
430
  address = _getAddress.call(this.llamalend, address);
506
431
  const { debt: currentDebt } = await this.market.userPosition.userState(address);
507
432
  if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
508
433
 
509
434
  const _debt = parseUnits(debt);
510
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
511
435
  const [, n1] = await this.market.userPosition.userBands(address);
512
436
  const { borrowed } = await this.market.userPosition.userState(address);
513
- const n = (BN(borrowed).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1; // In liquidation mode it doesn't matter if active band moves
514
- const gas = await contract.repay.estimateGas(_debt, address, n, this.llamalend.constantOptions);
515
- if (estimateGas) return smartNumber(gas);
516
-
517
- await this.llamalend.updateFeeData();
518
- const gasLimit = _mulBy1_3(DIGas(gas));
519
- // TODO: shrink parameter is added, which changes bands calculation
520
- return (await contract.repay(_debt, address, n, { ...this.llamalend.options, gasLimit })).hash
437
+ const n = (BN(borrowed).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1;
438
+ return this._repayContractCall({ _debt, address, n, estimateGas, shrink });
521
439
  }
522
440
 
523
- public async repayEstimateGas(debt: number | string, address = ""): Promise<TGas> {
441
+ public async repayEstimateGas({ debt, address = "", shrink = false }: { debt: number | string; address?: string; shrink?: boolean }): Promise<TGas> {
524
442
  if (!(await this.repayIsApproved(debt))) throw Error("Approval is needed for gas estimation");
525
- return await this._repay(debt, address, true) as TGas;
443
+ return await this._repay(debt, address, true, shrink) as TGas;
526
444
  }
527
445
 
528
- public async repay(debt: number | string, address = ""): Promise<string> {
446
+ public async repay({ debt, address = "", shrink = false }: { debt: number | string; address?: string; shrink?: boolean }): Promise<string> {
529
447
  await this.repayApprove(debt);
530
- return await this._repay(debt, address, false) as string;
448
+ return await this._repay(debt, address, false, shrink) as string;
531
449
  }
532
450
 
533
451
  public async repayFutureLeverage(debt: number | string, userAddress = ''): Promise<string> {
@@ -661,28 +579,7 @@ export class LoanBaseModule {
661
579
  const minAmountBN = expectedBorrowedBN.times(100 - slippage).div(100);
662
580
  const _minAmount = fromBN(minAmountBN);
663
581
 
664
- const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
665
- const gas = (await contract.liquidate_extended.estimateGas(
666
- address,
667
- _minAmount,
668
- frac,
669
- this.llamalend.constants.ZERO_ADDRESS,
670
- [],
671
- this.llamalend.constantOptions
672
- ));
673
-
674
- if (estimateGas) return smartNumber(gas);
675
-
676
- await this.llamalend.updateFeeData();
677
- const gasLimit = _mulBy1_3(DIGas(gas));
678
- return (await contract.liquidate_extended(
679
- address,
680
- _minAmount,
681
- frac,
682
- this.llamalend.constants.ZERO_ADDRESS,
683
- [],
684
- { ...this.llamalend.options, gasLimit }
685
- )).hash;
582
+ return this._partialLiquidateContractCall(address, _minAmount, frac, estimateGas);
686
583
  }
687
584
 
688
585
  public async liquidateEstimateGas(address: string, slippage = 0.1): Promise<TGas> {
@@ -1,9 +1,172 @@
1
1
  import { LoanBaseModule } from "../common/loanBase.js";
2
2
  import { ILoanV1 } from "../../interfaces/v1/loanV1";
3
- import {_getAddress, formatUnits, parseUnits} from "../../../utils";
3
+ import {
4
+ _getAddress,
5
+ formatUnits,
6
+ parseUnits,
7
+ smartNumber,
8
+ _mulBy1_3,
9
+ DIGas,
10
+ } from "../../../utils";
11
+ import { TGas, TAmount } from "../../../interfaces";
4
12
 
5
13
  export class LoanV1Module extends LoanBaseModule implements ILoanV1 {
6
- public async repayHealth(debt: number | string, full = true, address = ""): Promise<string> {
14
+ protected _maxBorrowable = async (collateralAmount: TAmount, range?: number): Promise<bigint> => {
15
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
16
+ const _collateral = _currentCollateral + parseUnits(collateralAmount, this.market.collateral_token.decimals);
17
+ const N = range ? BigInt(range) : _N;
18
+
19
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
20
+ return (await contract.max_borrowable(_collateral, N, _currentDebt, this.llamalend.constantOptions) - _currentDebt);
21
+ }
22
+
23
+ protected _getMaxBorrowableCall(_collateral: bigint, N: number): any {
24
+ return this.llamalend.contracts[this.market.addresses.controller].multicallContract.max_borrowable(_collateral, N, 0);
25
+ }
26
+
27
+ protected async _calcN1(_collateral: bigint, _debt: bigint, range: number): Promise<bigint> {
28
+ this._checkRange(range);
29
+
30
+ return await this.llamalend.contracts[this.market.addresses.controller].contract.calculate_debt_n1(_collateral, _debt, range, this.llamalend.constantOptions);
31
+ }
32
+
33
+ protected async _calcN1AllRanges(_collateral: bigint, _debt: bigint, maxN: number): Promise<bigint[]> {
34
+ const calls = [];
35
+
36
+ for (let N = this.market.minBands; N <= maxN; N++) {
37
+ calls.push(this.llamalend.contracts[this.market.addresses.controller].multicallContract.calculate_debt_n1(_collateral, _debt, N));
38
+ }
39
+ return await this.llamalend.multicallProvider.all(calls) as bigint[];
40
+ }
41
+
42
+ public async createLoanHealth(collateral: number | string, debt: number | string, range: number, full = true): Promise<string> {
43
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
44
+ const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
45
+
46
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
47
+ const _health = await contract.health_calculator(this.llamalend.constants.ZERO_ADDRESS, _collateral, _debt, full, range, this.llamalend.constantOptions) as bigint;
48
+
49
+ return formatUnits(_health * BigInt(100));
50
+ }
51
+
52
+ public async borrowMoreHealth(collateral: number | string, debt: number | string, full = true, address = ""): Promise<string> {
53
+ address = _getAddress.call(this.llamalend, address);
54
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
55
+ const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
56
+
57
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
58
+ const _health = await contract.health_calculator(address, _collateral, _debt, full, 0, this.llamalend.constantOptions) as bigint;
59
+
60
+ return formatUnits(_health * BigInt(100));
61
+ }
62
+
63
+ public async addCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
64
+ address = _getAddress.call(this.llamalend, address);
65
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
66
+
67
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
68
+ const _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
69
+
70
+ return formatUnits(_health * BigInt(100));
71
+ }
72
+
73
+ public async removeCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
74
+ address = _getAddress.call(this.llamalend, address);
75
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals) * BigInt(-1);
76
+
77
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
78
+ const _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
79
+
80
+ return formatUnits(_health * BigInt(100));
81
+ }
82
+
83
+ protected async _repayBands({ debt, address }: { debt: number | string, address: string, shrink?: boolean }): Promise<[bigint, bigint]> {
84
+ const { _collateral: _currentCollateral, _borrowed, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt(address);
85
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
86
+ if (_borrowed > BigInt(0)) return await this.market.userPosition.userBandsBigInt(address) as [bigint, bigint];
87
+ const _debt = _currentDebt - parseUnits(debt, this.market.borrowed_token.decimals);
88
+ const _n1 = await this._calcN1(_currentCollateral, _debt, Number(_N));
89
+ const _n2 = _n1 + _N - BigInt(1);
90
+
91
+ return [_n2, _n1];
92
+ }
93
+
94
+ public async repayBands({ debt, address = "" }: { debt: number | string; address?: string }): Promise<[number, number]> {
95
+ const [_n2, _n1] = await this._repayBands({ debt, address });
96
+
97
+ return [Number(_n2), Number(_n1)];
98
+ }
99
+
100
+ public async repayPrices({ debt, address = "" }: { debt: number | string; address?: string }): Promise<string[]> {
101
+ const [_n2, _n1] = await this._repayBands({ debt, address });
102
+
103
+ return await this.market.prices.getPrices(_n2, _n1);
104
+ }
105
+
106
+ protected async _repayContractCall(
107
+ { _debt, address, n, estimateGas }: { _debt: bigint, address: string, n: number | bigint, estimateGas: boolean, shrink?: boolean }
108
+ ): Promise<string | TGas> {
109
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
110
+ const gas = await contract.repay.estimateGas(_debt, address, n, this.llamalend.constantOptions);
111
+ if (estimateGas) return smartNumber(gas);
112
+
113
+ await this.llamalend.updateFeeData();
114
+ const gasLimit = _mulBy1_3(DIGas(gas));
115
+ return (await contract.repay(_debt, address, n, { ...this.llamalend.options, gasLimit })).hash;
116
+ }
117
+
118
+ protected async _createLoanContractCall(
119
+ _collateral: bigint, _debt: bigint, range: number, estimateGas: boolean
120
+ ): Promise<string | TGas> {
121
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
122
+ const gas = await contract.create_loan.estimateGas(_collateral, _debt, range, { ...this.llamalend.constantOptions });
123
+ if (estimateGas) return smartNumber(gas);
124
+
125
+ await this.llamalend.updateFeeData();
126
+ const gasLimit = _mulBy1_3(DIGas(gas));
127
+ return (await contract.create_loan(_collateral, _debt, range, { ...this.llamalend.options, gasLimit })).hash;
128
+ }
129
+
130
+ protected async _borrowMoreContractCall(
131
+ _collateral: bigint, _debt: bigint, estimateGas: boolean
132
+ ): Promise<string | TGas> {
133
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
134
+ const gas = await contract.borrow_more.estimateGas(_collateral, _debt, { ...this.llamalend.constantOptions });
135
+ if (estimateGas) return smartNumber(gas);
136
+
137
+ await this.llamalend.updateFeeData();
138
+ const gasLimit = _mulBy1_3(DIGas(gas));
139
+ return (await contract.borrow_more(_collateral, _debt, { ...this.llamalend.options, gasLimit })).hash;
140
+ }
141
+
142
+ protected async _partialLiquidateContractCall(
143
+ address: string, _minAmount: bigint, frac: string, estimateGas: boolean
144
+ ): Promise<string | TGas> {
145
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
146
+ const gas = (await contract.liquidate_extended.estimateGas(
147
+ address,
148
+ _minAmount,
149
+ frac,
150
+ this.llamalend.constants.ZERO_ADDRESS,
151
+ [],
152
+ this.llamalend.constantOptions
153
+ ));
154
+
155
+ if (estimateGas) return smartNumber(gas);
156
+
157
+ await this.llamalend.updateFeeData();
158
+ const gasLimit = _mulBy1_3(DIGas(gas));
159
+ return (await contract.liquidate_extended(
160
+ address,
161
+ _minAmount,
162
+ frac,
163
+ this.llamalend.constants.ZERO_ADDRESS,
164
+ [],
165
+ { ...this.llamalend.options, gasLimit }
166
+ )).hash;
167
+ }
168
+
169
+ public async repayHealth({ debt, full = true, address = "" }: { debt: number | string; full?: boolean; address?: string }): Promise<string> {
7
170
  address = _getAddress.call(this.llamalend, address);
8
171
  const _debt = parseUnits(debt) * BigInt(-1);
9
172
 
@@ -1,6 +1,14 @@
1
1
  import { LoanBaseModule } from "../common/loanBase.js";
2
2
  import { ILoanV2 } from "../../interfaces/v2";
3
- import {_getAddress, formatUnits, parseUnits} from "../../../utils";
3
+ import { TGas, TAmount } from "../../../interfaces";
4
+ import {
5
+ _getAddress,
6
+ formatUnits,
7
+ parseUnits,
8
+ smartNumber,
9
+ _mulBy1_3,
10
+ DIGas,
11
+ } from "../../../utils";
4
12
 
5
13
  export class LoanV2Module extends LoanBaseModule implements ILoanV2 {
6
14
  public async createLoanHealth(collateral: number | string, debt: number | string, range: number, full = true): Promise<string> {
@@ -46,7 +54,7 @@ export class LoanV2Module extends LoanBaseModule implements ILoanV2 {
46
54
  return formatUnits(_health * BigInt(100));
47
55
  }
48
56
 
49
- public async repayHealth(debt: number | string, shrink = false, full = true, address = ""): Promise<string> {
57
+ public async repayHealth({ debt, shrink = false, full = true, address = "" }: { debt: number | string; shrink?: boolean; full?: boolean; address?: string }): Promise<string> {
50
58
  address = _getAddress.call(this.llamalend, address);
51
59
  const _debt = parseUnits(debt);
52
60
 
@@ -55,4 +63,158 @@ export class LoanV2Module extends LoanBaseModule implements ILoanV2 {
55
63
 
56
64
  return formatUnits(_health * BigInt(100));
57
65
  }
66
+
67
+ protected _maxBorrowable = async (collateralAmount: TAmount, range?: number): Promise<bigint> => {
68
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
69
+ const collateral = parseUnits(collateralAmount, this.market.collateral_token.decimals)
70
+ const address = _getAddress.call(this.llamalend, '');
71
+ const N = range ? BigInt(range) : null;
72
+
73
+ return contract.max_borrowable(collateral, N, address, this.llamalend.constantOptions);
74
+ }
75
+
76
+ protected async _calcN1(_collateral: bigint, _debt: bigint, range: number): Promise<bigint> {
77
+ this._checkRange(range);
78
+ const address = _getAddress.call(this.llamalend, '');
79
+
80
+ return await this.llamalend.contracts[this.market.addresses.controller].contract.calculate_debt_n1(_collateral, _debt, range, address, this.llamalend.constantOptions);
81
+ }
82
+
83
+ protected async _calcN1AllRanges(_collateral: bigint, _debt: bigint, maxN: number): Promise<bigint[]> {
84
+ const calls = [];
85
+ const address = _getAddress.call(this.llamalend, '');
86
+
87
+ for (let N = this.market.minBands; N <= maxN; N++) {
88
+ calls.push(this.llamalend.contracts[this.market.addresses.controller].multicallContract.calculate_debt_n1(_collateral, _debt, N, address));
89
+ }
90
+ return await this.llamalend.multicallProvider.all(calls) as bigint[];
91
+ }
92
+
93
+ protected _getMaxBorrowableCall(_collateral: bigint, N: number): any {
94
+ const address = _getAddress.call(this.llamalend, '');
95
+ return this.llamalend.contracts[this.market.addresses.controller].multicallContract.max_borrowable(_collateral, N, address);
96
+ }
97
+
98
+ protected async _repayBands({ debt, address, shrink = false }: { debt: number | string, address: string, shrink?: boolean }): Promise<[bigint, bigint]> {
99
+ const { _collateral: _currentCollateral, _borrowed, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt(address);
100
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
101
+
102
+ if (_borrowed > BigInt(0) && !shrink) {
103
+ return await this.market.userPosition.userBandsBigInt(address) as [bigint, bigint];
104
+ }
105
+
106
+ const _debtRepaid = parseUnits(debt, this.market.borrowed_token.decimals);
107
+
108
+ let newN = _N;
109
+ let _debt: bigint;
110
+
111
+ if (shrink) {
112
+ _debt = _currentDebt - _debtRepaid - _borrowed;
113
+ const [n2] = await this.market.userPosition.userBandsBigInt(address) as [bigint, bigint];
114
+ const { activeBand } = await this.market.stats.bandsInfo();
115
+ newN = n2 - BigInt(activeBand);
116
+ } else {
117
+ _debt = _currentDebt - _debtRepaid;
118
+ }
119
+
120
+ const _n1 = await this._calcN1(_currentCollateral, _debt, Number(newN));
121
+ const _n2 = _n1 + newN - BigInt(1);
122
+
123
+ return [_n2, _n1];
124
+ }
125
+
126
+ public async repayBands({ debt, address = "", shrink = false }: { debt: number | string; address?: string; shrink?: boolean }): Promise<[number, number]> {
127
+ const [_n2, _n1] = await this._repayBands({ debt, address, shrink });
128
+
129
+ return [Number(_n2), Number(_n1)];
130
+ }
131
+
132
+ public async repayPrices({ debt, address = "", shrink = false }: { debt: number | string; address?: string; shrink?: boolean }): Promise<string[]> {
133
+ const [_n2, _n1] = await this._repayBands({ debt, address, shrink });
134
+
135
+ return await this.market.prices.getPrices(_n2, _n1);
136
+ }
137
+
138
+ protected async _createLoanContractCall(
139
+ _collateral: bigint, _debt: bigint, range: number, estimateGas: boolean
140
+ ): Promise<string | TGas> {
141
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
142
+ const _for = _getAddress.call(this.llamalend, '');
143
+ const gas = await contract.create_loan.estimateGas(
144
+ _collateral, _debt, range, _for,
145
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
146
+ { ...this.llamalend.constantOptions }
147
+ );
148
+ if (estimateGas) return smartNumber(gas);
149
+
150
+ await this.llamalend.updateFeeData();
151
+ const gasLimit = _mulBy1_3(DIGas(gas));
152
+ return (await contract.create_loan(
153
+ _collateral, _debt, range, _for,
154
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
155
+ { ...this.llamalend.options, gasLimit }
156
+ )).hash;
157
+ }
158
+
159
+ protected async _borrowMoreContractCall(
160
+ _collateral: bigint, _debt: bigint, estimateGas: boolean
161
+ ): Promise<string | TGas> {
162
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
163
+ const _for = _getAddress.call(this.llamalend, '');
164
+ const gas = await contract.borrow_more.estimateGas(
165
+ _collateral, _debt, _for,
166
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
167
+ { ...this.llamalend.constantOptions }
168
+ );
169
+ if (estimateGas) return smartNumber(gas);
170
+
171
+ await this.llamalend.updateFeeData();
172
+ const gasLimit = _mulBy1_3(DIGas(gas));
173
+ return (await contract.borrow_more(
174
+ _collateral, _debt, _for,
175
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
176
+ { ...this.llamalend.options, gasLimit }
177
+ )).hash;
178
+ }
179
+
180
+ protected async _repayContractCall(
181
+ { _debt, address, n, estimateGas, shrink = false }: { _debt: bigint, address: string, n: number | bigint, estimateGas: boolean, shrink?: boolean }
182
+ ): Promise<string | TGas> {
183
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
184
+ const gas = await contract.repay.estimateGas(
185
+ _debt, address, n,
186
+ this.llamalend.constants.ZERO_ADDRESS, "0x", shrink,
187
+ { ...this.llamalend.constantOptions }
188
+ );
189
+ if (estimateGas) return smartNumber(gas);
190
+
191
+ await this.llamalend.updateFeeData();
192
+ const gasLimit = _mulBy1_3(DIGas(gas));
193
+ return (await contract.repay(
194
+ _debt, address, n,
195
+ this.llamalend.constants.ZERO_ADDRESS, "0x", shrink,
196
+ { ...this.llamalend.options, gasLimit }
197
+ )).hash;
198
+ }
199
+
200
+ protected async _partialLiquidateContractCall(
201
+ address: string, _minAmount: bigint, frac: string, estimateGas: boolean
202
+ ): Promise<string | TGas> {
203
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
204
+ const gas = await contract.liquidate.estimateGas(
205
+ address, _minAmount, frac,
206
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
207
+ this.llamalend.constantOptions
208
+ );
209
+ if (estimateGas) return smartNumber(gas);
210
+
211
+ await this.llamalend.updateFeeData();
212
+ const gasLimit = _mulBy1_3(DIGas(gas));
213
+ return (await contract.liquidate(
214
+ address, _minAmount, frac,
215
+ this.llamalend.constants.ZERO_ADDRESS, "0x",
216
+ { ...this.llamalend.options, gasLimit }
217
+ )).hash;
218
+ }
219
+
58
220
  }