@gearbox-protocol/sdk 3.0.0-next.13 → 3.0.0-next.15
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/apy/index.d.ts +2 -2
- package/lib/core/assets.d.ts +2 -2
- package/lib/core/assets.js +2 -2
- package/lib/core/creditAccount.d.ts +22 -5
- package/lib/core/creditAccount.js +67 -26
- package/lib/core/creditAccount.spec.js +469 -8
- package/lib/core/creditManager.d.ts +1 -1
- package/lib/core/creditManager.js +2 -2
- package/lib/core/transactions.d.ts +15 -1
- package/lib/core/transactions.js +37 -1
- package/lib/utils/math.d.ts +2 -0
- package/lib/utils/math.js +2 -0
- package/package.json +1 -1
package/lib/apy/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LPTokens, SupportedToken } from "@gearbox-protocol/sdk-gov";
|
|
1
|
+
import { LPTokens, PartialRecord, SupportedToken } from "@gearbox-protocol/sdk-gov";
|
|
2
2
|
export type AdditionalTokenWithAPY = Extract<SupportedToken, "STETH">;
|
|
3
3
|
export declare const additionalTokensWIthAPY: Record<AdditionalTokenWithAPY, true>;
|
|
4
4
|
export type TokensWithAPY = LPTokens | Extract<SupportedToken, "STETH">;
|
|
5
|
-
export type LpTokensAPY =
|
|
5
|
+
export type LpTokensAPY = PartialRecord<TokensWithAPY, number>;
|
|
6
6
|
export declare const isTokenWithAPY: (t: unknown) => t is TokensWithAPY;
|
|
7
7
|
export * from "./convexAPY";
|
|
8
8
|
export * from "./curveAPY";
|
package/lib/core/assets.d.ts
CHANGED
|
@@ -24,12 +24,12 @@ export declare class AssetUtils {
|
|
|
24
24
|
static memoWrap: (unwrappedAddress: string, wrappedAddress: string, prices: Record<string, bigint>, tokensList: Record<string, TokenData>) => (assets: Array<Asset>) => WrapResult;
|
|
25
25
|
/**
|
|
26
26
|
* Sums the the second assets list into the first assets list
|
|
27
|
-
* Creates new assets.
|
|
27
|
+
* Balances cant be negative; Creates new assets.
|
|
28
28
|
*/
|
|
29
29
|
static sumAssets<A extends Asset, B extends Asset>(a: Array<A>, b: Array<B>): Array<A | B>;
|
|
30
30
|
/**
|
|
31
31
|
* Subtracts the the second assets list from the first assets list
|
|
32
|
-
*
|
|
32
|
+
* Balances cant be negative; doesn't create new assets.
|
|
33
33
|
*/
|
|
34
34
|
static subAssets<A extends Asset, B extends Asset>(a: Array<A>, b: Array<B>): Array<A>;
|
|
35
35
|
}
|
package/lib/core/assets.js
CHANGED
|
@@ -65,7 +65,7 @@ class AssetUtils {
|
|
|
65
65
|
};
|
|
66
66
|
/**
|
|
67
67
|
* Sums the the second assets list into the first assets list
|
|
68
|
-
* Creates new assets.
|
|
68
|
+
* Balances cant be negative; Creates new assets.
|
|
69
69
|
*/
|
|
70
70
|
static sumAssets(a, b) {
|
|
71
71
|
const aRecord = AssetUtils.constructAssetRecord(a);
|
|
@@ -84,7 +84,7 @@ class AssetUtils {
|
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Subtracts the the second assets list from the first assets list
|
|
87
|
-
*
|
|
87
|
+
* Balances cant be negative; doesn't create new assets.
|
|
88
88
|
*/
|
|
89
89
|
static subAssets(a, b) {
|
|
90
90
|
const bRecord = AssetUtils.constructAssetRecord(b);
|
|
@@ -1,23 +1,39 @@
|
|
|
1
1
|
import { LpTokensAPY } from "../apy";
|
|
2
2
|
import { CaTokenBalance, CreditAccountDataPayload, ScheduledWithdrawal } from "../payload/creditAccount";
|
|
3
|
+
import { QuotaInfo } from "../payload/creditManager";
|
|
3
4
|
import { TokenData } from "../tokens/tokenData";
|
|
4
|
-
import { Asset } from "./assets";
|
|
5
|
+
import { Asset, AssetWithAmountInTarget } from "./assets";
|
|
5
6
|
export interface CalcOverallAPYProps {
|
|
6
7
|
caAssets: Array<Asset>;
|
|
7
8
|
lpAPY: LpTokensAPY | undefined;
|
|
9
|
+
quotas: Record<string, Asset>;
|
|
10
|
+
quotaRates: Record<string, Pick<QuotaInfo, "rate">>;
|
|
8
11
|
prices: Record<string, bigint>;
|
|
9
12
|
totalValue: bigint | undefined;
|
|
10
13
|
debt: bigint | undefined;
|
|
11
|
-
|
|
14
|
+
baseBorrowRate: number;
|
|
12
15
|
underlyingToken: string;
|
|
13
16
|
}
|
|
14
17
|
export interface CalcHealthFactorProps {
|
|
15
18
|
assets: Array<Asset>;
|
|
19
|
+
quotas: Record<string, Asset>;
|
|
16
20
|
prices: Record<string, bigint>;
|
|
17
21
|
liquidationThresholds: Record<string, bigint>;
|
|
18
22
|
underlyingToken: string;
|
|
19
23
|
borrowed: bigint;
|
|
20
24
|
}
|
|
25
|
+
export interface CalcQuotaUpdateProps {
|
|
26
|
+
quotas: Record<string, Pick<QuotaInfo, "isActive" | "token">>;
|
|
27
|
+
initialQuotas: Record<string, Pick<CaTokenBalance, "quota">>;
|
|
28
|
+
assetsAfterUpdate: Record<string, AssetWithAmountInTarget>;
|
|
29
|
+
allowedToSpend: Record<string, {}>;
|
|
30
|
+
allowedToObtain: Record<string, {}>;
|
|
31
|
+
}
|
|
32
|
+
interface CalcQuotaUpdateReturnType {
|
|
33
|
+
desiredQuota: Record<string, Asset>;
|
|
34
|
+
quotaIncrease: Array<Asset>;
|
|
35
|
+
quotaDecrease: Array<Asset>;
|
|
36
|
+
}
|
|
21
37
|
export declare class CreditAccountData {
|
|
22
38
|
readonly addr: string;
|
|
23
39
|
readonly borrower: string;
|
|
@@ -54,7 +70,6 @@ export declare class CreditAccountData {
|
|
|
54
70
|
readonly schedultedWithdrawals: Array<ScheduledWithdrawal>;
|
|
55
71
|
constructor(payload: CreditAccountDataPayload);
|
|
56
72
|
setDeleteInProgress(d: boolean): void;
|
|
57
|
-
balancesSorted(prices: Record<string, bigint>, tokens: Record<string, TokenData>): Array<Asset>;
|
|
58
73
|
static sortBalances(balances: Record<string, bigint>, prices: Record<string, bigint>, tokens: Record<string, TokenData>): Array<[string, bigint]>;
|
|
59
74
|
static tokensAbcComparator(t1?: TokenData, t2?: TokenData): 1 | -1;
|
|
60
75
|
static amountAbcComparator(t1: bigint, t2: bigint): 1 | -1;
|
|
@@ -63,8 +78,10 @@ export declare class CreditAccountData {
|
|
|
63
78
|
isTokenEnabled(index: number): boolean;
|
|
64
79
|
static isTokenEnabled(index: number, enabledTokenMask: bigint): boolean;
|
|
65
80
|
static calcMaxDebtIncrease(healthFactor: number, borrowAmountPlusInterest: bigint, underlyingLT: number, minHf?: number): bigint;
|
|
66
|
-
static calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt,
|
|
81
|
+
static calcOverallAPY({ caAssets, lpAPY, prices, quotas, quotaRates, totalValue, debt, baseBorrowRate, underlyingToken, }: CalcOverallAPYProps): number | undefined;
|
|
67
82
|
hash(): string;
|
|
68
83
|
static hash(creditManager: string, borrower: string): string;
|
|
69
|
-
static calcHealthFactor({ assets,
|
|
84
|
+
static calcHealthFactor({ assets, quotas, liquidationThresholds, underlyingToken, borrowed, prices, }: CalcHealthFactorProps): number;
|
|
85
|
+
static calcQuotaUpdate({ quotas, initialQuotas, assetsAfterUpdate, allowedToSpend, allowedToObtain, }: CalcQuotaUpdateProps): CalcQuotaUpdateReturnType;
|
|
70
86
|
}
|
|
87
|
+
export {};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CreditAccountData = void 0;
|
|
4
4
|
const sdk_gov_1 = require("@gearbox-protocol/sdk-gov");
|
|
5
|
-
const apy_1 = require("../apy");
|
|
6
5
|
const formatter_1 = require("../utils/formatter");
|
|
6
|
+
const math_1 = require("../utils/math");
|
|
7
7
|
const price_1 = require("../utils/price");
|
|
8
8
|
class CreditAccountData {
|
|
9
9
|
addr;
|
|
@@ -105,9 +105,6 @@ class CreditAccountData {
|
|
|
105
105
|
setDeleteInProgress(d) {
|
|
106
106
|
this.isDeleting = d;
|
|
107
107
|
}
|
|
108
|
-
balancesSorted(prices, tokens) {
|
|
109
|
-
return CreditAccountData.sortBalances(this.balances, prices, tokens).map(([token, balance]) => ({ token, balance }));
|
|
110
|
-
}
|
|
111
108
|
static sortBalances(balances, prices, tokens) {
|
|
112
109
|
return Object.entries(balances).sort(([addr1, amount1], [addr2, amount2]) => {
|
|
113
110
|
const addr1Lc = addr1.toLowerCase();
|
|
@@ -149,36 +146,38 @@ class CreditAccountData {
|
|
|
149
146
|
static calcMaxDebtIncrease(healthFactor, borrowAmountPlusInterest, underlyingLT, minHf = Number(sdk_gov_1.PERCENTAGE_FACTOR)) {
|
|
150
147
|
const result = (borrowAmountPlusInterest * BigInt(healthFactor - minHf)) /
|
|
151
148
|
BigInt(minHf - underlyingLT);
|
|
152
|
-
return
|
|
149
|
+
return math_1.BigIntMath.max(0n, result);
|
|
153
150
|
}
|
|
154
|
-
static calcOverallAPY({ caAssets, lpAPY, prices, totalValue, debt,
|
|
151
|
+
static calcOverallAPY({ caAssets, lpAPY, prices, quotas, quotaRates, totalValue, debt, baseBorrowRate, underlyingToken, }) {
|
|
155
152
|
if (!lpAPY ||
|
|
156
153
|
!totalValue ||
|
|
157
154
|
totalValue <= 0n ||
|
|
158
155
|
!debt ||
|
|
159
156
|
totalValue <= debt)
|
|
160
157
|
return undefined;
|
|
158
|
+
const underlyingTokenAddressLC = underlyingToken.toLowerCase();
|
|
159
|
+
const underlyingTokenSymbol = sdk_gov_1.tokenSymbolByAddress[underlyingTokenAddressLC] || "";
|
|
160
|
+
const underlyingTokenDecimals = sdk_gov_1.decimals[underlyingTokenSymbol] || 18;
|
|
161
|
+
const underlyingPrice = prices[underlyingTokenAddressLC];
|
|
161
162
|
const assetAPYMoney = caAssets.reduce((acc, { token: tokenAddress, balance: amount }) => {
|
|
162
163
|
const tokenAddressLC = tokenAddress.toLowerCase();
|
|
163
|
-
const symbol = sdk_gov_1.tokenSymbolByAddress[tokenAddressLC];
|
|
164
|
-
if (!(0, apy_1.isTokenWithAPY)(symbol))
|
|
165
|
-
return acc;
|
|
164
|
+
const symbol = sdk_gov_1.tokenSymbolByAddress[tokenAddressLC] || "";
|
|
166
165
|
const apy = lpAPY[symbol] || 0;
|
|
167
166
|
const price = prices[tokenAddressLC] || 0n;
|
|
168
167
|
const tokenDecimals = sdk_gov_1.decimals[symbol];
|
|
169
168
|
const money = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
|
|
170
169
|
const apyMoney = money * BigInt(apy);
|
|
171
|
-
|
|
170
|
+
const { balance: quotaAmount = 0n } = quotas[tokenAddressLC] || {};
|
|
171
|
+
const quotaMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice || 0n, quotaAmount, underlyingTokenDecimals);
|
|
172
|
+
const { rate: quotaAPY = 0 } = quotaRates[tokenAddressLC] || {};
|
|
173
|
+
const quotaAPYMoney = quotaMoney * BigInt(quotaAPY);
|
|
174
|
+
return acc + apyMoney - quotaAPYMoney;
|
|
172
175
|
}, 0n);
|
|
173
|
-
const underlyingTokenAddressLC = underlyingToken.toLowerCase();
|
|
174
|
-
const underlyingTokenSymbol = sdk_gov_1.tokenSymbolByAddress[underlyingTokenAddressLC] || "";
|
|
175
|
-
const underlyingTokenDecimals = sdk_gov_1.decimals[underlyingTokenSymbol] || 18;
|
|
176
|
-
const underlyingPrice = prices[underlyingTokenAddressLC] || sdk_gov_1.PRICE_DECIMALS;
|
|
177
176
|
const assetAPYAmountInUnderlying = price_1.PriceUtils.convertByPrice(assetAPYMoney, {
|
|
178
|
-
price: underlyingPrice,
|
|
177
|
+
price: underlyingPrice || sdk_gov_1.PRICE_DECIMALS,
|
|
179
178
|
decimals: underlyingTokenDecimals,
|
|
180
179
|
});
|
|
181
|
-
const debtAPY = debt * BigInt(
|
|
180
|
+
const debtAPY = debt * BigInt(baseBorrowRate);
|
|
182
181
|
const yourAssets = totalValue - debt;
|
|
183
182
|
const apyInPercent = ((assetAPYAmountInUnderlying - debtAPY) * sdk_gov_1.WAD) /
|
|
184
183
|
yourAssets /
|
|
@@ -191,22 +190,64 @@ class CreditAccountData {
|
|
|
191
190
|
static hash(creditManager, borrower) {
|
|
192
191
|
return `${creditManager.toLowerCase()}:${borrower.toLowerCase()}`;
|
|
193
192
|
}
|
|
194
|
-
static calcHealthFactor({ assets,
|
|
193
|
+
static calcHealthFactor({ assets, quotas, liquidationThresholds, underlyingToken, borrowed, prices, }) {
|
|
194
|
+
const [, underlyingDecimals] = (0, sdk_gov_1.extractTokenData)(underlyingToken);
|
|
195
|
+
const underlyingPrice = prices[underlyingToken];
|
|
195
196
|
const assetLTMoney = assets.reduce((acc, { token: tokenAddress, balance: amount }) => {
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
const
|
|
197
|
+
const [, tokenDecimals] = (0, sdk_gov_1.extractTokenData)(tokenAddress);
|
|
198
|
+
const lt = liquidationThresholds[tokenAddress] || 0n;
|
|
199
|
+
const price = prices[tokenAddress] || 0n;
|
|
200
|
+
const tokenMoney = price_1.PriceUtils.calcTotalPrice(price, amount, tokenDecimals);
|
|
201
|
+
const quota = quotas[tokenAddress];
|
|
202
|
+
const quotaMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice, quota?.balance || 0n, underlyingDecimals);
|
|
203
|
+
// if quota is undefined, then it is not a quoted token
|
|
204
|
+
const money = quota
|
|
205
|
+
? math_1.BigIntMath.min(quotaMoney, tokenMoney)
|
|
206
|
+
: tokenMoney;
|
|
201
207
|
const ltMoney = money * lt;
|
|
202
208
|
return acc + ltMoney;
|
|
203
209
|
}, 0n);
|
|
204
|
-
const
|
|
205
|
-
const underlyingDecimals = sdk_gov_1.decimals[underlyingSymbol];
|
|
206
|
-
const underlyingPrice = prices[underlyingToken.toLowerCase()] || sdk_gov_1.PRICE_DECIMALS;
|
|
207
|
-
const borrowedMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice, borrowed, underlyingDecimals);
|
|
210
|
+
const borrowedMoney = price_1.PriceUtils.calcTotalPrice(underlyingPrice || sdk_gov_1.PRICE_DECIMALS, borrowed, underlyingDecimals);
|
|
208
211
|
const hfInPercent = borrowedMoney > 0n ? assetLTMoney / borrowedMoney : 0n;
|
|
209
212
|
return Number(hfInPercent);
|
|
210
213
|
}
|
|
214
|
+
static calcQuotaUpdate({ quotas, initialQuotas, assetsAfterUpdate, allowedToSpend, allowedToObtain, }) {
|
|
215
|
+
const r = Object.values(quotas).reduce((acc, cmQuota) => {
|
|
216
|
+
const { token } = cmQuota;
|
|
217
|
+
const { quota: initialQuota = 0n } = initialQuotas[token] || {};
|
|
218
|
+
const after = assetsAfterUpdate[token];
|
|
219
|
+
const { amountInTarget = 0n } = after || {};
|
|
220
|
+
const desiredQuota = (amountInTarget * 101n) / 100n;
|
|
221
|
+
const quotaChange = desiredQuota - initialQuota;
|
|
222
|
+
const correctIncrease = after && allowedToObtain[token] && quotaChange > 0;
|
|
223
|
+
const correctDecrease = after && allowedToSpend[token] && quotaChange < 0;
|
|
224
|
+
if (correctIncrease || correctDecrease) {
|
|
225
|
+
acc.desiredQuota[token] = {
|
|
226
|
+
balance: desiredQuota,
|
|
227
|
+
token,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
acc.desiredQuota[token] = {
|
|
232
|
+
balance: initialQuota,
|
|
233
|
+
token,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (correctIncrease) {
|
|
237
|
+
acc.quotaIncrease.push({
|
|
238
|
+
balance: quotaChange,
|
|
239
|
+
token,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (correctDecrease) {
|
|
243
|
+
acc.quotaDecrease.push({
|
|
244
|
+
balance: quotaChange,
|
|
245
|
+
token,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return acc;
|
|
249
|
+
}, { desiredQuota: {}, quotaIncrease: [], quotaDecrease: [] });
|
|
250
|
+
return r;
|
|
251
|
+
}
|
|
211
252
|
}
|
|
212
253
|
exports.CreditAccountData = CreditAccountData;
|
|
@@ -27,6 +27,17 @@ const caWithoutLP = {
|
|
|
27
27
|
debt: (0, formatter_1.toBN)("54780", sdk_gov_1.decimals.DAI),
|
|
28
28
|
borrowRate: 7712,
|
|
29
29
|
underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
|
|
30
|
+
quotas: {
|
|
31
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: {
|
|
32
|
+
balance: (0, formatter_1.toBN)("173811.830000", sdk_gov_1.decimals.WETH),
|
|
33
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
rates: {
|
|
37
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: {
|
|
38
|
+
rate: 38434,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
30
41
|
};
|
|
31
42
|
const caWithLP = {
|
|
32
43
|
assets: [
|
|
@@ -43,6 +54,17 @@ const caWithLP = {
|
|
|
43
54
|
debt: (0, formatter_1.toBN)("90.000000000000000000", sdk_gov_1.decimals.WETH),
|
|
44
55
|
borrowRate: 5736,
|
|
45
56
|
underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
|
|
57
|
+
quotas: {
|
|
58
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: {
|
|
59
|
+
balance: (0, formatter_1.toBN)(String((1703.87588096 * 119.9999999999999) / 1738.1183), sdk_gov_1.decimals.WETH),
|
|
60
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase(),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
rates: {
|
|
64
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: {
|
|
65
|
+
rate: 38434,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
46
68
|
};
|
|
47
69
|
describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
48
70
|
it("overall APY calculation for caWithoutLP is correct", () => {
|
|
@@ -50,8 +72,10 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
50
72
|
caAssets: caWithoutLP.assets,
|
|
51
73
|
totalValue: caWithoutLP.totalValue,
|
|
52
74
|
debt: caWithoutLP.debt,
|
|
53
|
-
|
|
75
|
+
baseBorrowRate: caWithoutLP.borrowRate,
|
|
54
76
|
underlyingToken: caWithoutLP.underlyingToken,
|
|
77
|
+
quotaRates: {},
|
|
78
|
+
quotas: {},
|
|
55
79
|
lpAPY,
|
|
56
80
|
prices,
|
|
57
81
|
});
|
|
@@ -62,8 +86,10 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
62
86
|
caAssets: caWithLP.assets,
|
|
63
87
|
totalValue: caWithLP.totalValue,
|
|
64
88
|
debt: caWithLP.debt,
|
|
65
|
-
|
|
89
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
66
90
|
underlyingToken: caWithLP.underlyingToken,
|
|
91
|
+
quotaRates: {},
|
|
92
|
+
quotas: {},
|
|
67
93
|
lpAPY,
|
|
68
94
|
prices,
|
|
69
95
|
});
|
|
@@ -74,8 +100,10 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
74
100
|
caAssets: caWithLP.assets,
|
|
75
101
|
totalValue: caWithLP.totalValue,
|
|
76
102
|
debt: caWithLP.debt,
|
|
77
|
-
|
|
103
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
78
104
|
underlyingToken: caWithLP.underlyingToken,
|
|
105
|
+
quotaRates: {},
|
|
106
|
+
quotas: {},
|
|
79
107
|
lpAPY: undefined,
|
|
80
108
|
prices,
|
|
81
109
|
});
|
|
@@ -86,8 +114,10 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
86
114
|
caAssets: caWithLP.assets,
|
|
87
115
|
totalValue: undefined,
|
|
88
116
|
debt: caWithLP.debt,
|
|
89
|
-
|
|
117
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
90
118
|
underlyingToken: caWithLP.underlyingToken,
|
|
119
|
+
quotaRates: {},
|
|
120
|
+
quotas: {},
|
|
91
121
|
lpAPY,
|
|
92
122
|
prices,
|
|
93
123
|
});
|
|
@@ -98,8 +128,10 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
98
128
|
caAssets: caWithLP.assets,
|
|
99
129
|
totalValue: caWithLP.totalValue,
|
|
100
130
|
debt: undefined,
|
|
101
|
-
|
|
131
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
102
132
|
underlyingToken: caWithLP.underlyingToken,
|
|
133
|
+
quotaRates: {},
|
|
134
|
+
quotas: {},
|
|
103
135
|
lpAPY,
|
|
104
136
|
prices,
|
|
105
137
|
});
|
|
@@ -110,13 +142,48 @@ describe("CreditAccount CreditAccountData.calcOverallAPY test", () => {
|
|
|
110
142
|
caAssets: caWithLP.assets,
|
|
111
143
|
totalValue: 0n,
|
|
112
144
|
debt: undefined,
|
|
113
|
-
|
|
145
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
114
146
|
underlyingToken: caWithLP.underlyingToken,
|
|
147
|
+
quotaRates: {},
|
|
148
|
+
quotas: {},
|
|
115
149
|
lpAPY,
|
|
116
150
|
prices,
|
|
117
151
|
});
|
|
118
152
|
(0, chai_1.expect)(result).to.be.eq(undefined);
|
|
119
153
|
});
|
|
154
|
+
it("overall APY calculation for caWithLP with sufficient quota is correct", () => {
|
|
155
|
+
const result = creditAccount_1.CreditAccountData.calcOverallAPY({
|
|
156
|
+
caAssets: caWithLP.assets,
|
|
157
|
+
totalValue: caWithLP.totalValue,
|
|
158
|
+
debt: caWithLP.debt,
|
|
159
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
160
|
+
underlyingToken: caWithLP.underlyingToken,
|
|
161
|
+
quotaRates: caWithLP.rates,
|
|
162
|
+
quotas: caWithLP.quotas,
|
|
163
|
+
lpAPY,
|
|
164
|
+
prices,
|
|
165
|
+
});
|
|
166
|
+
(0, chai_1.expect)(result).to.be.eq(-1.86801);
|
|
167
|
+
});
|
|
168
|
+
it("overall APY calculation for caWithLP with insufficient quota is correct", () => {
|
|
169
|
+
const result = creditAccount_1.CreditAccountData.calcOverallAPY({
|
|
170
|
+
caAssets: caWithLP.assets,
|
|
171
|
+
totalValue: caWithLP.totalValue,
|
|
172
|
+
debt: caWithLP.debt,
|
|
173
|
+
baseBorrowRate: caWithLP.borrowRate,
|
|
174
|
+
underlyingToken: caWithLP.underlyingToken,
|
|
175
|
+
quotaRates: caWithLP.rates,
|
|
176
|
+
quotas: {
|
|
177
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase()]: {
|
|
178
|
+
balance: 0n,
|
|
179
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH.toLowerCase(),
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
lpAPY,
|
|
183
|
+
prices,
|
|
184
|
+
});
|
|
185
|
+
(0, chai_1.expect)(result).to.be.eq(14.4919);
|
|
186
|
+
});
|
|
120
187
|
});
|
|
121
188
|
describe("CreditAccount calcMaxIncreaseBorrow test", () => {
|
|
122
189
|
it("health max increase borrow is zero if hf < 1", () => {
|
|
@@ -152,10 +219,17 @@ const defaultCA = {
|
|
|
152
219
|
healthFactor: 10244,
|
|
153
220
|
underlyingToken: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI.toLowerCase(),
|
|
154
221
|
underlyingDecimals: sdk_gov_1.decimals.DAI,
|
|
222
|
+
quotas: {
|
|
223
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: {
|
|
224
|
+
balance: (0, formatter_1.toBN)(String(1750 * 10), sdk_gov_1.decimals.DAI),
|
|
225
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
|
|
226
|
+
},
|
|
227
|
+
},
|
|
155
228
|
};
|
|
156
|
-
describe("
|
|
157
|
-
it("health factor
|
|
229
|
+
describe("CreditAccount calcHealthFactor test", () => {
|
|
230
|
+
it("health factor is calculated correctly", () => {
|
|
158
231
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
232
|
+
quotas: {},
|
|
159
233
|
assets: defaultCA.assets,
|
|
160
234
|
prices,
|
|
161
235
|
liquidationThresholds,
|
|
@@ -166,6 +240,7 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
166
240
|
});
|
|
167
241
|
it("health factor calculation has no division by zero error", () => {
|
|
168
242
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
243
|
+
quotas: {},
|
|
169
244
|
assets: [],
|
|
170
245
|
prices: {},
|
|
171
246
|
liquidationThresholds: {},
|
|
@@ -181,6 +256,7 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
181
256
|
};
|
|
182
257
|
const afterAdd = assets_1.AssetUtils.sumAssets(defaultCA.assets, [collateral]);
|
|
183
258
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
259
|
+
quotas: {},
|
|
184
260
|
assets: afterAdd,
|
|
185
261
|
prices,
|
|
186
262
|
liquidationThresholds,
|
|
@@ -199,6 +275,7 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
199
275
|
debtDecrease,
|
|
200
276
|
]);
|
|
201
277
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
278
|
+
quotas: {},
|
|
202
279
|
assets: afterDecrease,
|
|
203
280
|
prices,
|
|
204
281
|
liquidationThresholds,
|
|
@@ -217,6 +294,7 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
217
294
|
debtIncrease,
|
|
218
295
|
]);
|
|
219
296
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
297
|
+
quotas: {},
|
|
220
298
|
assets: afterIncrease,
|
|
221
299
|
prices,
|
|
222
300
|
liquidationThresholds,
|
|
@@ -240,6 +318,7 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
240
318
|
const afterSub = assets_1.AssetUtils.subAssets(defaultCA.assets, [swapAsset]);
|
|
241
319
|
const afterSwap = assets_1.AssetUtils.sumAssets(afterSub, [getAsset]);
|
|
242
320
|
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
321
|
+
quotas: {},
|
|
243
322
|
assets: afterSwap,
|
|
244
323
|
prices,
|
|
245
324
|
liquidationThresholds,
|
|
@@ -248,4 +327,386 @@ describe("CreditManager calcHealthFactor test", () => {
|
|
|
248
327
|
});
|
|
249
328
|
(0, chai_1.expect)(result).to.be.eq(9444);
|
|
250
329
|
});
|
|
330
|
+
it("health factor with sufficient quotas is calculated correctly", () => {
|
|
331
|
+
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
332
|
+
quotas: defaultCA.quotas,
|
|
333
|
+
assets: defaultCA.assets,
|
|
334
|
+
prices,
|
|
335
|
+
liquidationThresholds,
|
|
336
|
+
underlyingToken: defaultCA.underlyingToken,
|
|
337
|
+
borrowed: defaultCA.debt,
|
|
338
|
+
});
|
|
339
|
+
(0, chai_1.expect)(result).to.be.eq(defaultCA.healthFactor);
|
|
340
|
+
});
|
|
341
|
+
it("health factor with insufficient quotas is calculated correctly", () => {
|
|
342
|
+
const result = creditAccount_1.CreditAccountData.calcHealthFactor({
|
|
343
|
+
quotas: {
|
|
344
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase()]: {
|
|
345
|
+
balance: 0n,
|
|
346
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH.toLowerCase(),
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
assets: defaultCA.assets,
|
|
350
|
+
prices,
|
|
351
|
+
liquidationThresholds,
|
|
352
|
+
underlyingToken: defaultCA.underlyingToken,
|
|
353
|
+
borrowed: defaultCA.debt,
|
|
354
|
+
});
|
|
355
|
+
(0, chai_1.expect)(result).to.be.eq(9300);
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
const cmQuotas = {
|
|
359
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
360
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
361
|
+
isActive: true,
|
|
362
|
+
},
|
|
363
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
364
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
365
|
+
isActive: true,
|
|
366
|
+
},
|
|
367
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
368
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
369
|
+
isActive: true,
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
const caQuota = {
|
|
373
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
374
|
+
quota: 5n,
|
|
375
|
+
},
|
|
376
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
377
|
+
quota: 10n,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
describe("CreditAccount calcQuotaUpdate test", () => {
|
|
381
|
+
it("open account should buy quota", () => {
|
|
382
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
383
|
+
quotas: cmQuotas,
|
|
384
|
+
initialQuotas: {},
|
|
385
|
+
assetsAfterUpdate: {
|
|
386
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
387
|
+
amountInTarget: 10n,
|
|
388
|
+
balance: 0n,
|
|
389
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
390
|
+
},
|
|
391
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
392
|
+
amountInTarget: 20n,
|
|
393
|
+
balance: 0n,
|
|
394
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
allowedToObtain: {
|
|
398
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {},
|
|
399
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {},
|
|
400
|
+
},
|
|
401
|
+
allowedToSpend: {},
|
|
402
|
+
});
|
|
403
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([
|
|
404
|
+
{
|
|
405
|
+
balance: 10n,
|
|
406
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
balance: 20n,
|
|
410
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
411
|
+
},
|
|
412
|
+
]);
|
|
413
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([]);
|
|
414
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
415
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
416
|
+
balance: 10n,
|
|
417
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
418
|
+
},
|
|
419
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
420
|
+
balance: 20n,
|
|
421
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
422
|
+
},
|
|
423
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
424
|
+
balance: 0n,
|
|
425
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
it("add collateral should buy quota", () => {
|
|
430
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
431
|
+
quotas: cmQuotas,
|
|
432
|
+
initialQuotas: caQuota,
|
|
433
|
+
assetsAfterUpdate: {
|
|
434
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
435
|
+
amountInTarget: 10n,
|
|
436
|
+
balance: 0n,
|
|
437
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
allowedToObtain: {
|
|
441
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {},
|
|
442
|
+
},
|
|
443
|
+
allowedToSpend: {},
|
|
444
|
+
});
|
|
445
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([
|
|
446
|
+
{
|
|
447
|
+
balance: 10n,
|
|
448
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
449
|
+
},
|
|
450
|
+
]);
|
|
451
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([]);
|
|
452
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
453
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
454
|
+
balance: 5n,
|
|
455
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
456
|
+
},
|
|
457
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
458
|
+
balance: 10n,
|
|
459
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
460
|
+
},
|
|
461
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
462
|
+
balance: 10n,
|
|
463
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
it("add collateral should add additional quota", () => {
|
|
468
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
469
|
+
quotas: cmQuotas,
|
|
470
|
+
initialQuotas: caQuota,
|
|
471
|
+
assetsAfterUpdate: {
|
|
472
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
473
|
+
amountInTarget: 10n,
|
|
474
|
+
balance: 0n,
|
|
475
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
allowedToObtain: {
|
|
479
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {},
|
|
480
|
+
},
|
|
481
|
+
allowedToSpend: {},
|
|
482
|
+
});
|
|
483
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([
|
|
484
|
+
{
|
|
485
|
+
balance: 5n,
|
|
486
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
487
|
+
},
|
|
488
|
+
]);
|
|
489
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([]);
|
|
490
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
491
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
492
|
+
balance: 10n,
|
|
493
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
494
|
+
},
|
|
495
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
496
|
+
balance: 10n,
|
|
497
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
498
|
+
},
|
|
499
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
500
|
+
balance: 0n,
|
|
501
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
it("add collateral shouldn't add additional quota", () => {
|
|
506
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
507
|
+
quotas: cmQuotas,
|
|
508
|
+
initialQuotas: caQuota,
|
|
509
|
+
assetsAfterUpdate: {
|
|
510
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
511
|
+
amountInTarget: 10n,
|
|
512
|
+
balance: 0n,
|
|
513
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
allowedToObtain: {
|
|
517
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {},
|
|
518
|
+
},
|
|
519
|
+
allowedToSpend: {},
|
|
520
|
+
});
|
|
521
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([]);
|
|
522
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([]);
|
|
523
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
524
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
525
|
+
balance: 5n,
|
|
526
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
527
|
+
},
|
|
528
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
529
|
+
balance: 10n,
|
|
530
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
531
|
+
},
|
|
532
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
533
|
+
balance: 0n,
|
|
534
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
it("swap should buy quota", () => {
|
|
539
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
540
|
+
quotas: cmQuotas,
|
|
541
|
+
initialQuotas: caQuota,
|
|
542
|
+
assetsAfterUpdate: {
|
|
543
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
544
|
+
amountInTarget: 10n,
|
|
545
|
+
balance: 0n,
|
|
546
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
547
|
+
},
|
|
548
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
549
|
+
amountInTarget: 0n,
|
|
550
|
+
balance: 0n,
|
|
551
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
allowedToObtain: {
|
|
555
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {},
|
|
556
|
+
},
|
|
557
|
+
allowedToSpend: { [sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {} },
|
|
558
|
+
});
|
|
559
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([
|
|
560
|
+
{
|
|
561
|
+
balance: 10n,
|
|
562
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
563
|
+
},
|
|
564
|
+
]);
|
|
565
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([
|
|
566
|
+
{ balance: -10n, token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH },
|
|
567
|
+
]);
|
|
568
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
569
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
570
|
+
balance: 5n,
|
|
571
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
572
|
+
},
|
|
573
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
574
|
+
balance: 0n,
|
|
575
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
576
|
+
},
|
|
577
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
578
|
+
balance: 10n,
|
|
579
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
it("swap should add additional quota", () => {
|
|
584
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
585
|
+
quotas: cmQuotas,
|
|
586
|
+
initialQuotas: caQuota,
|
|
587
|
+
assetsAfterUpdate: {
|
|
588
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
589
|
+
amountInTarget: 10n,
|
|
590
|
+
balance: 0n,
|
|
591
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
592
|
+
},
|
|
593
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
594
|
+
amountInTarget: 0n,
|
|
595
|
+
balance: 0n,
|
|
596
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
allowedToObtain: {
|
|
600
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {},
|
|
601
|
+
},
|
|
602
|
+
allowedToSpend: {
|
|
603
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {},
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([
|
|
607
|
+
{
|
|
608
|
+
balance: 5n,
|
|
609
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
610
|
+
},
|
|
611
|
+
]);
|
|
612
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([
|
|
613
|
+
{
|
|
614
|
+
balance: -10n,
|
|
615
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
616
|
+
},
|
|
617
|
+
]);
|
|
618
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
619
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
620
|
+
balance: 10n,
|
|
621
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
622
|
+
},
|
|
623
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
624
|
+
balance: 0n,
|
|
625
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
626
|
+
},
|
|
627
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
628
|
+
balance: 0n,
|
|
629
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
it("swap shouldn't add additional quota", () => {
|
|
634
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
635
|
+
quotas: cmQuotas,
|
|
636
|
+
initialQuotas: caQuota,
|
|
637
|
+
assetsAfterUpdate: {
|
|
638
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
639
|
+
amountInTarget: 10n,
|
|
640
|
+
balance: 0n,
|
|
641
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
642
|
+
},
|
|
643
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
644
|
+
amountInTarget: 0n,
|
|
645
|
+
balance: 0n,
|
|
646
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
allowedToObtain: {
|
|
650
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {},
|
|
651
|
+
},
|
|
652
|
+
allowedToSpend: { [sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {} },
|
|
653
|
+
});
|
|
654
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([]);
|
|
655
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([
|
|
656
|
+
{
|
|
657
|
+
balance: -5n,
|
|
658
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
659
|
+
},
|
|
660
|
+
]);
|
|
661
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
662
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
663
|
+
balance: 0n,
|
|
664
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
665
|
+
},
|
|
666
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
667
|
+
balance: 10n,
|
|
668
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
669
|
+
},
|
|
670
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
671
|
+
balance: 0n,
|
|
672
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
673
|
+
},
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
it("shouldn't change quota if disallowed", () => {
|
|
677
|
+
const result = creditAccount_1.CreditAccountData.calcQuotaUpdate({
|
|
678
|
+
quotas: cmQuotas,
|
|
679
|
+
initialQuotas: caQuota,
|
|
680
|
+
assetsAfterUpdate: {
|
|
681
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
682
|
+
amountInTarget: 10n,
|
|
683
|
+
balance: 0n,
|
|
684
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
685
|
+
},
|
|
686
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
687
|
+
amountInTarget: 0n,
|
|
688
|
+
balance: 0n,
|
|
689
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
allowedToObtain: {},
|
|
693
|
+
allowedToSpend: {},
|
|
694
|
+
});
|
|
695
|
+
(0, chai_1.expect)(result.quotaIncrease).to.be.deep.eq([]);
|
|
696
|
+
(0, chai_1.expect)(result.quotaDecrease).to.be.deep.eq([]);
|
|
697
|
+
(0, chai_1.expect)(result.desiredQuota).to.be.deep.eq({
|
|
698
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.DAI]: {
|
|
699
|
+
balance: 5n,
|
|
700
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.DAI,
|
|
701
|
+
},
|
|
702
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.WETH]: {
|
|
703
|
+
balance: 10n,
|
|
704
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.WETH,
|
|
705
|
+
},
|
|
706
|
+
[sdk_gov_1.tokenDataByNetwork.Mainnet.STETH]: {
|
|
707
|
+
balance: 0n,
|
|
708
|
+
token: sdk_gov_1.tokenDataByNetwork.Mainnet.STETH,
|
|
709
|
+
},
|
|
710
|
+
});
|
|
711
|
+
});
|
|
251
712
|
});
|
|
@@ -14,7 +14,7 @@ export declare class CreditManagerData {
|
|
|
14
14
|
readonly forbiddenTokenMask: bigint;
|
|
15
15
|
readonly maxEnabledTokensLength: number;
|
|
16
16
|
readonly name: string;
|
|
17
|
-
readonly
|
|
17
|
+
readonly baseBorrowRate: number;
|
|
18
18
|
readonly minDebt: bigint;
|
|
19
19
|
readonly maxDebt: bigint;
|
|
20
20
|
readonly availableToBorrow: bigint;
|
|
@@ -17,7 +17,7 @@ class CreditManagerData {
|
|
|
17
17
|
forbiddenTokenMask; // V2 only: mask which forbids some particular tokens
|
|
18
18
|
maxEnabledTokensLength;
|
|
19
19
|
name;
|
|
20
|
-
|
|
20
|
+
baseBorrowRate;
|
|
21
21
|
minDebt;
|
|
22
22
|
maxDebt;
|
|
23
23
|
availableToBorrow;
|
|
@@ -47,7 +47,7 @@ class CreditManagerData {
|
|
|
47
47
|
this.forbiddenTokenMask = (0, sdk_gov_1.toBigInt)(payload.forbiddenTokenMask);
|
|
48
48
|
this.maxEnabledTokensLength = payload.maxEnabledTokensLength;
|
|
49
49
|
this.name = payload.name;
|
|
50
|
-
this.
|
|
50
|
+
this.baseBorrowRate = Number(((0, sdk_gov_1.toBigInt)(payload.baseBorrowRate) *
|
|
51
51
|
((0, sdk_gov_1.toBigInt)(payload.feeInterest) + sdk_gov_1.PERCENTAGE_FACTOR) *
|
|
52
52
|
sdk_gov_1.PERCENTAGE_DECIMALS) /
|
|
53
53
|
sdk_gov_1.RAY);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SupportedContract } from "@gearbox-protocol/sdk-gov";
|
|
2
|
+
import { Asset } from "./assets";
|
|
2
3
|
import { EVMTx, EVMTxProps } from "./eventOrTx";
|
|
3
4
|
export interface TxSerialized {
|
|
4
|
-
type: "TxAddLiquidity" | "TxRemoveLiquidity" | "TxSwap" | "TxAddCollateral" | "TxIncreaseBorrowAmount" | "TxDecreaseBorrowAmount" | "TxOpenAccount" | "TxRepayAccount" | "TxCloseAccount" | "TxApprove" | "TxOpenMultitokenAccount" | "TxClaimReward" | "TxClaimNFT" | "TxClaimGearRewards" | "TxEnableTokens";
|
|
5
|
+
type: "TxAddLiquidity" | "TxRemoveLiquidity" | "TxSwap" | "TxAddCollateral" | "TxIncreaseBorrowAmount" | "TxDecreaseBorrowAmount" | "TxOpenAccount" | "TxRepayAccount" | "TxCloseAccount" | "TxApprove" | "TxOpenMultitokenAccount" | "TxClaimReward" | "TxClaimNFT" | "TxClaimGearRewards" | "TxEnableTokens" | "TxUpdateQuota";
|
|
5
6
|
content: string;
|
|
6
7
|
}
|
|
7
8
|
export declare class TxSerializer {
|
|
@@ -190,4 +191,17 @@ export declare class TxEnableTokens extends EVMTx {
|
|
|
190
191
|
toString(): string;
|
|
191
192
|
serialize(): TxSerialized;
|
|
192
193
|
}
|
|
194
|
+
interface TxUpdateQuotaProps extends EVMTxProps {
|
|
195
|
+
updatedQuotas: Array<Asset>;
|
|
196
|
+
underlyingToken: string;
|
|
197
|
+
creditManager: string;
|
|
198
|
+
}
|
|
199
|
+
export declare class TxUpdateQuota extends EVMTx {
|
|
200
|
+
readonly updatedQuotas: Array<Asset>;
|
|
201
|
+
readonly underlyingToken: string;
|
|
202
|
+
readonly creditManager: string;
|
|
203
|
+
constructor(opts: TxUpdateQuotaProps);
|
|
204
|
+
toString(): string;
|
|
205
|
+
serialize(): TxSerialized;
|
|
206
|
+
}
|
|
193
207
|
export {};
|
package/lib/core/transactions.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TxEnableTokens = exports.TxApprove = exports.TxCloseAccount = exports.TxRepayAccount = exports.TxClaimGearRewards = exports.TxClaimNFT = exports.TxClaimReward = exports.TxOpenMultitokenAccount = exports.TxOpenAccount = exports.TxDecreaseBorrowAmount = exports.TxIncreaseBorrowAmount = exports.TxAddCollateral = exports.TXSwap = exports.TxRemoveLiquidity = exports.TxAddLiquidity = exports.TxSerializer = void 0;
|
|
3
|
+
exports.TxUpdateQuota = exports.TxEnableTokens = exports.TxApprove = exports.TxCloseAccount = exports.TxRepayAccount = exports.TxClaimGearRewards = exports.TxClaimNFT = exports.TxClaimReward = exports.TxOpenMultitokenAccount = exports.TxOpenAccount = exports.TxDecreaseBorrowAmount = exports.TxIncreaseBorrowAmount = exports.TxAddCollateral = exports.TXSwap = exports.TxRemoveLiquidity = exports.TxAddLiquidity = exports.TxSerializer = void 0;
|
|
4
4
|
const sdk_gov_1 = require("@gearbox-protocol/sdk-gov");
|
|
5
5
|
const contractsRegister_1 = require("../contracts/contractsRegister");
|
|
6
6
|
const formatter_1 = require("../utils/formatter");
|
|
7
|
+
const math_1 = require("../utils/math");
|
|
7
8
|
const eventOrTx_1 = require("./eventOrTx");
|
|
8
9
|
class TxSerializer {
|
|
9
10
|
static serialize(items) {
|
|
@@ -43,6 +44,8 @@ class TxSerializer {
|
|
|
43
44
|
return new TxClaimGearRewards(params);
|
|
44
45
|
case "TxEnableTokens":
|
|
45
46
|
return new TxEnableTokens(params);
|
|
47
|
+
case "TxUpdateQuota":
|
|
48
|
+
return new TxUpdateQuota(params);
|
|
46
49
|
default:
|
|
47
50
|
throw new Error(`Unknown transaction for parsing: ${e.type}`);
|
|
48
51
|
}
|
|
@@ -470,3 +473,36 @@ class TxEnableTokens extends eventOrTx_1.EVMTx {
|
|
|
470
473
|
}
|
|
471
474
|
}
|
|
472
475
|
exports.TxEnableTokens = TxEnableTokens;
|
|
476
|
+
class TxUpdateQuota extends eventOrTx_1.EVMTx {
|
|
477
|
+
updatedQuotas;
|
|
478
|
+
underlyingToken;
|
|
479
|
+
creditManager;
|
|
480
|
+
constructor(opts) {
|
|
481
|
+
super({
|
|
482
|
+
block: opts.block,
|
|
483
|
+
txHash: opts.txHash,
|
|
484
|
+
txStatus: opts.txStatus,
|
|
485
|
+
timestamp: opts.timestamp,
|
|
486
|
+
});
|
|
487
|
+
this.updatedQuotas = opts.updatedQuotas;
|
|
488
|
+
this.creditManager = opts.creditManager;
|
|
489
|
+
this.underlyingToken = opts.underlyingToken;
|
|
490
|
+
}
|
|
491
|
+
toString() {
|
|
492
|
+
const [, underlyingDecimals] = (0, sdk_gov_1.extractTokenData)(this.underlyingToken);
|
|
493
|
+
const quota = this.updatedQuotas.map(({ token, balance }) => {
|
|
494
|
+
const [tokenSymbol] = (0, sdk_gov_1.extractTokenData)(token);
|
|
495
|
+
const sign = balance < 0 ? "-" : "";
|
|
496
|
+
const amountString = (0, formatter_1.formatBN)(math_1.BigIntMath.abs(balance), underlyingDecimals || 18);
|
|
497
|
+
return `${tokenSymbol} by ${sign}${amountString}`;
|
|
498
|
+
});
|
|
499
|
+
return `Credit account ${(0, contractsRegister_1.getContractName)(this.creditManager)} quota updated: ${quota.join("; ")}`;
|
|
500
|
+
}
|
|
501
|
+
serialize() {
|
|
502
|
+
return {
|
|
503
|
+
type: "TxEnableTokens",
|
|
504
|
+
content: JSON.stringify(this),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
exports.TxUpdateQuota = TxUpdateQuota;
|
package/lib/utils/math.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export declare const nonNegativeBn: (v: bigint) => bigint;
|
|
|
7
7
|
export declare class BigIntMath {
|
|
8
8
|
static abs: (x: bigint) => bigint;
|
|
9
9
|
static toHexString: (x: bigint) => string;
|
|
10
|
+
static max: (a: bigint, b: bigint) => bigint;
|
|
11
|
+
static min: (a: bigint, b: bigint) => bigint;
|
|
10
12
|
}
|
package/lib/utils/math.js
CHANGED
|
@@ -41,5 +41,7 @@ exports.nonNegativeBn = nonNegativeBn;
|
|
|
41
41
|
class BigIntMath {
|
|
42
42
|
static abs = (x) => (x < 0n ? -x : x);
|
|
43
43
|
static toHexString = (x) => ethers_1.BigNumber.from(x).toHexString();
|
|
44
|
+
static max = (a, b) => (a > b ? a : b);
|
|
45
|
+
static min = (a, b) => (a < b ? a : b);
|
|
44
46
|
}
|
|
45
47
|
exports.BigIntMath = BigIntMath;
|