@gearbox-protocol/sdk 3.0.0-next.189 → 3.0.0-next.190

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.
@@ -17,6 +17,13 @@ export interface CalcOverallAPYProps {
17
17
  baseRateWithFee: number;
18
18
  underlyingToken: string;
19
19
  }
20
+ export interface CalcMaxLendingDebtProps {
21
+ assets: Array<Asset>;
22
+ prices: Record<string, bigint>;
23
+ liquidationThresholds: Record<string, bigint>;
24
+ underlyingToken: string;
25
+ targetHF?: bigint;
26
+ }
20
27
  export interface CalcHealthFactorProps {
21
28
  assets: Array<Asset>;
22
29
  quotas: Record<string, Asset>;
@@ -115,6 +122,7 @@ export declare class CreditAccountData {
115
122
  isQuoted(token: string): boolean;
116
123
  isTokenEnabled(token: string): boolean;
117
124
  static calcMaxDebtIncrease(healthFactor: number, debt: bigint, underlyingLT: number, minHf?: number): bigint;
125
+ static calcMaxLendingDebt({ assets, liquidationThresholds, underlyingToken, prices, targetHF, }: CalcMaxLendingDebtProps): bigint;
118
126
  static calcOverallAPY({ caAssets, lpAPY, prices, quotas, quotaRates, feeInterest, totalValue, debt, baseRateWithFee, underlyingToken, }: CalcOverallAPYProps): bigint | undefined;
119
127
  hash(): string;
120
128
  static hash(creditManager: string, borrower: string): string;
@@ -155,9 +155,33 @@ class CreditAccountData {
155
155
  return this.allBalances[token].isEnabled;
156
156
  }
157
157
  static calcMaxDebtIncrease(healthFactor, debt, underlyingLT, minHf = Number(sdk_gov_1.PERCENTAGE_FACTOR)) {
158
+ // HF = (TWV + d*lt) / (D + d) => d = (HF*D - TWV) / (l - HF)
159
+ // hf = TWV / D
160
+ // HF = (TVW * D / D + d*lt) / (D + d) = (hf*D + d*lt) / (d + D) => d = D * (hf-HF) / (HF - lt)
158
161
  const result = (debt * BigInt(healthFactor - minHf)) / BigInt(minHf - underlyingLT);
159
162
  return math_1.BigIntMath.max(0n, result);
160
163
  }
164
+ static calcMaxLendingDebt({ assets, liquidationThresholds, underlyingToken, prices, targetHF = sdk_gov_1.PERCENTAGE_FACTOR, }) {
165
+ const assetsLTMoney = assets.reduce((acc, { token: tokenAddress, balance: amount }) => {
166
+ const [, tokenDecimals] = (0, sdk_gov_1.extractTokenData)(tokenAddress);
167
+ const lt = liquidationThresholds[tokenAddress] || 0n;
168
+ const price = prices[tokenAddress] || 0n;
169
+ const tokenMoney = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
170
+ const tokenLtMoney = tokenMoney * lt;
171
+ return acc + tokenLtMoney;
172
+ }, 0n);
173
+ const underlyingPrice = prices[underlyingToken] || 0n;
174
+ const [, underlyingDecimals = 18] = (0, sdk_gov_1.extractTokenData)(underlyingToken);
175
+ // HF = TWV / D => D = TWV / HF; D = amount * price
176
+ // Debt_max = sum(LT_i * Asset_i * price_i) / (price_underlying * HF)
177
+ const max = underlyingPrice > 0
178
+ ? (assetsLTMoney * 10n ** BigInt(underlyingDecimals)) /
179
+ underlyingPrice /
180
+ targetHF /
181
+ 10n ** BigInt(sdk_gov_1.WAD_DECIMALS_POW - sdk_gov_1.PRICE_DECIMALS_POW)
182
+ : 0n;
183
+ return max;
184
+ }
161
185
  static calcOverallAPY({ caAssets, lpAPY, prices, quotas, quotaRates, feeInterest, totalValue, debt, baseRateWithFee, underlyingToken, }) {
162
186
  if (!lpAPY ||
163
187
  !totalValue ||
@@ -171,10 +195,9 @@ class CreditAccountData {
171
195
  const underlyingPrice = prices[underlyingTokenAddressLC];
172
196
  const assetAPYMoney = caAssets.reduce((acc, { token: tokenAddress, balance: amount }) => {
173
197
  const tokenAddressLC = tokenAddress.toLowerCase();
174
- const symbol = sdk_gov_1.tokenSymbolByAddress[tokenAddressLC] || "";
198
+ const [symbol = "", tokenDecimals] = (0, sdk_gov_1.extractTokenData)(tokenAddressLC);
175
199
  const apy = lpAPY[symbol] || 0;
176
200
  const price = prices[tokenAddressLC] || 0n;
177
- const tokenDecimals = sdk_gov_1.decimals[symbol];
178
201
  const money = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
179
202
  const apyMoney = money * BigInt(apy);
180
203
  const { rate: quotaAPY = 0n, isActive = false } = quotaRates?.[tokenAddressLC] || {};
@@ -9,6 +9,7 @@ const creditAccount_1 = require("./creditAccount");
9
9
  const prices = {
10
10
  [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: (0, formatter_1.toBN)("1738.11830000", sdk_gov_1.PRICE_DECIMALS_POW),
11
11
  [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: (0, formatter_1.toBN)("0.99941103", sdk_gov_1.PRICE_DECIMALS_POW),
12
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: (0, formatter_1.toBN)("0.999", sdk_gov_1.PRICE_DECIMALS_POW),
12
13
  [sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: (0, formatter_1.toBN)("1703.87588096", sdk_gov_1.PRICE_DECIMALS_POW),
13
14
  };
14
15
  const lpAPY = { STETH: 38434 };
@@ -195,7 +196,7 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
195
196
  (0, chai_1.expect)(result).to.be.eq(144919n);
196
197
  });
197
198
  });
198
- describe("CreditAccount calcMaxIncreaseBorrow test", () => {
199
+ describe("CreditAccount calcMaxDebtIncrease test", () => {
199
200
  it("health max increase borrow is zero if hf < 1", () => {
200
201
  const result = creditAccount_1.CreditAccountData.calcMaxDebtIncrease(9999, BigInt("156522834253690396032546"), 9300);
201
202
  (0, chai_1.expect)(result.toString()).to.be.eq("0");
@@ -211,9 +212,121 @@ describe("CreditAccount calcMaxIncreaseBorrow test", () => {
211
212
  });
212
213
  });
213
214
  const liquidationThresholds = {
215
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: 9800n,
214
216
  [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 9300n,
215
217
  [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 8500n,
218
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: 8000n,
216
219
  };
220
+ describe("CreditAccount calcMaxLendingDebt test", () => {
221
+ it("calcMaxLendingDebt for several collaterals with zero lt", () => {
222
+ const result = creditAccount_1.CreditAccountData.calcMaxLendingDebt({
223
+ assets: [
224
+ {
225
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
226
+ balance: (0, formatter_1.toBN)("1000", sdk_gov_1.decimals.DAI),
227
+ },
228
+ {
229
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
230
+ balance: (0, formatter_1.toBN)("1", sdk_gov_1.decimals.WETH),
231
+ },
232
+ ],
233
+ liquidationThresholds: {
234
+ ...liquidationThresholds,
235
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 0n,
236
+ },
237
+ underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase(),
238
+ prices: {
239
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 1n,
240
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: 1n,
241
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 1000n,
242
+ },
243
+ });
244
+ (0, chai_1.expect)(result).to.be.eq((0, formatter_1.toBN)("850", sdk_gov_1.decimals.USDC));
245
+ });
246
+ it("calcMaxLendingDebt for several collaterals with zero underlying price", () => {
247
+ const result = creditAccount_1.CreditAccountData.calcMaxLendingDebt({
248
+ assets: [
249
+ {
250
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
251
+ balance: (0, formatter_1.toBN)("1000", sdk_gov_1.decimals.DAI),
252
+ },
253
+ {
254
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
255
+ balance: (0, formatter_1.toBN)("1", sdk_gov_1.decimals.WETH),
256
+ },
257
+ ],
258
+ liquidationThresholds: liquidationThresholds,
259
+ underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase(),
260
+ prices: {
261
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 1n,
262
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 1000n,
263
+ },
264
+ });
265
+ (0, chai_1.expect)(result).to.be.eq(0n);
266
+ });
267
+ it("calcMaxLendingDebt for simplest case", () => {
268
+ const result = creditAccount_1.CreditAccountData.calcMaxLendingDebt({
269
+ assets: [
270
+ {
271
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
272
+ balance: (0, formatter_1.toBN)("1000", sdk_gov_1.decimals.DAI),
273
+ },
274
+ ],
275
+ liquidationThresholds,
276
+ underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase(),
277
+ prices: {
278
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 1n,
279
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: 1n,
280
+ },
281
+ });
282
+ (0, chai_1.expect)(result).to.be.eq((0, formatter_1.toBN)("930", sdk_gov_1.decimals.USDC));
283
+ });
284
+ it("calcMaxLendingDebt for several collaterals", () => {
285
+ const result = creditAccount_1.CreditAccountData.calcMaxLendingDebt({
286
+ assets: [
287
+ {
288
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
289
+ balance: (0, formatter_1.toBN)("1000", sdk_gov_1.decimals.DAI),
290
+ },
291
+ {
292
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
293
+ balance: (0, formatter_1.toBN)("1", sdk_gov_1.decimals.WETH),
294
+ },
295
+ ],
296
+ liquidationThresholds,
297
+ underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase(),
298
+ prices: {
299
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 1n,
300
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: 1n,
301
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 1000n,
302
+ },
303
+ });
304
+ (0, chai_1.expect)(result).to.be.eq((0, formatter_1.toBN)("1780", sdk_gov_1.decimals.USDC));
305
+ });
306
+ it("calcMaxLendingDebt for several collaterals with target HF", () => {
307
+ const result = creditAccount_1.CreditAccountData.calcMaxLendingDebt({
308
+ assets: [
309
+ {
310
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
311
+ balance: (0, formatter_1.toBN)("1000", sdk_gov_1.decimals.DAI),
312
+ },
313
+ {
314
+ token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
315
+ balance: (0, formatter_1.toBN)("1", sdk_gov_1.decimals.WETH),
316
+ },
317
+ ],
318
+ liquidationThresholds,
319
+ underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase(),
320
+ prices: {
321
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 1n,
322
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.USDC.toLowerCase()]: 1n,
323
+ [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 1000n,
324
+ },
325
+ targetHF: 12500n,
326
+ });
327
+ (0, chai_1.expect)(result).to.be.eq((0, formatter_1.toBN)("1424", sdk_gov_1.decimals.USDC));
328
+ });
329
+ });
217
330
  const defaultCA = {
218
331
  assets: [
219
332
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "3.0.0-next.189",
3
+ "version": "3.0.0-next.190",
4
4
  "description": "Gearbox SDK",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",