@gearbox-protocol/sdk 1.25.0 → 1.25.2

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.
@@ -13,7 +13,7 @@ class AssetUtils {
13
13
  const alreadySelected = selectedRecord[allowedToken.toLowerCase()];
14
14
  return !alreadySelected;
15
15
  });
16
- const sorted = (0, creditAccount_1.sortBalances)(AssetUtils.getBalances(notSelected, balances), prices, tokensList);
16
+ const sorted = creditAccount_1.CreditAccountData.sortBalances(AssetUtils.getBalances(notSelected, balances), prices, tokensList);
17
17
  const [address] = sorted[0] || [];
18
18
  return address;
19
19
  }
@@ -17,7 +17,7 @@ export declare const CHAINS: {
17
17
  readonly Polygon: 137;
18
18
  };
19
19
  export declare const supportedChains: readonly ["Mainnet", "Arbitrum"];
20
- export type NetworkType = typeof supportedChains[number];
20
+ export type NetworkType = (typeof supportedChains)[number];
21
21
  export declare const getNetworkType: (chainId: number, localAs?: NetworkType) => NetworkType;
22
22
  export declare const isSupportedNetwork: (chainId: number | undefined) => chainId is number;
23
23
  export declare function detectNetwork(provider: ethers.providers.Provider): Promise<NetworkType>;
@@ -4,6 +4,22 @@ import { TokenData } from "../tokens/tokenData";
4
4
  import { Asset } from "./assets";
5
5
  import { CreditManagerData } from "./creditManager";
6
6
  import { PriceOracleData } from "./priceOracle";
7
+ export interface CalcOverallAPYProps {
8
+ caAssets: Array<Asset>;
9
+ lpAPY: LpTokensAPY | undefined;
10
+ prices: Record<string, bigint>;
11
+ totalValue: bigint | undefined;
12
+ debt: bigint | undefined;
13
+ borrowRate: number;
14
+ underlyingToken: string;
15
+ }
16
+ export interface CalcHealthFactorProps {
17
+ assets: Array<Asset>;
18
+ prices: Record<string, bigint>;
19
+ liquidationThresholds: Record<string, bigint>;
20
+ underlyingToken: string;
21
+ borrowed: bigint;
22
+ }
7
23
  export declare class CreditAccountData {
8
24
  readonly addr: string;
9
25
  readonly borrower: string;
@@ -14,40 +30,33 @@ export declare class CreditAccountData {
14
30
  readonly cumulativeIndexAtOpen: bigint;
15
31
  readonly borrowedAmount: bigint;
16
32
  readonly borrowedAmountPlusInterestAndFees: bigint;
17
- borrowedAmountPlusInterest: bigint;
18
- totalValue: bigint;
33
+ readonly borrowedAmountPlusInterest: bigint;
34
+ readonly totalValue: bigint;
19
35
  healthFactor: number;
20
- borrowRate: number;
21
- readonly collateralTokens: Array<string>;
22
- readonly allTokens: Array<string>;
23
- balances: Record<string, bigint>;
24
- allBalances: Record<string, bigint>;
36
+ readonly borrowRate: number;
25
37
  isDeleting: boolean;
26
- enabledTokenMask: bigint;
38
+ readonly enabledTokenMask: bigint;
27
39
  readonly version: number;
40
+ readonly collateralTokens: Array<string>;
41
+ readonly allTokens: Array<string>;
42
+ readonly forbiddenTokens: Array<string>;
43
+ readonly balances: Record<string, bigint>;
44
+ readonly allBalances: Record<string, bigint>;
28
45
  readonly repayAmount: bigint;
29
46
  readonly liquidationAmount: bigint;
30
47
  readonly canBeClosed: boolean;
31
48
  constructor(payload: CreditAccountDataPayload);
32
49
  balancesSorted(prices: Record<string, bigint>, tokens: Record<string, TokenData>): Array<Asset>;
50
+ static sortBalances(balances: Record<string, bigint>, prices: Record<string, bigint>, tokens: Record<string, TokenData>): Array<[string, bigint]>;
51
+ static tokensAbcComparator(t1?: TokenData, t2?: TokenData): 1 | -1;
52
+ static amountAbcComparator(t1: bigint, t2: bigint): 1 | -1;
33
53
  calcBorrowAmountPlusInterestRate(currentCumulativeIndex: bigint): bigint;
54
+ isForbidden(token: string): boolean;
34
55
  updateHealthFactor(creditManager: CreditManagerData, currentCumulativeIndex: bigint, priceOracle: PriceOracleData): void;
35
56
  static isTokenEnabled(index: number, enabledTokenMask: bigint): boolean;
36
57
  static calcMaxIncreaseBorrow(healthFactor: number, borrowAmountPlusInterest: bigint, maxLeverageFactor: number, underlyingLT: number, minHf?: bigint): bigint;
37
- get id(): string;
58
+ static calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt, borrowRate, underlyingToken, }: CalcOverallAPYProps): number | undefined;
38
59
  hash(): string;
39
60
  static hash(creditManager: string, borrower: string): string;
61
+ static calcHealthFactor({ assets, prices, liquidationThresholds, underlyingToken, borrowed, }: CalcHealthFactorProps): number;
40
62
  }
41
- export declare function sortBalances(balances: Record<string, bigint>, prices: Record<string, bigint>, tokens: Record<string, TokenData>): Array<[string, bigint]>;
42
- export declare function tokensAbcComparator(t1?: TokenData, t2?: TokenData): 1 | -1;
43
- export declare function amountAbcComparator(t1: bigint, t2: bigint): 1 | -1;
44
- export interface CalcOverallAPYProps {
45
- caAssets: Array<Asset>;
46
- lpAPY: LpTokensAPY | undefined;
47
- prices: Record<string, bigint>;
48
- totalValue: bigint | undefined;
49
- debt: bigint | undefined;
50
- borrowRate: number;
51
- underlyingToken: string;
52
- }
53
- export declare function calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt, borrowRate, underlyingToken, }: CalcOverallAPYProps): number | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calcOverallAPY = exports.amountAbcComparator = exports.tokensAbcComparator = exports.sortBalances = exports.CreditAccountData = void 0;
3
+ exports.CreditAccountData = void 0;
4
4
  const apy_1 = require("../apy");
5
5
  const decimals_1 = require("../tokens/decimals");
6
6
  const token_1 = require("../tokens/token");
@@ -21,13 +21,14 @@ class CreditAccountData {
21
21
  totalValue;
22
22
  healthFactor;
23
23
  borrowRate;
24
+ isDeleting;
25
+ enabledTokenMask;
26
+ version = 1;
24
27
  collateralTokens = [];
25
28
  allTokens = [];
29
+ forbiddenTokens = [];
26
30
  balances = {};
27
31
  allBalances = {};
28
- isDeleting;
29
- enabledTokenMask;
30
- version = 1;
31
32
  /// V1 Artifacts
32
33
  repayAmount;
33
34
  liquidationAmount;
@@ -55,6 +56,9 @@ class CreditAccountData {
55
56
  this.balances[tokenLC] = (0, formatter_1.toBigInt)(b.balance || 0);
56
57
  this.collateralTokens.push(tokenLC);
57
58
  }
59
+ else {
60
+ this.forbiddenTokens.push(tokenLC);
61
+ }
58
62
  this.allBalances[tokenLC] = (0, formatter_1.toBigInt)(b.balance || 0);
59
63
  this.allTokens.push(tokenLC);
60
64
  });
@@ -66,12 +70,41 @@ class CreditAccountData {
66
70
  this.canBeClosed = payload.canBeClosed;
67
71
  }
68
72
  balancesSorted(prices, tokens) {
69
- return sortBalances(this.balances, prices, tokens).map(([token, balance]) => ({ token, balance }));
73
+ return CreditAccountData.sortBalances(this.balances, prices, tokens).map(([token, balance]) => ({ token, balance }));
74
+ }
75
+ static sortBalances(balances, prices, tokens) {
76
+ return Object.entries(balances).sort(([addr1, amount1], [addr2, amount2]) => {
77
+ const addr1Lc = addr1.toLowerCase();
78
+ const addr2Lc = addr2.toLowerCase();
79
+ const token1 = tokens[addr1Lc];
80
+ const token2 = tokens[addr2Lc];
81
+ const price1 = prices[addr1Lc] || constants_1.PRICE_DECIMALS;
82
+ const price2 = prices[addr2Lc] || constants_1.PRICE_DECIMALS;
83
+ const totalPrice1 = price_1.PriceUtils.calcTotalPrice(price1, amount1, token1?.decimals);
84
+ const totalPrice2 = price_1.PriceUtils.calcTotalPrice(price2, amount2, token2?.decimals);
85
+ if (totalPrice1 === totalPrice2) {
86
+ return amount1 === amount2
87
+ ? CreditAccountData.tokensAbcComparator(token1, token2)
88
+ : CreditAccountData.amountAbcComparator(amount1, amount2);
89
+ }
90
+ return CreditAccountData.amountAbcComparator(totalPrice1, totalPrice2);
91
+ });
92
+ }
93
+ static tokensAbcComparator(t1, t2) {
94
+ const { symbol: symbol1 = "" } = t1 || {};
95
+ const { symbol: symbol2 = "" } = t2 || {};
96
+ return symbol1 > symbol2 ? 1 : -1;
97
+ }
98
+ static amountAbcComparator(t1, t2) {
99
+ return t1 > t2 ? -1 : 1;
70
100
  }
71
101
  calcBorrowAmountPlusInterestRate(currentCumulativeIndex) {
72
102
  return ((this.borrowedAmount * currentCumulativeIndex) /
73
103
  this.cumulativeIndexAtOpen);
74
104
  }
105
+ isForbidden(token) {
106
+ return this.balances[token] === undefined;
107
+ }
75
108
  updateHealthFactor(creditManager, currentCumulativeIndex, priceOracle) {
76
109
  const twvUSDValue = this.collateralTokens
77
110
  .filter((_, num) => CreditAccountData.isTokenEnabled(num, this.enabledTokenMask))
@@ -93,8 +126,39 @@ class CreditAccountData {
93
126
  BigInt(minHealthFactor - underlyingLT);
94
127
  return result < 0 ? 0n : result;
95
128
  }
96
- get id() {
97
- return this.creditManager;
129
+ static calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt, borrowRate, underlyingToken, }) {
130
+ if (!lpAPY ||
131
+ !totalValue ||
132
+ totalValue <= 0n ||
133
+ !debt ||
134
+ totalValue <= debt)
135
+ return undefined;
136
+ const assetAPYMoney = caAssets.reduce((acc, { token: tokenAddress, balance: amount }) => {
137
+ const tokenAddressLC = tokenAddress.toLowerCase();
138
+ const symbol = token_1.tokenSymbolByAddress[tokenAddressLC];
139
+ if (!(0, apy_1.isTokenWithAPY)(symbol))
140
+ return acc;
141
+ const apy = lpAPY[symbol] || 0;
142
+ const price = prices[tokenAddressLC] || 0n;
143
+ const tokenDecimals = decimals_1.decimals[symbol];
144
+ const money = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
145
+ const apyMoney = money * BigInt(apy);
146
+ return acc + apyMoney;
147
+ }, 0n);
148
+ const underlyingTokenAddressLC = underlyingToken.toLowerCase();
149
+ const underlyingTokenSymbol = token_1.tokenSymbolByAddress[underlyingTokenAddressLC] || "";
150
+ const underlyingTokenDecimals = decimals_1.decimals[underlyingTokenSymbol] || 18;
151
+ const underlyingPrice = prices[underlyingTokenAddressLC] || constants_1.PRICE_DECIMALS;
152
+ const assetAPYAmountInUnderlying = price_1.PriceUtils.convertByPrice(assetAPYMoney, {
153
+ price: underlyingPrice,
154
+ decimals: underlyingTokenDecimals,
155
+ });
156
+ const debtAPY = debt * BigInt(borrowRate);
157
+ const yourAssets = totalValue - debt;
158
+ const apyInPercent = ((assetAPYAmountInUnderlying - debtAPY) * constants_1.WAD) /
159
+ yourAssets /
160
+ constants_1.PERCENTAGE_FACTOR;
161
+ return Number((0, formatter_1.toSignificant)(apyInPercent, constants_1.WAD_DECIMALS_POW));
98
162
  }
99
163
  hash() {
100
164
  return CreditAccountData.hash(this.creditManager, this.borrower);
@@ -102,65 +166,22 @@ class CreditAccountData {
102
166
  static hash(creditManager, borrower) {
103
167
  return `${creditManager.toLowerCase()}:${borrower.toLowerCase()}`;
104
168
  }
169
+ static calcHealthFactor({ assets, prices, liquidationThresholds, underlyingToken, borrowed, }) {
170
+ const assetLTMoney = assets.reduce((acc, { token: tokenAddress, balance: amount }) => {
171
+ const tokenSymbol = token_1.tokenSymbolByAddress[tokenAddress.toLowerCase()];
172
+ const tokenDecimals = decimals_1.decimals[tokenSymbol];
173
+ const lt = liquidationThresholds[tokenAddress.toLowerCase()] || 0n;
174
+ const price = prices[tokenAddress.toLowerCase()] || 0n;
175
+ const money = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
176
+ const ltMoney = money * lt;
177
+ return acc + ltMoney;
178
+ }, 0n);
179
+ const underlyingSymbol = token_1.tokenSymbolByAddress[underlyingToken.toLowerCase()];
180
+ const underlyingDecimals = decimals_1.decimals[underlyingSymbol];
181
+ const underlyingPrice = prices[underlyingToken.toLowerCase()] || constants_1.PRICE_DECIMALS;
182
+ const borrowedMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice, borrowed, underlyingDecimals);
183
+ const hfInPercent = borrowedMoney > 0n ? assetLTMoney / borrowedMoney : 0n;
184
+ return Number(hfInPercent);
185
+ }
105
186
  }
106
187
  exports.CreditAccountData = CreditAccountData;
107
- function sortBalances(balances, prices, tokens) {
108
- return Object.entries(balances).sort(([addr1, amount1], [addr2, amount2]) => {
109
- const addr1Lc = addr1.toLowerCase();
110
- const addr2Lc = addr2.toLowerCase();
111
- const token1 = tokens[addr1Lc];
112
- const token2 = tokens[addr2Lc];
113
- const price1 = prices[addr1Lc] || constants_1.PRICE_DECIMALS;
114
- const price2 = prices[addr2Lc] || constants_1.PRICE_DECIMALS;
115
- const totalPrice1 = (0, price_1.calcTotalPrice)(price1, amount1, token1?.decimals);
116
- const totalPrice2 = (0, price_1.calcTotalPrice)(price2, amount2, token2?.decimals);
117
- if (totalPrice1 === totalPrice2) {
118
- return amount1 === amount2
119
- ? tokensAbcComparator(token1, token2)
120
- : amountAbcComparator(amount1, amount2);
121
- }
122
- return amountAbcComparator(totalPrice1, totalPrice2);
123
- });
124
- }
125
- exports.sortBalances = sortBalances;
126
- function tokensAbcComparator(t1, t2) {
127
- const { symbol: symbol1 = "" } = t1 || {};
128
- const { symbol: symbol2 = "" } = t2 || {};
129
- return symbol1 > symbol2 ? 1 : -1;
130
- }
131
- exports.tokensAbcComparator = tokensAbcComparator;
132
- function amountAbcComparator(t1, t2) {
133
- return t1 > t2 ? -1 : 1;
134
- }
135
- exports.amountAbcComparator = amountAbcComparator;
136
- function calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt, borrowRate, underlyingToken, }) {
137
- if (!lpAPY || !totalValue || totalValue <= 0n || !debt || totalValue <= debt)
138
- return undefined;
139
- const assetAPYMoney = caAssets.reduce((acc, { token: tokenAddress, balance: amount }) => {
140
- const tokenAddressLC = tokenAddress.toLowerCase();
141
- const symbol = token_1.tokenSymbolByAddress[tokenAddressLC];
142
- if (!(0, apy_1.isTokenWithAPY)(symbol))
143
- return acc;
144
- const apy = lpAPY[symbol] || 0;
145
- const price = prices[tokenAddressLC] || 0n;
146
- const tokenDecimals = decimals_1.decimals[symbol];
147
- const money = (0, price_1.calcTotalPrice)(price, amount, tokenDecimals);
148
- const apyMoney = money * BigInt(apy);
149
- return acc + apyMoney;
150
- }, 0n);
151
- const underlyingTokenAddressLC = underlyingToken.toLowerCase();
152
- const underlyingTokenSymbol = token_1.tokenSymbolByAddress[underlyingTokenAddressLC] || "";
153
- const underlyingTokenDecimals = decimals_1.decimals[underlyingTokenSymbol] || 18;
154
- const underlyingPrice = prices[underlyingTokenAddressLC] || constants_1.PRICE_DECIMALS;
155
- const assetAPYAmountInUnderlying = (0, price_1.convertByPrice)(assetAPYMoney, {
156
- price: underlyingPrice,
157
- decimals: underlyingTokenDecimals,
158
- });
159
- const debtAPY = debt * BigInt(borrowRate);
160
- const yourAssets = totalValue - debt;
161
- const apyInPercent = ((assetAPYAmountInUnderlying - debtAPY) * constants_1.WAD) /
162
- yourAssets /
163
- constants_1.PERCENTAGE_FACTOR;
164
- return Number((0, formatter_1.toSignificant)(apyInPercent, constants_1.WAD_DECIMALS_POW));
165
- }
166
- exports.calcOverallAPY = calcOverallAPY;
@@ -4,6 +4,8 @@ const chai_1 = require("chai");
4
4
  const decimals_1 = require("../tokens/decimals");
5
5
  const token_1 = require("../tokens/token");
6
6
  const formatter_1 = require("../utils/formatter");
7
+ const price_1 = require("../utils/price");
8
+ const assets_1 = require("./assets");
7
9
  const constants_1 = require("./constants");
8
10
  const creditAccount_1 = require("./creditAccount");
9
11
  const prices = {
@@ -44,9 +46,9 @@ const caWithLP = {
44
46
  borrowRate: 5736,
45
47
  underlyingToken: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
46
48
  };
47
- describe("CreditAccount calcOverallAPY test", () => {
49
+ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
48
50
  it("overall APY calculation for caWithoutLP is correct", () => {
49
- const result = (0, creditAccount_1.calcOverallAPY)({
51
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
50
52
  caAssets: caWithoutLP.assets,
51
53
  totalValue: caWithoutLP.totalValue,
52
54
  debt: caWithoutLP.debt,
@@ -58,7 +60,7 @@ describe("CreditAccount calcOverallAPY test", () => {
58
60
  (0, chai_1.expect)(result).to.be.eq(-6.94841);
59
61
  });
60
62
  it("overall APY calculation for caWithLP is correct", () => {
61
- const result = (0, creditAccount_1.calcOverallAPY)({
63
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
62
64
  caAssets: caWithLP.assets,
63
65
  totalValue: caWithLP.totalValue,
64
66
  debt: caWithLP.debt,
@@ -70,7 +72,7 @@ describe("CreditAccount calcOverallAPY test", () => {
70
72
  (0, chai_1.expect)(result).to.be.eq(14.4919);
71
73
  });
72
74
  it("overall APY is undefined when !lpAPY", () => {
73
- const result = (0, creditAccount_1.calcOverallAPY)({
75
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
74
76
  caAssets: caWithLP.assets,
75
77
  totalValue: caWithLP.totalValue,
76
78
  debt: caWithLP.debt,
@@ -82,7 +84,7 @@ describe("CreditAccount calcOverallAPY test", () => {
82
84
  (0, chai_1.expect)(result).to.be.eq(undefined);
83
85
  });
84
86
  it("overall APY is undefined when !totalValue", () => {
85
- const result = (0, creditAccount_1.calcOverallAPY)({
87
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
86
88
  caAssets: caWithLP.assets,
87
89
  totalValue: undefined,
88
90
  debt: caWithLP.debt,
@@ -94,7 +96,7 @@ describe("CreditAccount calcOverallAPY test", () => {
94
96
  (0, chai_1.expect)(result).to.be.eq(undefined);
95
97
  });
96
98
  it("overall APY is undefined when !debt", () => {
97
- const result = (0, creditAccount_1.calcOverallAPY)({
99
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
98
100
  caAssets: caWithLP.assets,
99
101
  totalValue: caWithLP.totalValue,
100
102
  debt: undefined,
@@ -106,7 +108,7 @@ describe("CreditAccount calcOverallAPY test", () => {
106
108
  (0, chai_1.expect)(result).to.be.eq(undefined);
107
109
  });
108
110
  it("overall APY is undefined when totalValue lte 0", () => {
109
- const result = (0, creditAccount_1.calcOverallAPY)({
111
+ const result = creditAccount_1.CreditAccountData.calcOverallAPY({
110
112
  caAssets: caWithLP.assets,
111
113
  totalValue: 0n,
112
114
  debt: undefined,
@@ -133,3 +135,119 @@ describe("CreditAccount calcMaxIncreaseBorrow test", () => {
133
135
  (0, chai_1.expect)(result.toString()).to.be.eq("19095785778950228315970");
134
136
  });
135
137
  });
138
+ const liquidationThresholds = {
139
+ [token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 9300n,
140
+ [token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 8500n,
141
+ };
142
+ const defaultCA = {
143
+ assets: [
144
+ {
145
+ balance: (0, formatter_1.toBN)("156552", decimals_1.decimals.DAI),
146
+ token: token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
147
+ },
148
+ {
149
+ balance: (0, formatter_1.toBN)("10", decimals_1.decimals.WETH),
150
+ token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
151
+ },
152
+ ],
153
+ debt: (0, formatter_1.toBN)("156552", decimals_1.decimals.DAI),
154
+ healthFactor: 10244,
155
+ underlyingToken: token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
156
+ underlyingDecimals: decimals_1.decimals.DAI,
157
+ };
158
+ describe("CreditManager calcHealthFactor test", () => {
159
+ it("health factor calculation is calculated correctly", () => {
160
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
161
+ assets: defaultCA.assets,
162
+ prices,
163
+ liquidationThresholds,
164
+ underlyingToken: defaultCA.underlyingToken,
165
+ borrowed: defaultCA.debt,
166
+ });
167
+ (0, chai_1.expect)(result).to.be.eq(defaultCA.healthFactor);
168
+ });
169
+ it("health factor calculation has no division by zero error", () => {
170
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
171
+ assets: [],
172
+ prices: {},
173
+ liquidationThresholds: {},
174
+ underlyingToken: "",
175
+ borrowed: 0n,
176
+ });
177
+ (0, chai_1.expect)(result).to.be.eq(0);
178
+ });
179
+ it("health factor after add collateral is calculated correctly", () => {
180
+ const collateral = {
181
+ balance: (0, formatter_1.toBN)("10", decimals_1.decimals.WETH),
182
+ token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
183
+ };
184
+ const afterAdd = assets_1.AssetUtils.sumAssets(defaultCA.assets, [collateral]);
185
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
186
+ assets: afterAdd,
187
+ prices,
188
+ liquidationThresholds,
189
+ underlyingToken: defaultCA.underlyingToken,
190
+ borrowed: defaultCA.debt,
191
+ });
192
+ (0, chai_1.expect)(result).to.be.eq(11188);
193
+ });
194
+ it("health factor after decrease debt is calculated correctly", () => {
195
+ const amountDecrease = (0, formatter_1.toBN)("10000", defaultCA.underlyingDecimals);
196
+ const debtDecrease = {
197
+ balance: amountDecrease,
198
+ token: defaultCA.underlyingToken,
199
+ };
200
+ const afterDecrease = assets_1.AssetUtils.subAssets(defaultCA.assets, [
201
+ debtDecrease,
202
+ ]);
203
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
204
+ assets: afterDecrease,
205
+ prices,
206
+ liquidationThresholds,
207
+ underlyingToken: defaultCA.underlyingToken,
208
+ borrowed: defaultCA.debt - amountDecrease,
209
+ });
210
+ (0, chai_1.expect)(result).to.be.eq(10308);
211
+ });
212
+ it("health factor after increase debt is calculated correctly", () => {
213
+ const amountIncrease = (0, formatter_1.toBN)("20000", defaultCA.underlyingDecimals);
214
+ const debtIncrease = {
215
+ balance: amountIncrease,
216
+ token: defaultCA.underlyingToken,
217
+ };
218
+ const afterIncrease = assets_1.AssetUtils.sumAssets(defaultCA.assets, [
219
+ debtIncrease,
220
+ ]);
221
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
222
+ assets: afterIncrease,
223
+ prices,
224
+ liquidationThresholds,
225
+ underlyingToken: defaultCA.underlyingToken,
226
+ borrowed: defaultCA.debt + amountIncrease,
227
+ });
228
+ (0, chai_1.expect)(result).to.be.eq(10137);
229
+ });
230
+ it("health factor after swap is calculated correctly", () => {
231
+ const swapAsset = {
232
+ balance: defaultCA.debt,
233
+ token: defaultCA.underlyingToken,
234
+ };
235
+ const underlyingPrice = prices[defaultCA.underlyingToken];
236
+ const wethPrice = prices[token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()];
237
+ const getAmount = price_1.PriceUtils.convertByPrice(price_1.PriceUtils.calcTotalPrice(underlyingPrice, defaultCA.debt, defaultCA.underlyingDecimals), { price: wethPrice, decimals: decimals_1.decimals.WETH });
238
+ const getAsset = {
239
+ balance: getAmount,
240
+ token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
241
+ };
242
+ const afterSub = assets_1.AssetUtils.subAssets(defaultCA.assets, [swapAsset]);
243
+ const afterSwap = assets_1.AssetUtils.sumAssets(afterSub, [getAsset]);
244
+ const result = creditAccount_1.CreditAccountData.calcHealthFactor({
245
+ assets: afterSwap,
246
+ prices,
247
+ liquidationThresholds,
248
+ underlyingToken: defaultCA.underlyingToken,
249
+ borrowed: defaultCA.debt,
250
+ });
251
+ (0, chai_1.expect)(result).to.be.eq(9444);
252
+ });
253
+ });
@@ -2,7 +2,6 @@ import { ethers, Signer } from "ethers";
2
2
  import { MultiCall } from "../pathfinder/core";
3
3
  import { ChartsCreditManagerPayload, CreditManagerDataPayload } from "../payload/creditManager";
4
4
  import { ICreditManager } from "../types";
5
- import { Asset } from "./assets";
6
5
  export declare class CreditManagerData {
7
6
  readonly address: string;
8
7
  readonly underlyingToken: string;
@@ -85,11 +84,3 @@ export declare class ChartsCreditManagerData {
85
84
  readonly liquidationThresholds: Record<string, bigint>;
86
85
  constructor(payload: ChartsCreditManagerPayload);
87
86
  }
88
- export interface CalcHealthFactorProps {
89
- assets: Array<Asset>;
90
- prices: Record<string, bigint>;
91
- liquidationThresholds: Record<string, bigint>;
92
- underlyingToken: string;
93
- borrowed: bigint;
94
- }
95
- export declare function calcHealthFactor({ assets, prices, liquidationThresholds, underlyingToken, borrowed, }: CalcHealthFactorProps): number;
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calcHealthFactor = exports.ChartsCreditManagerData = exports.CreditManagerData = void 0;
3
+ exports.ChartsCreditManagerData = exports.CreditManagerData = void 0;
4
4
  const txParser_1 = require("../parsers/txParser");
5
- const decimals_1 = require("../tokens/decimals");
6
5
  const token_1 = require("../tokens/token");
7
6
  const types_1 = require("../types");
8
7
  const formatter_1 = require("../utils/formatter");
9
- const price_1 = require("../utils/price");
10
8
  const constants_1 = require("./constants");
11
9
  const errors_1 = require("./errors");
12
10
  class CreditManagerData {
@@ -242,21 +240,3 @@ class ChartsCreditManagerData {
242
240
  }
243
241
  }
244
242
  exports.ChartsCreditManagerData = ChartsCreditManagerData;
245
- function calcHealthFactor({ assets, prices, liquidationThresholds, underlyingToken, borrowed, }) {
246
- const assetLTMoney = assets.reduce((acc, { token: tokenAddress, balance: amount }) => {
247
- const tokenSymbol = token_1.tokenSymbolByAddress[tokenAddress.toLowerCase()];
248
- const tokenDecimals = decimals_1.decimals[tokenSymbol];
249
- const lt = liquidationThresholds[tokenAddress.toLowerCase()] || 0n;
250
- const price = prices[tokenAddress.toLowerCase()] || 0n;
251
- const money = (0, price_1.calcTotalPrice)(price, amount, tokenDecimals);
252
- const ltMoney = money * lt;
253
- return acc + ltMoney;
254
- }, 0n);
255
- const underlyingSymbol = token_1.tokenSymbolByAddress[underlyingToken.toLowerCase()];
256
- const underlyingDecimals = decimals_1.decimals[underlyingSymbol];
257
- const underlyingPrice = prices[underlyingToken.toLowerCase()] || constants_1.PRICE_DECIMALS;
258
- const borrowedMoney = (0, price_1.calcTotalPrice)(underlyingPrice, borrowed, underlyingDecimals);
259
- const hfInPercent = borrowedMoney > 0n ? assetLTMoney / borrowedMoney : 0n;
260
- return Number(hfInPercent);
261
- }
262
- exports.calcHealthFactor = calcHealthFactor;
@@ -25,7 +25,7 @@ class EventOrTx {
25
25
  if (!this.isPending && item.isPending) {
26
26
  return 1;
27
27
  }
28
- return this.block > item.block ? -1 : 1;
28
+ return item.block - this.block;
29
29
  }
30
30
  }
31
31
  exports.EventOrTx = EventOrTx;
@@ -7,6 +7,7 @@ export declare class PoolData {
7
7
  readonly underlyingToken: string;
8
8
  readonly dieselToken: string;
9
9
  readonly isWETH: boolean;
10
+ readonly isWSTETH: boolean;
10
11
  readonly expectedLiquidity: bigint;
11
12
  readonly expectedLiquidityLimit: bigint;
12
13
  readonly availableLiquidity: bigint;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UserPoolData = exports.ChartsPoolData = exports.PoolData = void 0;
4
+ const token_1 = require("../../tokens/token");
4
5
  const types_1 = require("../../types");
5
6
  const formatter_1 = require("../../utils/formatter");
6
7
  const constants_1 = require("../constants");
@@ -10,6 +11,7 @@ class PoolData {
10
11
  underlyingToken;
11
12
  dieselToken;
12
13
  isWETH;
14
+ isWSTETH;
13
15
  // Information
14
16
  expectedLiquidity;
15
17
  expectedLiquidityLimit;
@@ -30,6 +32,8 @@ class PoolData {
30
32
  this.underlyingToken = payload.underlying.toLowerCase();
31
33
  this.dieselToken = payload.dieselToken.toLowerCase();
32
34
  this.isWETH = payload.isWETH || false;
35
+ this.isWSTETH =
36
+ token_1.tokenSymbolByAddress[payload.underlying.toLowerCase()] === "wstETH";
33
37
  this.expectedLiquidity = (0, formatter_1.toBigInt)(payload.expectedLiquidity || 0);
34
38
  this.expectedLiquidityLimit = (0, formatter_1.toBigInt)(payload.expectedLiquidityLimit || 0);
35
39
  this.availableLiquidity = (0, formatter_1.toBigInt)(payload.availableLiquidity || 0);
@@ -54,13 +54,13 @@ describe("RewardConvex test", () => {
54
54
  // method: "earned(address)",
55
55
  // params: [CREDIT_ACCOUNT],
56
56
  // },
57
- {
58
- address: contracts_1.contractParams.CONVEX_FRAX3CRV_POOL
59
- .extraRewards[0].poolAddress.Mainnet,
60
- interface: rewardConvex_1.RewardConvex.poolInterface,
61
- method: "earned(address)",
62
- params: [CREDIT_ACCOUNT],
63
- },
57
+ // {
58
+ // address: (contractParams.CONVEX_FRAX3CRV_POOL as ConvexPoolParams)
59
+ // .extraRewards[0].poolAddress.Mainnet,
60
+ // interface: RewardConvex.poolInterface,
61
+ // method: "earned(address)",
62
+ // params: [CREDIT_ACCOUNT],
63
+ // },
64
64
  ];
65
65
  const distribution = [
66
66
  {
@@ -88,8 +88,8 @@ describe("RewardConvex test", () => {
88
88
  it("parseResults parse data correctly", () => {
89
89
  const rewards = [
90
90
  ethers_1.BigNumber.from(1000n),
91
- ethers_1.BigNumber.from(2000n),
92
- ethers_1.BigNumber.from(4000n),
91
+ // BigNumber.from(2000n),
92
+ // BigNumber.from(4000n),
93
93
  ];
94
94
  const distribution = [
95
95
  {
@@ -126,19 +126,19 @@ describe("RewardConvex test", () => {
126
126
  },
127
127
  ],
128
128
  },
129
- {
130
- contract: "CONVEX_FRAX3CRV_POOL",
131
- rewards: {
132
- CRV: 2000n,
133
- FXS: 4000n,
134
- },
135
- calls: [
136
- {
137
- target: ADAPTER_CONVEX_FRAX3CRV_POOL,
138
- callData,
139
- },
140
- ],
141
- },
129
+ // {
130
+ // contract: "CONVEX_FRAX3CRV_POOL",
131
+ // rewards: {
132
+ // CRV: 2000n,
133
+ // FXS: 4000n,
134
+ // },
135
+ // calls: [
136
+ // {
137
+ // target: ADAPTER_CONVEX_FRAX3CRV_POOL,
138
+ // callData,
139
+ // },
140
+ // ],
141
+ // },
142
142
  ];
143
143
  (0, chai_1.expect)(parsed).to.be.eql(expected);
144
144
  });
@@ -42,13 +42,13 @@ class Strategy {
42
42
  const underlyingTokenSymbol = token_1.tokenSymbolByAddress[underlyingTokenAddressLC];
43
43
  const underlyingTokenDecimals = decimals_1.decimals[underlyingTokenSymbol];
44
44
  const underlyingPrice = prices[underlyingTokenAddressLC] || constants_1.PRICE_DECIMALS;
45
- const borrowedMoney = (0, price_1.calcTotalPrice)(underlyingPrice, borrowed, underlyingTokenDecimals);
45
+ const borrowedMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice, borrowed, underlyingTokenDecimals);
46
46
  const lpTokenAddressLC = lpToken.toLowerCase();
47
47
  const lpTokenSymbol = token_1.tokenSymbolByAddress[lpTokenAddressLC];
48
48
  const lpTokenDecimals = decimals_1.decimals[lpTokenSymbol];
49
49
  const lpLT = liquidationThresholds[lpTokenAddressLC] || 0n;
50
50
  const lpPrice = prices[lpTokenAddressLC] || constants_1.PRICE_DECIMALS;
51
- const lpMoney = (0, price_1.calcTotalPrice)(lpPrice, lpAmount, lpTokenDecimals);
51
+ const lpMoney = price_1.PriceUtils.calcTotalPrice(lpPrice, lpAmount, lpTokenDecimals);
52
52
  const lpLTMoney = (lpMoney * lpLT) / constants_1.PERCENTAGE_FACTOR;
53
53
  if (lpLTMoney > 0) {
54
54
  const lqPrice = (borrowedMoney * constants_1.WAD) / lpLTMoney;
@@ -23,30 +23,41 @@ describe("UniswapV3AdapterParser test", () => {
23
23
  it("swap functions works well", () => {
24
24
  let parser = new uniV3AdapterParser_1.UniswapV3AdapterParser("UNISWAP_V3_ROUTER", false);
25
25
  const ifc = types_1.IUniswapV3Adapter__factory.createInterface();
26
- let parsed = parser.parse(ifc.encodeFunctionData("exactInputSingle", [
27
- {
28
- tokenIn: token_1.tokenDataByNetwork.Arbitrum["1INCH"],
29
- tokenOut: token_1.tokenDataByNetwork.Arbitrum["3Crv"],
30
- fee: 3000,
31
- recipient: constants_1.DUMB_ADDRESS,
32
- deadline: 12300,
33
- amountIn: constants_1.WAD * 1299000n,
34
- amountOutMinimum: constants_1.WAD * 10200n,
35
- sqrtPriceLimitX96: 0,
36
- },
37
- ]));
38
- (0, chai_1.expect)(parsed).to.be.eq("UniswapV3Adapter[UNISWAP_V3_ROUTER].exactInputSingle(amountIn: 1.29M [1299000000000000000000000], amountOutMinimum: 10.20K [10200000000000000000000], path: 1INCH ==(fee: 3000)==> 3Crv)", "Incorrect parse swapExactTokensForTokens");
39
- parsed = parser.parse(ifc.encodeFunctionData("exactAllInputSingle", [
40
- {
41
- tokenIn: token_1.tokenDataByNetwork.Arbitrum["1INCH"],
42
- tokenOut: token_1.tokenDataByNetwork.Arbitrum["3Crv"],
43
- fee: 3000,
44
- deadline: 12300,
45
- rateMinRAY: constants_1.RAY * 1200n,
46
- sqrtPriceLimitX96: 0,
47
- },
48
- ]));
49
- (0, chai_1.expect)(parsed).to.be.eq("UniswapV3Adapter[UNISWAP_V3_ROUTER].exactAllInputSingle(rate: 1.20K, path: 1INCH ==(fee: 3000)==> 3Crv)", "Incorrect parse swapExactTokensForTokens");
26
+ let parsed;
27
+ // let parsed = parser.parse(
28
+ // ifc.encodeFunctionData("exactInputSingle", [
29
+ // {
30
+ // tokenIn: tokenDataByNetwork.Arbitrum["1INCH"],
31
+ // tokenOut: tokenDataByNetwork.Arbitrum["3Crv"],
32
+ // fee: 3000,
33
+ // recipient: DUMB_ADDRESS,
34
+ // deadline: 12300,
35
+ // amountIn: WAD * 1299000n,
36
+ // amountOutMinimum: WAD * 10200n,
37
+ // sqrtPriceLimitX96: 0,
38
+ // },
39
+ // ]),
40
+ // );
41
+ // expect(parsed).to.be.eq(
42
+ // "UniswapV3Adapter[UNISWAP_V3_ROUTER].exactInputSingle(amountIn: 1.29M [1299000000000000000000000], amountOutMinimum: 10.20K [10200000000000000000000], path: 1INCH ==(fee: 3000)==> 3Crv)",
43
+ // "Incorrect parse swapExactTokensForTokens",
44
+ // );
45
+ // parsed = parser.parse(
46
+ // ifc.encodeFunctionData("exactAllInputSingle", [
47
+ // {
48
+ // tokenIn: tokenDataByNetwork.Arbitrum["1INCH"],
49
+ // tokenOut: tokenDataByNetwork.Arbitrum["3Crv"],
50
+ // fee: 3000,
51
+ // deadline: 12300,
52
+ // rateMinRAY: RAY * 1200n,
53
+ // sqrtPriceLimitX96: 0,
54
+ // },
55
+ // ]),
56
+ // );
57
+ // expect(parsed).to.be.eq(
58
+ // "UniswapV3Adapter[UNISWAP_V3_ROUTER].exactAllInputSingle(rate: 1.20K, path: 1INCH ==(fee: 3000)==> 3Crv)",
59
+ // "Incorrect parse swapExactTokensForTokens",
60
+ // );
50
61
  parsed = parser.parse(ifc.encodeFunctionData("exactInput", [
51
62
  {
52
63
  path: pathToUniV3Path([
@@ -73,19 +84,24 @@ describe("UniswapV3AdapterParser test", () => {
73
84
  },
74
85
  ]));
75
86
  (0, chai_1.expect)(parsed).to.be.eq("UniswapV3Adapter[UNISWAP_V3_ROUTER].exactAllInput(rate: 1.20K, path: AAVE ==(fee: 3000)==> LINK ==(fee: 3000)==> USDC", "Incorrect parse swapExactTokensForTokens");
76
- parsed = parser.parse(ifc.encodeFunctionData("exactOutputSingle", [
77
- {
78
- tokenIn: token_1.tokenDataByNetwork.Arbitrum["1INCH"],
79
- tokenOut: token_1.tokenDataByNetwork.Arbitrum.USDC,
80
- fee: 10000,
81
- recipient: constants_1.DUMB_ADDRESS,
82
- deadline: 12300,
83
- amountInMaximum: (constants_1.WAD * 149n) / 1000n,
84
- amountOut: 102e6,
85
- sqrtPriceLimitX96: 0,
86
- },
87
- ]));
88
- (0, chai_1.expect)(parsed).to.be.eq("UniswapV3Adapter[UNISWAP_V3_ROUTER].exactOutputSingle(amountInMaximum: 0.14 [149000000000000000], amountOut: 102.00 [102000000], path: 1INCH ==(fee: 10000)==> USDC)", "Incorrect parse swapExactTokensForTokens");
87
+ // parsed = parser.parse(
88
+ // ifc.encodeFunctionData("exactOutputSingle", [
89
+ // {
90
+ // tokenIn: tokenDataByNetwork.Arbitrum["1INCH"],
91
+ // tokenOut: tokenDataByNetwork.Arbitrum.USDC,
92
+ // fee: 10000,
93
+ // recipient: DUMB_ADDRESS,
94
+ // deadline: 12300,
95
+ // amountInMaximum: (WAD * 149n) / 1000n,
96
+ // amountOut: 102e6,
97
+ // sqrtPriceLimitX96: 0,
98
+ // },
99
+ // ]),
100
+ // );
101
+ // expect(parsed).to.be.eq(
102
+ // "UniswapV3Adapter[UNISWAP_V3_ROUTER].exactOutputSingle(amountInMaximum: 0.14 [149000000000000000], amountOut: 102.00 [102000000], path: 1INCH ==(fee: 10000)==> USDC)",
103
+ // "Incorrect parse swapExactTokensForTokens",
104
+ // );
89
105
  parsed = parser.parse(ifc.encodeFunctionData("exactOutput", [
90
106
  {
91
107
  path: pathToUniV3Path([
@@ -1,7 +1,9 @@
1
- export declare const calcTotalPrice: (price: bigint, amount: bigint, decimals?: number) => bigint;
2
1
  interface Target {
3
2
  price: bigint;
4
3
  decimals: number | undefined;
5
4
  }
6
- export declare function convertByPrice(totalMoney: bigint, { price: targetPrice, decimals: targetDecimals }: Target): bigint;
5
+ export declare class PriceUtils {
6
+ static calcTotalPrice: (price: bigint, amount: bigint, decimals?: number) => bigint;
7
+ static convertByPrice(totalMoney: bigint, { price: targetPrice, decimals: targetDecimals }: Target): bigint;
8
+ }
7
9
  export {};
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertByPrice = exports.calcTotalPrice = void 0;
3
+ exports.PriceUtils = void 0;
4
4
  const constants_1 = require("../core/constants");
5
- const calcTotalPrice = (price, amount, decimals = 18) => (amount * constants_1.WAD * price) / 10n ** BigInt(decimals) / constants_1.PRICE_DECIMALS;
6
- exports.calcTotalPrice = calcTotalPrice;
7
- function convertByPrice(totalMoney, { price: targetPrice, decimals: targetDecimals = 18 }) {
8
- if (targetPrice <= 0n)
9
- return 0n;
10
- return ((totalMoney * 10n ** BigInt(targetDecimals) * constants_1.PRICE_DECIMALS) /
11
- targetPrice /
12
- constants_1.WAD);
5
+ class PriceUtils {
6
+ static calcTotalPrice = (price, amount, decimals = 18) => (amount * constants_1.WAD * price) / 10n ** BigInt(decimals) / constants_1.PRICE_DECIMALS;
7
+ static convertByPrice(totalMoney, { price: targetPrice, decimals: targetDecimals = 18 }) {
8
+ if (targetPrice <= 0n)
9
+ return 0n;
10
+ return ((totalMoney * 10n ** BigInt(targetDecimals) * constants_1.PRICE_DECIMALS) /
11
+ targetPrice /
12
+ constants_1.WAD);
13
+ }
13
14
  }
14
- exports.convertByPrice = convertByPrice;
15
+ exports.PriceUtils = PriceUtils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "1.25.0",
3
+ "version": "1.25.2",
4
4
  "description": "Gearbox SDK",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -12,10 +12,10 @@
12
12
  "license": "MIT",
13
13
  "scripts": {
14
14
  "clean": "rm -rf lib",
15
- "build": "tsc && rm -rf lib/scripts && mv ./lib/src/* ./lib",
15
+ "build": "tsc --p tsconfig.build.json",
16
16
  "bindings": "yarn ts-node ./scripts/generate.ts",
17
- "dev": "tsc -w",
18
- "pub": "rm -rf ./src/types/hardhat.ts && cp ./src/types/*.d.ts ./lib/types && tsc && yarn publish",
17
+ "dev": "tsc -w --p tsconfig.build.json",
18
+ "pub": "rm -rf ./src/types/hardhat.ts && cp ./src/types/*.d.ts ./lib/types && tsc --p tsconfig.build.json && yarn publish",
19
19
  "copyTypes": "node ./scripts/copyTypes.js",
20
20
  "prepare": "husky install",
21
21
  "prettier": "prettier --write .",
@@ -1 +0,0 @@
1
- export {};
@@ -1,131 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const chai_1 = require("chai");
4
- const decimals_1 = require("../tokens/decimals");
5
- const token_1 = require("../tokens/token");
6
- const formatter_1 = require("../utils/formatter");
7
- const price_1 = require("../utils/price");
8
- const assets_1 = require("./assets");
9
- const constants_1 = require("./constants");
10
- const creditManager_1 = require("./creditManager");
11
- const liquidationThresholds = {
12
- [token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: 9300n,
13
- [token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: 8500n,
14
- };
15
- const prices = {
16
- [token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: (0, formatter_1.toBN)("1738.11830000", constants_1.PRICE_DECIMALS_POW),
17
- [token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase()]: (0, formatter_1.toBN)("0.99941103", constants_1.PRICE_DECIMALS_POW),
18
- [token_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: (0, formatter_1.toBN)("1703.87588096", constants_1.PRICE_DECIMALS_POW),
19
- };
20
- const defaultCA = {
21
- assets: [
22
- {
23
- balance: (0, formatter_1.toBN)("156552", decimals_1.decimals.DAI),
24
- token: token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
25
- },
26
- {
27
- balance: (0, formatter_1.toBN)("10", decimals_1.decimals.WETH),
28
- token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
29
- },
30
- ],
31
- debt: (0, formatter_1.toBN)("156552", decimals_1.decimals.DAI),
32
- healthFactor: 10244,
33
- underlyingToken: token_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
34
- underlyingDecimals: decimals_1.decimals.DAI,
35
- };
36
- describe("CreditManager calcHealthFactor test", () => {
37
- it("health factor calculation is calculated correctly", () => {
38
- const result = (0, creditManager_1.calcHealthFactor)({
39
- assets: defaultCA.assets,
40
- prices,
41
- liquidationThresholds,
42
- underlyingToken: defaultCA.underlyingToken,
43
- borrowed: defaultCA.debt,
44
- });
45
- (0, chai_1.expect)(result).to.be.eq(defaultCA.healthFactor);
46
- });
47
- it("health factor calculation has no division by zero error", () => {
48
- const result = (0, creditManager_1.calcHealthFactor)({
49
- assets: [],
50
- prices: {},
51
- liquidationThresholds: {},
52
- underlyingToken: "",
53
- borrowed: 0n,
54
- });
55
- (0, chai_1.expect)(result).to.be.eq(0);
56
- });
57
- it("health factor after add collateral is calculated correctly", () => {
58
- const collateral = {
59
- balance: (0, formatter_1.toBN)("10", decimals_1.decimals.WETH),
60
- token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
61
- };
62
- const afterAdd = assets_1.AssetUtils.sumAssets(defaultCA.assets, [collateral]);
63
- const result = (0, creditManager_1.calcHealthFactor)({
64
- assets: afterAdd,
65
- prices,
66
- liquidationThresholds,
67
- underlyingToken: defaultCA.underlyingToken,
68
- borrowed: defaultCA.debt,
69
- });
70
- (0, chai_1.expect)(result).to.be.eq(11188);
71
- });
72
- it("health factor after decrease debt is calculated correctly", () => {
73
- const amountDecrease = (0, formatter_1.toBN)("10000", defaultCA.underlyingDecimals);
74
- const debtDecrease = {
75
- balance: amountDecrease,
76
- token: defaultCA.underlyingToken,
77
- };
78
- const afterDecrease = assets_1.AssetUtils.subAssets(defaultCA.assets, [
79
- debtDecrease,
80
- ]);
81
- const result = (0, creditManager_1.calcHealthFactor)({
82
- assets: afterDecrease,
83
- prices,
84
- liquidationThresholds,
85
- underlyingToken: defaultCA.underlyingToken,
86
- borrowed: defaultCA.debt - amountDecrease,
87
- });
88
- (0, chai_1.expect)(result).to.be.eq(10308);
89
- });
90
- it("health factor after increase debt is calculated correctly", () => {
91
- const amountIncrease = (0, formatter_1.toBN)("20000", defaultCA.underlyingDecimals);
92
- const debtIncrease = {
93
- balance: amountIncrease,
94
- token: defaultCA.underlyingToken,
95
- };
96
- const afterIncrease = assets_1.AssetUtils.sumAssets(defaultCA.assets, [
97
- debtIncrease,
98
- ]);
99
- const result = (0, creditManager_1.calcHealthFactor)({
100
- assets: afterIncrease,
101
- prices,
102
- liquidationThresholds,
103
- underlyingToken: defaultCA.underlyingToken,
104
- borrowed: defaultCA.debt + amountIncrease,
105
- });
106
- (0, chai_1.expect)(result).to.be.eq(10137);
107
- });
108
- it("health factor after swap is calculated correctly", () => {
109
- const swapAsset = {
110
- balance: defaultCA.debt,
111
- token: defaultCA.underlyingToken,
112
- };
113
- const underlyingPrice = prices[defaultCA.underlyingToken];
114
- const wethPrice = prices[token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()];
115
- const getAmount = (0, price_1.convertByPrice)((0, price_1.calcTotalPrice)(underlyingPrice, defaultCA.debt, defaultCA.underlyingDecimals), { price: wethPrice, decimals: decimals_1.decimals.WETH });
116
- const getAsset = {
117
- balance: getAmount,
118
- token: token_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
119
- };
120
- const afterSub = assets_1.AssetUtils.subAssets(defaultCA.assets, [swapAsset]);
121
- const afterSwap = assets_1.AssetUtils.sumAssets(afterSub, [getAsset]);
122
- const result = (0, creditManager_1.calcHealthFactor)({
123
- assets: afterSwap,
124
- prices,
125
- liquidationThresholds,
126
- underlyingToken: defaultCA.underlyingToken,
127
- borrowed: defaultCA.debt,
128
- });
129
- (0, chai_1.expect)(result).to.be.eq(9444);
130
- });
131
- });