@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.
- package/lib/core/assets.js +1 -1
- package/lib/core/chains.d.ts +1 -1
- package/lib/core/creditAccount.d.ts +31 -22
- package/lib/core/creditAccount.js +88 -67
- package/lib/core/creditAccount.spec.js +125 -7
- package/lib/core/creditManager.d.ts +0 -9
- package/lib/core/creditManager.js +1 -21
- package/lib/core/eventOrTx.js +1 -1
- package/lib/core/pool/data.d.ts +1 -0
- package/lib/core/pool/data.js +4 -0
- package/lib/core/rewardConvex.spec.js +22 -22
- package/lib/core/strategy.js +2 -2
- package/lib/parsers/uniV3AdapterParser.spec.js +53 -37
- package/lib/utils/price.d.ts +4 -2
- package/lib/utils/price.js +11 -10
- package/package.json +4 -4
- package/lib/core/creditManager.spec.d.ts +0 -1
- package/lib/core/creditManager.spec.js +0 -131
package/lib/core/assets.js
CHANGED
|
@@ -13,7 +13,7 @@ class AssetUtils {
|
|
|
13
13
|
const alreadySelected = selectedRecord[allowedToken.toLowerCase()];
|
|
14
14
|
return !alreadySelected;
|
|
15
15
|
});
|
|
16
|
-
const sorted =
|
|
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
|
}
|
package/lib/core/chains.d.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
-
|
|
97
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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;
|
package/lib/core/eventOrTx.js
CHANGED
package/lib/core/pool/data.d.ts
CHANGED
|
@@ -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;
|
package/lib/core/pool/data.js
CHANGED
|
@@ -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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
});
|
package/lib/core/strategy.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
]
|
|
49
|
-
|
|
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(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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([
|
package/lib/utils/price.d.ts
CHANGED
|
@@ -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
|
|
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 {};
|
package/lib/utils/price.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.PriceUtils = void 0;
|
|
4
4
|
const constants_1 = require("../core/constants");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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.
|
|
15
|
+
exports.PriceUtils = PriceUtils;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gearbox-protocol/sdk",
|
|
3
|
-
"version": "1.25.
|
|
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
|
|
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
|
-
});
|