@curvefi/llamalend-api 1.1.10 → 2.0.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.
Files changed (138) hide show
  1. package/docs/MIGRATION.md +325 -0
  2. package/docs/SUPPORT_LLv2.md +409 -0
  3. package/lib/constants/abis/OneWayLendingFactoryV2ABI.json +543 -0
  4. package/lib/constants/aliases.d.ts +0 -11
  5. package/lib/constants/aliases.js +1 -86
  6. package/lib/constants/coins.d.ts +0 -11
  7. package/lib/constants/coins.js +0 -14
  8. package/lib/constants/utils.d.ts +2 -0
  9. package/lib/constants/utils.js +2 -0
  10. package/lib/index.d.ts +10 -4
  11. package/lib/interfaces.d.ts +3 -2
  12. package/lib/lendMarkets/LendMarketTemplate.d.ts +13 -502
  13. package/lib/lendMarkets/LendMarketTemplate.js +237 -2860
  14. package/lib/lendMarkets/fetch/fetchFactoryData.d.ts +13 -0
  15. package/lib/lendMarkets/fetch/fetchFactoryData.js +101 -0
  16. package/lib/lendMarkets/fetch/fetchLendMarkets.d.ts +3 -0
  17. package/lib/lendMarkets/fetch/fetchLendMarkets.js +94 -0
  18. package/lib/lendMarkets/interfaces/common/amm.d.ts +10 -0
  19. package/lib/lendMarkets/interfaces/common/amm.js +1 -0
  20. package/lib/lendMarkets/interfaces/common/index.d.ts +5 -0
  21. package/lib/lendMarkets/interfaces/common/index.js +5 -0
  22. package/lib/lendMarkets/interfaces/common/prices.d.ts +13 -0
  23. package/lib/lendMarkets/interfaces/common/prices.js +1 -0
  24. package/lib/lendMarkets/interfaces/common/userPosition.d.ts +39 -0
  25. package/lib/lendMarkets/interfaces/common/userPosition.js +1 -0
  26. package/lib/lendMarkets/interfaces/common/vault.d.ts +55 -0
  27. package/lib/lendMarkets/interfaces/common/vault.js +1 -0
  28. package/lib/lendMarkets/interfaces/common/wallet.d.ts +8 -0
  29. package/lib/lendMarkets/interfaces/common/wallet.js +1 -0
  30. package/lib/lendMarkets/interfaces/v1/index.d.ts +4 -0
  31. package/lib/lendMarkets/interfaces/v1/index.js +4 -0
  32. package/lib/lendMarkets/interfaces/v1/leverageV1.d.ts +90 -0
  33. package/lib/lendMarkets/interfaces/v1/leverageV1.js +1 -0
  34. package/lib/lendMarkets/interfaces/v1/loanV1.d.ts +73 -0
  35. package/lib/lendMarkets/interfaces/v1/loanV1.js +1 -0
  36. package/lib/lendMarkets/interfaces/v1/statsV1.d.ts +49 -0
  37. package/lib/lendMarkets/interfaces/v1/statsV1.js +1 -0
  38. package/lib/lendMarkets/interfaces/v2/index.d.ts +3 -0
  39. package/lib/lendMarkets/interfaces/v2/index.js +3 -0
  40. package/lib/lendMarkets/interfaces/v2/leverageV2.d.ts +90 -0
  41. package/lib/lendMarkets/interfaces/v2/leverageV2.js +1 -0
  42. package/lib/lendMarkets/interfaces/v2/loanV2.d.ts +73 -0
  43. package/lib/lendMarkets/interfaces/v2/loanV2.js +1 -0
  44. package/lib/lendMarkets/interfaces/v2/statsV2.d.ts +49 -0
  45. package/lib/lendMarkets/interfaces/v2/statsV2.js +1 -0
  46. package/lib/lendMarkets/lendMarketConstructor.js +1 -1
  47. package/lib/lendMarkets/modules/common/amm.d.ts +19 -0
  48. package/lib/lendMarkets/modules/common/amm.js +137 -0
  49. package/lib/lendMarkets/modules/common/index.d.ts +9 -0
  50. package/lib/lendMarkets/modules/common/index.js +9 -0
  51. package/lib/lendMarkets/modules/common/leverageZapV1Base.d.ts +118 -0
  52. package/lib/lendMarkets/modules/common/leverageZapV1Base.js +770 -0
  53. package/lib/lendMarkets/modules/{leverageZapV2.d.ts → common/leverageZapV2Base.d.ts} +10 -5
  54. package/lib/lendMarkets/modules/{leverageZapV2.js → common/leverageZapV2Base.js} +36 -32
  55. package/lib/lendMarkets/modules/common/loanBase.d.ts +115 -0
  56. package/lib/lendMarkets/modules/common/loanBase.js +793 -0
  57. package/lib/lendMarkets/modules/common/prices.d.ts +19 -0
  58. package/lib/lendMarkets/modules/common/prices.js +104 -0
  59. package/lib/lendMarkets/modules/common/statsBase.d.ts +69 -0
  60. package/lib/lendMarkets/modules/common/statsBase.js +291 -0
  61. package/lib/lendMarkets/modules/common/userPosition.d.ts +46 -0
  62. package/lib/lendMarkets/modules/common/userPosition.js +223 -0
  63. package/lib/lendMarkets/modules/common/vault.d.ts +69 -0
  64. package/lib/lendMarkets/modules/common/vault.js +535 -0
  65. package/lib/lendMarkets/modules/common/wallet.d.ts +13 -0
  66. package/lib/lendMarkets/modules/common/wallet.js +28 -0
  67. package/lib/lendMarkets/modules/index.d.ts +1 -1
  68. package/lib/lendMarkets/modules/index.js +1 -1
  69. package/lib/lendMarkets/modules/v1/index.d.ts +4 -0
  70. package/lib/lendMarkets/modules/v1/index.js +4 -0
  71. package/lib/lendMarkets/modules/v1/leverageV1ZapV1.d.ts +3 -0
  72. package/lib/lendMarkets/modules/v1/leverageV1ZapV1.js +3 -0
  73. package/lib/lendMarkets/modules/v1/leverageV1ZapV2.d.ts +3 -0
  74. package/lib/lendMarkets/modules/v1/leverageV1ZapV2.js +3 -0
  75. package/lib/lendMarkets/modules/v1/loanV1.d.ts +4 -0
  76. package/lib/lendMarkets/modules/v1/loanV1.js +3 -0
  77. package/lib/lendMarkets/modules/v1/statsV1.d.ts +3 -0
  78. package/lib/lendMarkets/modules/v1/statsV1.js +3 -0
  79. package/lib/lendMarkets/modules/v2/index.d.ts +4 -0
  80. package/lib/lendMarkets/modules/v2/index.js +4 -0
  81. package/lib/lendMarkets/modules/v2/leverageV2ZapV1.d.ts +3 -0
  82. package/lib/lendMarkets/modules/v2/leverageV2ZapV1.js +3 -0
  83. package/lib/lendMarkets/modules/v2/leverageV2ZapV2.d.ts +3 -0
  84. package/lib/lendMarkets/modules/v2/leverageV2ZapV2.js +3 -0
  85. package/lib/lendMarkets/modules/v2/loanV2.d.ts +4 -0
  86. package/lib/lendMarkets/modules/v2/loanV2.js +3 -0
  87. package/lib/lendMarkets/modules/v2/statsV2.d.ts +3 -0
  88. package/lib/lendMarkets/modules/v2/statsV2.js +3 -0
  89. package/lib/llamalend.d.ts +6 -6
  90. package/lib/llamalend.js +46 -210
  91. package/lib/utils.js +2 -33
  92. package/package.json +1 -1
  93. package/src/constants/abis/OneWayLendingFactoryV2ABI.json +543 -0
  94. package/src/constants/aliases.ts +1 -97
  95. package/src/constants/coins.ts +0 -25
  96. package/src/constants/utils.ts +4 -0
  97. package/src/interfaces.ts +3 -2
  98. package/src/lendMarkets/LendMarketTemplate.ts +318 -3222
  99. package/src/lendMarkets/fetch/fetchFactoryData.ts +113 -0
  100. package/src/lendMarkets/fetch/fetchLendMarkets.ts +108 -0
  101. package/src/lendMarkets/interfaces/common/amm.ts +11 -0
  102. package/src/lendMarkets/interfaces/common/index.ts +5 -0
  103. package/src/lendMarkets/interfaces/common/prices.ts +13 -0
  104. package/src/lendMarkets/interfaces/common/userPosition.ts +24 -0
  105. package/src/lendMarkets/interfaces/common/vault.ts +48 -0
  106. package/src/lendMarkets/interfaces/common/wallet.ts +3 -0
  107. package/src/lendMarkets/interfaces/v1/index.ts +4 -0
  108. package/src/lendMarkets/interfaces/v1/leverageV1.ts +84 -0
  109. package/src/lendMarkets/interfaces/v1/loanV1.ts +77 -0
  110. package/src/lendMarkets/interfaces/v1/statsV1.ts +21 -0
  111. package/src/lendMarkets/interfaces/v2/index.ts +3 -0
  112. package/src/lendMarkets/interfaces/v2/leverageV2.ts +84 -0
  113. package/src/lendMarkets/interfaces/v2/loanV2.ts +77 -0
  114. package/src/lendMarkets/interfaces/v2/statsV2.ts +21 -0
  115. package/src/lendMarkets/lendMarketConstructor.ts +1 -1
  116. package/src/lendMarkets/modules/common/amm.ts +132 -0
  117. package/src/lendMarkets/modules/common/index.ts +9 -0
  118. package/src/lendMarkets/modules/common/leverageZapV1Base.ts +912 -0
  119. package/src/lendMarkets/modules/{leverageZapV2.ts → common/leverageZapV2Base.ts} +41 -37
  120. package/src/lendMarkets/modules/common/loanBase.ts +773 -0
  121. package/src/lendMarkets/modules/common/prices.ts +111 -0
  122. package/src/lendMarkets/modules/common/statsBase.ts +313 -0
  123. package/src/lendMarkets/modules/common/userPosition.ts +243 -0
  124. package/src/lendMarkets/modules/common/vault.ts +551 -0
  125. package/src/lendMarkets/modules/common/wallet.ts +29 -0
  126. package/src/lendMarkets/modules/index.ts +1 -1
  127. package/src/lendMarkets/modules/v1/index.ts +4 -0
  128. package/src/lendMarkets/modules/v1/leverageV1ZapV1.ts +3 -0
  129. package/src/lendMarkets/modules/v1/leverageV1ZapV2.ts +3 -0
  130. package/src/lendMarkets/modules/v1/loanV1.ts +4 -0
  131. package/src/lendMarkets/modules/v1/statsV1.ts +3 -0
  132. package/src/lendMarkets/modules/v2/index.ts +4 -0
  133. package/src/lendMarkets/modules/v2/leverageV2ZapV1.ts +3 -0
  134. package/src/lendMarkets/modules/v2/leverageV2ZapV2.ts +3 -0
  135. package/src/lendMarkets/modules/v2/loanV2.ts +4 -0
  136. package/src/lendMarkets/modules/v2/statsV2.ts +3 -0
  137. package/src/llamalend.ts +47 -244
  138. package/src/utils.ts +2 -35
@@ -0,0 +1,773 @@
1
+ import memoize from "memoizee";
2
+ import {TAmount, TGas, IPartialFrac} from "../../../interfaces";
3
+ import type { LendMarketTemplate } from "../../LendMarketTemplate";
4
+ import {
5
+ _getAddress,
6
+ parseUnits,
7
+ BN,
8
+ ensureAllowance,
9
+ hasAllowance,
10
+ ensureAllowanceEstimateGas,
11
+ formatUnits,
12
+ smartNumber,
13
+ _mulBy1_3,
14
+ DIGas, calculateFutureLeverage, MAX_ACTIVE_BAND, fromBN,
15
+ } from "../../../utils";
16
+ import {Llamalend} from "../../../llamalend";
17
+ import BigNumber from "bignumber.js";
18
+ import {_getUserCollateral} from "../../../external-api";
19
+ export class LoanBaseModule {
20
+ protected market: LendMarketTemplate;
21
+ protected llamalend: Llamalend;
22
+
23
+ constructor(market: LendMarketTemplate) {
24
+ this.market = market;
25
+ this.llamalend = market.getLlamalend();
26
+ }
27
+
28
+ public _checkRange(range: number): void {
29
+ if (range < this.market.minBands) throw Error(`range must be >= ${this.market.minBands}`);
30
+ if (range > this.market.maxBands) throw Error(`range must be <= ${this.market.maxBands}`);
31
+ }
32
+
33
+ public async createLoanMaxRecv(collateral: number | string, range: number): Promise<string> {
34
+ 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
+
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);
40
+ }
41
+
42
+ public createLoanMaxRecvAllRanges = memoize(async (collateral: number | string): Promise<{ [index: number]: string }> => {
43
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
44
+
45
+ const calls = [];
46
+ 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));
49
+ }
50
+ const _amounts = await this.llamalend.multicallProvider.all(calls) as bigint[];
51
+
52
+ const res: { [index: number]: string } = {};
53
+ for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
54
+ res[N] = formatUnits(_amounts[N - this.market.minBands], this.market.borrowed_token.decimals);
55
+ }
56
+
57
+ return res;
58
+ },
59
+ {
60
+ promise: true,
61
+ maxAge: 5 * 60 * 1000, // 5m
62
+ });
63
+
64
+ public async getMaxRange(collateral: number | string, debt: number | string): Promise<number> {
65
+ const maxRecv = await this.createLoanMaxRecvAllRanges(collateral);
66
+ for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
67
+ if (BN(debt).gt(BN(maxRecv[N]))) return N - 1;
68
+ }
69
+
70
+ return this.market.maxBands;
71
+ }
72
+
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
+ private async _createLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[bigint, bigint]> {
89
+ const _n1 = await this._calcN1(parseUnits(collateral, this.market.collateral_token.decimals), parseUnits(debt, this.market.borrowed_token.decimals), range);
90
+ const _n2 = _n1 + BigInt(range - 1);
91
+
92
+ return [_n2, _n1];
93
+ }
94
+
95
+ private async _createLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [bigint, bigint] }> {
96
+ const maxN = await this.getMaxRange(collateral, debt);
97
+ const _n1_arr = await this._calcN1AllRanges(parseUnits(collateral, this.market.collateral_token.decimals), parseUnits(debt, this.market.borrowed_token.decimals), maxN);
98
+ const _n2_arr: bigint[] = [];
99
+ for (let N = this.market.minBands; N <= maxN; N++) {
100
+ _n2_arr.push(_n1_arr[N - this.market.minBands] + BigInt(N - 1));
101
+ }
102
+
103
+ const res: { [index: number]: [bigint, bigint] } = {};
104
+ for (let N = this.market.minBands; N <= maxN; N++) {
105
+ res[N] = [_n2_arr[N - this.market.minBands], _n1_arr[N - this.market.minBands]];
106
+ }
107
+
108
+ return res;
109
+ }
110
+
111
+ public async createLoanBands(collateral: number | string, debt: number | string, range: number): Promise<[number, number]> {
112
+ const [_n2, _n1] = await this._createLoanBands(collateral, debt, range);
113
+
114
+ return [Number(_n2), Number(_n1)];
115
+ }
116
+
117
+ public async createLoanBandsAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [number, number] | null }> {
118
+ const _bandsAllRanges = await this._createLoanBandsAllRanges(collateral, debt);
119
+
120
+ const bandsAllRanges: { [index: number]: [number, number] | null } = {};
121
+ for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
122
+ if (_bandsAllRanges[N]) {
123
+ bandsAllRanges[N] = _bandsAllRanges[N].map(Number) as [number, number];
124
+ } else {
125
+ bandsAllRanges[N] = null
126
+ }
127
+ }
128
+
129
+ return bandsAllRanges;
130
+ }
131
+
132
+ public async createLoanPrices(collateral: number | string, debt: number | string, range: number): Promise<string[]> {
133
+ const [_n2, _n1] = await this._createLoanBands(collateral, debt, range);
134
+
135
+ return await this.market.prices.getPrices(_n2, _n1);
136
+ }
137
+
138
+ public async createLoanPricesAllRanges(collateral: number | string, debt: number | string): Promise<{ [index: number]: [string, string] | null }> {
139
+ const _bandsAllRanges = await this._createLoanBandsAllRanges(collateral, debt);
140
+
141
+ const pricesAllRanges: { [index: number]: [string, string] | null } = {};
142
+ for (let N = this.market.minBands; N <= this.market.maxBands; N++) {
143
+ if (_bandsAllRanges[N]) {
144
+ pricesAllRanges[N] = await this.market.prices.calcPrices(..._bandsAllRanges[N]);
145
+ } else {
146
+ pricesAllRanges[N] = null
147
+ }
148
+ }
149
+
150
+ return pricesAllRanges;
151
+ }
152
+
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
+ // TODO: verify parameters
159
+ let _health = await contract.health_calculator(this.llamalend.constants.ZERO_ADDRESS, _collateral, _debt, full, range, this.llamalend.constantOptions) as bigint;
160
+ _health = _health * BigInt(100);
161
+
162
+ return formatUnits(_health);
163
+ }
164
+
165
+ public async createLoanIsApproved(collateral: number | string): Promise<boolean> {
166
+ return await hasAllowance.call(this.llamalend, [this.market.collateral_token.address], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
167
+ }
168
+
169
+ private async createLoanApproveEstimateGas (collateral: number | string): Promise<TGas> {
170
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.collateral_token.address], [collateral], this.market.addresses.controller);
171
+ }
172
+
173
+ public async createLoanApprove(collateral: number | string): Promise<string[]> {
174
+ return await ensureAllowance.call(this.llamalend, [this.market.collateral_token.address], [collateral], this.market.addresses.controller);
175
+ }
176
+
177
+ private async _createLoan(collateral: number | string, debt: number | string, range: number, estimateGas: boolean): Promise<string | TGas> {
178
+ if (await this.market.userPosition.userLoanExists()) throw Error("Loan already created");
179
+ this._checkRange(range);
180
+
181
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
182
+ const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
183
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
184
+ const gas = await contract.create_loan.estimateGas(_collateral, _debt, range, { ...this.llamalend.constantOptions });
185
+ if (estimateGas) return smartNumber(gas);
186
+
187
+ await this.llamalend.updateFeeData();
188
+ const gasLimit = _mulBy1_3(DIGas(gas));
189
+ // TODO: ABI has changed (see docs)
190
+ return (await contract.create_loan(_collateral, _debt, range, { ...this.llamalend.options, gasLimit })).hash
191
+ }
192
+
193
+ public async createLoanEstimateGas(collateral: number | string, debt: number | string, range: number): Promise<TGas> {
194
+ if (!(await this.createLoanIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
195
+ return await this._createLoan(collateral, debt, range, true) as TGas;
196
+ }
197
+
198
+ public async createLoan(collateral: number | string, debt: number | string, range: number): Promise<string> {
199
+ await this.createLoanApprove(collateral);
200
+ return await this._createLoan(collateral, debt, range, false) as string;
201
+ }
202
+
203
+ // ---------------- BORROW MORE ----------------
204
+
205
+ public async borrowMoreMaxRecv(collateralAmount: number | string): Promise<string> {
206
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
207
+ const _collateral = _currentCollateral + parseUnits(collateralAmount, this.market.collateral_token.decimals);
208
+
209
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
210
+ const _debt: bigint = await contract.max_borrowable(_collateral, _N, _currentDebt, this.llamalend.constantOptions);
211
+ // TODO: max_borrowable(deltaCollateral, _N, user) - debt is now calculated under the hood, return as is
212
+ return formatUnits(_debt - _currentDebt, this.market.borrowed_token.decimals);
213
+ }
214
+
215
+ private async _borrowMoreBands(collateral: number | string, debt: number | string): Promise<[bigint, bigint]> {
216
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
217
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${this.llamalend.signerAddress} does not exist`);
218
+
219
+ const _collateral = _currentCollateral + parseUnits(collateral, this.market.collateral_token.decimals);
220
+ const _debt = _currentDebt + parseUnits(debt, this.market.borrowed_token.decimals);
221
+
222
+ const _n1 = await this._calcN1(_collateral, _debt, Number(_N));
223
+ const _n2 = _n1 + _N - BigInt(1);
224
+
225
+ return [_n2, _n1];
226
+ }
227
+
228
+ public async borrowMoreBands(collateral: number | string, debt: number | string): Promise<[number, number]> {
229
+ const [_n2, _n1] = await this._borrowMoreBands(collateral, debt);
230
+
231
+ return [Number(_n2), Number(_n1)];
232
+ }
233
+
234
+ public async borrowMorePrices(collateral: number | string, debt: number | string): Promise<string[]> {
235
+ const [_n2, _n1] = await this._borrowMoreBands(collateral, debt);
236
+
237
+ return await this.market.prices.getPrices(_n2, _n1);
238
+ }
239
+
240
+ public async borrowMoreHealth(collateral: number | string, debt: number | string, full = true, address = ""): Promise<string> {
241
+ address = _getAddress.call(this.llamalend, address);
242
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
243
+ const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
244
+
245
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
246
+ let _health = await contract.health_calculator(address, _collateral, _debt, full, 0, this.llamalend.constantOptions) as bigint;
247
+ _health = _health * BigInt(100);
248
+
249
+ return formatUnits(_health);
250
+ }
251
+
252
+ public async borrowMoreIsApproved(collateral: number | string): Promise<boolean> {
253
+ return await hasAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
254
+ }
255
+
256
+ private async borrowMoreApproveEstimateGas (collateral: number | string): Promise<TGas> {
257
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.market.addresses.controller);
258
+ }
259
+
260
+ public async borrowMoreApprove(collateral: number | string): Promise<string[]> {
261
+ return await ensureAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.market.addresses.controller);
262
+ }
263
+
264
+ private async _borrowMore(collateral: number | string, debt: number | string, estimateGas: boolean): Promise<string | TGas> {
265
+ const { borrowed, debt: currentDebt } = await this.market.userPosition.userState();
266
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${this.llamalend.signerAddress} does not exist`);
267
+ if (Number(borrowed) > 0) throw Error(`User ${this.llamalend.signerAddress} is already in liquidation mode`);
268
+
269
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
270
+ const _debt = parseUnits(debt, this.market.borrowed_token.decimals);
271
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
272
+ const gas = await contract.borrow_more.estimateGas(_collateral, _debt, { ...this.llamalend.constantOptions });
273
+ if (estimateGas) return smartNumber(gas);
274
+
275
+ await this.llamalend.updateFeeData();
276
+ const gasLimit = _mulBy1_3(DIGas(gas));
277
+ return (await contract.borrow_more(_collateral, _debt, { ...this.llamalend.options, gasLimit })).hash
278
+ }
279
+
280
+ public async borrowMoreEstimateGas(collateral: number | string, debt: number | string): Promise<TGas> {
281
+ if (!(await this.borrowMoreIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
282
+ return await this._borrowMore(collateral, debt, true) as TGas;
283
+ }
284
+
285
+ public async borrowMore(collateral: number | string, debt: number | string): Promise<string> {
286
+ await this.borrowMoreApprove(collateral);
287
+ return await this._borrowMore(collateral, debt, false) as string;
288
+ }
289
+
290
+ public async borrowMoreFutureLeverage(collateral: number | string, debt: number | string, userAddress = ''): Promise<string> {
291
+ userAddress = _getAddress.call(this.llamalend, userAddress);
292
+ const { stateCollateral, totalDepositFromUser } = await this.market.userPosition.getCurrentLeverageParams(userAddress);
293
+
294
+ const collateralFromDebt = await this.market.amm.swapExpected(0, 1, debt);
295
+
296
+ const futureCollateralState = BN(stateCollateral).plus(collateralFromDebt);
297
+ const futureTotalDepositFromUserPrecise = BN(totalDepositFromUser).plus(collateral);
298
+
299
+ return futureCollateralState.div(futureTotalDepositFromUserPrecise).toString();
300
+ }
301
+
302
+ // ---------------- ADD COLLATERAL ----------------
303
+
304
+ private async _addCollateralBands(collateral: number | string, address = ""): Promise<[bigint, bigint]> {
305
+ address = _getAddress.call(this.llamalend, address);
306
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt(address);
307
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
308
+
309
+ const _collateral = _currentCollateral + parseUnits(collateral, this.market.collateral_token.decimals);
310
+ const _n1 = await this._calcN1(_collateral, _currentDebt, Number(_N));
311
+ const _n2 = _n1 + _N - BigInt(1);
312
+
313
+ return [_n2, _n1];
314
+ }
315
+
316
+ public async addCollateralBands(collateral: number | string, address = ""): Promise<[number, number]> {
317
+ const [_n2, _n1] = await this._addCollateralBands(collateral, address);
318
+
319
+ return [Number(_n2), Number(_n1)];
320
+ }
321
+
322
+ public async addCollateralPrices(collateral: number | string, address = ""): Promise<string[]> {
323
+ const [_n2, _n1] = await this._addCollateralBands(collateral, address);
324
+
325
+ return await this.market.prices.getPrices(_n2, _n1);
326
+ }
327
+
328
+ public async addCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
329
+ address = _getAddress.call(this.llamalend, address);
330
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
331
+
332
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
333
+ let _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
334
+ _health = _health * BigInt(100);
335
+
336
+ return formatUnits(_health);
337
+ }
338
+
339
+ public async addCollateralIsApproved(collateral: number | string): Promise<boolean> {
340
+ return await hasAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.llamalend.signerAddress, this.market.addresses.controller);
341
+ }
342
+
343
+ private async addCollateralApproveEstimateGas (collateral: number | string): Promise<TGas> {
344
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.market.addresses.controller);
345
+ }
346
+
347
+ public async addCollateralApprove(collateral: number | string): Promise<string[]> {
348
+ return await ensureAllowance.call(this.llamalend, [this.market.addresses.collateral_token], [collateral], this.market.addresses.controller);
349
+ }
350
+
351
+ private async _addCollateral(collateral: number | string, address: string, estimateGas: boolean): Promise<string | TGas> {
352
+ const { borrowed, debt: currentDebt } = await this.market.userPosition.userState(address);
353
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
354
+ if (Number(borrowed) > 0) throw Error(`User ${address} is already in liquidation mode`);
355
+
356
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
357
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
358
+ const gas = await contract.add_collateral.estimateGas(_collateral, address, { ...this.llamalend.constantOptions });
359
+ if (estimateGas) return smartNumber(gas);
360
+
361
+ await this.llamalend.updateFeeData();
362
+ const gasLimit = _mulBy1_3(DIGas(gas));
363
+ return (await contract.add_collateral(_collateral, address, { ...this.llamalend.options, gasLimit })).hash
364
+ }
365
+
366
+ public async addCollateralEstimateGas(collateral: number | string, address = ""): Promise<TGas> {
367
+ address = _getAddress.call(this.llamalend, address);
368
+ if (!(await this.addCollateralIsApproved(collateral))) throw Error("Approval is needed for gas estimation");
369
+ return await this._addCollateral(collateral, address, true) as TGas;
370
+ }
371
+
372
+ public async addCollateral(collateral: number | string, address = ""): Promise<string> {
373
+ address = _getAddress.call(this.llamalend, address);
374
+ await this.addCollateralApprove(collateral);
375
+ return await this._addCollateral(collateral, address, false) as string;
376
+ }
377
+
378
+ public async addCollateralFutureLeverage(collateral: number | string, userAddress = ''): Promise<string> {
379
+ userAddress = _getAddress.call(this.llamalend, userAddress);
380
+ const [userCollateral, {collateral: currentCollateral}] = await Promise.all([
381
+ _getUserCollateral(this.llamalend.constants.NETWORK_NAME, this.market.addresses.controller, userAddress),
382
+ this.market.userPosition.userState(userAddress),
383
+ ]);
384
+
385
+ const total_deposit_from_user = userCollateral.total_deposit_from_user_precise;
386
+
387
+ return calculateFutureLeverage(currentCollateral, total_deposit_from_user, collateral, 'add');
388
+ }
389
+
390
+ // ---------------- REMOVE COLLATERAL ----------------
391
+
392
+ public async maxRemovable(): Promise<string> {
393
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
394
+ const _requiredCollateral = await this.llamalend.contracts[this.market.addresses.controller].contract.min_collateral(_currentDebt, _N, this.llamalend.constantOptions)
395
+
396
+ return formatUnits(_currentCollateral - _requiredCollateral, this.market.collateral_token.decimals);
397
+ }
398
+
399
+ private async _removeCollateralBands(collateral: number | string): Promise<[bigint, bigint]> {
400
+ const { _collateral: _currentCollateral, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt();
401
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${this.llamalend.signerAddress} does not exist`);
402
+
403
+ const _collateral = _currentCollateral - parseUnits(collateral, this.market.collateral_token.decimals);
404
+ const _n1 = await this._calcN1(_collateral, _currentDebt, Number(_N));
405
+ const _n2 = _n1 + _N - BigInt(1);
406
+
407
+ return [_n2, _n1];
408
+ }
409
+
410
+ public async removeCollateralBands(collateral: number | string): Promise<[number, number]> {
411
+ const [_n2, _n1] = await this._removeCollateralBands(collateral);
412
+
413
+ return [Number(_n2), Number(_n1)];
414
+ }
415
+
416
+ public async removeCollateralPrices(collateral: number | string): Promise<string[]> {
417
+ const [_n2, _n1] = await this._removeCollateralBands(collateral);
418
+
419
+ return await this.market.prices.getPrices(_n2, _n1);
420
+ }
421
+
422
+ public async removeCollateralHealth(collateral: number | string, full = true, address = ""): Promise<string> {
423
+ address = _getAddress.call(this.llamalend, address);
424
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals) * BigInt(-1);
425
+
426
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
427
+ let _health = await contract.health_calculator(address, _collateral, 0, full, 0, this.llamalend.constantOptions) as bigint;
428
+ _health = _health * BigInt(100);
429
+
430
+ return formatUnits(_health);
431
+ }
432
+
433
+ private async _removeCollateral(collateral: number | string, estimateGas: boolean): Promise<string | TGas> {
434
+ const { borrowed, debt: currentDebt } = await this.market.userPosition.userState();
435
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${this.llamalend.signerAddress} does not exist`);
436
+ if (Number(borrowed) > 0) throw Error(`User ${this.llamalend.signerAddress} is already in liquidation mode`);
437
+
438
+ const _collateral = parseUnits(collateral, this.market.collateral_token.decimals);
439
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
440
+ const gas = await contract.remove_collateral.estimateGas(_collateral, this.llamalend.constantOptions);
441
+ if (estimateGas) return smartNumber(gas);
442
+
443
+ await this.llamalend.updateFeeData();
444
+ const gasLimit = _mulBy1_3(DIGas(gas));
445
+ return (await contract.remove_collateral(_collateral, { ...this.llamalend.options, gasLimit })).hash
446
+ }
447
+
448
+ public async removeCollateralEstimateGas(collateral: number | string): Promise<TGas> {
449
+ return await this._removeCollateral(collateral, true) as TGas;
450
+ }
451
+
452
+ public async removeCollateral(collateral: number | string): Promise<string> {
453
+ return await this._removeCollateral(collateral, false) as string;
454
+ }
455
+
456
+ public async removeCollateralFutureLeverage(collateral: number | string, userAddress = ''): Promise<string> {
457
+ userAddress = _getAddress.call(this.llamalend, userAddress);
458
+ const [userCollateral, {collateral: currentCollateral}] = await Promise.all([
459
+ _getUserCollateral(this.llamalend.constants.NETWORK_NAME, this.market.addresses.controller, userAddress),
460
+ this.market.userPosition.userState(userAddress),
461
+ ]);
462
+
463
+ const total_deposit_from_user = userCollateral.total_deposit_from_user_precise;
464
+
465
+ return calculateFutureLeverage(currentCollateral, total_deposit_from_user, collateral, 'remove');
466
+ }
467
+
468
+ // ---------------- REPAY ----------------
469
+ // TODO: add shrink: bool parameter
470
+ // If bool is true, _N = n2 - n1 + 1 -> _N = n2 - activeBand
471
+ private async _repayBands(debt: number | string, address: string): Promise<[bigint, bigint]> {
472
+ const { _collateral: _currentCollateral, _borrowed, _debt: _currentDebt, _N } = await this.market.userPosition.userStateBigInt(address);
473
+ if (_currentDebt === BigInt(0)) throw Error(`Loan for ${address} does not exist`);
474
+ // && shrink === false
475
+ if (_borrowed > BigInt(0)) return await this.market.userPosition.userBandsBigInt(address) as [bigint, bigint];
476
+ // If shrink == true, then _debt = _currentDebt - parseUnits(debt, this.market.borrowed_token.decimals) - _borrowed
477
+ const _debt = _currentDebt - parseUnits(debt, this.market.borrowed_token.decimals);
478
+ const _n1 = await this._calcN1(_currentCollateral, _debt, Number(_N));
479
+ const _n2 = _n1 + _N - BigInt(1);
480
+
481
+ return [_n2, _n1];
482
+ }
483
+
484
+ public async repayBands(debt: number | string, address = ""): Promise<[number, number]> {
485
+ const [_n2, _n1] = await this._repayBands(debt, address);
486
+
487
+ return [Number(_n2), Number(_n1)];
488
+ }
489
+
490
+ public async repayPrices(debt: number | string, address = ""): Promise<string[]> {
491
+ const [_n2, _n1] = await this._repayBands(debt, address);
492
+
493
+ return await this.market.prices.getPrices(_n2, _n1);
494
+ }
495
+
496
+ public async repayIsApproved(debt: number | string): Promise<boolean> {
497
+ return await hasAllowance.call(this.llamalend, [this.market.borrowed_token.address], [debt], this.llamalend.signerAddress, this.market.addresses.controller);
498
+ }
499
+
500
+ private async repayApproveEstimateGas (debt: number | string): Promise<TGas> {
501
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.borrowed_token.address], [debt], this.market.addresses.controller);
502
+ }
503
+
504
+ public async repayApprove(debt: number | string): Promise<string[]> {
505
+ return await ensureAllowance.call(this.llamalend, [this.market.borrowed_token.address], [debt], this.market.addresses.controller);
506
+ }
507
+
508
+ public async repayHealth(debt: number | string, full = true, address = ""): Promise<string> {
509
+ address = _getAddress.call(this.llamalend, address);
510
+ const _debt = parseUnits(debt) * BigInt(-1);
511
+
512
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
513
+ let _health = await contract.health_calculator(address, 0, _debt, full, 0, this.llamalend.constantOptions) as bigint;
514
+ _health = _health * BigInt(100);
515
+
516
+ return formatUnits(_health);
517
+ }
518
+
519
+ private async _repay(debt: number | string, address: string, estimateGas: boolean): Promise<string | TGas> {
520
+ address = _getAddress.call(this.llamalend, address);
521
+ const { debt: currentDebt } = await this.market.userPosition.userState(address);
522
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
523
+
524
+ const _debt = parseUnits(debt);
525
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
526
+ const [, n1] = await this.market.userPosition.userBands(address);
527
+ const { borrowed } = await this.market.userPosition.userState(address);
528
+ const n = (BN(borrowed).gt(0)) ? MAX_ACTIVE_BAND : n1 - 1; // In liquidation mode it doesn't matter if active band moves
529
+ const gas = await contract.repay.estimateGas(_debt, address, n, this.llamalend.constantOptions);
530
+ if (estimateGas) return smartNumber(gas);
531
+
532
+ await this.llamalend.updateFeeData();
533
+ const gasLimit = _mulBy1_3(DIGas(gas));
534
+ // TODO: shrink parameter is added, which changes bands calculation
535
+ return (await contract.repay(_debt, address, n, { ...this.llamalend.options, gasLimit })).hash
536
+ }
537
+
538
+ public async repayEstimateGas(debt: number | string, address = ""): Promise<TGas> {
539
+ if (!(await this.repayIsApproved(debt))) throw Error("Approval is needed for gas estimation");
540
+ return await this._repay(debt, address, true) as TGas;
541
+ }
542
+
543
+ public async repay(debt: number | string, address = ""): Promise<string> {
544
+ await this.repayApprove(debt);
545
+ return await this._repay(debt, address, false) as string;
546
+ }
547
+
548
+ public async repayFutureLeverage(debt: number | string, userAddress = ''): Promise<string> {
549
+ userAddress = _getAddress.call(this.llamalend, userAddress);
550
+ const { stateCollateral, totalDepositFromUser } = await this.market.userPosition.getCurrentLeverageParams(userAddress);
551
+
552
+ const collateralFromDebt = await this.market.amm.swapExpected(0, 1, debt);
553
+
554
+ const futureCollateralState = BN(stateCollateral);
555
+ const futureTotalDepositFromUserPrecise = BN(totalDepositFromUser).plus(collateralFromDebt);
556
+
557
+ return futureCollateralState.div(futureTotalDepositFromUserPrecise).toString();
558
+ }
559
+
560
+ // ---------------- FULL REPAY ----------------
561
+
562
+ private async _fullRepayAmount(address = ""): Promise<string> {
563
+ address = _getAddress.call(this.llamalend, address);
564
+ // TODO: now debt is _borrowed
565
+ const { debt } = await this.market.userPosition.userState(address);
566
+ return BN(debt).times(1.0001).toString();
567
+ }
568
+
569
+ public async fullRepayIsApproved(address = ""): Promise<boolean> {
570
+ address = _getAddress.call(this.llamalend, address);
571
+ const fullRepayAmount = await this._fullRepayAmount(address);
572
+ return await this.repayIsApproved(fullRepayAmount);
573
+ }
574
+
575
+ private async fullRepayApproveEstimateGas (address = ""): Promise<TGas> {
576
+ address = _getAddress.call(this.llamalend, address);
577
+ const fullRepayAmount = await this._fullRepayAmount(address);
578
+ return await this.repayApproveEstimateGas(fullRepayAmount);
579
+ }
580
+
581
+ public async fullRepayApprove(address = ""): Promise<string[]> {
582
+ address = _getAddress.call(this.llamalend, address);
583
+ const fullRepayAmount = await this._fullRepayAmount(address);
584
+ return await this.repayApprove(fullRepayAmount);
585
+ }
586
+
587
+ public async fullRepayEstimateGas(address = ""): Promise<TGas> {
588
+ address = _getAddress.call(this.llamalend, address);
589
+ const fullRepayAmount = await this._fullRepayAmount(address);
590
+ if (!(await this.repayIsApproved(fullRepayAmount))) throw Error("Approval is needed for gas estimation");
591
+ return await this._repay(fullRepayAmount, address, true) as TGas;
592
+ }
593
+
594
+ public async fullRepay(address = ""): Promise<string> {
595
+ address = _getAddress.call(this.llamalend, address);
596
+ const fullRepayAmount = await this._fullRepayAmount(address);
597
+ await this.repayApprove(fullRepayAmount);
598
+ return await this._repay(fullRepayAmount, address, false) as string;
599
+ }
600
+
601
+ // ---------------- LIQUIDATE ----------------
602
+
603
+ public async tokensToLiquidate(address = ""): Promise<string> {
604
+ address = _getAddress.call(this.llamalend, address);
605
+ const _tokens = await this.llamalend.contracts[this.market.addresses.controller].contract.tokens_to_liquidate(address, this.llamalend.constantOptions) as bigint;
606
+ return formatUnits(_tokens, this.market.borrowed_token.decimals)
607
+ }
608
+
609
+ public async calcPartialFrac(amount: TAmount, address = ""): Promise<IPartialFrac> {
610
+ address = _getAddress.call(this.llamalend, address);
611
+ const tokensToLiquidate = await this.tokensToLiquidate(address);
612
+
613
+ const amountBN = BN(amount);
614
+ const tokensToLiquidateBN = BN(tokensToLiquidate);
615
+
616
+ if (amountBN.gt(tokensToLiquidateBN)) throw Error("Amount cannot be greater than total tokens to liquidate");
617
+ if (amountBN.lte(0)) throw Error("Amount must be greater than 0");
618
+
619
+ // Calculate frac = amount / tokensToLiquidate * 10**18
620
+ // 100% = 10**18
621
+ const fracDecimalBN = amountBN.div(tokensToLiquidateBN);
622
+ const frac = fromBN(fracDecimalBN);
623
+ return {
624
+ frac: frac.toString(),
625
+ fracDecimal: fracDecimalBN.toString(),
626
+ amount: amountBN.toString(),
627
+ };
628
+ }
629
+
630
+
631
+ public async liquidateIsApproved(address = ""): Promise<boolean> {
632
+ const tokensToLiquidate = await this.tokensToLiquidate(address);
633
+ return await hasAllowance.call(this.llamalend, [this.market.addresses.borrowed_token], [tokensToLiquidate], this.llamalend.signerAddress, this.market.addresses.controller);
634
+ }
635
+
636
+ private async liquidateApproveEstimateGas (address = ""): Promise<TGas> {
637
+ const tokensToLiquidate = await this.tokensToLiquidate(address);
638
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.addresses.borrowed_token], [tokensToLiquidate], this.market.addresses.controller);
639
+ }
640
+
641
+ public async liquidateApprove(address = ""): Promise<string[]> {
642
+ const tokensToLiquidate = await this.tokensToLiquidate(address);
643
+ return await ensureAllowance.call(this.llamalend, [this.market.addresses.borrowed_token], [tokensToLiquidate], this.market.addresses.controller);
644
+ }
645
+
646
+ private async _liquidate(address: string, slippage: number, estimateGas: boolean): Promise<string | TGas> {
647
+ const { borrowed, debt: currentDebt } = await this.market.userPosition.userState(address);
648
+ if (slippage <= 0) throw Error("Slippage must be > 0");
649
+ if (slippage > 100) throw Error("Slippage must be <= 100");
650
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
651
+ if (Number(borrowed) === 0) throw Error(`User ${address} is not in liquidation mode`);
652
+
653
+ const minAmountBN: BigNumber = BN(borrowed).times(100 - slippage).div(100);
654
+ const _minAmount = fromBN(minAmountBN);
655
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
656
+ const gas = (await contract.liquidate.estimateGas(address, _minAmount, this.llamalend.constantOptions))
657
+ if (estimateGas) return smartNumber(gas);
658
+
659
+ await this.llamalend.updateFeeData();
660
+ const gasLimit = _mulBy1_3(DIGas(gas));
661
+ return (await contract.liquidate(address, _minAmount, { ...this.llamalend.options, gasLimit })).hash
662
+ }
663
+
664
+ private async _partialLiquidate(address: string, partialFrac: IPartialFrac, slippage: number, estimateGas: boolean): Promise<string | TGas> {
665
+ const { borrowed, debt: currentDebt } = await this.market.userPosition.userState(address);
666
+ if (slippage <= 0) throw Error("Slippage must be > 0");
667
+ if (slippage > 100) throw Error("Slippage must be <= 100");
668
+ if (Number(currentDebt) === 0) throw Error(`Loan for ${address} does not exist`);
669
+ if (Number(borrowed) === 0) throw Error(`User ${address} is not in liquidation mode`);
670
+
671
+ const frac = partialFrac.frac;
672
+ const fracBN = BN(partialFrac.fracDecimal);
673
+
674
+ const borrowedBN = BN(borrowed);
675
+ const expectedBorrowedBN = borrowedBN.times(fracBN);
676
+ const minAmountBN = expectedBorrowedBN.times(100 - slippage).div(100);
677
+ const _minAmount = fromBN(minAmountBN);
678
+
679
+ const contract = this.llamalend.contracts[this.market.addresses.controller].contract;
680
+ const gas = (await contract.liquidate_extended.estimateGas(
681
+ address,
682
+ _minAmount,
683
+ frac,
684
+ this.llamalend.constants.ZERO_ADDRESS,
685
+ [],
686
+ this.llamalend.constantOptions
687
+ ));
688
+
689
+ if (estimateGas) return smartNumber(gas);
690
+
691
+ await this.llamalend.updateFeeData();
692
+ const gasLimit = _mulBy1_3(DIGas(gas));
693
+ return (await contract.liquidate_extended(
694
+ address,
695
+ _minAmount,
696
+ frac,
697
+ this.llamalend.constants.ZERO_ADDRESS,
698
+ [],
699
+ { ...this.llamalend.options, gasLimit }
700
+ )).hash;
701
+ }
702
+
703
+ public async liquidateEstimateGas(address: string, slippage = 0.1): Promise<TGas> {
704
+ if (!(await this.liquidateIsApproved(address))) throw Error("Approval is needed for gas estimation");
705
+ return await this._liquidate(address, slippage, true) as TGas;
706
+ }
707
+
708
+ public async liquidate(address: string, slippage = 0.1): Promise<string> {
709
+ await this.liquidateApprove(address);
710
+ return await this._liquidate(address, slippage, false) as string;
711
+ }
712
+
713
+ // ---------------- SELF-LIQUIDATE ----------------
714
+
715
+ public async selfLiquidateIsApproved(): Promise<boolean> {
716
+ return await this.liquidateIsApproved()
717
+ }
718
+
719
+ private async selfLiquidateApproveEstimateGas (): Promise<TGas> {
720
+ return this.liquidateApproveEstimateGas()
721
+ }
722
+
723
+ public async selfLiquidateApprove(): Promise<string[]> {
724
+ return await this.liquidateApprove()
725
+ }
726
+
727
+ public async selfLiquidateEstimateGas(slippage = 0.1): Promise<TGas> {
728
+ if (!(await this.selfLiquidateIsApproved())) throw Error("Approval is needed for gas estimation");
729
+ return await this._liquidate(this.llamalend.signerAddress, slippage, true) as TGas;
730
+ }
731
+
732
+ public async selfLiquidate(slippage = 0.1): Promise<string> {
733
+ await this.selfLiquidateApprove();
734
+ return await this._liquidate(this.llamalend.signerAddress, slippage, false) as string;
735
+ }
736
+
737
+ // ---------------- PARTIAL SELF-LIQUIDATE ----------------
738
+
739
+ public async partialSelfLiquidateIsApproved(partialFrac: IPartialFrac): Promise<boolean> {
740
+ return await hasAllowance.call(this.llamalend, [this.market.addresses.borrowed_token], [partialFrac.amount], this.llamalend.signerAddress, this.market.addresses.controller);
741
+ }
742
+
743
+ private async partialSelfLiquidateApproveEstimateGas(partialFrac: IPartialFrac): Promise<TGas> {
744
+ return await ensureAllowanceEstimateGas.call(this.llamalend, [this.market.addresses.borrowed_token], [partialFrac.amount], this.market.addresses.controller);
745
+ }
746
+
747
+ public async partialSelfLiquidateApprove(partialFrac: IPartialFrac): Promise<string[]> {
748
+ return await ensureAllowance.call(this.llamalend, [this.market.addresses.borrowed_token], [partialFrac.amount], this.market.addresses.controller);
749
+ }
750
+
751
+ public async partialSelfLiquidateEstimateGas(partialFrac: IPartialFrac, slippage = 0.1): Promise<TGas> {
752
+ if (!(await this.partialSelfLiquidateIsApproved(partialFrac))) throw Error("Approval is needed for gas estimation");
753
+ return await this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, true) as TGas;
754
+ }
755
+
756
+ public async partialSelfLiquidate(partialFrac: IPartialFrac, slippage = 0.1): Promise<string> {
757
+ await this.partialSelfLiquidateApprove(partialFrac);
758
+ return await this._partialLiquidate(this.llamalend.signerAddress, partialFrac, slippage, false) as string;
759
+ }
760
+
761
+ public estimateGas = {
762
+ createLoan: this.createLoanEstimateGas.bind(this),
763
+ borrowMore: this.borrowMoreEstimateGas.bind(this),
764
+ addCollateral: this.addCollateralEstimateGas.bind(this),
765
+ removeCollateral: this.removeCollateralEstimateGas.bind(this),
766
+ repay: this.repayEstimateGas.bind(this),
767
+ fullRepay: this.fullRepayEstimateGas.bind(this),
768
+ liquidate: this.liquidateEstimateGas.bind(this),
769
+ selfLiquidate: this.selfLiquidateEstimateGas.bind(this),
770
+ partialSelfLiquidate: this.partialSelfLiquidateEstimateGas.bind(this),
771
+ };
772
+
773
+ }